-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add transfer admin role workflow and scripts for multi-chain su… #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c221857
2379869
07c4d7b
484c6be
266e94c
f83d5d7
2bbfac6
7328144
1707f23
d2c4479
ea6801f
fcc0607
34eb919
749a8bf
40ab8c3
9835548
6c65563
632d8ff
6853fef
2fb7dfb
122c285
5552f3e
8ad0628
dcced88
0fc947e
982a700
75528a0
8514c7e
9d1c452
42251ee
dfda2cd
2743dd4
a3c8e88
7931ece
b38d231
cef039a
e353cc0
b5229b9
a7254a8
2c3d917
4e62e76
66cf967
bb43519
5451587
59be92d
bf0f0c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| name: Transfer Default Admin Role | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| network: | ||
| description: 'Network to transfer admin role on' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - ethereum | ||
| - arbitrum | ||
| - sepolia | ||
| - arbitrum_sepolia | ||
| default: sepolia | ||
| new_default_admin_address: | ||
| description: 'New admin address' | ||
| required: true | ||
| type: string | ||
|
|
||
| jobs: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we sure we can transmit the ownership to the same wallet (multi-sig) address other all networks ? @zguesmi
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it's better to do each chain separately to avoid issues. For example if we use a multisig that is not available on a specific network. |
||
| # TODO: check if setup-matrix is needed | ||
| transfer-admin: | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ inputs.network }} | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Install Foundry | ||
| uses: foundry-rs/foundry-toolchain@v1 | ||
| with: | ||
| version: stable | ||
| cache: true | ||
|
|
||
| - name: Transfer default admin role | ||
| env: | ||
| ADMIN_PRIVATE_KEY: ${{ secrets.ADMIN_PRIVATE_KEY }} | ||
| CHAIN: ${{ inputs.network }} | ||
| RPC_URL: ${{ secrets.RPC_URL }} | ||
| NEW_DEFAULT_ADMIN: ${{ inputs.new_default_admin_address }} | ||
| run: make begin-default-admin-transfer | ||
gfournierPro marked this conversation as resolved.
Show resolved
Hide resolved
gfournierPro marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it could be nice to move run() function as the first function of each contracts
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| // SPDX-FileCopyrightText: 2025 IEXEC BLOCKCHAIN TECH <[email protected]> | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| pragma solidity ^0.8.22; | ||
|
|
||
| import {Script} from "forge-std/Script.sol"; | ||
| import {console} from "forge-std/console.sol"; | ||
| import {IAccessControlDefaultAdminRules} from | ||
| "@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol"; | ||
| import {ConfigLib} from "./lib/ConfigLib.sol"; | ||
| import {RLCLiquidityUnifier} from "../src/RLCLiquidityUnifier.sol"; | ||
| import {RLCCrosschainToken} from "../src/RLCCrosschainToken.sol"; | ||
| import {IexecLayerZeroBridge} from "../src/bridges/layerZero/IexecLayerZeroBridge.sol"; | ||
|
|
||
| /** | ||
| * @title BeginTransferAdminRole | ||
| * @dev Script to transfer the default admin role to a new admin address | ||
| * for all deployed smart contracts on the current chain. | ||
| */ | ||
| contract BeginTransferAdminRole is Script { | ||
| /** | ||
| * @notice Transfers the default admin role to a new admin for all contracts on the current chain | ||
| * @dev This function automatically detects which contracts are deployed on the current chain | ||
| * based on the configuration and transfers admin roles accordingly | ||
| */ | ||
| function run() external virtual { | ||
| address newAdmin = vm.envAddress("NEW_DEFAULT_ADMIN"); | ||
| string memory chain = vm.envString("CHAIN"); | ||
gfournierPro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| console.log("Starting admin role transfer on chain:", chain); | ||
| console.log("New admin address:", newAdmin); | ||
|
|
||
| ConfigLib.CommonConfigParams memory params = ConfigLib.readCommonConfig(chain); | ||
| vm.startBroadcast(); | ||
| beginTransferForAllContracts(params, newAdmin); | ||
| vm.stopBroadcast(); | ||
| } | ||
| /** | ||
| * @notice Validates that the new admin is different from the current admin | ||
| * @param currentDefaultAdmin The current admin address | ||
| * @param newAdmin The new admin address | ||
| */ | ||
|
|
||
| function validateAdminTransfer(address currentDefaultAdmin, address newAdmin) internal pure { | ||
| require(newAdmin != address(0), "BeginTransferAdminRole: new admin cannot be zero address"); | ||
| require( | ||
zguesmi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| newAdmin != currentDefaultAdmin, "BeginTransferAdminRole: New admin must be different from current admin" | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Begins the admin transfer process for all relevant contracts | ||
| * @param params The configuration parameters for the current chain | ||
| * @param newAdmin The new admin address | ||
| */ | ||
| function beginTransferForAllContracts(ConfigLib.CommonConfigParams memory params, address newAdmin) internal { | ||
| if (params.approvalRequired) { | ||
| beginTransfer(params.rlcLiquidityUnifierAddress, newAdmin, "RLCLiquidityUnifier"); | ||
| } else { | ||
| beginTransfer(params.rlcCrosschainTokenAddress, newAdmin, "RLCCrosschainToken"); | ||
| } | ||
| beginTransfer(params.iexecLayerZeroBridgeAddress, newAdmin, "IexecLayerZeroBridge"); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Transfers the default admin role for any contract implementing IAccessControlDefaultAdminRules | ||
| * @param contractAddress The address of the contract | ||
| * @param newAdmin The new admin address | ||
| * @param contractName The name of the contract for logging purposes | ||
| */ | ||
| function beginTransfer(address contractAddress, address newAdmin, string memory contractName) public virtual { | ||
| IAccessControlDefaultAdminRules contractInstance = IAccessControlDefaultAdminRules(contractAddress); | ||
|
|
||
| address currentAdmin = contractInstance.defaultAdmin(); | ||
| console.log("Current admin for", contractName, ":", currentAdmin); | ||
| validateAdminTransfer(currentAdmin, newAdmin); | ||
| contractInstance.beginDefaultAdminTransfer(newAdmin); | ||
| console.log("Admin transfer initiated for", contractName, "at:", contractAddress); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @title AcceptAdminRole | ||
| * @dev Script to accept the default admin role transfer for all contracts on the current chain. | ||
| * This script should be run by the new admin after the BeginTransferAdminRole script has been executed. | ||
| */ | ||
| contract AcceptAdminRole is Script { | ||
| /** | ||
| * @notice Accepts the default admin role transfer for all contracts on the current chain | ||
| * @dev This function should be called by the new admin to complete the transfer process | ||
| */ | ||
| function run() external virtual { | ||
| string memory chain = vm.envString("CHAIN"); | ||
| console.log("Accepting admin role transfer on chain:", chain); | ||
| ConfigLib.CommonConfigParams memory params = ConfigLib.readCommonConfig(chain); | ||
|
|
||
| vm.startBroadcast(); | ||
| acceptAdminRoleTransfer(params); | ||
| vm.stopBroadcast(); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Accepts the default admin role transfer for all contracts on the current chain | ||
| * @dev This function should be called by the new admin to complete the transfer process | ||
| */ | ||
| function acceptAdminRoleTransfer(ConfigLib.CommonConfigParams memory params) internal { | ||
| if (params.approvalRequired) { | ||
| acceptContractAdmin(params.rlcLiquidityUnifierAddress, "RLCLiquidityUnifier"); | ||
| } else { | ||
| acceptContractAdmin(params.rlcCrosschainTokenAddress, "RLCCrosschainToken"); | ||
| } | ||
| acceptContractAdmin(params.iexecLayerZeroBridgeAddress, "IexecLayerZeroBridge"); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Accepts the default admin role transfer for any contract implementing IAccessControlDefaultAdminRules | ||
| * @param contractAddress The address of the contract | ||
| * @param contractName The name of the contract for logging purposes | ||
| */ | ||
| function acceptContractAdmin(address contractAddress, string memory contractName) internal virtual { | ||
| console.log("Accepting admin role for", contractName, "at:", contractAddress); | ||
| IAccessControlDefaultAdminRules contractInstance = IAccessControlDefaultAdminRules(contractAddress); | ||
| contractInstance.acceptDefaultAdminTransfer(); | ||
| console.log("New admin for", contractName, ":", contractInstance.defaultAdmin()); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use mainnets & testnets here