DVN
0x282b3386571f7f794450d5789911a9804fa346b4
Verification
Verified
v0.8.22+commit.4fc1097e
Type
Contract
20,004 bytes
ABI entries
81
26 read · 18 write
License
none
Contract information
- Address
- 0x282b3386571f7f794450d5789911a9804fa346b4
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.22+commit.4fc1097e
- Optimization
- Enabled
- Creator
- 0x9F403140Bc…1Bbd4eF327
- Creation tx
- 0xe3df47f49f…5b6ef9ad8a
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (26)
DEFAULT_ADMIN_ROLE() → bytes32
allowlistSize() → uint64
defaultMultiplierBps() → uint16
dstConfig(uint32) → uint64, uint16, uint128
getFee(uint32, uint64, address, bytes) → uint256
getFee(uint16, uint16, uint64, address) → uint256
getFee(address, bytes, bytes, bytes) → uint256
getRoleAdmin(bytes32) → bytes32
getSigners() → address[]
getSupportedOptionTypes(uint32) → uint8[]
hasAcl(address) → bool
hasRole(bytes32, address) → bool
hashCallData(uint32, address, bytes, uint256) → bytes32
isSigner(address) → bool
localEidV2() → uint32
paused() → bool
priceFeed() → address
quorum() → uint64
renounceRole(bytes32, address)
signerSize() → uint256
signers(address) → bool
supportsInterface(bytes4) → bool
usedHashes(bytes32) → bool
verifySignatures(bytes32, bytes) → bool, uint8
vid() → uint32
workerFeeLib() → address
Events (17)
ExecuteFailedHashAlreadyUsedPausedRoleAdminChangedRoleGrantedRoleRevokedSetDefaultMultiplierBpsSetDstConfigSetPriceFeedSetSupportedOptionTypesSetWorkerLibUnpausedUpdateQuorumUpdateSignerVerifierFeePaidVerifySignaturesFailedWithdraw
ABI
[
{
"inputs": [
{
"internalType": "uint32",
"name": "_localEidV2",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "_vid",
"type": "uint32"
},
{
"internalType": "address[]",
"name": "_messageLibs",
"type": "address[]"
},
{
"internalType": "address",
"name": "_priceFeed",
"type": "address"
},
{
"internalType": "address[]",
"name": "_signers",
"type": "address[]"
},
{
"internalType": "uint64",
"name": "_quorum",
"type": "uint64"
},
{
"internalType": "address[]",
"name": "_admins",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "executableHash",
"type": "bytes32"
}
],
"name": "DVN_DuplicatedHash",
"type": "error"
},
{
"inputs": [],
"name": "DVN_InstructionExpired",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "DVN_InvalidRole",
"type": "error"
},
{
"inputs": [],
"name": "DVN_InvalidSignatures",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
}
],
"name": "DVN_InvalidTarget",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "vid",
"type": "uint32"
}
],
"name": "DVN_InvalidVid",
"type": "error"
},
{
"inputs": [],
"name": "DVN_OnlySelf",
"type": "error"
},
{
"inputs": [],
"name": "MultiSig_InvalidSigner",
"type": "error"
},
{
"inputs": [],
"name": "MultiSig_OnlySigner",
"type": "error"
},
{
"inputs": [],
"name": "MultiSig_QuorumIsZero",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "signersSize",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "quorum",
"type": "uint64"
}
],
"name": "MultiSig_SignersSizeIsLessThanQuorum",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"internalType": "bool",
"name": "active",
"type": "bool"
}
],
"name": "MultiSig_StateAlreadySet",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"internalType": "bool",
"name": "active",
"type": "bool"
}
],
"name": "MultiSig_StateNotSet",
"type": "error"
},
{
"inputs": [],
"name": "MultiSig_UnorderedSigners",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer_NativeFailed",
"type": "error"
},
{
"inputs": [],
"name": "Transfer_ToAddressIsZero",
"type": "error"
},
{
"inputs": [],
"name": "Worker_NotAllowed",
"type": "error"
},
{
"inputs": [],
"name": "Worker_OnlyMessageLib",
"type": "error"
},
{
"inputs": [],
"name": "Worker_RoleRenouncingDisabled",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "_index",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "ExecuteFailed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "vid",
"type": "uint32"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "expiration",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "signatures",
"type": "bytes"
}
],
"indexed": false,
"internalType": "struct ExecuteParam",
"name": "param",
"type": "tuple"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "_hash",
"type": "bytes32"
}
],
"name": "HashAlreadyUsed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint16",
"name": "multiplierBps",
"type": "uint16"
}
],
"name": "SetDefaultMultiplierBps",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "dstEid",
"type": "uint32"
},
{
"internalType": "uint64",
"name": "gas",
"type": "uint64"
},
{
"internalType": "uint16",
"name": "multiplierBps",
"type": "uint16"
},
{
"internalType": "uint128",
"name": "floorMarginUSD",
"type": "uint128"
}
],
"indexed": false,
"internalType": "struct IDVN.DstConfigParam[]",
"name": "params",
"type": "tuple[]"
}
],
"name": "SetDstConfig",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "priceFeed",
"type": "address"
}
],
"name": "SetPriceFeed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint32",
"name": "dstEid",
"type": "uint32"
},
{
"indexed": false,
"internalType": "uint8[]",
"name": "optionTypes",
"type": "uint8[]"
}
],
"name": "SetSupportedOptionTypes",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "workerLib",
"type": "address"
}
],
"name": "SetWorkerLib",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint64",
"name": "_quorum",
"type": "uint64"
}
],
"name": "UpdateQuorum",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "_signer",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "_active",
"type": "bool"
}
],
"name": "UpdateSigner",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"name": "VerifierFeePaid",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "idx",
"type": "uint256"
}
],
"name": "VerifySignaturesFailed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "lib",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Withdraw",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allowlistSize",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "dstEid",
"type": "uint32"
},
{
"internalType": "bytes",
"name": "packetHeader",
"type": "bytes"
},
{
"internalType": "bytes32",
"name": "payloadHash",
"type": "bytes32"
},
{
"internalType": "uint64",
"name": "confirmations",
"type": "uint64"
},
{
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"internalType": "struct ILayerZeroDVN.AssignJobParam",
"name": "_param",
"type": "tuple"
},
{
"internalType": "bytes",
"name": "_options",
"type": "bytes"
}
],
"name": "assignJob",
"outputs": [
{
"internalType": "uint256",
"name": "totalFee",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "_dstEid",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "_confirmations",
"type": "uint64"
},
{
"internalType": "address",
"name": "_sender",
"type": "address"
}
],
"name": "assignJob",
"outputs": [
{
"internalType": "uint256",
"name": "totalFee",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_sender",
"type": "address"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_cmd",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_options",
"type": "bytes"
}
],
"name": "assignJob",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "defaultMultiplierBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "dstEid",
"type": "uint32"
}
],
"name": "dstConfig",
"outputs": [
{
"internalType": "uint64",
"name": "gas",
"type": "uint64"
},
{
"internalType": "uint16",
"name": "multiplierBps",
"type": "uint16"
},
{
"internalType": "uint128",
"name": "floorMarginUSD",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "vid",
"type": "uint32"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "expiration",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "signatures",
"type": "bytes"
}
],
"internalType": "struct ExecuteParam[]",
"name": "_params",
"type": "tuple[]"
}
],
"name": "execute",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_dstEid",
"type": "uint32"
},
{
"internalType": "uint64",
"name": "_confirmations",
"type": "uint64"
},
{
"internalType": "address",
"name": "_sender",
"type": "address"
},
{
"internalType": "bytes",
"name": "_options",
"type": "bytes"
}
],
"name": "getFee",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "_dstEid",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "_confirmations",
"type": "uint64"
},
{
"internalType": "address",
"name": "_sender",
"type": "address"
}
],
"name": "getFee",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_sender",
"type": "address"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_cmd",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_options",
"type": "bytes"
}
],
"name": "getFee",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getSigners",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_eid",
"type": "uint32"
}
],
"name": "getSupportedOptionTypes",
"outputs": [
{
"internalType": "uint8[]",
"name": "",
"type": "uint8[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "_account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_sender",
"type": "address"
}
],
"name": "hasAcl",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_vid",
"type": "uint32"
},
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_callData",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_expiration",
"type": "uint256"
}
],
"name": "hashCallData",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_signer",
"type": "address"
}
],
"name": "isSigner",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "localEidV2",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "priceFeed",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "quorum",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "vid",
"type": "uint32"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "callData",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "expiration",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "signatures",
"type": "bytes"
}
],
"internalType": "struct ExecuteParam",
"name": "_param",
"type": "tuple"
}
],
"name": "quorumChangeAdmin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "_account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "_multiplierBps",
"type": "uint16"
}
],
"name": "setDefaultMultiplierBps",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint32",
"name": "dstEid",
"type": "uint32"
},
{
"internalType": "uint64",
"name": "gas",
"type": "uint64"
},
{
"internalType": "uint16",
"name": "multiplierBps",
"type": "uint16"
},
{
"internalType": "uint128",
"name": "floorMarginUSD",
"type": "uint128"
}
],
"internalType": "struct IDVN.DstConfigParam[]",
"name": "_params",
"type": "tuple[]"
}
],
"name": "setDstConfig",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "_paused",
"type": "bool"
}
],
"name": "setPaused",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_priceFeed",
"type": "address"
}
],
"name": "setPriceFeed",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "_quorum",
"type": "uint64"
}
],
"name": "setQuorum",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_signer",
"type": "address"
},
{
"internalType": "bool",
"name": "_active",
"type": "bool"
}
],
"name": "setSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_eid",
"type": "uint32"
},
{
"internalType": "uint8[]",
"name": "_optionTypes",
"type": "uint8[]"
}
],
"name": "setSupportedOptionTypes",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_workerFeeLib",
"type": "address"
}
],
"name": "setWorkerFeeLib",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "signerSize",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_signer",
"type": "address"
}
],
"name": "signers",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "executableHash",
"type": "bytes32"
}
],
"name": "usedHashes",
"outputs": [
{
"internalType": "bool",
"name": "used",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_hash",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "_signatures",
"type": "bytes"
}
],
"name": "verifySignatures",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
},
{
"internalType": "enum MultiSig.Errors",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "vid",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_lib",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_lib",
"type": "address"
},
{
"internalType": "address payable",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawFeeFromUlnV2",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_token",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "workerFeeLib",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { ILayerZeroUltraLightNodeV2 } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroUltraLightNodeV2.sol";
import { Worker } from "../../Worker.sol";
import { MultiSig } from "./MultiSig.sol";
import { ReadLib1002 } from "../readlib/ReadLib1002.sol";
import { IDVN } from "../interfaces/IDVN.sol";
import { IDVNFeeLib } from "../interfaces/IDVNFeeLib.sol";
import { IReceiveUlnE2 } from "../interfaces/IReceiveUlnE2.sol";
struct ExecuteParam {
uint32 vid;
address target;
bytes callData;
uint256 expiration;
bytes signatures;
}
contract DVN is Worker, MultiSig, IDVN {
// to uniquely identify this DVN instance
// set to endpoint v1 eid if available OR endpoint v2 eid % 30_000
uint32 public immutable vid;
uint32 public immutable localEidV2; // endpoint-v2 only, for read call
mapping(uint32 dstEid => DstConfig) public dstConfig;
mapping(bytes32 executableHash => bool used) public usedHashes;
error DVN_OnlySelf();
error DVN_InvalidRole(bytes32 role);
error DVN_InstructionExpired();
error DVN_InvalidTarget(address target);
error DVN_InvalidVid(uint32 vid);
error DVN_InvalidSignatures();
error DVN_DuplicatedHash(bytes32 executableHash);
event VerifySignaturesFailed(uint256 idx);
event ExecuteFailed(uint256 _index, bytes _data);
event HashAlreadyUsed(ExecuteParam param, bytes32 _hash);
// same as DVNFeePaid, but for ULNv2
event VerifierFeePaid(uint256 fee);
// ========================= Constructor =========================
/// @dev DVN doesn't have a roleAdmin (address(0x0))
/// @dev Supports all of ULNv2, ULN301, ULN302 and more
/// @param _localEidV2 local endpoint-v2 eid
/// @param _vid unique identifier for this DVN instance
/// @param _messageLibs array of message lib addresses that are granted the MESSAGE_LIB_ROLE
/// @param _priceFeed price feed address
/// @param _signers array of signer addresses for multisig
/// @param _quorum quorum for multisig
/// @param _admins array of admin addresses that are granted the ADMIN_ROLE
constructor(
uint32 _localEidV2,
uint32 _vid,
address[] memory _messageLibs,
address _priceFeed,
address[] memory _signers,
uint64 _quorum,
address[] memory _admins
) Worker(_messageLibs, _priceFeed, 12000, address(0x0), _admins) MultiSig(_signers, _quorum) {
vid = _vid;
localEidV2 = _localEidV2;
}
// ========================= Modifier =========================
/// @dev depending on role, restrict access to only self or admin
/// @dev ALLOWLIST, DENYLIST, MESSAGE_LIB_ROLE can only be granted/revoked by self
/// @dev ADMIN_ROLE can only be granted/revoked by admin
/// @dev reverts if not one of the above roles
/// @param _role role to check
modifier onlySelfOrAdmin(bytes32 _role) {
if (_role == ALLOWLIST || _role == DENYLIST || _role == MESSAGE_LIB_ROLE) {
// self required
if (address(this) != msg.sender) {
revert DVN_OnlySelf();
}
} else if (_role == ADMIN_ROLE) {
// admin required
_checkRole(ADMIN_ROLE);
} else {
revert DVN_InvalidRole(_role);
}
_;
}
modifier onlySelf() {
if (address(this) != msg.sender) {
revert DVN_OnlySelf();
}
_;
}
// ========================= OnlySelf =========================
/// @dev set signers for multisig
/// @dev function sig 0x31cb6105
/// @param _signer signer address
/// @param _active true to add, false to remove
function setSigner(address _signer, bool _active) external onlySelf {
_setSigner(_signer, _active);
}
/// @dev set quorum for multisig
/// @dev function sig 0x8585c945
/// @param _quorum to set
function setQuorum(uint64 _quorum) external onlySelf {
_setQuorum(_quorum);
}
// ========================= OnlySelf / OnlyAdmin =========================
/// @dev overrides AccessControl to allow self/admin to grant role'
/// @dev function sig 0x2f2ff15d
/// @param _role role to grant
/// @param _account account to grant role to
function grantRole(bytes32 _role, address _account) public override onlySelfOrAdmin(_role) {
_grantRole(_role, _account);
}
/// @dev overrides AccessControl to allow self/admin to revoke role
/// @dev function sig 0xd547741f
/// @param _role role to revoke
/// @param _account account to revoke role from
function revokeRole(bytes32 _role, address _account) public override onlySelfOrAdmin(_role) {
_revokeRole(_role, _account);
}
// ========================= OnlyQuorum =========================
/// @notice function for quorum to change admin without going through execute function
/// @dev calldata in the case is abi.encode new admin address
function quorumChangeAdmin(ExecuteParam calldata _param) external {
if (_param.expiration <= block.timestamp) {
revert DVN_InstructionExpired();
}
if (_param.target != address(this)) {
revert DVN_InvalidTarget(_param.target);
}
if (_param.vid != vid) {
revert DVN_InvalidVid(_param.vid);
}
// generate and validate hash
bytes32 hash = hashCallData(_param.vid, _param.target, _param.callData, _param.expiration);
(bool sigsValid, ) = verifySignatures(hash, _param.signatures);
if (!sigsValid) {
revert DVN_InvalidSignatures();
}
if (usedHashes[hash]) {
revert DVN_DuplicatedHash(hash);
}
usedHashes[hash] = true;
_grantRole(ADMIN_ROLE, abi.decode(_param.callData, (address)));
}
// ========================= OnlyAdmin =========================
/// @param _params array of DstConfigParam
function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
for (uint256 i = 0; i < _params.length; ++i) {
DstConfigParam calldata param = _params[i];
dstConfig[param.dstEid] = DstConfig(param.gas, param.multiplierBps, param.floorMarginUSD);
}
emit SetDstConfig(_params);
}
/// @dev takes a list of instructions and executes them in order
/// @dev if any of the instructions fail, it will emit an error event and continue to execute the rest of the instructions
/// @param _params array of ExecuteParam, includes target, callData, expiration, signatures
function execute(ExecuteParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
for (uint256 i = 0; i < _params.length; ++i) {
ExecuteParam calldata param = _params[i];
// 1. skip if invalid vid
if (param.vid != vid) {
continue;
}
// 2. skip if expired
if (param.expiration <= block.timestamp) {
continue;
}
// generate and validate hash
bytes32 hash = hashCallData(param.vid, param.target, param.callData, param.expiration);
// 3. check signatures
(bool sigsValid, ) = verifySignatures(hash, param.signatures);
if (!sigsValid) {
emit VerifySignaturesFailed(i);
continue;
}
// 4. should check hash
bool shouldCheckHash = _shouldCheckHash(bytes4(param.callData));
if (shouldCheckHash) {
if (usedHashes[hash]) {
emit HashAlreadyUsed(param, hash);
continue;
} else {
usedHashes[hash] = true; // prevent reentry and replay attack
}
}
(bool success, bytes memory rtnData) = param.target.call(param.callData);
if (!success) {
if (shouldCheckHash) {
// need to unset the usedHash otherwise it cant be used
usedHashes[hash] = false;
}
// emit an event in any case
emit ExecuteFailed(i, rtnData);
}
}
}
/// @dev to support ULNv2
/// @dev the withdrawFee function for ULN30X is built in the Worker contract
/// @param _lib message lib address
/// @param _to address to withdraw to
/// @param _amount amount to withdraw
function withdrawFeeFromUlnV2(address _lib, address payable _to, uint256 _amount) external onlyRole(ADMIN_ROLE) {
if (!hasRole(MESSAGE_LIB_ROLE, _lib)) {
revert Worker_OnlyMessageLib();
}
ILayerZeroUltraLightNodeV2(_lib).withdrawNative(_to, _amount);
}
// ========================= OnlyMessageLib =========================
/// @dev for ULN301, ULN302 and more to assign job
/// @dev dvn network can reject job from _sender by adding/removing them from allowlist/denylist
/// @param _param assign job param
/// @param _options dvn options
function assignJob(
AssignJobParam calldata _param,
bytes calldata _options
) external payable onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_param.sender) returns (uint256 totalFee) {
IDVNFeeLib.FeeParams memory feeParams = IDVNFeeLib.FeeParams(
priceFeed,
_param.dstEid,
_param.confirmations,
_param.sender,
quorum,
defaultMultiplierBps
);
totalFee = IDVNFeeLib(workerFeeLib).getFeeOnSend(feeParams, dstConfig[_param.dstEid], _options);
}
/// @dev to support ULNv2
/// @dev dvn network can reject job from _sender by adding/removing them from allowlist/denylist
/// @param _dstEid destination EndpointId
/// @param //_outboundProofType outbound proof type
/// @param _confirmations block confirmations
/// @param _sender message sender address
function assignJob(
uint16 _dstEid,
uint16 /*_outboundProofType*/,
uint64 _confirmations,
address _sender
) external onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_sender) returns (uint256 totalFee) {
IDVNFeeLib.FeeParams memory params = IDVNFeeLib.FeeParams(
priceFeed,
_dstEid,
_confirmations,
_sender,
quorum,
defaultMultiplierBps
);
// ULNV2 does not have dvn options
totalFee = IDVNFeeLib(workerFeeLib).getFeeOnSend(params, dstConfig[_dstEid], bytes(""));
emit VerifierFeePaid(totalFee);
}
/// @dev to support ReadLib
// @param _packetHeader - version + nonce + path
// @param _cmd - the command to be executed to obtain the payload
// @param _options - options
function assignJob(
address _sender,
bytes calldata /*_packetHeader*/,
bytes calldata _cmd,
bytes calldata _options
) external payable onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_sender) returns (uint256 fee) {
IDVNFeeLib.FeeParamsForRead memory feeParams = IDVNFeeLib.FeeParamsForRead(
priceFeed,
_sender,
quorum,
defaultMultiplierBps
);
fee = IDVNFeeLib(workerFeeLib).getFeeOnSend(feeParams, dstConfig[localEidV2], _cmd, _options);
}
// ========================= View =========================
/// @dev getFee can revert if _sender doesn't pass ACL
/// @param _dstEid destination EndpointId
/// @param _confirmations block confirmations
/// @param _sender message sender address
/// @param _options dvn options
/// @return fee fee in native amount
function getFee(
uint32 _dstEid,
uint64 _confirmations,
address _sender,
bytes calldata _options
) external view onlyAcl(_sender) returns (uint256 fee) {
IDVNFeeLib.FeeParams memory params = IDVNFeeLib.FeeParams(
priceFeed,
_dstEid,
_confirmations,
_sender,
quorum,
defaultMultiplierBps
);
fee = IDVNFeeLib(workerFeeLib).getFee(params, dstConfig[_dstEid], _options);
}
/// @dev to support ULNv2
/// @dev getFee can revert if _sender doesn't pass ACL
/// @param _dstEid destination EndpointId
/// @param //_outboundProofType outbound proof type
/// @param _confirmations block confirmations
/// @param _sender message sender address
function getFee(
uint16 _dstEid,
uint16 /*_outboundProofType*/,
uint64 _confirmations,
address _sender
) public view onlyAcl(_sender) returns (uint256 fee) {
IDVNFeeLib.FeeParams memory params = IDVNFeeLib.FeeParams(
priceFeed,
_dstEid,
_confirmations,
_sender,
quorum,
defaultMultiplierBps
);
fee = IDVNFeeLib(workerFeeLib).getFee(params, dstConfig[_dstEid], bytes(""));
}
/// @dev to support ReadLib
// @param _packetHeader - version + nonce + path
// @param _cmd - the command to be executed to obtain the payload
// @param _options - options
function getFee(
address _sender,
bytes calldata /*_packetHeader*/,
bytes calldata _cmd,
bytes calldata _options
) external view onlyAcl(_sender) returns (uint256 fee) {
IDVNFeeLib.FeeParamsForRead memory feeParams = IDVNFeeLib.FeeParamsForRead(
priceFeed,
_sender,
quorum,
defaultMultiplierBps
);
fee = IDVNFeeLib(workerFeeLib).getFee(feeParams, dstConfig[localEidV2], _cmd, _options);
}
/// @param _target target address
/// @param _callData call data
/// @param _expiration expiration timestamp
/// @return hash of above
function hashCallData(
uint32 _vid,
address _target,
bytes calldata _callData,
uint256 _expiration
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_vid, _target, _expiration, _callData));
}
// ========================= Internal =========================
/// @dev to save gas, we don't check hash for some functions (where replaying won't change the state)
/// @dev for example, some administrative functions like changing signers, the contract should check hash to double spending
/// @dev should ensure that all onlySelf functions have unique functionSig
/// @param _functionSig function signature
/// @return true if should check hash
function _shouldCheckHash(bytes4 _functionSig) internal pure returns (bool) {
// never check for these selectors to save gas
return
_functionSig != IReceiveUlnE2.verify.selector && // 0x0223536e, replaying won't change the state
_functionSig != ReadLib1002.verify.selector && // 0xab750e75, replaying won't change the state
_functionSig != ILayerZeroUltraLightNodeV2.updateHash.selector; // 0x704316e5, replaying will be revert at uln
}
}
Chain explorer5033msChain node92ms