Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Setup
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// contracts/Implementation.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./Governance.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
contract Setup is Setters, ERC1967Upgrade {
function setup(
address implementation,
address[] memory initialGuardians,
uint16 chainId,
uint16 governanceChainId,
bytes32 governanceContract,
uint256 evmChainId
) public {
require(initialGuardians.length > 0, "no guardians specified");
Structs.GuardianSet memory initialGuardianSet = Structs.GuardianSet({
keys : initialGuardians,
expirationTime : 0
});
storeGuardianSet(initialGuardianSet, 0);
// initial guardian set index is 0, which is the default value of the storage slot anyways
setChainId(chainId);
setGovernanceChainId(governanceChainId);
setGovernanceContract(governanceContract);
setEvmChainId(evmChainId);
_upgradeTo(implementation);
// See https://github.com/wormhole-foundation/wormhole/issues/1930 for
// why we set this here
setInitialized(implementation);
}
}// contracts/Governance.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./Structs.sol";
import "./GovernanceStructs.sol";
import "./Messages.sol";
import "./Setters.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/**
* @dev `Governance` defines a means to enacting changes to the core bridge contract,
* guardianSets, message fees, and transfer fees
*/
abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upgrade {
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event GuardianSetAdded(uint32 indexed index);
// "Core" (left padded)
bytes32 constant module = 0x00000000000000000000000000000000000000000000000000000000436f7265;
/**
* @dev Upgrades a contract via Governance VAA/VM
*/
function submitContractUpgrade(bytes memory _vm) public {
require(!isFork(), "invalid fork");
Structs.VM memory vm = parseVM(_vm);
// Verify the VAA is valid before processing it
(bool isValid, string memory reason) = verifyGovernanceVM(vm);
require(isValid, reason);
GovernanceStructs.ContractUpgrade memory upgrade = parseContractUpgrade(vm.payload);
// Verify the VAA is for this module
require(upgrade.module == module, "Invalid Module");
// Verify the VAA is for this chain
require(upgrade.chain == chainId(), "Invalid Chain");
// Record the governance action as consumed
setGovernanceActionConsumed(vm.hash);
// Upgrades the implementation to the new contract
upgradeImplementation(upgrade.newContract);
}
/**
* @dev Sets a `messageFee` via Governance VAA/VM
*/
function submitSetMessageFee(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
// Verify the VAA is valid before processing it
(bool isValid, string memory reason) = verifyGovernanceVM(vm);
require(isValid, reason);
GovernanceStructs.SetMessageFee memory upgrade = parseSetMessageFee(vm.payload);
// Verify the VAA is for this module
require(upgrade.module == module, "Invalid Module");
// Verify the VAA is for this chain
require(upgrade.chain == chainId() && !isFork(), "Invalid Chain");
// Record the governance action as consumed to prevent reentry
setGovernanceActionConsumed(vm.hash);
// Updates the messageFee
setMessageFee(upgrade.messageFee);
}
/**
* @dev Deploys a new `guardianSet` via Governance VAA/VM
*/
function submitNewGuardianSet(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
// Verify the VAA is valid before processing it
(bool isValid, string memory reason) = verifyGovernanceVM(vm);
require(isValid, reason);
GovernanceStructs.GuardianSetUpgrade memory upgrade = parseGuardianSetUpgrade(vm.payload);
// Verify the VAA is for this module
require(upgrade.module == module, "invalid Module");
// Verify the VAA is for this chain
require((upgrade.chain == chainId() && !isFork()) || upgrade.chain == 0, "invalid Chain");
// Verify the Guardian Set keys are not empty, this guards
// against the accidential upgrade to an empty GuardianSet
require(upgrade.newGuardianSet.keys.length > 0, "new guardian set is empty");
// Verify that the index is incrementing via a predictable +1 pattern
require(upgrade.newGuardianSetIndex == getCurrentGuardianSetIndex() + 1, "index must increase in steps of 1");
// Record the governance action as consumed to prevent reentry
setGovernanceActionConsumed(vm.hash);
// Trigger a time-based expiry of current guardianSet
expireGuardianSet(getCurrentGuardianSetIndex());
// Add the new guardianSet to guardianSets
storeGuardianSet(upgrade.newGuardianSet, upgrade.newGuardianSetIndex);
// Makes the new guardianSet effective
updateGuardianSetIndex(upgrade.newGuardianSetIndex);
}
/**
* @dev Submits transfer fees to the recipient via Governance VAA/VM
*/
function submitTransferFees(bytes memory _vm) public {
Structs.VM memory vm = parseVM(_vm);
// Verify the VAA is valid before processing it
(bool isValid, string memory reason) = verifyGovernanceVM(vm);
require(isValid, reason);
// Obtains the transfer from the VAA payload
GovernanceStructs.TransferFees memory transfer = parseTransferFees(vm.payload);
// Verify the VAA is for this module
require(transfer.module == module, "invalid Module");
// Verify the VAA is for this chain
require((transfer.chain == chainId() && !isFork()) || transfer.chain == 0, "invalid Chain");
// Record the governance action as consumed to prevent reentry
setGovernanceActionConsumed(vm.hash);
// Obtains the recipient address to be paid transfer fees
address payable recipient = payable(address(uint160(uint256(transfer.recipient))));
// Transfers transfer fees to the recipient
recipient.transfer(transfer.amount);
}
/**
* @dev Updates the `chainId` and `evmChainId` on a forked chain via Governance VAA/VM
*/
function submitRecoverChainId(bytes memory _vm) public {
require(isFork(), "not a fork");
Structs.VM memory vm = parseVM(_vm);
// Verify the VAA is valid before processing it
(bool isValid, string memory reason) = verifyGovernanceVM(vm);
require(isValid, reason);
GovernanceStructs.RecoverChainId memory rci = parseRecoverChainId(vm.payload);
// Verify the VAA is for this module
require(rci.module == module, "invalid Module");
// Verify the VAA is for this chain
require(rci.evmChainId == block.chainid, "invalid EVM Chain");
// Record the governance action as consumed to prevent reentry
setGovernanceActionConsumed(vm.hash);
// Update the chainIds
setEvmChainId(rci.evmChainId);
setChainId(rci.newChainId);
}
/**
* @dev Upgrades the `currentImplementation` with a `newImplementation`
*/
function upgradeImplementation(address newImplementation) internal {
address currentImplementation = _getImplementation();
_upgradeTo(newImplementation);
// Call initialize function of the new implementation
(bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()"));
require(success, string(reason));
emit ContractUpgraded(currentImplementation, newImplementation);
}
/**
* @dev Verifies a Governance VAA/VM is valid
*/
function verifyGovernanceVM(Structs.VM memory vm) internal view returns (bool, string memory){
// Verify the VAA is valid
(bool isValid, string memory reason) = verifyVM(vm);
if (!isValid){
return (false, reason);
}
// only current guardianset can sign governance packets
if (vm.guardianSetIndex != getCurrentGuardianSetIndex()) {
return (false, "not signed by current guardian set");
}
// Verify the VAA is from the governance chain (Solana)
if (uint16(vm.emitterChainId) != governanceChainId()) {
return (false, "wrong governance chain");
}
// Verify the emitter contract is the governance contract (0x4 left padded)
if (vm.emitterAddress != governanceContract()) {
return (false, "wrong governance contract");
}
// Verify this governance action hasn't already been
// consumed to prevent reentry and replay
if (governanceActionIsConsumed(vm.hash)){
return (false, "governance action already consumed");
}
// Confirm the governance VAA/VM is valid
return (true, "");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallSecure(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
address oldImplementation = _getImplementation();
// Initial upgrade and setup call
_setImplementation(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
// Perform rollback test if not already in progress
StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
if (!rollbackTesting.value) {
// Trigger rollback using upgradeTo from the new implementation
rollbackTesting.value = true;
Address.functionDelegateCall(
newImplementation,
abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
);
rollbackTesting.value = false;
// Check rollback was effective
require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
// Finally reset to the new implementation and log the upgrade
_upgradeTo(newImplementation);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// contracts/Structs.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface Structs {
struct Provider {
uint16 chainId;
uint16 governanceChainId;
bytes32 governanceContract;
}
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
}// contracts/GovernanceStructs.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./libraries/external/BytesLib.sol";
import "./Structs.sol";
/**
* @dev `GovernanceStructs` defines a set of structs and parsing functions
* for minimal struct validation
*/
contract GovernanceStructs {
using BytesLib for bytes;
enum GovernanceAction {
UpgradeContract,
UpgradeGuardianset
}
struct ContractUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
address newContract;
}
struct GuardianSetUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
Structs.GuardianSet newGuardianSet;
uint32 newGuardianSetIndex;
}
struct SetMessageFee {
bytes32 module;
uint8 action;
uint16 chain;
uint256 messageFee;
}
struct TransferFees {
bytes32 module;
uint8 action;
uint16 chain;
uint256 amount;
bytes32 recipient;
}
struct RecoverChainId {
bytes32 module;
uint8 action;
uint256 evmChainId;
uint16 newChainId;
}
/// @dev Parse a contract upgrade (action 1) with minimal validation
function parseContractUpgrade(bytes memory encodedUpgrade) public pure returns (ContractUpgrade memory cu) {
uint index = 0;
cu.module = encodedUpgrade.toBytes32(index);
index += 32;
cu.action = encodedUpgrade.toUint8(index);
index += 1;
require(cu.action == 1, "invalid ContractUpgrade");
cu.chain = encodedUpgrade.toUint16(index);
index += 2;
cu.newContract = address(uint160(uint256(encodedUpgrade.toBytes32(index))));
index += 32;
require(encodedUpgrade.length == index, "invalid ContractUpgrade");
}
/// @dev Parse a guardianSet upgrade (action 2) with minimal validation
function parseGuardianSetUpgrade(bytes memory encodedUpgrade) public pure returns (GuardianSetUpgrade memory gsu) {
uint index = 0;
gsu.module = encodedUpgrade.toBytes32(index);
index += 32;
gsu.action = encodedUpgrade.toUint8(index);
index += 1;
require(gsu.action == 2, "invalid GuardianSetUpgrade");
gsu.chain = encodedUpgrade.toUint16(index);
index += 2;
gsu.newGuardianSetIndex = encodedUpgrade.toUint32(index);
index += 4;
uint8 guardianLength = encodedUpgrade.toUint8(index);
index += 1;
gsu.newGuardianSet = Structs.GuardianSet({
keys : new address[](guardianLength),
expirationTime : 0
});
for(uint i = 0; i < guardianLength; i++) {
gsu.newGuardianSet.keys[i] = encodedUpgrade.toAddress(index);
index += 20;
}
require(encodedUpgrade.length == index, "invalid GuardianSetUpgrade");
}
/// @dev Parse a setMessageFee (action 3) with minimal validation
function parseSetMessageFee(bytes memory encodedSetMessageFee) public pure returns (SetMessageFee memory smf) {
uint index = 0;
smf.module = encodedSetMessageFee.toBytes32(index);
index += 32;
smf.action = encodedSetMessageFee.toUint8(index);
index += 1;
require(smf.action == 3, "invalid SetMessageFee");
smf.chain = encodedSetMessageFee.toUint16(index);
index += 2;
smf.messageFee = encodedSetMessageFee.toUint256(index);
index += 32;
require(encodedSetMessageFee.length == index, "invalid SetMessageFee");
}
/// @dev Parse a transferFees (action 4) with minimal validation
function parseTransferFees(bytes memory encodedTransferFees) public pure returns (TransferFees memory tf) {
uint index = 0;
tf.module = encodedTransferFees.toBytes32(index);
index += 32;
tf.action = encodedTransferFees.toUint8(index);
index += 1;
require(tf.action == 4, "invalid TransferFees");
tf.chain = encodedTransferFees.toUint16(index);
index += 2;
tf.amount = encodedTransferFees.toUint256(index);
index += 32;
tf.recipient = encodedTransferFees.toBytes32(index);
index += 32;
require(encodedTransferFees.length == index, "invalid TransferFees");
}
/// @dev Parse a recoverChainId (action 5) with minimal validation
function parseRecoverChainId(bytes memory encodedRecoverChainId) public pure returns (RecoverChainId memory rci) {
uint index = 0;
rci.module = encodedRecoverChainId.toBytes32(index);
index += 32;
rci.action = encodedRecoverChainId.toUint8(index);
index += 1;
require(rci.action == 5, "invalid RecoverChainId");
rci.evmChainId = encodedRecoverChainId.toUint256(index);
index += 32;
rci.newChainId = encodedRecoverChainId.toUint16(index);
index += 2;
require(encodedRecoverChainId.length == index, "invalid RecoverChainId");
}
}// contracts/Messages.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./Getters.sol";
import "./Structs.sol";
import "./libraries/external/BytesLib.sol";
contract Messages is Getters {
using BytesLib for bytes;
/// @dev parseAndVerifyVM serves to parse an encodedVM and wholy validate it for consumption
function parseAndVerifyVM(bytes calldata encodedVM) public view returns (Structs.VM memory vm, bool valid, string memory reason) {
vm = parseVM(encodedVM);
/// setting checkHash to false as we can trust the hash field in this case given that parseVM computes and then sets the hash field above
(valid, reason) = verifyVMInternal(vm, false);
}
/**
* @dev `verifyVM` serves to validate an arbitrary vm against a valid Guardian set
* - it aims to make sure the VM is for a known guardianSet
* - it aims to ensure the guardianSet is not expired
* - it aims to ensure the VM has reached quorum
* - it aims to verify the signatures provided against the guardianSet
* - it aims to verify the hash field provided against the contents of the vm
*/
function verifyVM(Structs.VM memory vm) public view returns (bool valid, string memory reason) {
(valid, reason) = verifyVMInternal(vm, true);
}
/**
* @dev `verifyVMInternal` serves to validate an arbitrary vm against a valid Guardian set
* if checkHash is set then the hash field of the vm is verified against the hash of its contents
* in the case that the vm is securely parsed and the hash field can be trusted, checkHash can be set to false
* as the check would be redundant
*/
function verifyVMInternal(Structs.VM memory vm, bool checkHash) internal view returns (bool valid, string memory reason) {
/// @dev Obtain the current guardianSet for the guardianSetIndex provided
Structs.GuardianSet memory guardianSet = getGuardianSet(vm.guardianSetIndex);
/**
* Verify that the hash field in the vm matches with the hash of the contents of the vm if checkHash is set
* WARNING: This hash check is critical to ensure that the vm.hash provided matches with the hash of the body.
* Without this check, it would not be safe to call verifyVM on it's own as vm.hash can be a valid signed hash
* but the body of the vm could be completely different from what was actually signed by the guardians
*/
if(checkHash){
bytes memory body = abi.encodePacked(
vm.timestamp,
vm.nonce,
vm.emitterChainId,
vm.emitterAddress,
vm.sequence,
vm.consistencyLevel,
vm.payload
);
bytes32 vmHash = keccak256(abi.encodePacked(keccak256(body)));
if(vmHash != vm.hash){
return (false, "vm.hash doesn't match body");
}
}
/**
* @dev Checks whether the guardianSet has zero keys
* WARNING: This keys check is critical to ensure the guardianSet has keys present AND to ensure
* that guardianSet key size doesn't fall to zero and negatively impact quorum assessment. If guardianSet
* key length is 0 and vm.signatures length is 0, this could compromise the integrity of both vm and
* signature verification.
*/
if(guardianSet.keys.length == 0){
return (false, "invalid guardian set");
}
/// @dev Checks if VM guardian set index matches the current index (unless the current set is expired).
if(vm.guardianSetIndex != getCurrentGuardianSetIndex() && guardianSet.expirationTime < block.timestamp){
return (false, "guardian set has expired");
}
/**
* @dev We're using a fixed point number transformation with 1 decimal to deal with rounding.
* WARNING: This quorum check is critical to assessing whether we have enough Guardian signatures to validate a VM
* if making any changes to this, obtain additional peer review. If guardianSet key length is 0 and
* vm.signatures length is 0, this could compromise the integrity of both vm and signature verification.
*/
if (vm.signatures.length < quorum(guardianSet.keys.length)){
return (false, "no quorum");
}
/// @dev Verify the proposed vm.signatures against the guardianSet
(bool signaturesValid, string memory invalidReason) = verifySignatures(vm.hash, vm.signatures, guardianSet);
if(!signaturesValid){
return (false, invalidReason);
}
/// If we are here, we've validated the VM is a valid multi-sig that matches the guardianSet.
return (true, "");
}
/**
* @dev verifySignatures serves to validate arbitrary sigatures against an arbitrary guardianSet
* - it intentionally does not solve for expectations within guardianSet (you should use verifyVM if you need these protections)
* - it intentioanlly does not solve for quorum (you should use verifyVM if you need these protections)
* - it intentionally returns true when signatures is an empty set (you should use verifyVM if you need these protections)
*/
function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) public pure returns (bool valid, string memory reason) {
uint8 lastIndex = 0;
uint256 guardianCount = guardianSet.keys.length;
for (uint i = 0; i < signatures.length; i++) {
Structs.Signature memory sig = signatures[i];
address signatory = ecrecover(hash, sig.v, sig.r, sig.s);
// ecrecover returns 0 for invalid signatures. We explicitly require valid signatures to avoid unexpected
// behaviour due to the default storage slot value also being 0.
require(signatory != address(0), "ecrecover failed with signature");
/// Ensure that provided signature indices are ascending only
require(i == 0 || sig.guardianIndex > lastIndex, "signature indices must be ascending");
lastIndex = sig.guardianIndex;
/// @dev Ensure that the provided signature index is within the
/// bounds of the guardianSet. This is implicitly checked by the array
/// index operation below, so this check is technically redundant.
/// However, reverting explicitly here ensures that a bug is not
/// introduced accidentally later due to the nontrivial storage
/// semantics of solidity.
require(sig.guardianIndex < guardianCount, "guardian index out of bounds");
/// Check to see if the signer of the signature does not match a specific Guardian key at the provided index
if(signatory != guardianSet.keys[sig.guardianIndex]){
return (false, "VM signature invalid");
}
}
/// If we are here, we've validated that the provided signatures are valid for the provided guardianSet
return (true, "");
}
/**
* @dev parseVM serves to parse an encodedVM into a vm struct
* - it intentionally performs no validation functions, it simply parses raw into a struct
*/
function parseVM(bytes memory encodedVM) public pure virtual returns (Structs.VM memory vm) {
uint index = 0;
vm.version = encodedVM.toUint8(index);
index += 1;
// SECURITY: Note that currently the VM.version is not part of the hash
// and for reasons described below it cannot be made part of the hash.
// This means that this field's integrity is not protected and cannot be trusted.
// This is not a problem today since there is only one accepted version, but it
// could be a problem if we wanted to allow other versions in the future.
require(vm.version == 1, "VM version incompatible");
vm.guardianSetIndex = encodedVM.toUint32(index);
index += 4;
// Parse Signatures
uint256 signersLen = encodedVM.toUint8(index);
index += 1;
vm.signatures = new Structs.Signature[](signersLen);
for (uint i = 0; i < signersLen; i++) {
vm.signatures[i].guardianIndex = encodedVM.toUint8(index);
index += 1;
vm.signatures[i].r = encodedVM.toBytes32(index);
index += 32;
vm.signatures[i].s = encodedVM.toBytes32(index);
index += 32;
vm.signatures[i].v = encodedVM.toUint8(index) + 27;
index += 1;
}
/*
Hash the body
SECURITY: Do not change the way the hash of a VM is computed!
Changing it could result into two different hashes for the same observation.
But xDapps rely on the hash of an observation for replay protection.
*/
bytes memory body = encodedVM.slice(index, encodedVM.length - index);
vm.hash = keccak256(abi.encodePacked(keccak256(body)));
// Parse the body
vm.timestamp = encodedVM.toUint32(index);
index += 4;
vm.nonce = encodedVM.toUint32(index);
index += 4;
vm.emitterChainId = encodedVM.toUint16(index);
index += 2;
vm.emitterAddress = encodedVM.toBytes32(index);
index += 32;
vm.sequence = encodedVM.toUint64(index);
index += 8;
vm.consistencyLevel = encodedVM.toUint8(index);
index += 1;
vm.payload = encodedVM.slice(index, encodedVM.length - index);
}
/**
* @dev quorum serves solely to determine the number of signatures required to acheive quorum
*/
function quorum(uint numGuardians) public pure virtual returns (uint numSignaturesRequiredForQuorum) {
// The max number of guardians is 255
require(numGuardians < 256, "too many guardians");
return ((numGuardians * 2) / 3) + 1;
}
}// contracts/Setters.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./State.sol";
contract Setters is State {
function updateGuardianSetIndex(uint32 newIndex) internal {
_state.guardianSetIndex = newIndex;
}
function expireGuardianSet(uint32 index) internal {
_state.guardianSets[index].expirationTime = uint32(block.timestamp) + 86400;
}
function storeGuardianSet(Structs.GuardianSet memory set, uint32 index) internal {
uint setLength = set.keys.length;
for (uint i = 0; i < setLength; i++) {
require(set.keys[i] != address(0), "Invalid key");
}
_state.guardianSets[index] = set;
}
function setInitialized(address implementatiom) internal {
_state.initializedImplementations[implementatiom] = true;
}
function setGovernanceActionConsumed(bytes32 hash) internal {
_state.consumedGovernanceActions[hash] = true;
}
function setChainId(uint16 chainId) internal {
_state.provider.chainId = chainId;
}
function setGovernanceChainId(uint16 chainId) internal {
_state.provider.governanceChainId = chainId;
}
function setGovernanceContract(bytes32 governanceContract) internal {
_state.provider.governanceContract = governanceContract;
}
function setMessageFee(uint256 newFee) internal {
_state.messageFee = newFee;
}
function setNextSequence(address emitter, uint64 sequence) internal {
_state.sequences[emitter] = sequence;
}
function setEvmChainId(uint256 evmChainId) internal {
require(evmChainId == block.chainid, "invalid evmChainId");
_state.evmChainId = evmChainId;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// contracts/Getters.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./State.sol";
contract Getters is State {
function getGuardianSet(uint32 index) public view returns (Structs.GuardianSet memory) {
return _state.guardianSets[index];
}
function getCurrentGuardianSetIndex() public view returns (uint32) {
return _state.guardianSetIndex;
}
function getGuardianSetExpiry() public view returns (uint32) {
return _state.guardianSetExpiry;
}
function governanceActionIsConsumed(bytes32 hash) public view returns (bool) {
return _state.consumedGovernanceActions[hash];
}
function isInitialized(address impl) public view returns (bool) {
return _state.initializedImplementations[impl];
}
function chainId() public view returns (uint16) {
return _state.provider.chainId;
}
function evmChainId() public view returns (uint256) {
return _state.evmChainId;
}
function isFork() public view returns (bool) {
return evmChainId() != block.chainid;
}
function governanceChainId() public view returns (uint16){
return _state.provider.governanceChainId;
}
function governanceContract() public view returns (bytes32){
return _state.provider.governanceContract;
}
function messageFee() public view returns (uint256) {
return _state.messageFee;
}
function nextSequence(address emitter) public view returns (uint64) {
return _state.sequences[emitter];
}
}// contracts/State.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./Structs.sol";
contract Events {
event LogGuardianSetChanged(
uint32 oldGuardianIndex,
uint32 newGuardianIndex
);
event LogMessagePublished(
address emitter_address,
uint32 nonce,
bytes payload
);
}
contract Storage {
struct WormholeState {
Structs.Provider provider;
// Mapping of guardian_set_index => guardian set
mapping(uint32 => Structs.GuardianSet) guardianSets;
// Current active guardian set index
uint32 guardianSetIndex;
// Period for which a guardian set stays active after it has been replaced
uint32 guardianSetExpiry;
// Sequence numbers per emitter
mapping(address => uint64) sequences;
// Mapping of consumed governance actions
mapping(bytes32 => bool) consumedGovernanceActions;
// Mapping of initialized implementations
mapping(address => bool) initializedImplementations;
uint256 messageFee;
// EIP-155 Chain ID
uint256 evmChainId;
}
}
contract State {
Storage.WormholeState _state;
}{
"remappings": [
"@openzeppelin/=node_modules/@openzeppelin/",
"@solidity-parser/=node_modules/@solidity-parser/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"truffle/=node_modules/truffle/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "istanbul",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"address[]","name":"initialGuardians","type":"address[]"},{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint16","name":"governanceChainId","type":"uint16"},{"internalType":"bytes32","name":"governanceContract","type":"bytes32"},{"internalType":"uint256","name":"evmChainId","type":"uint256"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061055b806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a712ff9914610030575b600080fd5b61004361003e3660046103db565b610045565b005b60008551116100945760405162461bcd60e51b81526020600482015260166024820152751b9bc819dd585c991a585b9cc81cdc1958da599a595960521b60448201526064015b60405180910390fd5b604080518082019091528581526000602082018190526100b590829061011c565b6000805461ffff868116620100000263ffffffff199092169088161717905560018390556100e282610205565b6100eb8761024e565b610113876001600160a01b03166000908152600660205260409020805460ff19166001179055565b50505050505050565b81515160005b818110156101af5783518051600091908390811061015057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316141561019d5760405162461bcd60e51b815260206004820152600b60248201526a496e76616c6964206b657960a81b604482015260640161008b565b806101a7816104e8565b915050610122565b5063ffffffff821660009081526002602090815260409091208451805186936101dc928492910190610333565b50602091909101516001909101805463ffffffff191663ffffffff909216919091179055505050565b4681146102495760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a5908195d9b50da185a5b925960721b604482015260640161008b565b600855565b6102578161028e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b803b6102f25760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161008b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b828054828255906000526020600020908101928215610388579160200282015b8281111561038857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610353565b50610394929150610398565b5090565b5b808211156103945760008155600101610399565b80356001600160a01b03811681146103c457600080fd5b919050565b803561ffff811681146103c457600080fd5b60008060008060008060c087890312156103f3578182fd5b6103fc876103ad565b955060208088013567ffffffffffffffff80821115610419578485fd5b818a0191508a601f83011261042c578485fd5b81358181111561043e5761043e61050f565b8060051b604051601f19603f830116810181811085821117156104635761046361050f565b604052828152858101935084860182860187018f1015610481578889fd5b8895505b838610156104aa57610496816103ad565b855260019590950194938601938601610485565b50809a505050505050506104c0604088016103c9565b93506104ce606088016103c9565b92506080870135915060a087013590509295509295509295565b600060001982141561050857634e487b7160e01b81526011600452602481fd5b5060010190565b634e487b7160e01b600052604160045260246000fdfea26469706673582212201ef8336a42df29bb71b6242252f879704fbbe6a81fc8241f605e5740ad8c48c464736f6c63430008040033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a712ff9914610030575b600080fd5b61004361003e3660046103db565b610045565b005b60008551116100945760405162461bcd60e51b81526020600482015260166024820152751b9bc819dd585c991a585b9cc81cdc1958da599a595960521b60448201526064015b60405180910390fd5b604080518082019091528581526000602082018190526100b590829061011c565b6000805461ffff868116620100000263ffffffff199092169088161717905560018390556100e282610205565b6100eb8761024e565b610113876001600160a01b03166000908152600660205260409020805460ff19166001179055565b50505050505050565b81515160005b818110156101af5783518051600091908390811061015057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316141561019d5760405162461bcd60e51b815260206004820152600b60248201526a496e76616c6964206b657960a81b604482015260640161008b565b806101a7816104e8565b915050610122565b5063ffffffff821660009081526002602090815260409091208451805186936101dc928492910190610333565b50602091909101516001909101805463ffffffff191663ffffffff909216919091179055505050565b4681146102495760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a5908195d9b50da185a5b925960721b604482015260640161008b565b600855565b6102578161028e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b803b6102f25760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161008b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b828054828255906000526020600020908101928215610388579160200282015b8281111561038857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610353565b50610394929150610398565b5090565b5b808211156103945760008155600101610399565b80356001600160a01b03811681146103c457600080fd5b919050565b803561ffff811681146103c457600080fd5b60008060008060008060c087890312156103f3578182fd5b6103fc876103ad565b955060208088013567ffffffffffffffff80821115610419578485fd5b818a0191508a601f83011261042c578485fd5b81358181111561043e5761043e61050f565b8060051b604051601f19603f830116810181811085821117156104635761046361050f565b604052828152858101935084860182860187018f1015610481578889fd5b8895505b838610156104aa57610496816103ad565b855260019590950194938601938601610485565b50809a505050505050506104c0604088016103c9565b93506104ce606088016103c9565b92506080870135915060a087013590509295509295509295565b600060001982141561050857634e487b7160e01b81526011600452602481fd5b5060010190565b634e487b7160e01b600052604160045260246000fdfea26469706673582212201ef8336a42df29bb71b6242252f879704fbbe6a81fc8241f605e5740ad8c48c464736f6c63430008040033
Deployed Bytecode Sourcemap
225:1018:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;273:968;;;;;;:::i;:::-;;:::i;:::-;;;542:1;516:16;:23;:27;508:62;;;;-1:-1:-1;;;508:62:5;;2437:2:13;508:62:5;;;2419:21:13;2476:2;2456:18;;;2449:30;-1:-1:-1;;;2495:18:13;;;2488:52;2557:18;;508:62:5;;;;;;;;;629:100;;;;;;;;;;;;581:45;629:100;;;;;;740:39;;629:100;;740:16;:39::i;:::-;1023:6:4;:33;;;1134:43;;;;;-1:-1:-1;;1134:43:4;;;1023:33;;;1134:43;;;;-1:-1:-1;1268:55:4;;;1020:25:5;1034:10;1020:13;:25::i;:::-;1056:26;1067:14;1056:10;:26::i;:::-;1204:30;1219:14;-1:-1:-1;;;;;771:49:4;:6;:49;;;:33;:49;;;;;:56;;-1:-1:-1;;771:56:4;823:4;771:56;;;704:130;1204:30:5;273:968;;;;;;;:::o;406:292:4:-;514:8;;:15;497:14;539:111;560:9;556:1;:13;539:111;;;598:8;;:11;;621:1;;598:8;607:1;;598:11;;;;-1:-1:-1;;;598:11:4;;;;;;;;;;;;;;;-1:-1:-1;;;;;598:25:4;;;590:49;;;;-1:-1:-1;;;590:49:4;;2097:2:13;590:49:4;;;2079:21:13;2136:2;2116:18;;;2109:30;-1:-1:-1;;;2155:18:13;;;2148:41;2206:18;;590:49:4;2069:161:13;590:49:4;571:3;;;;:::i;:::-;;;;539:111;;;-1:-1:-1;659:26:4;;;:6;:26;;;:19;:26;;;;;;;;:32;;;;688:3;;659:32;;:26;;:32;;;;:::i;:::-;-1:-1:-1;659:32:4;;;;;;;;;;;;-1:-1:-1;;659:32:4;;;;;;;;;;;-1:-1:-1;;;406:292:4:o;1560:167::-;1644:13;1630:10;:27;1622:58;;;;-1:-1:-1;;;1622:58:4;;3202:2:13;1622:58:4;;;3184:21:13;3241:2;3221:18;;;3214:30;-1:-1:-1;;;3260:18:13;;;3253:48;3318:18;;1622:58:4;3174:168:13;1622:58:4;1690:17;:30;1560:167::o;1768:152:9:-;1834:37;1853:17;1834:18;:37::i;:::-;1886:27;;-1:-1:-1;;;;;1886:27:9;;;;;;;;1768:152;:::o;1403:259::-;1034:20:11;;1476:95:9;;;;-1:-1:-1;;;1476:95:9;;2788:2:13;1476:95:9;;;2770:21:13;2827:2;2807:18;;;2800:30;2866:34;2846:18;;;2839:62;-1:-1:-1;;;2917:18:13;;;2910:43;2970:19;;1476:95:9;2760:235:13;1476:95:9;901:66;1581:74;;-1:-1:-1;;;;;;1581:74:9;-1:-1:-1;;;;;1581:74:9;;;;;;;;;;1403:259::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:173:13;82:20;;-1:-1:-1;;;;;131:31:13;;121:42;;111:2;;177:1;174;167:12;111:2;63:124;;;:::o;192:159::-;259:20;;319:6;308:18;;298:29;;288:2;;341:1;338;331:12;356:1534;483:6;491;499;507;515;523;576:3;564:9;555:7;551:23;547:33;544:2;;;598:6;590;583:22;544:2;626:29;645:9;626:29;:::i;:::-;616:39;;674:2;727;716:9;712:18;699:32;750:18;791:2;783:6;780:14;777:2;;;812:6;804;797:22;777:2;855:6;844:9;840:22;830:32;;900:7;893:4;889:2;885:13;881:27;871:2;;927:6;919;912:22;871:2;968;955:16;990:2;986;983:10;980:2;;;996:18;;:::i;:::-;1042:2;1039:1;1035:10;1074:2;1068:9;1137:2;1133:7;1128:2;1124;1120:11;1116:25;1108:6;1104:38;1192:6;1180:10;1177:22;1172:2;1160:10;1157:18;1154:46;1151:2;;;1203:18;;:::i;:::-;1239:2;1232:22;1289:18;;;1323:15;;;;-1:-1:-1;1358:11:13;;;1388;;;1384:20;;1381:33;-1:-1:-1;1378:2:13;;;1432:6;1424;1417:22;1378:2;1459:6;1450:15;;1474:169;1488:2;1485:1;1482:9;1474:169;;;1545:23;1564:3;1545:23;:::i;:::-;1533:36;;1506:1;1499:9;;;;;1589:12;;;;1621;;1474:169;;;1478:3;1662:6;1652:16;;;;;;;;1687:37;1720:2;1709:9;1705:18;1687:37;:::i;:::-;1677:47;;1743:37;1776:2;1765:9;1761:18;1743:37;:::i;:::-;1733:47;;1827:3;1816:9;1812:19;1799:33;1789:43;;1879:3;1868:9;1864:19;1851:33;1841:43;;534:1356;;;;;;;;:::o;3347:236::-;3386:3;-1:-1:-1;;3407:17:13;;3404:2;;;-1:-1:-1;;;3447:33:13;;3503:4;3500:1;3493:15;3533:4;3454:3;3521:17;3404:2;-1:-1:-1;3575:1:13;3564:13;;3394:189::o;3588:127::-;3649:10;3644:3;3640:20;3637:1;3630:31;3680:4;3677:1;3670:15;3704:4;3701:1;3694:15
Swarm Source
ipfs://1ef8336a42df29bb71b6242252f879704fbbe6a81fc8241f605e5740ad8c48c4
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.