We can write proposals in Solidity and simulate them. Part of the simulation is also verification process, so we can be sure the state after proposal is correct.
Example: We initially deployed only 2 networks (Sepolia and Base Sepolia), therefore we needed to propose a change to whitelist another 2 chains we've added later.
The proposal is defined as Solidity script:
```/// @notice Sets up actions for the proposal
function _build() internal override {
/// STATICCALL -- not recorded for the run stage
address wormholeBridge = addresses.getAddress(
"WORMHOLE_BRIDGE_ADAPTER_PROXY"
);
WormholeTrustedSender.TrustedSender[]
memory trustedSenders = new WormholeTrustedSender.TrustedSender[](
2
);
trustedSenders[0] = WormholeTrustedSender.TrustedSender({
chainId: arbitrumSepoliaWormholeChainId,
addr: wormholeBridge
});
trustedSenders[1] = WormholeTrustedSender.TrustedSender({
chainId: optimismSepoliaWormholeChainId,
addr: wormholeBridge
});
WormholeBridgeAdapter(wormholeBridge).setTargetAddresses(
trustedSenders
);
WormholeBridgeAdapter(wormholeBridge).addTrustedSenders(trustedSenders);
}
/// @notice Executes the proposal actions.
function _run() internal override {
/// Call parent _run function to check if there are actions to execute
super._run();
address multisig = addresses.getAddress("GOV_MULTISIG");
/// CALLS -- mutative and recorded
_simulateActions(multisig);
}
/// @notice Validates the post-execution state.
function _validate() internal view override {
/// STATICCALL -- not recorded for the run stage
address wormholeBridge = addresses.getAddress(
"WORMHOLE_BRIDGE_ADAPTER_PROXY"
);
WormholeTrustedSender.TrustedSender[]
memory trustedSenders = new WormholeTrustedSender.TrustedSender[](
2
);
trustedSenders[0] = WormholeTrustedSender.TrustedSender({
chainId: arbitrumSepoliaWormholeChainId,
addr: wormholeBridge
});
trustedSenders[1] = WormholeTrustedSender.TrustedSender({
chainId: optimismSepoliaWormholeChainId,
addr: wormholeBridge
});
for (uint256 i = 0; i < trustedSenders.length; i++) {
require(
WormholeBridgeAdapter(wormholeBridge).isTrustedSender(
trustedSenders[i].chainId,
trustedSenders[i].addr
),
"Trusted sender not added"
);
}
}
Output of the proposal looks like this:
---------------- Proposal Description ----------------
Update trusted senders for the Wormhole Bridge Adapter
------------------ Proposal Actions ------------------
1). calling 0x48b02a246861abb10166d383787689793b1a51a6 with 0 eth and 8db0eb2400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000271300000000000000000000000048b02a246861abb10166d383787689793b1a51a6000000000000000000000000000000000000000000000000000000000000271500000000000000000000000048b02a246861abb10166d383787689793b1a51a6 data.
target: 0x48B02a246861Abb10166D383787689793b1A51a6
payload
0x8db0eb2400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000271300000000000000000000000048b02a246861abb10166d383787689793b1a51a6000000000000000000000000000000000000000000000000000000000000271500000000000000000000000048b02a246861abb10166d383787689793b1a51a6
2). calling 0x48b02a246861abb10166d383787689793b1a51a6 with 0 eth and d68d945b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000271300000000000000000000000048b02a246861abb10166d383787689793b1a51a6000000000000000000000000000000000000000000000000000000000000271500000000000000000000000048b02a246861abb10166d383787689793b1a51a6 data.
target: 0x48B02a246861Abb10166D383787689793b1A51a6
payload
0xd68d945b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000271300000000000000000000000048b02a246861abb10166d383787689793b1a51a6000000000000000000000000000000000000000000000000000000000000271500000000000000000000000048b02a246861abb10166d383787689793b1a51a6
Now, we can take that into our Safe, where we can simulate the batch of these 2 transactions:
And that was the first proposal that added 2 chains into our multichain stack.