From 669a606e30be695d45adb3d2ed05d18ea5e35117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Tue, 26 Mar 2024 11:29:41 +0100 Subject: [PATCH] WIP: parse multicall --- governance/helpers/multisig.js | 22 +++++++++++++++++++ governance/proposals/009-protocol-upgrade.js | 21 +++--------------- governance/proposals/010-test-multicall.js | 23 ++++++++++++++++++++ governance/scripts/multisig/submitTx.js | 21 +++++++++++------- 4 files changed, 61 insertions(+), 26 deletions(-) create mode 100644 governance/proposals/010-test-multicall.js diff --git a/governance/helpers/multisig.js b/governance/helpers/multisig.js index 439b91c79014..05117cad665c 100644 --- a/governance/helpers/multisig.js +++ b/governance/helpers/multisig.js @@ -4,6 +4,7 @@ const { getNetwork } = require('@unlock-protocol/hardhat-helpers') const multisigABI = require('@unlock-protocol/hardhat-helpers/dist/ABIs/multisig2.json') const multisigOldABI = require('@unlock-protocol/hardhat-helpers/dist/ABIs/multisig.json') const SafeApiKit = require('@safe-global/api-kit').default +const { encodeMultiSendData } = require('@safe-global/protocol-kit') // custom services URL for network not supported by Safe const safeServiceURLs = { @@ -190,6 +191,26 @@ const submitTxOldMultisig = async ({ safeAddress, tx, signer }) => { return nonce } +// pack multiple calls in a single multicall +const parseSafeMulticall = async (calls) => { + console.log(calls) + const metaTxs = calls.map( + ({ contractAddress, calldata = '0x', value = 0, operation = 0 }) => ({ + to: contractAddress, + value, + data: calldata, + // TODO? need to fetch if proxy or not ? + operation, // operation: 0 for CALL, 1 for DELEGATECALL + }) + ) + + const multicall = await encodeMultiSendData(metaTxs) + + // TODO: how to get multicall address (without a provider) + const multicallAddress = '' + return multicall +} + module.exports = { getProvider, getSafeAddress, @@ -202,4 +223,5 @@ module.exports = { getExpectedSigners, logError, getSafeService, + parseSafeMulticall, } diff --git a/governance/proposals/009-protocol-upgrade.js b/governance/proposals/009-protocol-upgrade.js index 0c5dee788958..3d22425532fd 100644 --- a/governance/proposals/009-protocol-upgrade.js +++ b/governance/proposals/009-protocol-upgrade.js @@ -5,7 +5,6 @@ const { ethers } = require('hardhat') const { UnlockV13 } = require('@unlock-protocol/contracts') const { networks } = require('@unlock-protocol/networks') -const { encodeMultiSendData } = require('@safe-global/protocol-kit') const { getProxyAdminAddress, @@ -16,6 +15,8 @@ const { abi: proxyAdminABI, } = require('@unlock-protocol/hardhat-helpers/dist/ABIs/ProxyAdmin.json') +const { parseSafeMulticall } = require('../helpers/multisig') + // TODO: move to hardhat-helpers const abiIConnext = [ { @@ -165,22 +166,6 @@ const parseCalls = async ({ unlockAddress, name, id }) => { return calls } -// -const parseForSafe = async (calls) => { - console.log(calls) - const metaTxs = calls.map(({ contractAddress, calldata }) => ({ - to: contractAddress, - value: 0, - data: calldata, - // TODO? need to fetch if proxy or not ? - operation: 0, // operation: 0 for CALL, 1 for DELEGATECALL - })) - - // pack calls in a single multicall - const multicall = await encodeMultiSendData(metaTxs) - return multicall -} - module.exports = async () => { const targetChains = Object.keys(networks) .filter((id) => Object.keys(deployedContracts).includes(id.toString())) @@ -229,7 +214,7 @@ module.exports = async () => { explainers[destChainId] = destCalls // parse calls for Safe - const moduleData = await parseForSafe(destCalls) + const moduleData = await parseSafeMulticall(destCalls) // add to the list of calls to be passed to the bridge bridgeCalls.push({ diff --git a/governance/proposals/010-test-multicall.js b/governance/proposals/010-test-multicall.js new file mode 100644 index 000000000000..bcb796ba606e --- /dev/null +++ b/governance/proposals/010-test-multicall.js @@ -0,0 +1,23 @@ +const { ethers, ZeroAddress } = require('ethers') +const { parseSafeMulticall } = require('../helpers/multisig') + +module.exports = async () => { + const calls = [ + { + contractAddress: ZeroAddress, + value: ethers.parseEther('0.0001'), + }, + { + contractAddress: ZeroAddress, + value: ethers.parseEther('0.0001'), + }, + ] + + // parse calls for Safe + const packedData = await parseSafeMulticall(calls) + console.log(packedData) + return { + proposalName: 'Test a multicall', + calls: { calldata: packedData }, + } +} diff --git a/governance/scripts/multisig/submitTx.js b/governance/scripts/multisig/submitTx.js index 9f805eed19dc..7bc8accdade9 100644 --- a/governance/scripts/multisig/submitTx.js +++ b/governance/scripts/multisig/submitTx.js @@ -46,14 +46,19 @@ async function main({ safeAddress, tx, signer }) { const safeSdk = await Safe.create({ ethAdapter, safeAddress }) const txs = !Array.isArray(tx) ? [tx] : tx - const explainer = txs - .map(({ functionName, functionArgs, explainer }) => - explainer - ? explainer - : `'${functionName}(${Object.values(functionArgs).toString()})'` - ) - .join(', ') - console.log(`Submitting txs: ${explainer}`) + let explainer = '' + try { + explainer = txs + .map(({ functionName, functionArgs, explainer }) => + explainer + ? explainer + : `'${functionName}(${Object.values(functionArgs).toString()})'` + ) + .join(', ') + console.log(`Submitting txs: ${explainer}`) + } catch (error) { + console.log(`Missing explainers...`) + } // parse transactions const transactions = await Promise.all(