Cross-Chain Governance
To fully decentralize the maintenance and management of the protocol contracts, we use a cross-chain governance that allows for a DAO proposal to reach the Unlock contracts on all supported networks.
How it works
To reach other chains, calls emitted from the mainnet DAO go through the Connext bridge and are executed on the other side of the bridge, after a period of cooldown.
(Base) (destination chain)
DAO proposal > Connext Bridge > Safe multisig > wait for 2 days > Execution
The workflow is as follows
- A DAO proposal is created, containing at least 1 call aimed at a different network.
- If the vote succeeds, the DAO proposal is executed. All crosschain calls are sent to the Connext bridge(s).
- Each call crosses the bridge separately towards its destination on a specific chain.
- The call is received on the destination chain by a SAFE multisig configured with a special bridge receiver Zodiac plugin. This plugin only accepts calls emanating from the Connext bridge, from the DAO's Timelock contract.
- Once received, the call is held in the multisig for a cooldown period of 2 days during which it can be cancelled by the multisig signers.
- After the cooldown period, the call is ready to be executed by anyone (signer on the multisig or not).
NB: The cooldown period is useful to prevent malicious or errored calls from being executed if the bridge itself has been compromised.
Supported Networks
To work, this workflow requires the Connext bridge, SAFE contracts and Unlock Protocol to be deployed and active on the network.
At this point, the supported networks are:
Ethereum
Optimism
BNB Chain
Gnosis Chain
Polygon
Base
Arbitrum
Linea
Please refer to Connext's docs to identify which network could be added.
How to setup the multisig on the "remote" chain
On every receiving chain, we need a SAFE multisig configured with two Zodiac plugins, namely:
- one Zodiac Connext bridge receiver
- one Delay
Important note: we use a multisig here, but no signature is required for transactions to be executed. The Safe contracts are actually flexible enough to include the ability to execute transactions directly as long as they have been through pre-configured modules.
Using the Gnosis web UI
- Go to Apps > Zodiac
- Add the Delay module (cooldown : 2 days, expiration: 90 days)
- Add the Connext module (Origin sender address : DAO address, Origin domain ID: 6648936 - see list of Connext domains)
- Go to Connext module > write >
setTarget
with the Delay address - Get the Connext module address then remove the Connext module
- Go to Delay > write >
enableModule
with the Connext module address
Using scripts
- Deploy the Delay module contract (see this guide)
(NB: You can use the
deploy_multisig_mods
script in thesmart-contracts
folder to help you parse the commands) - Add the
delayMod
to thebridge.modules
object in thenetworks
package - Deploy the Connext module contract (see this guide) (NB: you can use the
deploy_multisig_mods
script to help you parse the commands) - Add the
connextMod
to thebridge.modules
object in thenetworks
package - Send the
proposals/enableModule.js
to the multisig on the chain to check settings and activate the module there - NB: Make sure that
delayMod.target
is set tosafe.address
andconnextMod.target
is set todelayMod.address
Now the multisig can receive calls from the bridge through the connextMod
that will pass the call to the delayMod
which will put it in cooldown.
Write a multichain DAO proposal
We have a parser for DAO proposals that relies on an object being formatted as follows:
return {
proposalName, // title of the proposal
calls: [
{
contractAddress: bridgeAddress, // the address of the Connext bridge
contractNameOrAbi: abiIConnext, // Connext Abi of `xcall`
functionName: 'xcall', // standard Connext function for bridge call
functionArgs: [
destDomainId, // the Domain ID of the receiving chain
destMultisigAddress, // the safe address on the receiving chain
ADDRESS_ZERO, // asset
ADDRESS_ZERO, // delegate
0, // amount
30, // slippage
moduleData, // the calldata to be executed on the receiving chain
],
},
],
}
Once the proposal is correctly parsed, we can send it to the DAO.
yarn hardhat gov:submit --gov-address <governor> --proposal <proposal-filepath> --network gnosis <arguments>
Here the <arguments>
passed to the cli as POSIT args are passed to the proposal script. See an example in proposals/006-cross-bridge-proposal.js
yarn hardhat gov:submit --gov-address 0xE85696a3419162452e6925816D8073374e4190b7 --proposal proposals/006-cross-bridge-proposal.js --network gnosis 137 0xfa2709Aa98F051c4190d70dE38F7c7A330c60ab7 0x2411336105D4451713d23B5156038A48569EcE3a
Executing a call
Once a call has passed the cooldown delay, it can be executed by anyone (the address submitting the transaction does not need to be a signer on the multisig) via the executeNextTx
in the Delay module.
The arguments to pass to the function are the ones that were passed in the original DAO proposal. You can also find them here in the TransactionAdded
event that was fired by the bridge transaction (example )
There is a script that allows execution of a call stored in Safe Zodiac Delay module
yarn hardhat safe:bridge:execute --bridge-tx <tx hash> --delay-mod <contract address> --network <network name>
bridge-tx
: the tx sent by the bridge to the multisig. This is used to unpack and parse args from the original call (example on the “receive” end)
delay-mod
: the address of the Zodiac Delay module of the Safe that contains the tx
Canceling a call
During the cooldown period, a call can be cancelled by the Safe multisig signers. That can prevent malicious or errored calls from being executed.
To cancel a call, you need to call setTxNonce
from the multisig with the value returned by queueNonce()
. That way, the nonce will increase past the malicious tx, making the queue appear empty.