Research / Lido on BNB Chain bridges
Lido's governance on Ethereum sends messages to its executor on BNB Chain through bridge adapters: the controller allows four today (LayerZero, Hyperlane, CCIP and Wormhole), and a proposal in the forum thread would remove Wormhole and leave three. This page reads, at fixed blocks, what verifies a message on the LayerZero, Hyperlane and CCIP routes today, who can change it, and with what delay. It asks whether this is the intended setting; it does not say it is wrong. Every row can be replayed with a public RPC and no key.
| Route | What verifies a message today | Who can change it | Delay |
|---|---|---|---|
| LayerZero | All 4 verifiers (DVNs) must sign, after 15 confirmations. It is the default configuration: the Lido adapter has none of its own. The DVN names come from the LayerZero metadata API: Horizen, Nethermind, Canary, LayerZero Labs. | A OneSig contract owns the endpoint and the receive library: threshold 5, 7 signers. By simulation it can replace the default verifier set for this route; the Lido executor cannot (LZ_Unauthorized). | None found |
| Hyperlane | The Mailbox default applies (the adapter has no ISM of its own). For messages from Ethereum: a multisig of 9 validators, threshold 6, behind a pause switch. | A Safe owns the Mailbox and the routing module: threshold 6, 10 owners, no module. By simulation it can replace the default ISM and the Ethereum route. A separate account owns the pause switch and can pause the route. | None found |
| CCIP | Chainlink's network, through Router 1.2.0 and the off-ramps registered for Ethereum. How that network is composed was not read. | A timelock owns the router. By simulation, a call to change the registered off-ramps works from the timelock, and a bypass call through the timelock also works. | 3 hours through the timelock. Through the bypass call, no delay found (simulated). |
| Lido executor (receiving side) | The controller requires 3 confirmations out of the 4 adapters it allows, Wormhole included. The proposal in the forum thread would change this to 2 of 3; it has not been executed. | The executor owns the controller, the bridged wstETH and the NTT Manager on BNB Chain. It obeys Lido's governance on Ethereum. | 0 seconds after a message arrives; no guardian |
eth_call (cast call), and every simulation is an eth_call with a --from address: nothing is signed or sent, no key is used.0x...dEaD, which must revert. A call that works from the holder and reverts from the witness shows that the holder is the one the contract lets act.owner, setDelegate, setConfig and transferOwnership: none is present.127,626,770 to 127,626,952, 14 October 2026, 16:29 to 16:30 UTC127,631,186 to 127,631,211, 14 October 2026, 17:02 UTC UTC26,191,915, 14 October 2026, about 16:23 UTCEach call sends nothing and needs no key. The commands read the latest block, not the blocks above, so a value can differ if something changed since.
Expect: 3 confirmations required, 4 adapters allowed (the Wormhole adapter included), an owner that is the executor, no guardian, a delay of 0 seconds.
cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "getConfigurationByChain(uint256)((uint8,uint120))" 1 --rpc-url https://bsc-rpc.publicnode.com cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "getReceiverBridgeAdaptersByChain(uint256)(address[])" 1 --rpc-url https://bsc-rpc.publicnode.com cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "guardian()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d "getDelay()(uint256)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d "getGuardian()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d "getEthereumGovernanceExecutor()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x6981F5621691CBfE3DdD524dE71076b79F0A0278 "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com
Expect: each call reverts. A revert means the function does not exist on the adapter, so there is no admin call on the Lido side that changes what the adapter accepts.
cast call 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0xCd867B440c726461e5fAbe8d3a050b2f8701C230 "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x15AD245133568c2498c7dA0cf2204A03b0e9b98A "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 "setDelegate(address)" 0x000000000000000000000000000000000000dEaD --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD cast call 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 "setConfig(address,address,(uint32,uint32,bytes)[])" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "[]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD
Expect: 15 confirmations and 4 required verifiers (all four); no configuration of the adapter's own; the owner of the endpoint and of the receive library is a OneSig contract with threshold 5 and 7 signers.
cast call 0x1a44076050125825900e736c501f859c50fE728c "getReceiveLibrary(address,uint32)(address,bool)" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 30101 --rpc-url https://bsc-rpc.publicnode.com cast call 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "getUlnConfig(address,uint32)((uint64,uint8,uint8,uint8,address[],address[]))" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 30101 --rpc-url https://bsc-rpc.publicnode.com cast call 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "getAppUlnConfig(address,uint32)((uint64,uint8,uint8,uint8,address[],address[]))" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 30101 --rpc-url https://bsc-rpc.publicnode.com cast call 0x1a44076050125825900e736c501f859c50fE728c "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0xEFACCEc3B9661b5ff62418243c013f2F58Ce1350 "threshold()(uint256)" --rpc-url https://bsc-rpc.publicnode.com cast call 0xEFACCEc3B9661b5ff62418243c013f2F58Ce1350 "getSigners()(address[])" --rpc-url https://bsc-rpc.publicnode.com
Expect: the OneSig call returns and the witness reverts with Ownable. On the endpoint, setConfig returns from the adapter itself and reverts with LZ_Unauthorized from the Lido executor and from the witness.
cast call 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "setDefaultUlnConfigs((uint32,(uint64,uint8,uint8,uint8,address[],address[]))[])" "[(30101,(15,1,0,0,[0x247624e2143504730aeC22912ed41F092498bEf2],[]))]" --rpc-url https://bsc-rpc.publicnode.com --from 0xEFACCEc3B9661b5ff62418243c013f2F58Ce1350 cast call 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "setDefaultUlnConfigs((uint32,(uint64,uint8,uint8,uint8,address[],address[]))[])" "[(30101,(15,1,0,0,[0x247624e2143504730aeC22912ed41F092498bEf2],[]))]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD cast call 0x1a44076050125825900e736c501f859c50fE728c "setConfig(address,address,(uint32,uint32,bytes)[])" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "[]" --rpc-url https://bsc-rpc.publicnode.com --from 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d cast call 0x1a44076050125825900e736c501f859c50fE728c "setConfig(address,address,(uint32,uint32,bytes)[])" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "[]" --rpc-url https://bsc-rpc.publicnode.com --from 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 cast call 0x1a44076050125825900e736c501f859c50fE728c "setConfig(address,address,(uint32,uint32,bytes)[])" 0xc934433f4c433Cf80DE6fB65fd70C7a650D8a408 0xB217266c3A98C8B2709Ee26836C98cf12f6cCEC1 "[]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD
Expect: the adapter has no ISM of its own, so the Mailbox default applies; an aggregation of a pause switch and a routing module; for Ethereum, two multisig modules (1 of 2 must accept), each reading the same 9 validators with threshold 6; the Mailbox owner is a Safe with threshold 6, 10 owners and no module.
cast call 0xCd867B440c726461e5fAbe8d3a050b2f8701C230 "interchainSecurityModule()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4 "defaultIsm()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4 "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x7379D7bB2ccA68982E467632B6554fD4e72e9431 "getThreshold()(uint256)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x7379D7bB2ccA68982E467632B6554fD4e72e9431 "getOwners()(address[])" --rpc-url https://bsc-rpc.publicnode.com cast call 0x7379D7bB2ccA68982E467632B6554fD4e72e9431 "getModulesPaginated(address,uint256)(address[],address)" 0x0000000000000000000000000000000000000001 10 --rpc-url https://bsc-rpc.publicnode.com cast call 0x9Ec844699657B983C529382B0f00A605a53ED600 "modulesAndThreshold(bytes)(address[],uint8)" 0x --rpc-url https://bsc-rpc.publicnode.com cast call 0xc4C211467AF655E256b7e5F06F01CDb7b1722d75 "module(uint32)(address)" 1 --rpc-url https://bsc-rpc.publicnode.com cast call 0x2457cc3BA3eBc56D25662eFe32790D111BDA4122 "modulesAndThreshold(bytes)(address[],uint8)" 0x --rpc-url https://bsc-rpc.publicnode.com cast call 0x0953a7Ed2179ecD5BA896e20C85Fe1a5da75cDa9 "validatorsAndThreshold(bytes)(address[],uint8)" 0x --rpc-url https://bsc-rpc.publicnode.com cast call 0x11Da591a35ceEF6545059C35fd033AbA5D3e251B "validatorsAndThreshold(bytes)(address[],uint8)" 0x --rpc-url https://bsc-rpc.publicnode.com cast call 0x76cF9DdF1141806F40f73250d1e9D788eF3b045B "paused()(bool)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x76cF9DdF1141806F40f73250d1e9D788eF3b045B "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com
Expect: each call from the Safe (or from the owner of the pause switch, read just above into PAUSE_OWNER) returns; the same call from the witness account reverts with Ownable.
cast call 0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4 "setDefaultIsm(address)" 0x2457cc3BA3eBc56D25662eFe32790D111BDA4122 --rpc-url https://bsc-rpc.publicnode.com --from 0x7379D7bB2ccA68982E467632B6554fD4e72e9431 cast call 0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4 "setDefaultIsm(address)" 0x2457cc3BA3eBc56D25662eFe32790D111BDA4122 --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD cast call 0xc4C211467AF655E256b7e5F06F01CDb7b1722d75 "set(uint32,address)" 1 0x2457cc3BA3eBc56D25662eFe32790D111BDA4122 --rpc-url https://bsc-rpc.publicnode.com --from 0x7379D7bB2ccA68982E467632B6554fD4e72e9431 cast call 0xc4C211467AF655E256b7e5F06F01CDb7b1722d75 "set(uint32,address)" 1 0x2457cc3BA3eBc56D25662eFe32790D111BDA4122 --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD PAUSE_OWNER=$(cast call 0x76cF9DdF1141806F40f73250d1e9D788eF3b045B "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com) cast call 0x76cF9DdF1141806F40f73250d1e9D788eF3b045B "pause()" --rpc-url https://bsc-rpc.publicnode.com --from $PAUSE_OWNER cast call 0x76cF9DdF1141806F40f73250d1e9D788eF3b045B "pause()" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD
Expect: Router 1.2.0 owned by a timelock whose minimum delay is 10800 seconds (3 hours).
cast call 0x15AD245133568c2498c7dA0cf2204A03b0e9b98A "CCIP_ROUTER()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x34B03Cb9086d7D758AC55af71584F81A598759FE "typeAndVersion()(string)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x34B03Cb9086d7D758AC55af71584F81A598759FE "owner()(address)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x34B03Cb9086d7D758AC55af71584F81A598759FE "getOffRamps()((uint64,address)[])" --rpc-url https://bsc-rpc.publicnode.com cast call 0x950350b073956bD1d22bB1C18c4d45263b5Aa3a5 "getMinDelay()(uint256)" --rpc-url https://bsc-rpc.publicnode.com cast call 0x950350b073956bD1d22bB1C18c4d45263b5Aa3a5 "BYPASSER_ROLE()(bytes32)" --rpc-url https://bsc-rpc.publicnode.com
Expect: applyRampUpdates returns from the timelock and reverts from the witness; a bypass call through the timelock returns from the account used in the simulation and reverts from the witness with a missing-role error. The bypass call does not wait for the delay.
cast call 0x34B03Cb9086d7D758AC55af71584F81A598759FE "applyRampUpdates((uint64,address)[],(uint64,address)[],(uint64,address)[])" "[]" "[]" "[(5009297550715157269,0x000000000000000000000000000000000000dEaD)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x950350b073956bD1d22bB1C18c4d45263b5Aa3a5 cast call 0x34B03Cb9086d7D758AC55af71584F81A598759FE "applyRampUpdates((uint64,address)[],(uint64,address)[],(uint64,address)[])" "[]" "[]" "[(5009297550715157269,0x000000000000000000000000000000000000dEaD)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD cast call 0x950350b073956bD1d22bB1C18c4d45263b5Aa3a5 "bypasserExecuteBatch((address,uint256,bytes)[])" "[(0x34B03Cb9086d7D758AC55af71584F81A598759FE,0,0xda5fcac80000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000045849994fc9c7b15000000000000000000000000000000000000000000000000000000000000dead)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x07712e9618f20843ECDa8E61a6eE64F6Cef76ab4 cast call 0x950350b073956bD1d22bB1C18c4d45263b5Aa3a5 "bypasserExecuteBatch((address,uint256,bytes)[])" "[(0x34B03Cb9086d7D758AC55af71584F81A598759FE,0,0xda5fcac80000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000045849994fc9c7b15000000000000000000000000000000000000000000000000000000000000dead)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD
Expect: both calls return from the executor and both revert from the witness (0x...dEaD) with Ownable. This shows who can run these calls; it does not show that a vote has been scheduled.
cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "updateConfirmations((uint256,uint8)[])" "[(1,2)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "disallowReceiverBridgeAdapters((address,uint256[])[])" "[(0xBb1E43408BbF2C767Ff3Bd5bBC34E183CC1Ef119,[1])]" --rpc-url https://bsc-rpc.publicnode.com --from 0x8E5175D17f74d1D512de59b2f5d5A5d8177A123d cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "updateConfirmations((uint256,uint8)[])" "[(1,2)]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD cast call 0x40C4464fCa8caCd550C33B39d674fC257966022F "disallowReceiverBridgeAdapters((address,uint256[])[])" "[(0xBb1E43408BbF2C767Ff3Bd5bBC34E183CC1Ef119,[1])]" --rpc-url https://bsc-rpc.publicnode.com --from 0x000000000000000000000000000000000000dEaD
This is the longer form of a reply in the Lido research forum thread on the proposal to remove the Wormhole adapter: The thread on the Lido research forum. The question is whether the setting above is the one intended; this page does not say that it is wrong.
Built 2026-10-15 21:09 UTC from facts read directly from the chains. Not an audit, not investment advice. Research · Method · Dashboard.