-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add gha multisig #112
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
Merged
Merged
Changes from all commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
a8bfb15
feat: Add Safe multisig integration and bridge pause/unpause workflow
gfournierPro 8202b6d
feat: Enhance bridge pause/unpause workflow with dry run mode and tra…
gfournierPro 04ae516
fix: Correct path to bridge address in pause/unpause workflow
gfournierPro 4c7715e
fix: Update default dry run mode to true and correct RPC URL reference
gfournierPro 93f1fe6
feat: Add role management workflow for TOKEN_BRIDGE_ROLE in Safe mult…
gfournierPro 8c3dd28
feat: Add workflow for transferring admin role via Safe multisig
gfournierPro c2c2c55
refactor: Clean up import statements and improve code formatting acro…
gfournierPro 4e977b5
fix: error to trigger
gfournierPro 604cadf
fix: Correct RPC URL reference in role management workflow
gfournierPro 1a038c3
fix: Add missing fi statement for revokeRole transaction data prepara…
gfournierPro acd2c81
refactor: Enhance transaction details logging format in bridge pause …
gfournierPro 055a2e1
fix: add error to trigger
gfournierPro fb4a89b
fix: Correct reference to RPC URL in propose-bridge-to-safe job
gfournierPro ca0b55c
refactor: Simplify initialization data encoding in deploy function
gfournierPro 7a1756a
fix: Add missing fi statement to complete transaction creation for br…
gfournierPro 5e04c92
fix: Use compact JSON output for transaction creation in admin transf…
gfournierPro 7a55eb4
style: Improve code formatting and readability across multiple files
gfournierPro 3c0f1be
style: Refactor code for improved readability and formatting across m…
gfournierPro 4a62de4
Merge branch 'fix/formating' into feat/add-gha-multisig
gfournierPro 80e472e
style: Improve code formatting and readability across multiple files
gfournierPro 773ba33
Merge branch 'main' into feat/add-gha-multisig
gfournierPro d8e72cb
style: Update workflow to manage contract roles via Safe multisig wit…
gfournierPro 4451f86
feat: Add workflow for managing contract roles via Safe multisig with…
gfournierPro e2d1d4f
fix: Apply suggestion from @Copilot
gfournierPro 88221d1
Merge branch 'main' into feat/add-gha-multisig
gfournierPro 3d691ce
refactor: Rename job steps to standardize transaction calldata prepar…
gfournierPro beca9f7
refactor: Remove transaction value from multisig transaction preparat…
gfournierPro f0b098a
refactor: Rename propose-to-safe jobs to propose-to-safe-tx for consi…
gfournierPro 3c3f6dc
refactor: Replace if-else with case statement for operation handling …
gfournierPro e37f2cb
refactor: Rename propose-token-contract-to-safe job to propose-token-…
gfournierPro 2f36cee
refactor: Consolidate propose-to-safe jobs and implement matrix strat…
gfournierPro af37061
refactor: Remove dry_run condition from propose-to-safe-tx jobs and p…
gfournierPro 4c8c2dc
refactor: Standardize dry-run input naming across workflow files
gfournierPro 20fb6ea
refactor: Update safe address reference from secrets to vars in trans…
gfournierPro 92c5aae
refactor: Add rpc-url output to prepare-transaction-calldata job and …
gfournierPro d6ad734
refactor: Add safe-proposer-private-key and safe-api-key outputs to p…
gfournierPro 0c4826e
refactor: Update outputs in bridge-pause-safe workflow to use secrets…
gfournierPro 7720b82
refactor: Update safe address reference from outputs to vars in propo…
gfournierPro 3a10076
refactor: Update safe address reference in propose-to-safe-tx job to …
gfournierPro 250ba30
refactor: Update propose-to-safe-tx job to use secrets for RPC and AP…
gfournierPro 4902dc3
refactor: Update propose-to-safe-tx job to inherit secrets for improv…
gfournierPro a36165e
refactor: Enhance propose-to-safe-tx job to inherit environment secre…
gfournierPro 03db832
refactor: Update propose-to-safe-tx job to bridge environment secrets…
gfournierPro ec71340
refactor: Update Node.js version in bridge-pause-safe workflow from 2…
gfournierPro e0bcbea
refactor: Update checkout reference in bridge-pause-safe workflow fro…
gfournierPro 05ea315
refactor: Update checkout step in bridge-pause-safe workflow to use s…
gfournierPro d118bbc
refactor: Simplify propose-to-safe-tx job by using reusable workflow …
gfournierPro a855f66
refactor: Update propose-to-safe-tx job to use vars for safe address …
gfournierPro 20f75c7
refactor: Remove transfer-admin-role-safe workflow as it is no longer…
gfournierPro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| name: Bridge Pause/Unpause via Safe Multisig | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| operation: | ||
| description: 'Pause operation to perform' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - pause-bridge | ||
| - unpause-bridge | ||
| - pause-outbound | ||
| - unpause-outbound | ||
| network: | ||
| description: 'Network to perform operation on' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - ethereum | ||
| - arbitrum | ||
| - sepolia | ||
| - arbitrum_sepolia | ||
| default: sepolia | ||
| dry-run: | ||
| description: 'Dry run mode (only prepare and display transaction, do not propose to Safe)' | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
|
|
||
| jobs: | ||
| prepare-transaction-calldata: | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ inputs.network }} | ||
| outputs: | ||
| transaction-data: ${{ steps.prepare.outputs.transaction-data }} | ||
| safe-address: ${{ steps.prepare.outputs.safe-address }} | ||
| bridge-address: ${{ steps.prepare.outputs.bridge-address }} | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Install Foundry | ||
| uses: foundry-rs/foundry-toolchain@v1 | ||
| with: | ||
| version: stable | ||
| cache: true | ||
|
|
||
| - name: Prepare transaction calldata | ||
| id: prepare | ||
| env: | ||
| CHAIN: ${{ inputs.network }} | ||
| run: | | ||
| # Get bridge address from config | ||
| BRIDGE_ADDRESS=$(jq -r ".chains.${CHAIN}.iexecLayerZeroBridgeAddress" config/config.json) | ||
| echo "bridge-address=$BRIDGE_ADDRESS" >> $GITHUB_OUTPUT | ||
|
|
||
| # Determine the function selector and name based on operation | ||
| case "${{ inputs.operation }}" in | ||
| "pause-bridge") | ||
| TRANSACTION_DATA=$(cast calldata "pause()") | ||
| FUNCTION_NAME="pause()" | ||
| ;; | ||
| "unpause-bridge") | ||
| TRANSACTION_DATA=$(cast calldata "unpause()") | ||
| FUNCTION_NAME="unpause()" | ||
| ;; | ||
| "pause-outbound") | ||
| TRANSACTION_DATA=$(cast calldata "pauseOutboundTransfers()") | ||
| FUNCTION_NAME="pauseOutboundTransfers()" | ||
| ;; | ||
| "unpause-outbound") | ||
| TRANSACTION_DATA=$(cast calldata "unpauseOutboundTransfers()") | ||
| FUNCTION_NAME="unpauseOutboundTransfers()" | ||
| ;; | ||
| esac | ||
|
|
||
| echo "transaction-data=$TRANSACTION_DATA" >> $GITHUB_OUTPUT | ||
| echo "safe-address=${{ vars.SAFE_ADDRESS }}" >> $GITHUB_OUTPUT | ||
|
|
||
| # Display transaction details | ||
| echo "==========================================" | ||
| echo "Transaction Details" | ||
| echo "==========================================" | ||
| echo "Workflow Configuration:" | ||
| echo " • Network: ${{ inputs.network }}" | ||
| echo " • Operation: ${{ inputs.operation }}" | ||
| echo " • Function: $FUNCTION_NAME" | ||
| echo " • Safe Address: ${{ vars.SAFE_ADDRESS }}" | ||
| echo " • Dry Run: ${{ inputs.dry-run }}" | ||
| echo "" | ||
| echo "Transaction Details:" | ||
| echo " • Target: $BRIDGE_ADDRESS" | ||
| echo " • Value: 0 ETH" | ||
| echo " • Data: $TRANSACTION_DATA" | ||
| echo "" | ||
|
|
||
| if [ "${{ inputs.dry-run }}" == "true" ]; then | ||
| echo "✅ DRY RUN MODE: Transaction prepared successfully" | ||
| fi | ||
|
|
||
| propose-to-safe-tx: | ||
| needs: prepare-transaction-calldata | ||
| uses: ./.github/workflows/propose-safe-transaction.yml | ||
| secrets: | ||
| rpc-url: ${{ secrets.RPC_URL }} | ||
| safe-proposer-private-key: ${{ secrets.SAFE_PROPOSER_PRIVATE_KEY }} | ||
| safe-api-key: ${{ secrets.SAFE_API_KEY }} | ||
| with: | ||
| network: ${{ inputs.network }} | ||
| safe-address: ${{ needs.prepare-transaction-calldata.outputs.safe-address }} | ||
| transaction-to: ${{ needs.prepare-transaction-calldata.outputs.bridge-address }} | ||
| transaction-data: ${{ needs.prepare-transaction-calldata.outputs.transaction-data }} | ||
| dry-run: ${{ inputs.dry-run }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| name: Manage Contract Roles via Safe Multisig | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| operation: | ||
| description: 'Role operation to perform' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - grant | ||
| - revoke | ||
| role: | ||
| description: 'Role to grant or revoke' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - TOKEN_BRIDGE_ROLE | ||
| - PAUSER_ROLE | ||
| - UPGRADER_ROLE | ||
| default: TOKEN_BRIDGE_ROLE | ||
| network: | ||
| description: 'Network to perform operation on' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - ethereum | ||
| - arbitrum | ||
| - sepolia | ||
| - arbitrum_sepolia | ||
| default: sepolia | ||
| target_address: | ||
| description: 'Address to grant/revoke role to/from' | ||
| required: true | ||
| type: string | ||
| dry-run: | ||
| description: 'Dry run mode (only prepare and display transaction, do not propose to Safe)' | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
|
|
||
| jobs: | ||
| prepare-transaction-calldata: | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ inputs.network }} | ||
| outputs: | ||
| transactions: ${{ steps.prepare.outputs.transactions }} | ||
| safe-address: ${{ steps.prepare.outputs.safe-address }} | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Install Foundry | ||
| uses: foundry-rs/foundry-toolchain@v1 | ||
| with: | ||
| version: stable | ||
| cache: true | ||
|
|
||
| - name: Prepare transaction calldata | ||
| id: prepare | ||
| env: | ||
| CHAIN: ${{ inputs.network }} | ||
| ROLE_NAME: ${{ inputs.role }} | ||
| run: | | ||
| # Determine which contract to use based on role and network config | ||
| APPROVAL_REQUIRED=$(jq -r ".chains.${CHAIN}.approvalRequired" config/config.json) | ||
| BRIDGE_ADDRESS=$(jq -r ".chains.${CHAIN}.iexecLayerZeroBridgeAddress" config/config.json) | ||
|
|
||
| if [ "$APPROVAL_REQUIRED" = "true" ]; then | ||
| TOKEN_CONTRACT=$(jq -r ".chains.${CHAIN}.rlcLiquidityUnifierAddress" config/config.json) | ||
| else | ||
| TOKEN_CONTRACT=$(jq -r ".chains.${CHAIN}.rlcCrosschainTokenAddress" config/config.json) | ||
| fi | ||
|
|
||
| # Calculate role hash: keccak256("ROLE_NAME") | ||
| ROLE_HASH=$(cast keccak "$ROLE_NAME") | ||
|
|
||
| # Determine the function selector and encode calldata | ||
| case "${{ inputs.operation }}" in | ||
| grant) | ||
| TRANSACTION_DATA=$(cast calldata "grantRole(bytes32,address)" "$ROLE_HASH" "${{ inputs.target_address }}") | ||
| FUNCTION_NAME="grantRole(bytes32,address)" | ||
| ;; | ||
| revoke) | ||
| TRANSACTION_DATA=$(cast calldata "revokeRole(bytes32,address)" "$ROLE_HASH" "${{ inputs.target_address }}") | ||
| FUNCTION_NAME="revokeRole(bytes32,address)" | ||
| ;; | ||
| *) | ||
| echo "❌ Error: Unknown operation ${{ inputs.operation }}" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| # Prepare transactions array based on role type | ||
| TRANSACTIONS='[]' | ||
|
|
||
| case "$ROLE_NAME" in | ||
| TOKEN_BRIDGE_ROLE) | ||
| # TOKEN_BRIDGE_ROLE is only on token contract (RLCLiquidityUnifier or RLCCrosschainToken) | ||
| TRANSACTIONS=$(echo "$TRANSACTIONS" | jq -c --arg to "$TOKEN_CONTRACT" --arg data "$TRANSACTION_DATA" \ | ||
| '. += [{"to": $to, "data": $data, "contract": "token"}]') | ||
| ;; | ||
| PAUSER_ROLE) | ||
| # PAUSER_ROLE is only on bridge contract | ||
| TRANSACTIONS=$(echo "$TRANSACTIONS" | jq -c --arg to "$BRIDGE_ADDRESS" --arg data "$TRANSACTION_DATA" \ | ||
| '. += [{"to": $to, "data": $data, "contract": "bridge"}]') | ||
| ;; | ||
| UPGRADER_ROLE) | ||
| # UPGRADER_ROLE is on both bridge and token contracts | ||
| # Add transaction for token contract | ||
| TRANSACTIONS=$(echo "$TRANSACTIONS" | jq -c --arg to "$TOKEN_CONTRACT" --arg data "$TRANSACTION_DATA" \ | ||
| '. += [{"to": $to, "data": $data, "contract": "token"}]') | ||
| # Add transaction for bridge contract | ||
| TRANSACTIONS=$(echo "$TRANSACTIONS" | jq -c --arg to "$BRIDGE_ADDRESS" --arg data "$TRANSACTION_DATA" \ | ||
| '. += [{"to": $to, "data": $data, "contract": "bridge"}]') | ||
| ;; | ||
| *) | ||
| echo "❌ Error: Unknown role $ROLE_NAME" | ||
| '. += [{"to": $to, "data": $data, "contract": "bridge"}]') | ||
| ;; | ||
| esac | ||
|
|
||
| echo "transactions=$(echo $TRANSACTIONS | jq -c .)" >> $GITHUB_OUTPUT | ||
| echo "safe-address=${{ vars.SAFE_ADDRESS }}" >> $GITHUB_OUTPUT | ||
|
|
||
| # Display transaction details for dry-run or verification | ||
| echo "==========================================" | ||
| echo "Transaction Details" | ||
| echo "==========================================" | ||
| echo "Workflow Configuration:" | ||
| echo " • Network: ${{ inputs.network }}" | ||
| echo " • Role: $ROLE_NAME" | ||
| echo " • Operation: ${{ inputs.operation }}" | ||
| echo " • Function: $FUNCTION_NAME" | ||
| echo " • Safe Address: ${{ vars.SAFE_ADDRESS }}" | ||
| echo " • Dry Run: ${{ inputs.dry-run }}" | ||
| echo "" | ||
| echo "────────────────────────────────────────────────────────────────────────────────" | ||
| echo "" | ||
|
|
||
| # Display each transaction | ||
| TX_COUNT=$(echo $TRANSACTIONS | jq 'length') | ||
| for i in $(seq 0 $(($TX_COUNT - 1))); do | ||
| TX=$(echo $TRANSACTIONS | jq -r ".[$i]") | ||
| TX_TO=$(echo $TX | jq -r '.to') | ||
| TX_DATA=$(echo $TX | jq -r '.data') | ||
| TX_CONTRACT=$(echo $TX | jq -r '.contract') | ||
|
|
||
| echo "Transaction #$((i + 1)) - ${TX_CONTRACT^} Contract:" | ||
| echo " • Target: $TX_TO" | ||
| echo " • Address: ${{ inputs.target_address }}" | ||
| echo " • Role Name: $ROLE_NAME" | ||
| echo " • Role Hash: $ROLE_HASH" | ||
| echo " • Value: 0 ETH" | ||
| echo " • Data: $TX_DATA" | ||
| echo "" | ||
| done | ||
|
|
||
| echo "────────────────────────────────────────────────────────────────────────────────" | ||
| echo "" | ||
|
|
||
| if [ "${{ inputs.dry-run }}" == "true" ]; then | ||
| echo "✅ DRY RUN MODE: Transaction(s) prepared successfully" | ||
| echo "ℹ️ These transaction(s) would be proposed to Safe multisig" | ||
| echo "ℹ️ Re-run with dry-run=false to actually propose to Safe" | ||
| fi | ||
|
|
||
| propose-to-safe-tx: | ||
| needs: prepare-transaction-calldata | ||
| strategy: | ||
| matrix: | ||
| transaction: ${{ fromJson(needs.prepare-transaction-calldata.outputs.transactions) }} | ||
| uses: ./.github/workflows/propose-safe-transaction.yml | ||
| secrets: | ||
| rpc-url: ${{ secrets.RPC_URL }} | ||
| safe-proposer-private-key: ${{ secrets.SAFE_PROPOSER_PRIVATE_KEY }} | ||
| safe-api-key: ${{ secrets.SAFE_API_KEY }} | ||
| with: | ||
| network: ${{ inputs.network }} | ||
| safe-address: ${{ needs.prepare-transaction-calldata.outputs.safe-address }} | ||
| transaction-to: ${{ matrix.transaction.to }} | ||
| transaction-data: ${{ matrix.transaction.data }} | ||
| dry-run: ${{ inputs.dry-run }} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| name: Propose Safe Transaction (Reusable) | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| network: | ||
| description: 'Network environment' | ||
| required: true | ||
| type: string | ||
| safe-address: | ||
| description: 'Safe multisig address' | ||
| required: true | ||
| type: string | ||
| transaction-to: | ||
| description: 'Transaction target address' | ||
| required: true | ||
| type: string | ||
| transaction-data: | ||
| description: 'Transaction calldata' | ||
| required: true | ||
| type: string | ||
| transaction-value: | ||
| description: 'Transaction value in wei' | ||
| required: false | ||
| type: string | ||
| default: "0" | ||
| dry-run: | ||
| description: 'Dry run mode' | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
| secrets: | ||
| rpc-url: | ||
| description: 'RPC URL for the network' | ||
| required: true | ||
| safe-proposer-private-key: | ||
| description: 'Private key of the Safe proposer' | ||
| required: true | ||
| safe-api-key: | ||
| description: 'Safe API key' | ||
| required: true | ||
|
|
||
| jobs: | ||
| propose-transaction: | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ inputs.network }} | ||
| steps: | ||
| - name: Checkout Safe proposal repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: iExecBlockchainComputing/github-actions-workflows | ||
| path: .github-actions | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '22' | ||
|
|
||
| - name: Install dependencies | ||
| working-directory: .github-actions/propose-safe-multisig-tx | ||
| run: npm ci | ||
|
|
||
| - name: Build the action | ||
| working-directory: .github-actions/propose-safe-multisig-tx | ||
| run: npm run build | ||
|
|
||
| - name: Propose transaction to Safe | ||
| working-directory: .github-actions/propose-safe-multisig-tx | ||
| env: | ||
| SAFE_ADDRESS: ${{ inputs.safe-address }} | ||
| TRANSACTION_TO: ${{ inputs.transaction-to }} | ||
| TRANSACTION_VALUE: ${{ inputs.transaction-value }} | ||
| TRANSACTION_DATA: ${{ inputs.transaction-data }} | ||
| RPC_URL: ${{ secrets.rpc-url }} | ||
| SAFE_PROPOSER_PRIVATE_KEY: ${{ secrets.safe-proposer-private-key }} | ||
| SAFE_API_KEY: ${{ secrets.safe-api-key }} | ||
| DRY_RUN: ${{ inputs.dry-run }} | ||
| run: npm run propose |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
same