Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- SocketBatcher
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 999999
- EVM Version
- default
- Verified at
- 2024-10-23T11:04:31.020484Z
Constructor Arguments
0x00000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c
Arg [0] (address) : 0x44a44837894b5edc2bde64567fc62599b3b88f4c
contracts/socket/SocketBatcher.sol
// SPDX-License-Identifier: GPL-3.0-only // Sources flattened with hardhat v2.12.2 https://hardhat.org // File contracts/utils/Ownable.sol pragma solidity 0.8.19; /** * @title Ownable * @dev The Ownable contract provides a simple way to manage ownership of a contract * and allows for ownership to be transferred to a nominated address. */ abstract contract Ownable { address private _owner; address private _nominee; event OwnerNominated(address indexed nominee); event OwnerClaimed(address indexed claimer); error OnlyOwner(); error OnlyNominee(); /** * @dev Sets the contract's owner to the address that is passed to the constructor. */ constructor(address owner_) { _claimOwner(owner_); } /** * @dev Modifier that restricts access to only the contract's owner. * Throws an error if the caller is not the owner. */ modifier onlyOwner() { if (msg.sender != _owner) revert OnlyOwner(); _; } /** * @dev Returns the current owner of the contract. */ function owner() external view returns (address) { return _owner; } /** * @dev Returns the current nominee for ownership of the contract. */ function nominee() external view returns (address) { return _nominee; } /** * @dev Allows the current owner to nominate a new owner for the contract. * Throws an error if the caller is not the owner. * Emits an `OwnerNominated` event with the address of the nominee. */ function nominateOwner(address nominee_) external { if (msg.sender != _owner) revert OnlyOwner(); _nominee = nominee_; emit OwnerNominated(_nominee); } /** * @dev Allows the nominated owner to claim ownership of the contract. * Throws an error if the caller is not the nominee. * Sets the nominated owner as the new owner of the contract. * Emits an `OwnerClaimed` event with the address of the new owner. */ function claimOwner() external { if (msg.sender != _nominee) revert OnlyNominee(); _claimOwner(msg.sender); } /** * @dev Internal function that sets the owner of the contract to the specified address * and sets the nominee to address(0). */ function _claimOwner(address claimer_) internal { _owner = claimer_; _nominee = address(0); emit OwnerClaimed(claimer_); } } // File contracts/utils/AccessControl.sol pragma solidity 0.8.19; /** * @title AccessControl * @dev This abstract contract implements access control mechanism based on roles. * Each role can have one or more addresses associated with it, which are granted * permission to execute functions with the onlyRole modifier. */ abstract contract AccessControl is Ownable { /** * @dev A mapping of roles to a mapping of addresses to boolean values indicating whether or not they have the role. */ mapping(bytes32 => mapping(address => bool)) private _permits; /** * @dev Emitted when a role is granted to an address. */ event RoleGranted(bytes32 indexed role, address indexed grantee); /** * @dev Emitted when a role is revoked from an address. */ event RoleRevoked(bytes32 indexed role, address indexed revokee); /** * @dev Error message thrown when an address does not have permission to execute a function with onlyRole modifier. */ error NoPermit(bytes32 role); /** * @dev Constructor that sets the owner of the contract. */ constructor(address owner_) Ownable(owner_) {} /** * @dev Modifier that restricts access to addresses having roles * Throws an error if the caller do not have permit */ modifier onlyRole(bytes32 role) { if (!_permits[role][msg.sender]) revert NoPermit(role); _; } /** * @dev Checks and reverts if an address do not have a specific role. * @param role_ The role to check. * @param address_ The address to check. */ function _checkRole(bytes32 role_, address address_) internal virtual { if (!_hasRole(role_, address_)) revert NoPermit(role_); } /** * @dev Grants a role to a given address. * @param role_ The role to grant. * @param grantee_ The address to grant the role to. * Emits a RoleGranted event. * Can only be called by the owner of the contract. */ function grantRole( bytes32 role_, address grantee_ ) external virtual onlyOwner { _grantRole(role_, grantee_); } /** * @dev Revokes a role from a given address. * @param role_ The role to revoke. * @param revokee_ The address to revoke the role from. * Emits a RoleRevoked event. * Can only be called by the owner of the contract. */ function revokeRole( bytes32 role_, address revokee_ ) external virtual onlyOwner { _revokeRole(role_, revokee_); } /** * @dev Internal function to grant a role to a given address. * @param role_ The role to grant. * @param grantee_ The address to grant the role to. * Emits a RoleGranted event. */ function _grantRole(bytes32 role_, address grantee_) internal { _permits[role_][grantee_] = true; emit RoleGranted(role_, grantee_); } /** * @dev Internal function to revoke a role from a given address. * @param role_ The role to revoke. * @param revokee_ The address to revoke the role from. * Emits a RoleRevoked event. */ function _revokeRole(bytes32 role_, address revokee_) internal { _permits[role_][revokee_] = false; emit RoleRevoked(role_, revokee_); } /** * @dev Checks whether an address has a specific role. * @param role_ The role to check. * @param address_ The address to check. * @return A boolean value indicating whether or not the address has the role. */ function hasRole( bytes32 role_, address address_ ) external view returns (bool) { return _hasRole(role_, address_); } function _hasRole( bytes32 role_, address address_ ) internal view returns (bool) { return _permits[role_][address_]; } } // File contracts/interfaces/ITransmitManager.sol pragma solidity 0.8.19; /** * @title ITransmitManager * @dev The interface for a transmit manager contract */ interface ITransmitManager { /** * @notice Checks if a given transmitter is authorized to send transactions to the destination chain. * @param siblingSlug The unique identifier for the sibling chain. * @param digest The digest of the message being signed. * @param signature The signature of the message being signed. * @return The address of the transmitter and a boolean indicating whether the transmitter is authorized or not. */ function checkTransmitter( uint32 siblingSlug, bytes32 digest, bytes calldata signature ) external view returns (address, bool); /** * @notice sets the transmission fee needed to transmit message to given `siblingSlug_` * @dev recovered address should add have feeUpdater role for `siblingSlug_` * @param nonce_ The incremental nonce to prevent signature replay * @param siblingSlug_ sibling id for which fee updater is registered * @param transmissionFees_ digest which is signed by transmitter * @param signature_ signature */ function setTransmissionFees( uint256 nonce_, uint32 siblingSlug_, uint128 transmissionFees_, bytes calldata signature_ ) external; /** * @notice receives fees from Execution manager * @dev this function can be used to keep track of fees received for each slug * @param siblingSlug_ sibling id for which fee updater is registered */ function receiveFees(uint32 siblingSlug_) external payable; } // File contracts/interfaces/IExecutionManager.sol pragma solidity 0.8.19; /** * @title Execution Manager Interface * @dev This interface defines the functions for managing and executing transactions on external chains * @dev It is also responsible for collecting all the socket fees, which can then be pulled by others */ interface IExecutionManager { struct ExecutionFeesParam { // for calculating perGasCost * gasLimit uint80 perGasCost; // for calculating cost for executing payload (needed for rollups) uint80 perByteCost; // additional cost (differs based on chain) uint80 overhead; } /** * @notice Returns the executor of the packed message and whether the executor is authorized * @param packedMessage The message packed with payload, fees and config * @param sig The signature of the message * @return The address of the executor and a boolean indicating if the executor is authorized */ function isExecutor( bytes32 packedMessage, bytes memory sig ) external view returns (address, bool); /** * @notice Pays the fees for executing a transaction on the external chain * @dev This function is payable and assumes the socket is going to send correct amount of fees. * @param minMsgGasLimit_ The minimum gas limit for the transaction * @param payloadSize_ The payload size in bytes * @param executionParams_ Extra params for execution * @param transmissionParams_ Extra params for transmission * @param siblingChainSlug_ Sibling chain identifier * @param switchboardFees_ fee charged by switchboard for processing transaction * @param verificationOverheadFees_ fee charged for verifying transaction * @param transmitManager_ The transmitManager address * @param switchboard_ The switchboard address * @param maxPacketLength_ The maxPacketLength for the capacitor */ function payAndCheckFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 siblingChainSlug_, uint128 switchboardFees_, uint128 verificationOverheadFees_, address transmitManager_, address switchboard_, uint256 maxPacketLength_ ) external payable returns (uint128, uint128); /** * @notice Returns the minimum fees required for executing a transaction on the external chain * @param minMsgGasLimit_ minMsgGasLimit_ * @param siblingChainSlug_ The destination slug * @return The minimum fees required for executing the transaction */ function getMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, uint32 siblingChainSlug_ ) external view returns (uint128); /** * @notice function for getting the minimum fees required for executing and transmitting a cross-chain transaction * @dev this function is called at source to calculate the execution cost. * @param payloadSize_ byte length of payload. Currently only used to check max length, later on will be used for fees calculation. * @param executionParams_ Can be used for providing extra information. Currently used for msgValue * @param siblingChainSlug_ Sibling chain identifier * @return minExecutionFee : Minimum fees required for executing the transaction */ function getExecutionTransmissionMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 siblingChainSlug_, address transmitManager_ ) external view returns (uint128, uint128); /** * @notice Updates the execution fees for an executor and message ID * @param executor The executor address * @param executionFees The execution fees to update * @param msgId The ID of the message */ function updateExecutionFees( address executor, uint128 executionFees, bytes32 msgId ) external; /** * @notice updates the transmission fee * @param remoteChainSlug_ sibling chain identifier * @param transmitMinFees_ transmission fees collected */ function setTransmissionMinFees( uint32 remoteChainSlug_, uint128 transmitMinFees_ ) external; /** * @notice sets the minimum execution fees required for executing at `siblingChainSlug_` * @dev this function currently sets the price for a constant msg gas limit and payload size * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param executionFees_ total fees where price in destination native token is converted to source native tokens * @param signature_ signature of fee updater */ function setExecutionFees( uint256 nonce_, uint32 siblingChainSlug_, ExecutionFeesParam calldata executionFees_, bytes calldata signature_ ) external; /** * @notice sets the min limit for msg value for `siblingChainSlug_` * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param msgValueMinThreshold_ min msg value * @param signature_ signature of fee updater */ function setMsgValueMinThreshold( uint256 nonce_, uint32 siblingChainSlug_, uint256 msgValueMinThreshold_, bytes calldata signature_ ) external; /** * @notice sets the max limit for msg value for `siblingChainSlug_` * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param msgValueMaxThreshold_ max msg value * @param signature_ signature of fee updater */ function setMsgValueMaxThreshold( uint256 nonce_, uint32 siblingChainSlug_, uint256 msgValueMaxThreshold_, bytes calldata signature_ ) external; /** * @notice sets the relative token price for `siblingChainSlug_` * @dev this function is expected to be called frequently to match the original prices * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param relativeNativeTokenPrice_ relative price * @param signature_ signature of fee updater */ function setRelativeNativeTokenPrice( uint256 nonce_, uint32 siblingChainSlug_, uint256 relativeNativeTokenPrice_, bytes calldata signature_ ) external; /** * @notice called by socket while executing message to validate if the msg value provided is enough * @param executionParams_ a bytes32 string where first byte gives param type (if value is 0 or not) * and remaining bytes give the msg value needed * @param msgValue_ msg.value to be sent with inbound */ function verifyParams( bytes32 executionParams_, uint256 msgValue_ ) external view; /** * @notice withdraws switchboard fees from contract * @param siblingChainSlug_ withdraw fees corresponding to this slug * @param amount_ withdraw amount */ function withdrawSwitchboardFees( uint32 siblingChainSlug_, address switchboard_, uint128 amount_ ) external; /** * @dev this function gets the transmitManager address from the socket contract. If it is ever upgraded in socket, * @dev remove the fees from executionManager first, and then upgrade address at socket. * @notice withdraws transmission fees from contract * @param siblingChainSlug_ withdraw fees corresponding to this slug * @param amount_ withdraw amount */ function withdrawTransmissionFees( uint32 siblingChainSlug_, uint128 amount_ ) external; } // File contracts/interfaces/ISocket.sol pragma solidity 0.8.19; /** * @title ISocket * @notice An interface for a cross-chain communication contract * @dev This interface provides methods for transmitting and executing messages between chains, * connecting a plug to a remote chain and setting up switchboards for the message transmission * This interface also emits events for important operations such as message transmission, execution status, * and plug connection */ interface ISocket { /** * @notice A struct containing fees required for message transmission and execution * @param transmissionFees fees needed for transmission * @param switchboardFees fees needed by switchboard * @param executionFee fees needed for execution */ struct Fees { uint128 transmissionFees; uint128 executionFee; uint128 switchboardFees; } /** * @title MessageDetails * @dev This struct defines the details of a message to be executed in a Decapacitor contract. */ struct MessageDetails { // A unique identifier for the message. bytes32 msgId; // The fee to be paid for executing the message. uint256 executionFee; // The min amount of gas that can be used to execute the message. uint256 minMsgGasLimit; // The extra params which might provide msg value and additional info needed for message exec bytes32 executionParams; // The payload data to be executed in the message. bytes payload; } /** * @title ExecutionDetails * @dev This struct defines the execution details */ struct ExecutionDetails { // packet id bytes32 packetId; // proposal count uint256 proposalCount; // gas limit needed to execute inbound uint256 executionGasLimit; // proof data required by the Decapacitor contract to verify the message's authenticity bytes decapacitorProof; // signature of executor bytes signature; } /** * @notice emits the status of message after inbound call * @param msgId msg id which is executed */ event ExecutionSuccess(bytes32 msgId); /** * @notice emits the config set by a plug for a remoteChainSlug * @param plug address of plug on current chain * @param siblingChainSlug sibling chain slug * @param siblingPlug address of plug on sibling chain * @param inboundSwitchboard inbound switchboard (select from registered options) * @param outboundSwitchboard outbound switchboard (select from registered options) * @param capacitor capacitor selected based on outbound switchboard * @param decapacitor decapacitor selected based on inbound switchboard */ event PlugConnected( address plug, uint32 siblingChainSlug, address siblingPlug, address inboundSwitchboard, address outboundSwitchboard, address capacitor, address decapacitor ); /** * @notice registers a message * @dev Packs the message and includes it in a packet with capacitor * @param remoteChainSlug_ the remote chain slug * @param minMsgGasLimit_ the gas limit needed to execute the payload on remote * @param payload_ the data which is needed by plug at inbound call on remote */ function outbound( uint32 remoteChainSlug_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_, bytes calldata payload_ ) external payable returns (bytes32 msgId); /** * @notice executes a message * @param executionDetails_ the packet details, proof and signature needed for message execution * @param messageDetails_ the message details */ function execute( ISocket.ExecutionDetails calldata executionDetails_, ISocket.MessageDetails calldata messageDetails_ ) external payable; /** * @notice seals data in capacitor for specific batchSize * @param batchSize_ size of batch to be sealed * @param capacitorAddress_ address of capacitor * @param signature_ signed Data needed for verification */ function seal( uint256 batchSize_, address capacitorAddress_, bytes calldata signature_ ) external payable; /** * @notice proposes a packet * @param packetId_ packet id * @param root_ root data * @param switchboard_ The address of switchboard for which this packet is proposed * @param signature_ signed Data needed for verification */ function proposeForSwitchboard( bytes32 packetId_, bytes32 root_, address switchboard_, bytes calldata signature_ ) external payable; /** * @notice sets the config specific to the plug * @param siblingChainSlug_ the sibling chain slug * @param siblingPlug_ address of plug present at sibling chain to call inbound * @param inboundSwitchboard_ the address of switchboard to use for receiving messages * @param outboundSwitchboard_ the address of switchboard to use for sending messages */ function connect( uint32 siblingChainSlug_, address siblingPlug_, address inboundSwitchboard_, address outboundSwitchboard_ ) external; /** * @notice deploy capacitor and decapacitor for a switchboard with a specified max packet length, sibling chain slug, and capacitor type. * @param siblingChainSlug_ The slug of the sibling chain that the switchboard is registered with. * @param maxPacketLength_ The maximum length of a packet allowed by the switchboard. * @param capacitorType_ The type of capacitor that the switchboard uses. * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function registerSwitchboardForSibling( uint32 siblingChainSlug_, uint256 maxPacketLength_, uint256 capacitorType_, address siblingSwitchboard_ ) external returns (address capacitor, address decapacitor); /** * @notice Emits the sibling switchboard for given `siblingChainSlug_`. * @dev This function is expected to be only called by switchboard. * @dev the event emitted is tracked by transmitters to decide which switchboard a packet should be proposed on * @param siblingChainSlug_ The slug of the sibling chain * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function useSiblingSwitchboard( uint32 siblingChainSlug_, address siblingSwitchboard_ ) external; /** * @notice Retrieves the packet id roots for a specified packet id. * @param packetId_ The packet id for which to retrieve the root. * @param proposalCount_ The proposal id for packetId_ for which to retrieve the root. * @param switchboard_ The address of switchboard for which this packet is proposed * @return The packet id roots for the specified packet id. */ function packetIdRoots( bytes32 packetId_, uint256 proposalCount_, address switchboard_ ) external view returns (bytes32); /** * @notice Retrieves the latest proposalCount for a packet id. * @return The proposal count for the specified packet id. */ function proposalCount(bytes32 packetId_) external view returns (uint256); /** * @notice Retrieves the minimum fees required for a message with a specified gas limit and destination chain. * @param minMsgGasLimit_ The gas limit of the message. * @param remoteChainSlug_ The slug of the destination chain for the message. * @param plug_ The address of the plug through which the message is sent. * @return totalFees The minimum fees required for the specified message. */ function getMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 remoteChainSlug_, address plug_ ) external view returns (uint256 totalFees); /// return instance of transmit manager function transmitManager__() external view returns (ITransmitManager); /// return instance of execution manager function executionManager__() external view returns (IExecutionManager); } // File contracts/interfaces/ICapacitor.sol pragma solidity 0.8.19; /** * @title ICapacitor * @dev Interface for a Capacitor contract that stores and manages messages in packets */ interface ICapacitor { /** * @notice adds the packed message to a packet * @dev this should be only executable by socket * @param packedMessage the message packed with payload, fees and config */ function addPackedMessage(bytes32 packedMessage) external; /** * @notice returns the latest packet details which needs to be sealed * @return root root hash of the latest packet which is not yet sealed * @return packetCount latest packet id which is not yet sealed */ function getNextPacketToBeSealed() external view returns (bytes32 root, uint64 packetCount); /** * @notice returns the root of packet for given id * @param id the id assigned to packet * @return root root hash corresponding to given id */ function getRootByCount(uint64 id) external view returns (bytes32 root); /** * @notice returns the maxPacketLength * @return maxPacketLength of the capacitor */ function getMaxPacketLength() external view returns (uint256 maxPacketLength); /** * @notice seals the packet * @dev indicates the packet is ready to be shipped and no more messages can be added now. * @dev this should be called by socket only * @param batchSize_ used with packet batching capacitors * @return root root hash of the packet * @return packetCount id of the packed sealed */ function sealPacket( uint256 batchSize_ ) external returns (bytes32 root, uint64 packetCount); } // File contracts/utils/AccessRoles.sol pragma solidity 0.8.19; // contains role hashes used in socket dl for various different operations // used to rescue funds bytes32 constant RESCUE_ROLE = keccak256("RESCUE_ROLE"); // used to withdraw fees bytes32 constant WITHDRAW_ROLE = keccak256("WITHDRAW_ROLE"); // used to trip switchboards bytes32 constant TRIP_ROLE = keccak256("TRIP_ROLE"); // used to un trip switchboards bytes32 constant UN_TRIP_ROLE = keccak256("UN_TRIP_ROLE"); // used by governance bytes32 constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); //used by executors which executes message at destination bytes32 constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); // used by transmitters who seal and propose packets in socket bytes32 constant TRANSMITTER_ROLE = keccak256("TRANSMITTER_ROLE"); // used by switchboard watchers who work against transmitters bytes32 constant WATCHER_ROLE = keccak256("WATCHER_ROLE"); // used by fee updaters responsible for updating fees at switchboards, transmit manager and execution manager bytes32 constant FEES_UPDATER_ROLE = keccak256("FEES_UPDATER_ROLE"); // File lib/solmate/src/tokens/ERC20.sol pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } } // File lib/solmate/src/utils/SafeTransferLib.sol pragma solidity >=0.8.0; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } } // File contracts/libraries/RescueFundsLib.sol pragma solidity 0.8.19; error ZeroAddress(); /** * @title RescueFundsLib * @dev A library that provides a function to rescue funds from a contract. */ library RescueFundsLib { /** * @dev The address used to identify ETH. */ address public constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); /** * @dev thrown when the given token address don't have any code */ error InvalidTokenAddress(); /** * @dev Rescues funds from a contract. * @param token_ The address of the token contract. * @param rescueTo_ The address of the user. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) internal { if (rescueTo_ == address(0)) revert ZeroAddress(); if (token_ == ETH_ADDRESS) { SafeTransferLib.safeTransferETH(rescueTo_, amount_); } else { if (token_.code.length == 0) revert InvalidTokenAddress(); SafeTransferLib.safeTransfer(ERC20(token_), rescueTo_, amount_); } } } // File contracts/interfaces/INativeRelay.sol pragma solidity 0.8.19; /** * @title INativeRelay * @notice Interface for the NativeRelay contract which is used to relay packets between two chains. * It allows for the reception of messages on the PolygonRootReceiver and the initiation of native confirmations * for the given packet ID. * @dev this is only used by SocketBatcher currently */ interface INativeRelay { /** * @notice receiveMessage on PolygonRootReceiver * @param receivePacketProof receivePacketProof The proof of the packet being received on the Polygon network. */ function receiveMessage(bytes memory receivePacketProof) external; /** * @notice Function to initiate a native confirmation for the given packet ID. * @dev The function can be called with maxSubmissionCost, maxGas, and gasPriceBid to customize the confirmation transaction, * or with no parameters to use default values. * @param packetId The ID of the packet to initiate confirmation for. * @param maxSubmissionCost The maximum submission cost of the transaction. * @param maxGas The maximum gas limit of the transaction. * @param gasPriceBid The gas price bid for the transaction. * @param callValueRefundAddress l2 call value gets credited here on L2 if retryable txn times out or gets cancelled * @param remoteRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance */ function initiateNativeConfirmation( bytes32 packetId, uint256 maxSubmissionCost, uint256 maxGas, uint256 gasPriceBid, address callValueRefundAddress, address remoteRefundAddress ) external payable; /** * @notice Function to initiate a native confirmation for the given packet ID, using default values for transaction parameters. * @param packetId The ID of the packet to initiate confirmation for. */ function initiateNativeConfirmation(bytes32 packetId) external; } // File contracts/interfaces/ISwitchboard.sol pragma solidity 0.8.19; /** * @title ISwitchboard * @dev The interface for a switchboard contract that is responsible for verification of packets between * different blockchain networks. */ interface ISwitchboard { /** * @notice Registers itself in Socket for given `siblingChainSlug_`. * @dev This function is expected to be only called by admin as it handles the capacitor config for given chain * @param siblingChainSlug_ The slug of the sibling chain to register switchboard with. * @param maxPacketLength_ The maximum length of a packet allowed by the switchboard. * @param capacitorType_ The type of capacitor that the switchboard uses. * @param initialPacketCount_ The packet count at the time of registering switchboard. Packets with packet count below this won't be allowed * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function registerSiblingSlug( uint32 siblingChainSlug_, uint256 maxPacketLength_, uint256 capacitorType_, uint256 initialPacketCount_, address siblingSwitchboard_ ) external; /** * @notice Updates the sibling switchboard for given `siblingChainSlug_`. * @dev This function is expected to be only called by admin * @param siblingChainSlug_ The slug of the sibling chain to register switchboard with. * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function updateSibling( uint32 siblingChainSlug_, address siblingSwitchboard_ ) external; /** * @notice Checks if a packet can be allowed to go through the switchboard. * @param root the packet root. * @param packetId The unique identifier for the packet. * @param proposalCount The unique identifier for a proposal for the packet. * @param srcChainSlug The unique identifier for the source chain of the packet. * @param proposeTime The time when the packet was proposed. * @return A boolean indicating whether the packet is allowed to go through the switchboard or not. */ function allowPacket( bytes32 root, bytes32 packetId, uint256 proposalCount, uint32 srcChainSlug, uint256 proposeTime ) external view returns (bool); /** * @notice Retrieves the minimum fees required for the destination chain to process the packet. * @param dstChainSlug the unique identifier for the destination chain of the packet. * @return switchboardFee the switchboard fee required for the destination chain to process the packet. * @return verificationOverheadFees the verification fee required for the destination chain to process the packet. */ function getMinFees( uint32 dstChainSlug ) external view returns (uint128 switchboardFee, uint128 verificationOverheadFees); /** * @notice Receives the fees for processing of packet. * @param siblingChainSlug_ the chain slug of the sibling chain. */ function receiveFees(uint32 siblingChainSlug_) external payable; /** * @notice Sets the minimum fees required for the destination chain to process the packet. * @param nonce_ the nonce of fee Updater to avoid replay. * @param dstChainSlug_ the unique identifier for the destination chain. * @param switchboardFees_ the switchboard fee required for the destination chain to process the packet. * @param verificationOverheadFees_ the verification fee required for the destination chain to process the packet. * @param signature_ the signature of the request. * @dev not important to override in all switchboards */ function setFees( uint256 nonce_, uint32 dstChainSlug_, uint128 switchboardFees_, uint128 verificationOverheadFees_, bytes calldata signature_ ) external; } // File contracts/interfaces/ISignatureVerifier.sol pragma solidity 0.8.19; /** * @title Signature Verifier * @notice Verifies the signatures and returns the address of signer recovered from the input signature or digest. */ interface ISignatureVerifier { /** * @notice returns the address of signer recovered from input signature and digest */ function recoverSigner( bytes32 digest_, bytes memory signature_ ) external pure returns (address signer); } // File contracts/utils/AccessControlExtended.sol pragma solidity 0.8.19; /** * @title AccessControlExtended * @dev This contract extends the functionality of the AccessControl contract by adding * the ability to grant and revoke roles based on a combination of role name and a chain slug. * It also provides batch operations for granting and revoking roles. */ contract AccessControlExtended is AccessControl { /** * @dev Constructor that sets the owner of the contract. */ constructor(address owner_) AccessControl(owner_) {} /** * @dev thrown when array lengths are not equal */ error UnequalArrayLengths(); /** * @dev Checks if an address has the role. * @param roleName_ The name of the role. * @param chainSlug_ The chain slug associated with the role. * @param address_ The address to be granted the role. */ function _checkRoleWithSlug( bytes32 roleName_, uint256 chainSlug_, address address_ ) internal virtual { bytes32 roleHash = keccak256(abi.encode(roleName_, chainSlug_)); if (!_hasRole(roleHash, address_)) revert NoPermit(roleHash); } /** * @dev Grants a role to an address based on the role name and chain slug. * @param roleName_ The name of the role. * @param chainSlug_ The chain slug associated with the role. * @param grantee_ The address to be granted the role. */ function grantRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address grantee_ ) external virtual onlyOwner { _grantRoleWithSlug(roleName_, chainSlug_, grantee_); } /** * @dev Grants multiple roles to multiple addresses in batch. * @param roleNames_ The names of the roles to grant. * @param slugs_ The slugs for chain specific roles. For roles which are not chain-specific, we can use slug = 0 * @param grantees_ The addresses to be granted the roles. */ function grantBatchRole( bytes32[] calldata roleNames_, uint32[] calldata slugs_, address[] calldata grantees_ ) external virtual onlyOwner { if ( roleNames_.length != grantees_.length || roleNames_.length != slugs_.length ) revert UnequalArrayLengths(); uint256 totalRoles = roleNames_.length; for (uint256 index = 0; index < totalRoles; ) { if (slugs_[index] > 0) _grantRoleWithSlug( roleNames_[index], slugs_[index], grantees_[index] ); else _grantRole(roleNames_[index], grantees_[index]); // inputs are controlled by owner unchecked { ++index; } } } /** * @dev Revokes multiple roles from multiple addresses in batch. * @param roleNames_ The names of the roles to revoke. * @param slugs_ The slugs for chain specific roles. For roles which are not chain-specific, we can use slug = 0 * @param grantees_ The addresses to be revoked the roles. */ function revokeBatchRole( bytes32[] calldata roleNames_, uint32[] calldata slugs_, address[] calldata grantees_ ) external virtual onlyOwner { if ( roleNames_.length != grantees_.length || roleNames_.length != slugs_.length ) revert UnequalArrayLengths(); uint256 totalRoles = roleNames_.length; for (uint256 index = 0; index < totalRoles; ) { if (slugs_[index] > 0) _revokeRoleWithSlug( roleNames_[index], slugs_[index], grantees_[index] ); else _revokeRole(roleNames_[index], grantees_[index]); // inputs are controlled by owner unchecked { ++index; } } } function _grantRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address grantee_ ) internal { _grantRole(keccak256(abi.encode(roleName_, chainSlug_)), grantee_); } /** * @dev Checks if an address has a role based on the role name and chain slug. * @param roleName_ The name of the role. * @param chainSlug_ The chain slug associated with the role. * @param address_ The address to check for the role. * @return A boolean indicating whether the address has the specified role. */ function hasRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address address_ ) external view returns (bool) { return _hasRoleWithSlug(roleName_, chainSlug_, address_); } function _hasRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address address_ ) internal view returns (bool) { return _hasRole(keccak256(abi.encode(roleName_, chainSlug_)), address_); } /** * @dev Revokes roles from an address * @param roleName_ The names of the roles to revoke. * @param chainSlug_ The chain slug associated with the role. * @param grantee_ The addresses to be revoked the roles. */ function revokeRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address grantee_ ) external virtual onlyOwner { _revokeRoleWithSlug(roleName_, chainSlug_, grantee_); } function _revokeRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address revokee_ ) internal { _revokeRole(keccak256(abi.encode(roleName_, chainSlug_)), revokee_); } } // File contracts/utils/SigIdentifiers.sol pragma solidity 0.8.19; // contains unique identifiers which are hashes of strings, they help in making signature digest unique // hence preventing signature replay attacks // default switchboards bytes32 constant TRIP_PATH_SIG_IDENTIFIER = keccak256("TRIP_PATH"); bytes32 constant TRIP_PROPOSAL_SIG_IDENTIFIER = keccak256("TRIP_PROPOSAL"); bytes32 constant TRIP_GLOBAL_SIG_IDENTIFIER = keccak256("TRIP_GLOBAL"); bytes32 constant UN_TRIP_PATH_SIG_IDENTIFIER = keccak256("UN_TRIP_PATH"); bytes32 constant UN_TRIP_GLOBAL_SIG_IDENTIFIER = keccak256("UN_TRIP_GLOBAL"); // native switchboards bytes32 constant TRIP_NATIVE_SIG_IDENTIFIER = keccak256("TRIP_NATIVE"); bytes32 constant UN_TRIP_NATIVE_SIG_IDENTIFIER = keccak256("UN_TRIP_NATIVE"); // value threshold, price and fee updaters bytes32 constant FEES_UPDATE_SIG_IDENTIFIER = keccak256("FEES_UPDATE"); bytes32 constant RELATIVE_NATIVE_TOKEN_PRICE_UPDATE_SIG_IDENTIFIER = keccak256( "RELATIVE_NATIVE_TOKEN_PRICE_UPDATE" ); bytes32 constant MSG_VALUE_MIN_THRESHOLD_SIG_IDENTIFIER = keccak256( "MSG_VALUE_MIN_THRESHOLD_UPDATE" ); bytes32 constant MSG_VALUE_MAX_THRESHOLD_SIG_IDENTIFIER = keccak256( "MSG_VALUE_MAX_THRESHOLD_UPDATE" ); // File contracts/switchboard/default-switchboards/SwitchboardBase.sol pragma solidity 0.8.19; abstract contract SwitchboardBase is ISwitchboard, AccessControlExtended { // signature verifier contract ISignatureVerifier public immutable signatureVerifier__; // socket contract ISocket public immutable socket__; // chain slug of deployed chain uint32 public immutable chainSlug; // timeout after which packets become valid // optimistic switchboard: this is the wait time to validate packet // fast switchboard: this makes packets valid even if all watchers have not attested // used to make the system work when watchers are inactive due to infra etc problems // this is only applicable if none of the trips are triggered uint256 public immutable timeoutInSeconds; // variable to pause the switchboard completely, to be used only in case of smart contract bug // trip can be done by TRIP_ROLE holders // untrip can be done by UN_TRIP_ROLE holders bool public isGlobalTipped; // pause all proposals coming from given chain. // to be used if a transmitter has gone rogue and needs to be kicked to resume normal functioning // trip can be done by WATCHER_ROLE holders // untrip can be done by UN_TRIP_ROLE holders // sourceChain => isPaused mapping(uint32 => bool) public isPathTripped; // block execution of single proposal // to be used if transmitter proposes wrong packet root single time // trip can be done by WATCHER_ROLE holders // untrip not possible, but same root can be proposed again at next proposalCount // isProposalTripped(packetId => proposalCount => isTripped) mapping(bytes32 => mapping(uint256 => bool)) public isProposalTripped; // incrementing nonce for each signer // watcher => nextNonce mapping(address => uint256) public nextNonce; struct Fees { uint128 switchboardFees; // Fees paid to Switchboard per packet uint128 verificationOverheadFees; // Fees paid to executor per message } // destinationChainSlug => fees-struct with verificationOverheadFees and switchboardFees mapping(uint32 => Fees) public fees; // destinationChainSlug => initialPacketCount - packets with packetCount after this will be accepted at the switchboard. // This is to prevent attacks with sending messages for chain slugs before the switchboard is registered for them. mapping(uint32 => uint256) public initialPacketCount; /** * @dev Emitted when global trip status changes * @param isGlobalTipped New trip status of the contract */ event GlobalTripChanged(bool isGlobalTipped); /** * @dev Emitted when path trip status changes * @param srcChainSlug Chain slug of the source chain * @param isPathTripped New trip status of the path */ event PathTripChanged(uint32 srcChainSlug, bool isPathTripped); /** * @dev Emitted when a proposal for a packetId is tripped * @param packetId packetId of packet * @param proposalCount proposalCount being tripped */ event ProposalTripped(bytes32 packetId, uint256 proposalCount); /** * @dev Emitted when a fees is set for switchboard * @param siblingChainSlug Chain slug of the sibling chain * @param fees Fees struct with verificationOverheadFees and switchboardFees */ event SwitchboardFeesSet(uint32 siblingChainSlug, Fees fees); // Error hit when a signature with unexpected nonce is received error InvalidNonce(); // Error hit when tx from invalid ExecutionManager is received error OnlyExecutionManager(); /** * @dev Constructor of SwitchboardBase * @param socket_ Address of the socket contract * @param chainSlug_ Chain slug of deployment chain * @param timeoutInSeconds_ Time after which proposals become valid if not tripped * @param signatureVerifier_ signatureVerifier_ contract */ constructor( address socket_, uint32 chainSlug_, uint256 timeoutInSeconds_, ISignatureVerifier signatureVerifier_ ) { socket__ = ISocket(socket_); chainSlug = chainSlug_; timeoutInSeconds = timeoutInSeconds_; signatureVerifier__ = signatureVerifier_; } /** * @inheritdoc ISwitchboard */ function getMinFees( uint32 dstChainSlug_ ) external view override returns (uint128, uint128) { Fees memory minFees = fees[dstChainSlug_]; return (minFees.switchboardFees, minFees.verificationOverheadFees); } /** * @inheritdoc ISwitchboard */ function registerSiblingSlug( uint32 siblingChainSlug_, uint256 maxPacketLength_, uint256 capacitorType_, uint256 initialPacketCount_, address siblingSwitchboard_ ) external override onlyRole(GOVERNANCE_ROLE) { initialPacketCount[siblingChainSlug_] = initialPacketCount_; socket__.registerSwitchboardForSibling( siblingChainSlug_, maxPacketLength_, capacitorType_, siblingSwitchboard_ ); } /** * @notice Signals sibling switchboard for given `siblingChainSlug_`. * @dev This function is expected to be only called by governance * @param siblingChainSlug_ The slug of the sibling chain whos switchboard is being connected. * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function updateSibling( uint32 siblingChainSlug_, address siblingSwitchboard_ ) external onlyRole(GOVERNANCE_ROLE) { socket__.useSiblingSwitchboard(siblingChainSlug_, siblingSwitchboard_); } /** * @notice Pauses this switchboard completely. To be used in case of contract bug. * @param nonce_ The nonce used for signature. * @param signature_ The signature provided to validate the trip. */ function tripGlobal(uint256 nonce_, bytes memory signature_) external { address tripper = signatureVerifier__.recoverSigner( // it includes trip status at the end keccak256( abi.encode( TRIP_GLOBAL_SIG_IDENTIFIER, address(this), chainSlug, nonce_, true ) ), signature_ ); _checkRole(TRIP_ROLE, tripper); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[tripper]++) revert InvalidNonce(); } isGlobalTipped = true; emit GlobalTripChanged(true); } /** * @notice Pauses a path. To be used when a transmitter goes rogue and needs to be kicked. * @param nonce_ The nonce used for signature. * @param srcChainSlug_ The source chain slug of the path to be paused. * @param signature_ The signature provided to validate the trip. */ function tripPath( uint256 nonce_, uint32 srcChainSlug_, bytes memory signature_ ) external { address watcher = signatureVerifier__.recoverSigner( // it includes trip status at the end keccak256( abi.encode( TRIP_PATH_SIG_IDENTIFIER, address(this), srcChainSlug_, chainSlug, nonce_, true ) ), signature_ ); _checkRoleWithSlug(WATCHER_ROLE, srcChainSlug_, watcher); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[watcher]++) revert InvalidNonce(); } //source chain based tripping isPathTripped[srcChainSlug_] = true; emit PathTripChanged(srcChainSlug_, true); } /** * @notice Pauses a particular proposal of a packet. To be used if transmitter proposes wrong root. * @param nonce_ The nonce used for signature. * @param packetId_ The ID of the packet. * @param proposalCount_ The count of the proposal to be paused. * @param signature_ The signature provided to validate the trip. */ function tripProposal( uint256 nonce_, bytes32 packetId_, uint256 proposalCount_, bytes memory signature_ ) external { uint32 srcChainSlug = uint32(uint256(packetId_) >> 224); address watcher = signatureVerifier__.recoverSigner( keccak256( abi.encode( TRIP_PROPOSAL_SIG_IDENTIFIER, address(this), srcChainSlug, chainSlug, nonce_, packetId_, proposalCount_ ) ), signature_ ); _checkRoleWithSlug(WATCHER_ROLE, srcChainSlug, watcher); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[watcher]++) revert InvalidNonce(); } isProposalTripped[packetId_][proposalCount_] = true; emit ProposalTripped(packetId_, proposalCount_); } /** * @notice Unpauses a path. To be used after bad transmitter has been kicked from system. * @param nonce_ The nonce used for the signature. * @param srcChainSlug_ The source chain slug of the path to be unpaused. * @param signature_ The signature provided to validate the un trip. */ function unTripPath( uint256 nonce_, uint32 srcChainSlug_, bytes memory signature_ ) external { address unTripper = signatureVerifier__.recoverSigner( // it includes trip status at the end keccak256( abi.encode( UN_TRIP_PATH_SIG_IDENTIFIER, address(this), srcChainSlug_, chainSlug, nonce_, false ) ), signature_ ); _checkRole(UN_TRIP_ROLE, unTripper); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[unTripper]++) revert InvalidNonce(); } isPathTripped[srcChainSlug_] = false; emit PathTripChanged(srcChainSlug_, false); } /** * @notice Unpauses global execution. To be used if contract bug is addressed. * @param nonce_ The nonce used for the signature. * @param signature_ The signature provided to validate the un trip. */ function unTrip(uint256 nonce_, bytes memory signature_) external { address unTripper = signatureVerifier__.recoverSigner( // it includes trip status at the end keccak256( abi.encode( UN_TRIP_GLOBAL_SIG_IDENTIFIER, address(this), chainSlug, nonce_, false ) ), signature_ ); _checkRole(UN_TRIP_ROLE, unTripper); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[unTripper]++) revert InvalidNonce(); } isGlobalTipped = false; emit GlobalTripChanged(false); } /** * @notice Withdraw fees from the contract to an account. * @param withdrawTo_ The address where we should send the fees. */ function withdrawFees( address withdrawTo_ ) external onlyRole(WITHDRAW_ROLE) { if (withdrawTo_ == address(0)) revert ZeroAddress(); SafeTransferLib.safeTransferETH(withdrawTo_, address(this).balance); } /** * @notice Rescues funds from the contract if they are locked by mistake. * @param token_ The address of the token contract. * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyRole(RESCUE_ROLE) { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } /** * @inheritdoc ISwitchboard * @dev Receiving only allowed from execution manager * @dev Need to receive fees before change in case execution manager * is being updated on socket. */ function receiveFees(uint32) external payable override { if (msg.sender != address(socket__.executionManager__())) revert OnlyExecutionManager(); } } // File contracts/switchboard/default-switchboards/FastSwitchboard.sol pragma solidity 0.8.19; /** * @title FastSwitchboard contract * @dev This contract implements a fast version of the SwitchboardBase contract * that enables packet attestations and watchers registration. */ contract FastSwitchboard is SwitchboardBase { // dstChainSlug => totalWatchers registered mapping(uint32 => uint256) public totalWatchers; // used to track which watcher have attested a root // watcher => root => isAttested mapping(address => mapping(bytes32 => bool)) public isAttested; // used to detect when enough attestations are reached // root => attestationCount mapping(bytes32 => uint256) public attestations; // mapping to store if root is valid // marked when all watchers have attested for a root // root => isValid mapping(bytes32 => bool) public isRootValid; // Event emitted when a new socket is set event SocketSet(address newSocket); // Event emitted when a proposal is attested event ProposalAttested( bytes32 packetId, uint256 proposalCount, bytes32 root, address watcher, uint256 attestationsCount ); // Error emitted when a watcher already has role while granting error WatcherFound(); // Error emitted when a watcher is not found while attesting or while revoking role error WatcherNotFound(); // Error emitted when a root is already attested by a specific watcher. // This is hit even if they are attesting a new proposalCount with same root. error AlreadyAttested(); // Error emitted if grant/revoke is tried for watcher role using generic grant/revoke functions. // Watcher role is handled seperately bacause totalWatchers and fees need to be updated along with role change. error InvalidRole(); // Error emitted while attesting if root is zero or it doesnt match the root on socket for given proposal // helps in cases where attest tx has been sent but root changes on socket due to reorgs. error InvalidRoot(); /** * @dev Constructor function for the FastSwitchboard contract * @param owner_ Address of the owner of the contract * @param socket_ Address of the socket contract * @param chainSlug_ Chain slug of the chain where the contract is deployed * @param timeoutInSeconds_ Timeout in seconds after which proposals become valid if not tripped * @param signatureVerifier_ The address of the signature verifier contract */ constructor( address owner_, address socket_, uint32 chainSlug_, uint256 timeoutInSeconds_, ISignatureVerifier signatureVerifier_ ) AccessControlExtended(owner_) SwitchboardBase( socket_, chainSlug_, timeoutInSeconds_, signatureVerifier_ ) {} /** * @dev Function to attest a packet * @param packetId_ Packet ID * @param proposalCount_ Proposal count * @param root_ Root of the packet * @param signature_ Signature of the watcher * @notice we are attesting a root uniquely identified with packetId and proposalCount. However, * there can be multiple proposals for same root. To avoid need to re-attest for different proposals * with same root, we are storing attestations against root instead of packetId and proposalCount. */ function attest( bytes32 packetId_, uint256 proposalCount_, bytes32 root_, bytes calldata signature_ ) external { uint32 srcChainSlug = uint32(uint256(packetId_) >> 224); bytes32 root = socket__.packetIdRoots( packetId_, proposalCount_, address(this) ); if (root == bytes32(0)) revert InvalidRoot(); if (root != root_) revert InvalidRoot(); address watcher = signatureVerifier__.recoverSigner( keccak256( abi.encode( address(this), chainSlug, packetId_, proposalCount_, root_ ) ), signature_ ); if (isAttested[watcher][root]) revert AlreadyAttested(); if (!_hasRoleWithSlug(WATCHER_ROLE, srcChainSlug, watcher)) revert WatcherNotFound(); isAttested[watcher][root] = true; ++attestations[root]; if (attestations[root] >= totalWatchers[srcChainSlug]) isRootValid[root] = true; emit ProposalAttested( packetId_, proposalCount_, root, watcher, attestations[root] ); } /** * @inheritdoc ISwitchboard */ function setFees( uint256 nonce_, uint32 dstChainSlug_, uint128 switchboardFees_, uint128 verificationOverheadFees_, bytes calldata signature_ ) external override { address feesUpdater = signatureVerifier__.recoverSigner( keccak256( abi.encode( FEES_UPDATE_SIG_IDENTIFIER, address(this), chainSlug, dstChainSlug_, nonce_, switchboardFees_, verificationOverheadFees_ ) ), signature_ ); _checkRoleWithSlug(FEES_UPDATER_ROLE, dstChainSlug_, feesUpdater); // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 unchecked { if (nonce_ != nextNonce[feesUpdater]++) revert InvalidNonce(); } // switchboardFees_ input is amount needed per watcher, multipled and stored on chain to avoid watcher set tracking offchain. // switchboardFees_ are paid to switchboard per packet // verificationOverheadFees_ are paid to executor per message Fees memory feesObject = Fees({ switchboardFees: switchboardFees_ * uint128(totalWatchers[dstChainSlug_]), verificationOverheadFees: verificationOverheadFees_ }); fees[dstChainSlug_] = feesObject; emit SwitchboardFeesSet(dstChainSlug_, feesObject); } /** * @inheritdoc ISwitchboard */ function allowPacket( bytes32 root_, bytes32 packetId_, uint256 proposalCount_, uint32 srcChainSlug_, uint256 proposeTime_ ) external view override returns (bool) { uint64 packetCount = uint64(uint256(packetId_)); // any relevant trips triggered or invalid packet count. if ( isGlobalTipped || isPathTripped[srcChainSlug_] || isProposalTripped[packetId_][proposalCount_] || packetCount < initialPacketCount[srcChainSlug_] ) return false; // root has enough attestations if (isRootValid[root_]) return true; // this makes packets valid even if all watchers have not attested // used to make the system work when watchers are inactive due to infra etc problems if (block.timestamp - proposeTime_ > timeoutInSeconds) return true; // not enough attestations and timeout not hit return false; } /** * @notice adds a watcher for `srcChainSlug_` chain * @param srcChainSlug_ chain slug of the chain where the watcher is being added * @param watcher_ watcher address */ function grantWatcherRole( uint32 srcChainSlug_, address watcher_ ) external onlyRole(GOVERNANCE_ROLE) { if (_hasRoleWithSlug(WATCHER_ROLE, srcChainSlug_, watcher_)) revert WatcherFound(); _grantRoleWithSlug(WATCHER_ROLE, srcChainSlug_, watcher_); Fees storage fees = fees[srcChainSlug_]; uint128 watchersBefore = uint128(totalWatchers[srcChainSlug_]); // edge case handled by calling setFees function after boorstrapping is done. if (watchersBefore != 0 && fees.switchboardFees != 0) fees.switchboardFees = (fees.switchboardFees * (watchersBefore + 1)) / watchersBefore; ++totalWatchers[srcChainSlug_]; } /** * @notice removes a watcher from `srcChainSlug_` chain list * @param srcChainSlug_ chain slug of the chain where the watcher is being removed * @param watcher_ watcher address */ function revokeWatcherRole( uint32 srcChainSlug_, address watcher_ ) external onlyRole(GOVERNANCE_ROLE) { if (!_hasRoleWithSlug(WATCHER_ROLE, srcChainSlug_, watcher_)) revert WatcherNotFound(); _revokeRoleWithSlug(WATCHER_ROLE, srcChainSlug_, watcher_); Fees storage fees = fees[srcChainSlug_]; uint128 watchersBefore = uint128(totalWatchers[srcChainSlug_]); // revoking all watchers is an extreme case not expected to be hit after setup is done. if (watchersBefore > 1 && fees.switchboardFees != 0) fees.switchboardFees = (fees.switchboardFees * (watchersBefore - 1)) / watchersBefore; totalWatchers[srcChainSlug_]--; } /** * @notice returns true if non watcher role. Used to avoid granting watcher role directly * @dev If adding any new role to FastSwitchboard, have to add it here as well to make sure it can be set */ function isNonWatcherRole(bytes32 role_) public pure returns (bool) { if ( role_ == TRIP_ROLE || role_ == UN_TRIP_ROLE || role_ == WITHDRAW_ROLE || role_ == RESCUE_ROLE || role_ == GOVERNANCE_ROLE || role_ == FEES_UPDATER_ROLE ) return true; return false; } /** * @dev Overriding this function from AccessControl to make sure owner can't grant Watcher Role directly, and should * only use grantWatcherRole function instead. This is to make sure watcher count remains correct */ function grantRole( bytes32 role_, address grantee_ ) external override onlyOwner { if (isNonWatcherRole(role_)) { _grantRole(role_, grantee_); } else { revert InvalidRole(); } } /** * @dev Overriding this function from AccessControlExtended to make sure owner can't grant Watcher Role directly, and should * only use grantWatcherRole function instead. This is to make sure watcher count remains correct */ function grantRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address grantee_ ) external override onlyOwner { if (roleName_ != FEES_UPDATER_ROLE) revert InvalidRole(); _grantRoleWithSlug(roleName_, chainSlug_, grantee_); } /** * @dev Overriding this function from AccessControl to make sure owner can't revoke Watcher Role directly, and should * only use revokeWatcherRole function instead. This is to make sure watcher count remains correct */ function revokeRole( bytes32 role_, address grantee_ ) external override onlyOwner { if (isNonWatcherRole(role_)) { _revokeRole(role_, grantee_); } else { revert InvalidRole(); } } /** * @dev Overriding this function from AccessControlExtended to make sure owner can't revoke Watcher Role directly, and should * only use revokeWatcherRole function instead. This is to make sure watcher count remains correct */ function revokeRoleWithSlug( bytes32 roleName_, uint32 chainSlug_, address grantee_ ) external override onlyOwner { if (roleName_ != FEES_UPDATER_ROLE) revert InvalidRole(); _revokeRoleWithSlug(roleName_, chainSlug_, grantee_); } /** * @dev Overriding this function from AccessControlExtended to make sure owner can't grant Watcher Role directly, and should * only use grantWatcherRole function instead. This is to make sure watcher count remains correct */ function grantBatchRole( bytes32[] calldata roleNames_, uint32[] calldata slugs_, address[] calldata grantees_ ) external override onlyOwner { if ( roleNames_.length != grantees_.length || roleNames_.length != slugs_.length ) revert UnequalArrayLengths(); uint256 totalRoles = roleNames_.length; for (uint256 index = 0; index < totalRoles; ) { if (isNonWatcherRole(roleNames_[index])) { if (slugs_[index] > 0) _grantRoleWithSlug( roleNames_[index], slugs_[index], grantees_[index] ); else _grantRole(roleNames_[index], grantees_[index]); } else { revert InvalidRole(); } // we will reach block gas limit before this overflows unchecked { ++index; } } } /** * @dev Overriding this function from AccessControlExtended to make sure owner can't revoke Watcher Role directly, and should * only use revokeWatcherRole function instead. This is to make sure watcher count remains correct */ function revokeBatchRole( bytes32[] calldata roleNames_, uint32[] calldata slugs_, address[] calldata grantees_ ) external override onlyOwner { if ( roleNames_.length != grantees_.length || roleNames_.length != slugs_.length ) revert UnequalArrayLengths(); uint256 totalRoles = roleNames_.length; for (uint256 index = 0; index < totalRoles; ) { if (isNonWatcherRole(roleNames_[index])) { if (slugs_[index] > 0) _revokeRoleWithSlug( roleNames_[index], slugs_[index], grantees_[index] ); else _revokeRole(roleNames_[index], grantees_[index]); } else { revert InvalidRole(); } // we will reach block gas limit before this overflows unchecked { ++index; } } } } // File lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); } // File lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; // File contracts/socket/SocketBatcher.sol pragma solidity 0.8.19; interface IExecutionManagerOld { function setExecutionFees( uint256 nonce_, uint32 siblingChainSlug_, uint128 executionFees_, bytes calldata signature_ ) external; } /** * @title SocketBatcher * @notice A contract that facilitates the batching of packets across chains. It manages requests for sealing, proposing, attesting, and executing packets across multiple chains. * It also has functions for setting gas limits, execution overhead, and registering switchboards. * @dev This contract uses the AccessControl contract for managing role-based access control. */ contract SocketBatcher is AccessControl { address constant MOCK_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /* * @notice Constructs the SocketBatcher contract and grants the RESCUE_ROLE to the contract deployer. * @param owner_ The address of the contract deployer, who will be granted the RESCUE_ROLE. */ constructor(address owner_) AccessControl(owner_) { _grantRole(RESCUE_ROLE, owner_); } /** * @notice A struct representing a request to seal a batch of packets on the source chain. * @param batchSize The number of packets to be sealed in the batch. * @param capacitorAddress The address of the capacitor contract on the source chain. * @param signature The signature of the packet data. */ struct SealRequest { uint256 batchSize; address capacitorAddress; bytes signature; } /** * @notice A struct representing a proposal request for a packet. * @param packetId The ID of the packet being proposed. * @param root The Merkle root of the packet data. * @param switchboard The address of switchboard * @param signature The signature of the packet data. */ struct ProposeRequest { bytes32 packetId; bytes32 root; address switchboard; bytes signature; } /** * @notice A struct representing a proposal trip request. * @param switchboard The address of switchboard * @param nonce The nonce of watcher for this request. * @param packetId The ID of the packet being proposed. * @param proposalCount The proposal Count for the proposal. * @param signature The signature of the packet data. */ struct ProposalTripRequest { address switchboard; uint256 nonce; bytes32 packetId; uint256 proposalCount; bytes signature; } /** * @notice A struct representing an attestation request for a packet. * @param packetId The ID of the packet being attested. * @param srcChainSlug The slug of the source chain. * @param signature The signature of the packet data. */ struct AttestRequest { address switchboard; bytes32 packetId; uint256 proposalCount; bytes32 root; bytes signature; } /** * @notice A struct representing a request to execute a packet. * @param executionDetails The execution details. * @param messageDetails The message details of the packet. */ struct ExecuteRequest { ISocket.ExecutionDetails executionDetails; ISocket.MessageDetails messageDetails; } /** * @notice A struct representing a request to initiate an Arbitrum native transaction. * @param packetId The ID of the packet to be executed. * @param maxSubmissionCost The maximum submission cost of the transaction. * @param maxGas The maximum amount of gas for the transaction. * @param gasPriceBid The gas price bid for the transaction. * @param callValue The call value of the transaction. */ struct ArbitrumNativeInitiatorRequest { bytes32 packetId; uint256 maxSubmissionCost; uint256 maxGas; uint256 gasPriceBid; uint256 callValue; } /** * @notice A struct representing a request to send proof to polygon root * @param proof proof to submit on root tunnel */ struct ReceivePacketProofRequest { bytes proof; } /** * @notice A struct representing a request set fees in switchboard * @param nonce The nonce of fee setter address * @param dstChainSlug The sibling chain identifier * @param switchboardFees The fees needed by switchboard * @param verificationOverheadFees The fees needed for calling allowPacket while executing * @param signature The signature of the packet data. */ struct SwitchboardSetFeesRequest { uint256 nonce; uint32 dstChainSlug; uint128 switchboardFees; uint128 verificationOverheadFees; bytes signature; } /** * @notice A struct representing a request to set fees in execution manager and transmit manager * @param nonce The nonce of fee setter address * @param dstChainSlug The sibling chain identifier * @param fees The total fees needed * @param signature The signature of the packet data. */ struct SetTransmissionFeesRequest { uint256 nonce; uint32 dstChainSlug; uint128 fees; bytes signature; bytes4 functionSelector; } struct SetExecutionFeesRequest { uint256 nonce; uint32 dstChainSlug; uint80 perGasCost; uint80 perByteCost; uint80 overhead; uint256 fees; bytes signature; bytes4 functionSelector; } struct Call { address target; bytes callData; } event FailedLogBytes(bytes reason); event FailedLog(string reason); error MultiCallRevert(); /** * @notice sets fees in batch for switchboards * @param contractAddress_ address of contract to set fees * @param switchboardSetFeesRequest_ the list of requests */ function setFeesBatch( address contractAddress_, SwitchboardSetFeesRequest[] calldata switchboardSetFeesRequest_ ) external { uint256 executeRequestLength = switchboardSetFeesRequest_.length; for (uint256 index = 0; index < executeRequestLength; ) { FastSwitchboard(contractAddress_).setFees( switchboardSetFeesRequest_[index].nonce, switchboardSetFeesRequest_[index].dstChainSlug, switchboardSetFeesRequest_[index].switchboardFees, switchboardSetFeesRequest_[index].verificationOverheadFees, switchboardSetFeesRequest_[index].signature ); unchecked { ++index; } } } /** * @notice sets fees in batch for transmit manager * @param contractAddress_ address of contract to set fees * @param setTransmissionFeesRequests_ the list of requests */ function setTransmissionFeesBatch( address contractAddress_, SetTransmissionFeesRequest[] calldata setTransmissionFeesRequests_ ) external { uint256 feeRequestLength = setTransmissionFeesRequests_.length; for (uint256 index = 0; index < feeRequestLength; ) { ITransmitManager(contractAddress_).setTransmissionFees( setTransmissionFeesRequests_[index].nonce, setTransmissionFeesRequests_[index].dstChainSlug, setTransmissionFeesRequests_[index].fees, setTransmissionFeesRequests_[index].signature ); unchecked { ++index; } } } /** * @notice sets fees in batch for execution manager * @param contractAddress_ address of contract to set fees * @param setFeesRequests_ the list of requests */ function setExecutionFeesBatch( address contractAddress_, SetExecutionFeesRequest[] calldata setFeesRequests_ ) external { uint256 feeRequestLength = setFeesRequests_.length; for (uint256 index = 0; index < feeRequestLength; ) { if ( setFeesRequests_[index].functionSelector == IExecutionManagerOld.setExecutionFees.selector ) { IExecutionManagerOld(contractAddress_).setExecutionFees( setFeesRequests_[index].nonce, setFeesRequests_[index].dstChainSlug, uint128(setFeesRequests_[index].fees), setFeesRequests_[index].signature ); } else if ( setFeesRequests_[index].functionSelector == IExecutionManager.setExecutionFees.selector ) { IExecutionManager(contractAddress_).setExecutionFees( setFeesRequests_[index].nonce, setFeesRequests_[index].dstChainSlug, IExecutionManager.ExecutionFeesParam( setFeesRequests_[index].perGasCost, setFeesRequests_[index].perByteCost, setFeesRequests_[index].overhead ), setFeesRequests_[index].signature ); } else if ( setFeesRequests_[index].functionSelector == IExecutionManager.setRelativeNativeTokenPrice.selector ) { IExecutionManager(contractAddress_).setRelativeNativeTokenPrice( setFeesRequests_[index].nonce, setFeesRequests_[index].dstChainSlug, setFeesRequests_[index].fees, setFeesRequests_[index].signature ); } else if ( setFeesRequests_[index].functionSelector == IExecutionManager.setMsgValueMaxThreshold.selector ) { IExecutionManager(contractAddress_).setMsgValueMaxThreshold( setFeesRequests_[index].nonce, setFeesRequests_[index].dstChainSlug, setFeesRequests_[index].fees, setFeesRequests_[index].signature ); } else if ( setFeesRequests_[index].functionSelector == IExecutionManager.setMsgValueMinThreshold.selector ) { IExecutionManager(contractAddress_).setMsgValueMinThreshold( setFeesRequests_[index].nonce, setFeesRequests_[index].dstChainSlug, setFeesRequests_[index].fees, setFeesRequests_[index].signature ); } unchecked { ++index; } } } /** * @notice seal a batch of packets from capacitor on sourceChain mentioned in sealRequests * @param socketAddress_ address of socket * @param sealRequests_ the list of requests with packets to be sealed on sourceChain */ function _sealBatch( address socketAddress_, SealRequest[] calldata sealRequests_ ) internal { uint256 sealRequestLength = sealRequests_.length; for (uint256 index = 0; index < sealRequestLength; ) { ISocket(socketAddress_).seal( sealRequests_[index].batchSize, sealRequests_[index].capacitorAddress, sealRequests_[index].signature ); unchecked { ++index; } } } /** * @notice seal a batch of packets from capacitor on sourceChain mentioned in sealRequests * @param socketAddress_ address of socket * @param sealRequests_ the list of requests with packets to be sealed on sourceChain */ function sealBatch( address socketAddress_, SealRequest[] calldata sealRequests_ ) external { _sealBatch(socketAddress_, sealRequests_); } /** * @notice propose a batch of packets sequentially by socketDestination * @param socketAddress_ address of socket * @param proposeRequests_ the list of requests with packets to be proposed by socketDestination */ function _proposeBatch( address socketAddress_, ProposeRequest[] calldata proposeRequests_ ) internal { uint256 proposeRequestLength = proposeRequests_.length; for (uint256 index = 0; index < proposeRequestLength; ) { ISocket(socketAddress_).proposeForSwitchboard( proposeRequests_[index].packetId, proposeRequests_[index].root, proposeRequests_[index].switchboard, proposeRequests_[index].signature ); unchecked { ++index; } } } /** * @notice propose a batch of packets sequentially by socketDestination * @param socketAddress_ address of socket * @param proposeRequests_ the list of requests with packets to be proposed by socketDestination */ function proposeBatch( address socketAddress_, ProposeRequest[] calldata proposeRequests_ ) external { _proposeBatch(socketAddress_, proposeRequests_); } /** * @notice attests a batch of Packets * @param attestRequests_ the list of requests with packets to be attested by switchboard in sequence */ function _attestBatch(AttestRequest[] calldata attestRequests_) internal { uint256 attestRequestLength = attestRequests_.length; for (uint256 index = 0; index < attestRequestLength; ) { FastSwitchboard(attestRequests_[index].switchboard).attest( attestRequests_[index].packetId, attestRequests_[index].proposalCount, attestRequests_[index].root, attestRequests_[index].signature ); unchecked { ++index; } } } /** * @notice attests a batch of Packets * @param attestRequests_ the list of requests with packets to be attested by switchboard in sequence */ function attestBatch(AttestRequest[] calldata attestRequests_) external { _attestBatch(attestRequests_); } /** * @notice send a batch of propose, attest and execute transactions * @param socketAddress_ address of socket * @param proposeRequests_ the list of requests with packets to be proposed * @param attestRequests_ the list of requests with packets to be attested by switchboard * @param executeRequests_ the list of requests with messages to be executed */ function sendBatch( address socketAddress_, SealRequest[] calldata sealRequests_, ProposeRequest[] calldata proposeRequests_, AttestRequest[] calldata attestRequests_, ExecuteRequest[] calldata executeRequests_ ) external payable { _sealBatch(socketAddress_, sealRequests_); _proposeBatch(socketAddress_, proposeRequests_); _attestBatch(attestRequests_); _executeBatch(socketAddress_, executeRequests_); } /** * @notice trip a batch of Proposals * @param proposalTripRequests_ the list of requests for tripping proposals */ function proposalTripBatch( ProposalTripRequest[] calldata proposalTripRequests_ ) external { uint256 proposalTripRequestLength = proposalTripRequests_.length; for (uint256 index = 0; index < proposalTripRequestLength; ) { try FastSwitchboard(proposalTripRequests_[index].switchboard) .tripProposal( proposalTripRequests_[index].nonce, proposalTripRequests_[index].packetId, proposalTripRequests_[index].proposalCount, proposalTripRequests_[index].signature ) {} catch Error(string memory reason) { // catch failing revert() and require() emit FailedLog(reason); } catch (bytes memory reason) { // catch failing assert() emit FailedLogBytes(reason); } unchecked { ++index; } } } /** * @notice executes a batch of messages * @param socketAddress_ address of socket * @param executeRequests_ the list of requests with messages to be executed in sequence */ function _executeBatch( address socketAddress_, ExecuteRequest[] calldata executeRequests_ ) internal { uint256 executeRequestLength = executeRequests_.length; uint256 totalMsgValue = msg.value; for (uint256 index = 0; index < executeRequestLength; ) { bytes32 executionParams = executeRequests_[index] .messageDetails .executionParams; uint8 paramType = uint8(uint256(executionParams) >> 248); uint256 msgValue = uint256(uint248(uint256(executionParams))); if (paramType == 0) { msgValue = 0; } else totalMsgValue -= msgValue; ISocket(socketAddress_).execute{value: msgValue}( executeRequests_[index].executionDetails, executeRequests_[index].messageDetails ); unchecked { ++index; } } if (totalMsgValue > 0) { SafeTransferLib.safeTransferETH(msg.sender, totalMsgValue); } } /** * @notice executes a batch of messages * @param socketAddress_ address of socket * @param executeRequests_ the list of requests with messages to be executed in sequence */ function executeBatch( address socketAddress_, ExecuteRequest[] calldata executeRequests_ ) external payable { _executeBatch(socketAddress_, executeRequests_); } /** * @notice invoke receive Message on PolygonRootReceiver for a batch of messages in loop * @param polygonRootReceiverAddress_ address of polygonRootReceiver * @param receivePacketProofs_ the list of receivePacketProofs to be sent to receiveHook of polygonRootReceiver */ function receiveMessageBatch( address polygonRootReceiverAddress_, ReceivePacketProofRequest[] calldata receivePacketProofs_ ) external { uint256 receivePacketProofsLength = receivePacketProofs_.length; for (uint256 index = 0; index < receivePacketProofsLength; ) { INativeRelay(polygonRootReceiverAddress_).receiveMessage( receivePacketProofs_[index].proof ); unchecked { ++index; } } } /** * @notice returns latest proposalCounts for list of packetIds * @param socketAddress_ address of socket * @param packetIds_ the list of packetIds */ function getProposalCountBatch( address socketAddress_, bytes32[] calldata packetIds_ ) external view returns (uint256[] memory) { uint256 packetIdsLength = packetIds_.length; uint256[] memory proposalCounts = new uint256[](packetIdsLength); for (uint256 index = 0; index < packetIdsLength; ) { uint256 proposalCount = ISocket(socketAddress_).proposalCount( packetIds_[index] ); proposalCounts[index] = proposalCount; unchecked { ++index; } } return proposalCounts; } /** * @notice returns root for capacitorAddress and count * @param capacitorAddresses_ addresses of capacitor * @param packetCounts_ the list of packetCounts */ function getPacketRootBatch( address[] calldata capacitorAddresses_, uint64[] calldata packetCounts_ ) external view returns (bytes32[] memory) { uint256 capacitorAddressesLength = capacitorAddresses_.length; bytes32[] memory packetRoots = new bytes32[](capacitorAddressesLength); for (uint256 index = 0; index < capacitorAddressesLength; ) { packetRoots[index] = ICapacitor(capacitorAddresses_[index]) .getRootByCount(packetCounts_[index]); unchecked { ++index; } } return packetRoots; } /** * @notice initiate NativeConfirmation on arbitrumChain for a batch of packets in loop * @param switchboardAddress_ address of nativeArbitrumSwitchboard * @param arbitrumNativeInitiatorRequests_ the list of requests with packets to initiate nativeConfirmation on switchboard of arbitrumChain */ function initiateArbitrumNativeBatch( address switchboardAddress_, address callValueRefundAddress_, address remoteRefundAddress_, ArbitrumNativeInitiatorRequest[] calldata arbitrumNativeInitiatorRequests_ ) external payable { uint256 arbitrumNativeInitiatorRequestsLength = arbitrumNativeInitiatorRequests_ .length; uint256 totalMsgValue = msg.value; for ( uint256 index = 0; index < arbitrumNativeInitiatorRequestsLength; ) { totalMsgValue -= arbitrumNativeInitiatorRequests_[index].callValue; INativeRelay(switchboardAddress_).initiateNativeConfirmation{ value: arbitrumNativeInitiatorRequests_[index].callValue }( arbitrumNativeInitiatorRequests_[index].packetId, arbitrumNativeInitiatorRequests_[index].maxSubmissionCost, arbitrumNativeInitiatorRequests_[index].maxGas, arbitrumNativeInitiatorRequests_[index].gasPriceBid, callValueRefundAddress_, remoteRefundAddress_ ); unchecked { ++index; } } if (totalMsgValue > 0) { if (callValueRefundAddress_ == address(0)) revert ZeroAddress(); SafeTransferLib.safeTransferETH( callValueRefundAddress_, totalMsgValue ); } } /** * @notice initiate NativeConfirmation on nativeChain(s) for a batch of packets in loop * @param switchboardAddress_ address of nativeSwitchboard * @param nativePacketIds_ the list of requests with packets to initiate nativeConfirmation on switchboard of native chains */ function initiateNativeBatch( address switchboardAddress_, bytes32[] calldata nativePacketIds_ ) external { uint256 nativePacketIdsLength = nativePacketIds_.length; for (uint256 index = 0; index < nativePacketIdsLength; ) { INativeRelay(switchboardAddress_).initiateNativeConfirmation( nativePacketIds_[index] ); unchecked { ++index; } } } // RELAYER UTILITY FUNCTIONS function withdrawals( address payable[] memory addresses, uint[] memory amounts ) public payable { uint256 totalAmount; for (uint i; i < addresses.length; i++) { totalAmount += amounts[i]; addresses[i].transfer(amounts[i]); } require(totalAmount == msg.value, "LOW_MSG_VALUE"); } /** @dev Check the token balance of a wallet in a token contract Returns the balance of the token for user. Avoids possible errors: - return 0 on non-contract address **/ function balanceOf( address user, address token ) public view returns (uint256) { if (token == MOCK_ETH_ADDRESS) { return user.balance; // ETH balance } else { // check if token is actually a contract uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(token) } if (size > 0) { return IERC20(token).balanceOf(user); } } revert("INVALID_TOKEN"); } /** * @notice Fetches, for a list of _users and _tokens (ETH included with mock address), the balances * @param users The list of users * @param tokens The list of tokens * @return And array with the concatenation of, for each user, his/her balances **/ function batchBalanceOf( address[] calldata users, address[] calldata tokens ) external view returns (uint256[] memory) { uint256[] memory balances = new uint256[](users.length * tokens.length); for (uint256 i = 0; i < users.length; i++) { for (uint256 j = 0; j < tokens.length; j++) { balances[i * tokens.length + j] = balanceOf( users[i], tokens[j] ); } } return balances; } /** * @notice Rescues funds from the contract if they are locked by mistake. * @param token_ The address of the token contract. * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyRole(RESCUE_ROLE) { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } function multicall( Call[] calldata calls ) external view returns (uint256 blockNumber, bytes[] memory returnData) { uint256 length = calls.length; returnData = new bytes[](length); for (uint256 index = 0; index < length; ) { (bool success, bytes memory result) = calls[index] .target .staticcall(calls[index].callData); if (!success) revert MultiCallRevert(); returnData[index] = result; unchecked { ++index; } } } }
Compiler Settings
{"outputSelection":{"*":{"*":["*"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"owner_","internalType":"address"}]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"MultiCallRevert","inputs":[]},{"type":"error","name":"NoPermit","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"FailedLog","inputs":[{"type":"string","name":"reason","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"FailedLogBytes","inputs":[{"type":"bytes","name":"reason","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"OwnerClaimed","inputs":[{"type":"address","name":"claimer","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnerNominated","inputs":[{"type":"address","name":"nominee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"grantee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"revokee","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"attestBatch","inputs":[{"type":"tuple[]","name":"attestRequests_","internalType":"struct SocketBatcher.AttestRequest[]","components":[{"type":"address","name":"switchboard","internalType":"address"},{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"proposalCount","internalType":"uint256"},{"type":"bytes32","name":"root","internalType":"bytes32"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"batchBalanceOf","inputs":[{"type":"address[]","name":"users","internalType":"address[]"},{"type":"address[]","name":"tokens","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"executeBatch","inputs":[{"type":"address","name":"socketAddress_","internalType":"address"},{"type":"tuple[]","name":"executeRequests_","internalType":"struct SocketBatcher.ExecuteRequest[]","components":[{"type":"tuple","name":"executionDetails","internalType":"struct ISocket.ExecutionDetails","components":[{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"proposalCount","internalType":"uint256"},{"type":"uint256","name":"executionGasLimit","internalType":"uint256"},{"type":"bytes","name":"decapacitorProof","internalType":"bytes"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"tuple","name":"messageDetails","internalType":"struct ISocket.MessageDetails","components":[{"type":"bytes32","name":"msgId","internalType":"bytes32"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"uint256","name":"minMsgGasLimit","internalType":"uint256"},{"type":"bytes32","name":"executionParams","internalType":"bytes32"},{"type":"bytes","name":"payload","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"","internalType":"bytes32[]"}],"name":"getPacketRootBatch","inputs":[{"type":"address[]","name":"capacitorAddresses_","internalType":"address[]"},{"type":"uint64[]","name":"packetCounts_","internalType":"uint64[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getProposalCountBatch","inputs":[{"type":"address","name":"socketAddress_","internalType":"address"},{"type":"bytes32[]","name":"packetIds_","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"grantee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"address_","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"initiateArbitrumNativeBatch","inputs":[{"type":"address","name":"switchboardAddress_","internalType":"address"},{"type":"address","name":"callValueRefundAddress_","internalType":"address"},{"type":"address","name":"remoteRefundAddress_","internalType":"address"},{"type":"tuple[]","name":"arbitrumNativeInitiatorRequests_","internalType":"struct SocketBatcher.ArbitrumNativeInitiatorRequest[]","components":[{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"maxSubmissionCost","internalType":"uint256"},{"type":"uint256","name":"maxGas","internalType":"uint256"},{"type":"uint256","name":"gasPriceBid","internalType":"uint256"},{"type":"uint256","name":"callValue","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initiateNativeBatch","inputs":[{"type":"address","name":"switchboardAddress_","internalType":"address"},{"type":"bytes32[]","name":"nativePacketIds_","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256"},{"type":"bytes[]","name":"returnData","internalType":"bytes[]"}],"name":"multicall","inputs":[{"type":"tuple[]","name":"calls","internalType":"struct SocketBatcher.Call[]","components":[{"type":"address","name":"target","internalType":"address"},{"type":"bytes","name":"callData","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nominateOwner","inputs":[{"type":"address","name":"nominee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nominee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposalTripBatch","inputs":[{"type":"tuple[]","name":"proposalTripRequests_","internalType":"struct SocketBatcher.ProposalTripRequest[]","components":[{"type":"address","name":"switchboard","internalType":"address"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"proposalCount","internalType":"uint256"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposeBatch","inputs":[{"type":"address","name":"socketAddress_","internalType":"address"},{"type":"tuple[]","name":"proposeRequests_","internalType":"struct SocketBatcher.ProposeRequest[]","components":[{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"bytes32","name":"root","internalType":"bytes32"},{"type":"address","name":"switchboard","internalType":"address"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"receiveMessageBatch","inputs":[{"type":"address","name":"polygonRootReceiverAddress_","internalType":"address"},{"type":"tuple[]","name":"receivePacketProofs_","internalType":"struct SocketBatcher.ReceivePacketProofRequest[]","components":[{"type":"bytes","name":"proof","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueFunds","inputs":[{"type":"address","name":"token_","internalType":"address"},{"type":"address","name":"rescueTo_","internalType":"address"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"revokee_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sealBatch","inputs":[{"type":"address","name":"socketAddress_","internalType":"address"},{"type":"tuple[]","name":"sealRequests_","internalType":"struct SocketBatcher.SealRequest[]","components":[{"type":"uint256","name":"batchSize","internalType":"uint256"},{"type":"address","name":"capacitorAddress","internalType":"address"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"sendBatch","inputs":[{"type":"address","name":"socketAddress_","internalType":"address"},{"type":"tuple[]","name":"sealRequests_","internalType":"struct SocketBatcher.SealRequest[]","components":[{"type":"uint256","name":"batchSize","internalType":"uint256"},{"type":"address","name":"capacitorAddress","internalType":"address"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"tuple[]","name":"proposeRequests_","internalType":"struct SocketBatcher.ProposeRequest[]","components":[{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"bytes32","name":"root","internalType":"bytes32"},{"type":"address","name":"switchboard","internalType":"address"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"tuple[]","name":"attestRequests_","internalType":"struct SocketBatcher.AttestRequest[]","components":[{"type":"address","name":"switchboard","internalType":"address"},{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"proposalCount","internalType":"uint256"},{"type":"bytes32","name":"root","internalType":"bytes32"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"tuple[]","name":"executeRequests_","internalType":"struct SocketBatcher.ExecuteRequest[]","components":[{"type":"tuple","name":"executionDetails","internalType":"struct ISocket.ExecutionDetails","components":[{"type":"bytes32","name":"packetId","internalType":"bytes32"},{"type":"uint256","name":"proposalCount","internalType":"uint256"},{"type":"uint256","name":"executionGasLimit","internalType":"uint256"},{"type":"bytes","name":"decapacitorProof","internalType":"bytes"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"tuple","name":"messageDetails","internalType":"struct ISocket.MessageDetails","components":[{"type":"bytes32","name":"msgId","internalType":"bytes32"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"uint256","name":"minMsgGasLimit","internalType":"uint256"},{"type":"bytes32","name":"executionParams","internalType":"bytes32"},{"type":"bytes","name":"payload","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExecutionFeesBatch","inputs":[{"type":"address","name":"contractAddress_","internalType":"address"},{"type":"tuple[]","name":"setFeesRequests_","internalType":"struct SocketBatcher.SetExecutionFeesRequest[]","components":[{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint32","name":"dstChainSlug","internalType":"uint32"},{"type":"uint80","name":"perGasCost","internalType":"uint80"},{"type":"uint80","name":"perByteCost","internalType":"uint80"},{"type":"uint80","name":"overhead","internalType":"uint80"},{"type":"uint256","name":"fees","internalType":"uint256"},{"type":"bytes","name":"signature","internalType":"bytes"},{"type":"bytes4","name":"functionSelector","internalType":"bytes4"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeesBatch","inputs":[{"type":"address","name":"contractAddress_","internalType":"address"},{"type":"tuple[]","name":"switchboardSetFeesRequest_","internalType":"struct SocketBatcher.SwitchboardSetFeesRequest[]","components":[{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint32","name":"dstChainSlug","internalType":"uint32"},{"type":"uint128","name":"switchboardFees","internalType":"uint128"},{"type":"uint128","name":"verificationOverheadFees","internalType":"uint128"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTransmissionFeesBatch","inputs":[{"type":"address","name":"contractAddress_","internalType":"address"},{"type":"tuple[]","name":"setTransmissionFeesRequests_","internalType":"struct SocketBatcher.SetTransmissionFeesRequest[]","components":[{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint32","name":"dstChainSlug","internalType":"uint32"},{"type":"uint128","name":"fees","internalType":"uint128"},{"type":"bytes","name":"signature","internalType":"bytes"},{"type":"bytes4","name":"functionSelector","internalType":"bytes4"}]}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"withdrawals","inputs":[{"type":"address[]","name":"addresses","internalType":"address payable[]"},{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b50604051620038a6380380620038a6833981016040819052620000349162000125565b8080620000418162000077565b506200007090507fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f2925382620000ca565b5062000157565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000602082840312156200013857600080fd5b81516001600160a01b03811681146200015057600080fd5b9392505050565b61373f80620001676000396000f3fe6080604052600436106101a05760003560e01c8063861a3717116100e1578063b59b28ef1161008a578063d6c19d4b11610064578063d6c19d4b146104a9578063f15af7aa146104bc578063f7888aec146104dc578063fa98a33f1461050a57600080fd5b8063b59b28ef1461043b578063caa5c23f1461045b578063d547741f1461048957600080fd5b806391d14854116100bb57806391d14854146103cb578063a52b55eb146103fb578063a5c003f71461041b57600080fd5b8063861a37171461036d57806389601445146103805780638da5cb5b146103a057600080fd5b80633bd1adec1161014e578063634379561161012857806363437956146102e05780636ccae054146103005780636e9e1ab91461032057806374032c9e1461034d57600080fd5b80633bd1adec1461028b5780633cfa1bb0146102a05780635b94db27146102c057600080fd5b80631d86d44b1161017f5780631d86d44b146101fa57806320f99c0a1461021a5780632f2ff15d1461026b57600080fd5b806293ac86146101a557806309e3b0ea146101ba57806312337d0f146101da575b600080fd5b6101b86101b33660046128f6565b61051d565b005b3480156101c657600080fd5b506101b86101d53660046128f6565b61052d565b3480156101e657600080fd5b506101b86101f53660046128f6565b61067a565b34801561020657600080fd5b506101b86102153660046128f6565b61072a565b34801561022657600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027757600080fd5b506101b861028636600461294b565b610735565b34801561029757600080fd5b506101b8610794565b3480156102ac57600080fd5b506101b86102bb3660046128f6565b6107f0565b3480156102cc57600080fd5b506101b86102db36600461297b565b61096c565b3480156102ec57600080fd5b506101b86102fb3660046128f6565b610a2c565b34801561030c57600080fd5b506101b861031b36600461299f565b610a37565b34801561032c57600080fd5b5061034061033b3660046128f6565b610ada565b60405161026291906129e0565b34801561035957600080fd5b506101b86103683660046128f6565b610bf8565b6101b861037b366004612a24565b61138c565b34801561038c57600080fd5b506101b861039b3660046128f6565b61157f565b3480156103ac57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610241565b3480156103d757600080fd5b506103eb6103e636600461294b565b61161b565b6040519015158152602001610262565b34801561040757600080fd5b506101b8610416366004612acf565b611658565b34801561042757600080fd5b50610340610436366004612b11565b611877565b34801561044757600080fd5b50610340610456366004612b11565b6119e6565b34801561046757600080fd5b5061047b610476366004612acf565b611af5565b604051610262929190612be1565b34801561049557600080fd5b506101b86104a436600461294b565b611c8c565b6101b86104b7366004612d6d565b611ce7565b3480156104c857600080fd5b506101b86104d7366004612acf565b611e10565b3480156104e857600080fd5b506104fc6104f7366004612e3a565b611e1a565b604051908152602001610262565b6101b8610518366004612e68565b611f7a565b610528838383611fb0565b505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff16637348746b85858481811061056757610567612f41565b90506020028101906105799190612f70565b3586868581811061058c5761058c612f41565b905060200281019061059e9190612f70565b6105af906040810190602001612fae565b8787868181106105c1576105c1612f41565b90506020028101906105d39190612f70565b6105e4906060810190604001612fd4565b8888878181106105f6576105f6612f41565b90506020028101906106089190612f70565b610616906060810190613006565b6040518663ffffffff1660e01b81526004016106369594939291906130b4565b600060405180830381600087803b15801561065057600080fd5b505af1158015610664573d6000803e3d6000fd5b50505050806001019050610531565b5050505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663f953cec78585848181106106b4576106b4612f41565b90506020028101906106c691906130fd565b6106d09080613006565b6040518363ffffffff1660e01b81526004016106ed929190613131565b600060405180830381600087803b15801561070757600080fd5b505af115801561071b573d6000803e3d6000fd5b5050505080600101905061067e565b610528838383612127565b60005473ffffffffffffffffffffffffffffffffffffffff163314610786576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107908282612237565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107e5576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107ee336122bd565b565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663f22b460e85858481811061082a5761082a612f41565b905060200281019061083c9190612f70565b3586868581811061084f5761084f612f41565b90506020028101906108619190612f70565b610872906040810190602001612fae565b87878681811061088457610884612f41565b90506020028101906108969190612f70565b6108a7906060810190604001612fd4565b8888878181106108b9576108b9612f41565b90506020028101906108cb9190612f70565b6108dc906080810190606001612fd4565b8989888181106108ee576108ee612f41565b90506020028101906109009190612f70565b61090e906080810190613006565b6040518763ffffffff1660e01b815260040161092f9695949392919061314d565b600060405180830381600087803b15801561094957600080fd5b505af115801561095d573d6000803e3d6000fd5b505050508060010190506107f4565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109bd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b610528838383612335565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16610ac9576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b610ad484848461246e565b50505050565b60608160008167ffffffffffffffff811115610af857610af8612c69565b604051908082528060200260200182016040528015610b21578160200160208202803683370190505b50905060005b82811015610bee5760008773ffffffffffffffffffffffffffffffffffffffff166379cfc006888885818110610b5f57610b5f612f41565b905060200201356040518263ffffffff1660e01b8152600401610b8491815260200190565b602060405180830381865afa158015610ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc591906131a1565b905080838381518110610bda57610bda612f41565b602090810291909101015250600101610b27565b5095945050505050565b8060005b81811015610673577f9f4ad32e00000000000000000000000000000000000000000000000000000000848483818110610c3757610c37612f41565b9050602002810190610c4991906131ba565b610c5b9061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603610da9578473ffffffffffffffffffffffffffffffffffffffff16639f4ad32e858584818110610cb057610cb0612f41565b9050602002810190610cc291906131ba565b35868685818110610cd557610cd5612f41565b9050602002810190610ce791906131ba565b610cf8906040810190602001612fae565b878786818110610d0a57610d0a612f41565b9050602002810190610d1c91906131ba565b60a00135888887818110610d3257610d32612f41565b9050602002810190610d4491906131ba565b610d529060c0810190613006565b6040518663ffffffff1660e01b8152600401610d729594939291906130b4565b600060405180830381600087803b158015610d8c57600080fd5b505af1158015610da0573d6000803e3d6000fd5b50505050611384565b7f50a9cf6700000000000000000000000000000000000000000000000000000000848483818110610ddc57610ddc612f41565b9050602002810190610dee91906131ba565b610e009061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603610fc9578473ffffffffffffffffffffffffffffffffffffffff166350a9cf67858584818110610e5557610e55612f41565b9050602002810190610e6791906131ba565b35868685818110610e7a57610e7a612f41565b9050602002810190610e8c91906131ba565b610e9d906040810190602001612fae565b6040518060600160405280898988818110610eba57610eba612f41565b9050602002810190610ecc91906131ba565b610edd906060810190604001613230565b69ffffffffffffffffffff168152602001898988818110610f0057610f00612f41565b9050602002810190610f1291906131ba565b610f23906080810190606001613230565b69ffffffffffffffffffff168152602001898988818110610f4657610f46612f41565b9050602002810190610f5891906131ba565b610f699060a0810190608001613230565b69ffffffffffffffffffff169052888887818110610f8957610f89612f41565b9050602002810190610f9b91906131ba565b610fa99060c0810190613006565b6040518663ffffffff1660e01b8152600401610d7295949392919061325c565b7f9f10285500000000000000000000000000000000000000000000000000000000848483818110610ffc57610ffc612f41565b905060200281019061100e91906131ba565b6110209061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603611137578473ffffffffffffffffffffffffffffffffffffffff16639f10285585858481811061107557611075612f41565b905060200281019061108791906131ba565b3586868581811061109a5761109a612f41565b90506020028101906110ac91906131ba565b6110bd906040810190602001612fae565b8787868181106110cf576110cf612f41565b90506020028101906110e191906131ba565b60a001358888878181106110f7576110f7612f41565b905060200281019061110991906131ba565b6111179060c0810190613006565b6040518663ffffffff1660e01b8152600401610d729594939291906132af565b7fa18857000000000000000000000000000000000000000000000000000000000084848381811061116a5761116a612f41565b905060200281019061117c91906131ba565b61118e9061010081019060e0016131ee565b7fffffffff0000000000000000000000000000000000000000000000000000000016036111e3578473ffffffffffffffffffffffffffffffffffffffff1663a188570085858481811061107557611075612f41565b7f308795b20000000000000000000000000000000000000000000000000000000084848381811061121657611216612f41565b905060200281019061122891906131ba565b61123a9061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603611384578473ffffffffffffffffffffffffffffffffffffffff1663308795b285858481811061128f5761128f612f41565b90506020028101906112a191906131ba565b358686858181106112b4576112b4612f41565b90506020028101906112c691906131ba565b6112d7906040810190602001612fae565b8787868181106112e9576112e9612f41565b90506020028101906112fb91906131ba565b60a0013588888781811061131157611311612f41565b905060200281019061132391906131ba565b6113319060c0810190613006565b6040518663ffffffff1660e01b81526004016113519594939291906132af565b600060405180830381600087803b15801561136b57600080fd5b505af115801561137f573d6000803e3d6000fd5b505050505b600101610bfc565b803460005b82811015611518578484828181106113ab576113ab612f41565b905060a0020160800135826113c0919061330a565b91508773ffffffffffffffffffffffffffffffffffffffff1663190d5e4d8686848181106113f0576113f0612f41565b905060a002016080013587878581811061140c5761140c612f41565b905060a002016000013588888681811061142857611428612f41565b905060a002016020013589898781811061144457611444612f41565b905060a00201604001358a8a8881811061146057611460612f41565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815260048101969096526024860194909452506044840191909152606060a0909202010135606482015273ffffffffffffffffffffffffffffffffffffffff808c1660848301528a1660a482015260c4016000604051808303818588803b1580156114f457600080fd5b505af1158015611508573d6000803e3d6000fd5b5050505050806001019050611391565b5080156115765773ffffffffffffffffffffffffffffffffffffffff861661156c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611576868261255e565b50505050505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663a9a599e08585848181106115b9576115b9612f41565b905060200201356040518263ffffffff1660e01b81526004016115de91815260200190565b600060405180830381600087803b1580156115f857600080fd5b505af115801561160c573d6000803e3d6000fd5b50505050806001019050611583565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b90505b92915050565b8060005b81811015610ad45783838281811061167657611676612f41565b90506020028101906116889190612f70565b61169690602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff166389ee87558585848181106116c3576116c3612f41565b90506020028101906116d59190612f70565b602001358686858181106116eb576116eb612f41565b90506020028101906116fd9190612f70565b6040013587878681811061171357611713612f41565b90506020028101906117259190612f70565b6060013588888781811061173b5761173b612f41565b905060200281019061174d9190612f70565b61175b906080810190613006565b6040518663ffffffff1660e01b815260040161177b95949392919061331d565b600060405180830381600087803b15801561179557600080fd5b505af19250505080156117a6575060015b61186f576117b2613343565b806308c379a00361180e57506117c661335f565b806117d15750611810565b7f3f3d95f05f600551a08f68e59143bde093cf93527273b87a2d85d88cc684bea0816040516118009190613407565b60405180910390a15061186f565b505b3d80801561183a576040519150601f19603f3d011682016040523d82523d6000602084013e61183f565b606091505b507fbda109f4d5e5950ba8c4893817cda7a795c8ba5442b23e81f382f76f8d3a1ac3816040516118009190613407565b60010161165c565b60608360008167ffffffffffffffff81111561189557611895612c69565b6040519080825280602002602001820160405280156118be578160200160208202803683370190505b50905060005b828110156119db578787828181106118de576118de612f41565b90506020020160208101906118f3919061297b565b73ffffffffffffffffffffffffffffffffffffffff1663d1af313c87878481811061192057611920612f41565b9050602002016020810190611935919061341a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815267ffffffffffffffff9091166004820152602401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906131a1565b8282815181106119c8576119c8612f41565b60209081029190910101526001016118c4565b509695505050505050565b606060006119f48386613444565b67ffffffffffffffff811115611a0c57611a0c612c69565b604051908082528060200260200182016040528015611a35578160200160208202803683370190505b50905060005b85811015610bee5760005b84811015611ae257611a9f888884818110611a6357611a63612f41565b9050602002016020810190611a78919061297b565b878784818110611a8a57611a8a612f41565b90506020020160208101906104f7919061297b565b8382611aab8886613444565b611ab5919061345b565b81518110611ac557611ac5612f41565b602090810291909101015280611ada8161346e565b915050611a46565b5080611aed8161346e565b915050611a3b565b60006060828067ffffffffffffffff811115611b1357611b13612c69565b604051908082528060200260200182016040528015611b4657816020015b6060815260200190600190039081611b315790505b50915060005b81811015611c8357600080878784818110611b6957611b69612f41565b9050602002810190611b7b91906134a6565b611b8990602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff16888885818110611bb157611bb1612f41565b9050602002810190611bc391906134a6565b611bd1906020810190613006565b604051611bdf9291906134da565b600060405180830381855afa9150503d8060008114611c1a576040519150601f19603f3d011682016040523d82523d6000602084013e611c1f565b606091505b509150915081611c5b576040517f51ba533f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80858481518110611c6e57611c6e612f41565b60209081029190910101525050600101611b4c565b50509250929050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611cdd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079082826125d3565b6000805b8351811015611da657828181518110611d0657611d06612f41565b602002602001015182611d19919061345b565b9150838181518110611d2d57611d2d612f41565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc848381518110611d6057611d60612f41565b60200260200101519081150290604051600060405180830381858888f19350505050158015611d93573d6000803e3d6000fd5b5080611d9e8161346e565b915050611ceb565b50348114610528576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4c4f575f4d53475f56414c5545000000000000000000000000000000000000006044820152606401610ac0565b6107908282612656565b60007fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601611e77575073ffffffffffffffffffffffffffffffffffffffff821631611652565b813b8015611f17576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528416906370a0823190602401602060405180830381865afa158015611eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0f91906131a1565b915050611652565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f544f4b454e000000000000000000000000000000000000006044820152606401610ac0565b611f85898989612127565b611f90898787612335565b611f9a8484612656565b611fa5898383611fb0565b505050505050505050565b803460005b82811015612116576000858583818110611fd157611fd1612f41565b9050602002810190611fe391906134a6565b611ff1906020810190612f70565b60600135905060f881901c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8216600082900361202f5750600061203c565b612039818661330a565b94505b8873ffffffffffffffffffffffffffffffffffffffff1663275c41c9828a8a8881811061206b5761206b612f41565b905060200281019061207d91906134a6565b6120879080612f70565b8b8b8981811061209957612099612f41565b90506020028101906120ab91906134a6565b6120b9906020810190612f70565b6040518463ffffffff1660e01b81526004016120d692919061354e565b6000604051808303818588803b1580156120ef57600080fd5b505af1158015612103573d6000803e3d6000fd5b5050505050836001019350505050611fb5565b50801561067357610673338261255e565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663c85ce32585858481811061216157612161612f41565b90506020028101906121739190613625565b3586868581811061218657612186612f41565b90506020028101906121989190613625565b6121a990604081019060200161297b565b8787868181106121bb576121bb612f41565b90506020028101906121cd9190613625565b6121db906040810190613006565b6040518563ffffffff1660e01b81526004016121fa9493929190613659565b600060405180830381600087803b15801561221457600080fd5b505af1158015612228573d6000803e3d6000fd5b5050505080600101905061212b565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663dc30986385858481811061236f5761236f612f41565b90506020028101906123819190613699565b3586868581811061239457612394612f41565b90506020028101906123a69190613699565b602001358787868181106123bc576123bc612f41565b90506020028101906123ce9190613699565b6123df90606081019060400161297b565b8888878181106123f1576123f1612f41565b90506020028101906124039190613699565b612411906060810190613006565b6040518663ffffffff1660e01b81526004016124319594939291906136cd565b600060405180830381600087803b15801561244b57600080fd5b505af115801561245f573d6000803e3d6000fd5b50505050806001019050612339565b73ffffffffffffffffffffffffffffffffffffffff82166124bb576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161250257610528828261255e565b8273ffffffffffffffffffffffffffffffffffffffff163b600003612553576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105288383836127b6565b600080600080600085875af1905080610528576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610ac0565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b8060005b81811015610ad45783838281811061267457612674612f41565b90506020028101906126869190612f70565b61269490602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff1663d2883fbe8585848181106126c1576126c1612f41565b90506020028101906126d39190612f70565b602001358686858181106126e9576126e9612f41565b90506020028101906126fb9190612f70565b6040013587878681811061271157612711612f41565b90506020028101906127239190612f70565b6060013588888781811061273957612739612f41565b905060200281019061274b9190612f70565b612759906080810190613006565b6040518663ffffffff1660e01b815260040161277995949392919061331d565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b5050505080600101905061265a565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610ac0565b73ffffffffffffffffffffffffffffffffffffffff811681146128a757600080fd5b50565b60008083601f8401126128bc57600080fd5b50813567ffffffffffffffff8111156128d457600080fd5b6020830191508360208260051b85010111156128ef57600080fd5b9250929050565b60008060006040848603121561290b57600080fd5b833561291681612885565b9250602084013567ffffffffffffffff81111561293257600080fd5b61293e868287016128aa565b9497909650939450505050565b6000806040838503121561295e57600080fd5b82359150602083013561297081612885565b809150509250929050565b60006020828403121561298d57600080fd5b813561299881612885565b9392505050565b6000806000606084860312156129b457600080fd5b83356129bf81612885565b925060208401356129cf81612885565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b81811015612a18578351835292840192918401916001016129fc565b50909695505050505050565b600080600080600060808688031215612a3c57600080fd5b8535612a4781612885565b94506020860135612a5781612885565b93506040860135612a6781612885565b9250606086013567ffffffffffffffff80821115612a8457600080fd5b818801915088601f830112612a9857600080fd5b813581811115612aa757600080fd5b89602060a083028501011115612abc57600080fd5b9699959850939650602001949392505050565b60008060208385031215612ae257600080fd5b823567ffffffffffffffff811115612af957600080fd5b612b05858286016128aa565b90969095509350505050565b60008060008060408587031215612b2757600080fd5b843567ffffffffffffffff80821115612b3f57600080fd5b612b4b888389016128aa565b90965094506020870135915080821115612b6457600080fd5b50612b71878288016128aa565b95989497509550505050565b6000815180845260005b81811015612ba357602081850181015186830182015201612b87565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015612c5b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452612c49868351612b7d565b95509284019290840190600101612c0f565b509398975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715612cdc57612cdc612c69565b6040525050565b600067ffffffffffffffff821115612cfd57612cfd612c69565b5060051b60200190565b600082601f830112612d1857600080fd5b81356020612d2582612ce3565b604051612d328282612c98565b83815260059390931b8501820192828101915086841115612d5257600080fd5b8286015b848110156119db5780358352918301918301612d56565b60008060408385031215612d8057600080fd5b823567ffffffffffffffff80821115612d9857600080fd5b818501915085601f830112612dac57600080fd5b81356020612db982612ce3565b604051612dc68282612c98565b83815260059390931b8501820192828101915089841115612de657600080fd5b948201945b83861015612e0d578535612dfe81612885565b82529482019490820190612deb565b96505086013592505080821115612e2357600080fd5b50612e3085828601612d07565b9150509250929050565b60008060408385031215612e4d57600080fd5b8235612e5881612885565b9150602083013561297081612885565b600080600080600080600080600060a08a8c031215612e8657600080fd5b8935612e9181612885565b985060208a013567ffffffffffffffff80821115612eae57600080fd5b612eba8d838e016128aa565b909a50985060408c0135915080821115612ed357600080fd5b612edf8d838e016128aa565b909850965060608c0135915080821115612ef857600080fd5b612f048d838e016128aa565b909650945060808c0135915080821115612f1d57600080fd5b50612f2a8c828d016128aa565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112612fa457600080fd5b9190910192915050565b600060208284031215612fc057600080fd5b813563ffffffff8116811461299857600080fd5b600060208284031215612fe657600080fd5b81356fffffffffffffffffffffffffffffffff8116811461299857600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261303b57600080fd5b83018035915067ffffffffffffffff82111561305657600080fd5b6020019150368190038213156128ef57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b85815263ffffffff851660208201526fffffffffffffffffffffffffffffffff841660408201526080606082015260006130f260808301848661306b565b979650505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1833603018112612fa457600080fd5b60208152600061314560208301848661306b565b949350505050565b86815263ffffffff8616602082015260006fffffffffffffffffffffffffffffffff808716604084015280861660608401525060a0608083015261319560a08301848661306b565b98975050505050505050565b6000602082840312156131b357600080fd5b5051919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01833603018112612fa457600080fd5b60006020828403121561320057600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461299857600080fd5b60006020828403121561324257600080fd5b813569ffffffffffffffffffff8116811461299857600080fd5b85815263ffffffff85166020820152600069ffffffffffffffffffff8086511660408401528060208701511660608401528060408701511660808401525060c060a08301526130f260c08301848661306b565b85815263ffffffff851660208201528360408201526080606082015260006130f260808301848661306b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611652576116526132db565b8581528460208201528360408201526080606082015260006130f260808301848661306b565b600060033d111561335c5760046000803e5060005160e01c5b90565b600060443d101561336d5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156133bb57505050505090565b82850191508151818111156133d35750505050505090565b843d87010160208285010111156133ed5750505050505090565b6133fc60208286010187612c98565b509095945050505050565b60208152600061164f6020830184612b7d565b60006020828403121561342c57600080fd5b813567ffffffffffffffff8116811461299857600080fd5b8082028115828204841417611652576116526132db565b80820180821115611652576116526132db565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361349f5761349f6132db565b5060010190565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612fa457600080fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261351f57600080fd5b830160208101925035905067ffffffffffffffff81111561353f57600080fd5b8036038213156128ef57600080fd5b60408152823560408201526020830135606082015260408301356080820152600061357c60608501856134ea565b60a08085015261359060e08501828461306b565b9150506135a060808601866134ea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c08601526135d583828461306b565b9250505082810360208401528335815260208401356020820152604084013560408201526060840135606082015261361060808501856134ea565b60a060808401526130f260a08401828461306b565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112612fa457600080fd5b84815273ffffffffffffffffffffffffffffffffffffffff8416602082015260606040820152600061368f60608301848661306b565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612fa457600080fd5b85815284602082015273ffffffffffffffffffffffffffffffffffffffff841660408201526080606082015260006130f260808301848661306b56fea264697066735822122033851580707502fec00b2db61147bba7340db1fd418664df84cd7bd7f902a5d364736f6c6343000813003300000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c
Deployed ByteCode
0x6080604052600436106101a05760003560e01c8063861a3717116100e1578063b59b28ef1161008a578063d6c19d4b11610064578063d6c19d4b146104a9578063f15af7aa146104bc578063f7888aec146104dc578063fa98a33f1461050a57600080fd5b8063b59b28ef1461043b578063caa5c23f1461045b578063d547741f1461048957600080fd5b806391d14854116100bb57806391d14854146103cb578063a52b55eb146103fb578063a5c003f71461041b57600080fd5b8063861a37171461036d57806389601445146103805780638da5cb5b146103a057600080fd5b80633bd1adec1161014e578063634379561161012857806363437956146102e05780636ccae054146103005780636e9e1ab91461032057806374032c9e1461034d57600080fd5b80633bd1adec1461028b5780633cfa1bb0146102a05780635b94db27146102c057600080fd5b80631d86d44b1161017f5780631d86d44b146101fa57806320f99c0a1461021a5780632f2ff15d1461026b57600080fd5b806293ac86146101a557806309e3b0ea146101ba57806312337d0f146101da575b600080fd5b6101b86101b33660046128f6565b61051d565b005b3480156101c657600080fd5b506101b86101d53660046128f6565b61052d565b3480156101e657600080fd5b506101b86101f53660046128f6565b61067a565b34801561020657600080fd5b506101b86102153660046128f6565b61072a565b34801561022657600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561027757600080fd5b506101b861028636600461294b565b610735565b34801561029757600080fd5b506101b8610794565b3480156102ac57600080fd5b506101b86102bb3660046128f6565b6107f0565b3480156102cc57600080fd5b506101b86102db36600461297b565b61096c565b3480156102ec57600080fd5b506101b86102fb3660046128f6565b610a2c565b34801561030c57600080fd5b506101b861031b36600461299f565b610a37565b34801561032c57600080fd5b5061034061033b3660046128f6565b610ada565b60405161026291906129e0565b34801561035957600080fd5b506101b86103683660046128f6565b610bf8565b6101b861037b366004612a24565b61138c565b34801561038c57600080fd5b506101b861039b3660046128f6565b61157f565b3480156103ac57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610241565b3480156103d757600080fd5b506103eb6103e636600461294b565b61161b565b6040519015158152602001610262565b34801561040757600080fd5b506101b8610416366004612acf565b611658565b34801561042757600080fd5b50610340610436366004612b11565b611877565b34801561044757600080fd5b50610340610456366004612b11565b6119e6565b34801561046757600080fd5b5061047b610476366004612acf565b611af5565b604051610262929190612be1565b34801561049557600080fd5b506101b86104a436600461294b565b611c8c565b6101b86104b7366004612d6d565b611ce7565b3480156104c857600080fd5b506101b86104d7366004612acf565b611e10565b3480156104e857600080fd5b506104fc6104f7366004612e3a565b611e1a565b604051908152602001610262565b6101b8610518366004612e68565b611f7a565b610528838383611fb0565b505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff16637348746b85858481811061056757610567612f41565b90506020028101906105799190612f70565b3586868581811061058c5761058c612f41565b905060200281019061059e9190612f70565b6105af906040810190602001612fae565b8787868181106105c1576105c1612f41565b90506020028101906105d39190612f70565b6105e4906060810190604001612fd4565b8888878181106105f6576105f6612f41565b90506020028101906106089190612f70565b610616906060810190613006565b6040518663ffffffff1660e01b81526004016106369594939291906130b4565b600060405180830381600087803b15801561065057600080fd5b505af1158015610664573d6000803e3d6000fd5b50505050806001019050610531565b5050505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663f953cec78585848181106106b4576106b4612f41565b90506020028101906106c691906130fd565b6106d09080613006565b6040518363ffffffff1660e01b81526004016106ed929190613131565b600060405180830381600087803b15801561070757600080fd5b505af115801561071b573d6000803e3d6000fd5b5050505080600101905061067e565b610528838383612127565b60005473ffffffffffffffffffffffffffffffffffffffff163314610786576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107908282612237565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107e5576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107ee336122bd565b565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663f22b460e85858481811061082a5761082a612f41565b905060200281019061083c9190612f70565b3586868581811061084f5761084f612f41565b90506020028101906108619190612f70565b610872906040810190602001612fae565b87878681811061088457610884612f41565b90506020028101906108969190612f70565b6108a7906060810190604001612fd4565b8888878181106108b9576108b9612f41565b90506020028101906108cb9190612f70565b6108dc906080810190606001612fd4565b8989888181106108ee576108ee612f41565b90506020028101906109009190612f70565b61090e906080810190613006565b6040518763ffffffff1660e01b815260040161092f9695949392919061314d565b600060405180830381600087803b15801561094957600080fd5b505af115801561095d573d6000803e3d6000fd5b505050508060010190506107f4565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109bd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b610528838383612335565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16610ac9576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b610ad484848461246e565b50505050565b60608160008167ffffffffffffffff811115610af857610af8612c69565b604051908082528060200260200182016040528015610b21578160200160208202803683370190505b50905060005b82811015610bee5760008773ffffffffffffffffffffffffffffffffffffffff166379cfc006888885818110610b5f57610b5f612f41565b905060200201356040518263ffffffff1660e01b8152600401610b8491815260200190565b602060405180830381865afa158015610ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc591906131a1565b905080838381518110610bda57610bda612f41565b602090810291909101015250600101610b27565b5095945050505050565b8060005b81811015610673577f9f4ad32e00000000000000000000000000000000000000000000000000000000848483818110610c3757610c37612f41565b9050602002810190610c4991906131ba565b610c5b9061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603610da9578473ffffffffffffffffffffffffffffffffffffffff16639f4ad32e858584818110610cb057610cb0612f41565b9050602002810190610cc291906131ba565b35868685818110610cd557610cd5612f41565b9050602002810190610ce791906131ba565b610cf8906040810190602001612fae565b878786818110610d0a57610d0a612f41565b9050602002810190610d1c91906131ba565b60a00135888887818110610d3257610d32612f41565b9050602002810190610d4491906131ba565b610d529060c0810190613006565b6040518663ffffffff1660e01b8152600401610d729594939291906130b4565b600060405180830381600087803b158015610d8c57600080fd5b505af1158015610da0573d6000803e3d6000fd5b50505050611384565b7f50a9cf6700000000000000000000000000000000000000000000000000000000848483818110610ddc57610ddc612f41565b9050602002810190610dee91906131ba565b610e009061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603610fc9578473ffffffffffffffffffffffffffffffffffffffff166350a9cf67858584818110610e5557610e55612f41565b9050602002810190610e6791906131ba565b35868685818110610e7a57610e7a612f41565b9050602002810190610e8c91906131ba565b610e9d906040810190602001612fae565b6040518060600160405280898988818110610eba57610eba612f41565b9050602002810190610ecc91906131ba565b610edd906060810190604001613230565b69ffffffffffffffffffff168152602001898988818110610f0057610f00612f41565b9050602002810190610f1291906131ba565b610f23906080810190606001613230565b69ffffffffffffffffffff168152602001898988818110610f4657610f46612f41565b9050602002810190610f5891906131ba565b610f699060a0810190608001613230565b69ffffffffffffffffffff169052888887818110610f8957610f89612f41565b9050602002810190610f9b91906131ba565b610fa99060c0810190613006565b6040518663ffffffff1660e01b8152600401610d7295949392919061325c565b7f9f10285500000000000000000000000000000000000000000000000000000000848483818110610ffc57610ffc612f41565b905060200281019061100e91906131ba565b6110209061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603611137578473ffffffffffffffffffffffffffffffffffffffff16639f10285585858481811061107557611075612f41565b905060200281019061108791906131ba565b3586868581811061109a5761109a612f41565b90506020028101906110ac91906131ba565b6110bd906040810190602001612fae565b8787868181106110cf576110cf612f41565b90506020028101906110e191906131ba565b60a001358888878181106110f7576110f7612f41565b905060200281019061110991906131ba565b6111179060c0810190613006565b6040518663ffffffff1660e01b8152600401610d729594939291906132af565b7fa18857000000000000000000000000000000000000000000000000000000000084848381811061116a5761116a612f41565b905060200281019061117c91906131ba565b61118e9061010081019060e0016131ee565b7fffffffff0000000000000000000000000000000000000000000000000000000016036111e3578473ffffffffffffffffffffffffffffffffffffffff1663a188570085858481811061107557611075612f41565b7f308795b20000000000000000000000000000000000000000000000000000000084848381811061121657611216612f41565b905060200281019061122891906131ba565b61123a9061010081019060e0016131ee565b7fffffffff000000000000000000000000000000000000000000000000000000001603611384578473ffffffffffffffffffffffffffffffffffffffff1663308795b285858481811061128f5761128f612f41565b90506020028101906112a191906131ba565b358686858181106112b4576112b4612f41565b90506020028101906112c691906131ba565b6112d7906040810190602001612fae565b8787868181106112e9576112e9612f41565b90506020028101906112fb91906131ba565b60a0013588888781811061131157611311612f41565b905060200281019061132391906131ba565b6113319060c0810190613006565b6040518663ffffffff1660e01b81526004016113519594939291906132af565b600060405180830381600087803b15801561136b57600080fd5b505af115801561137f573d6000803e3d6000fd5b505050505b600101610bfc565b803460005b82811015611518578484828181106113ab576113ab612f41565b905060a0020160800135826113c0919061330a565b91508773ffffffffffffffffffffffffffffffffffffffff1663190d5e4d8686848181106113f0576113f0612f41565b905060a002016080013587878581811061140c5761140c612f41565b905060a002016000013588888681811061142857611428612f41565b905060a002016020013589898781811061144457611444612f41565b905060a00201604001358a8a8881811061146057611460612f41565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815260048101969096526024860194909452506044840191909152606060a0909202010135606482015273ffffffffffffffffffffffffffffffffffffffff808c1660848301528a1660a482015260c4016000604051808303818588803b1580156114f457600080fd5b505af1158015611508573d6000803e3d6000fd5b5050505050806001019050611391565b5080156115765773ffffffffffffffffffffffffffffffffffffffff861661156c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611576868261255e565b50505050505050565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663a9a599e08585848181106115b9576115b9612f41565b905060200201356040518263ffffffff1660e01b81526004016115de91815260200190565b600060405180830381600087803b1580156115f857600080fd5b505af115801561160c573d6000803e3d6000fd5b50505050806001019050611583565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b90505b92915050565b8060005b81811015610ad45783838281811061167657611676612f41565b90506020028101906116889190612f70565b61169690602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff166389ee87558585848181106116c3576116c3612f41565b90506020028101906116d59190612f70565b602001358686858181106116eb576116eb612f41565b90506020028101906116fd9190612f70565b6040013587878681811061171357611713612f41565b90506020028101906117259190612f70565b6060013588888781811061173b5761173b612f41565b905060200281019061174d9190612f70565b61175b906080810190613006565b6040518663ffffffff1660e01b815260040161177b95949392919061331d565b600060405180830381600087803b15801561179557600080fd5b505af19250505080156117a6575060015b61186f576117b2613343565b806308c379a00361180e57506117c661335f565b806117d15750611810565b7f3f3d95f05f600551a08f68e59143bde093cf93527273b87a2d85d88cc684bea0816040516118009190613407565b60405180910390a15061186f565b505b3d80801561183a576040519150601f19603f3d011682016040523d82523d6000602084013e61183f565b606091505b507fbda109f4d5e5950ba8c4893817cda7a795c8ba5442b23e81f382f76f8d3a1ac3816040516118009190613407565b60010161165c565b60608360008167ffffffffffffffff81111561189557611895612c69565b6040519080825280602002602001820160405280156118be578160200160208202803683370190505b50905060005b828110156119db578787828181106118de576118de612f41565b90506020020160208101906118f3919061297b565b73ffffffffffffffffffffffffffffffffffffffff1663d1af313c87878481811061192057611920612f41565b9050602002016020810190611935919061341a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815267ffffffffffffffff9091166004820152602401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906131a1565b8282815181106119c8576119c8612f41565b60209081029190910101526001016118c4565b509695505050505050565b606060006119f48386613444565b67ffffffffffffffff811115611a0c57611a0c612c69565b604051908082528060200260200182016040528015611a35578160200160208202803683370190505b50905060005b85811015610bee5760005b84811015611ae257611a9f888884818110611a6357611a63612f41565b9050602002016020810190611a78919061297b565b878784818110611a8a57611a8a612f41565b90506020020160208101906104f7919061297b565b8382611aab8886613444565b611ab5919061345b565b81518110611ac557611ac5612f41565b602090810291909101015280611ada8161346e565b915050611a46565b5080611aed8161346e565b915050611a3b565b60006060828067ffffffffffffffff811115611b1357611b13612c69565b604051908082528060200260200182016040528015611b4657816020015b6060815260200190600190039081611b315790505b50915060005b81811015611c8357600080878784818110611b6957611b69612f41565b9050602002810190611b7b91906134a6565b611b8990602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff16888885818110611bb157611bb1612f41565b9050602002810190611bc391906134a6565b611bd1906020810190613006565b604051611bdf9291906134da565b600060405180830381855afa9150503d8060008114611c1a576040519150601f19603f3d011682016040523d82523d6000602084013e611c1f565b606091505b509150915081611c5b576040517f51ba533f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80858481518110611c6e57611c6e612f41565b60209081029190910101525050600101611b4c565b50509250929050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611cdd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079082826125d3565b6000805b8351811015611da657828181518110611d0657611d06612f41565b602002602001015182611d19919061345b565b9150838181518110611d2d57611d2d612f41565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc848381518110611d6057611d60612f41565b60200260200101519081150290604051600060405180830381858888f19350505050158015611d93573d6000803e3d6000fd5b5080611d9e8161346e565b915050611ceb565b50348114610528576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4c4f575f4d53475f56414c5545000000000000000000000000000000000000006044820152606401610ac0565b6107908282612656565b60007fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601611e77575073ffffffffffffffffffffffffffffffffffffffff821631611652565b813b8015611f17576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528416906370a0823190602401602060405180830381865afa158015611eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0f91906131a1565b915050611652565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f544f4b454e000000000000000000000000000000000000006044820152606401610ac0565b611f85898989612127565b611f90898787612335565b611f9a8484612656565b611fa5898383611fb0565b505050505050505050565b803460005b82811015612116576000858583818110611fd157611fd1612f41565b9050602002810190611fe391906134a6565b611ff1906020810190612f70565b60600135905060f881901c7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8216600082900361202f5750600061203c565b612039818661330a565b94505b8873ffffffffffffffffffffffffffffffffffffffff1663275c41c9828a8a8881811061206b5761206b612f41565b905060200281019061207d91906134a6565b6120879080612f70565b8b8b8981811061209957612099612f41565b90506020028101906120ab91906134a6565b6120b9906020810190612f70565b6040518463ffffffff1660e01b81526004016120d692919061354e565b6000604051808303818588803b1580156120ef57600080fd5b505af1158015612103573d6000803e3d6000fd5b5050505050836001019350505050611fb5565b50801561067357610673338261255e565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663c85ce32585858481811061216157612161612f41565b90506020028101906121739190613625565b3586868581811061218657612186612f41565b90506020028101906121989190613625565b6121a990604081019060200161297b565b8787868181106121bb576121bb612f41565b90506020028101906121cd9190613625565b6121db906040810190613006565b6040518563ffffffff1660e01b81526004016121fa9493929190613659565b600060405180830381600087803b15801561221457600080fd5b505af1158015612228573d6000803e3d6000fd5b5050505080600101905061212b565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b8060005b81811015610673578473ffffffffffffffffffffffffffffffffffffffff1663dc30986385858481811061236f5761236f612f41565b90506020028101906123819190613699565b3586868581811061239457612394612f41565b90506020028101906123a69190613699565b602001358787868181106123bc576123bc612f41565b90506020028101906123ce9190613699565b6123df90606081019060400161297b565b8888878181106123f1576123f1612f41565b90506020028101906124039190613699565b612411906060810190613006565b6040518663ffffffff1660e01b81526004016124319594939291906136cd565b600060405180830381600087803b15801561244b57600080fd5b505af115801561245f573d6000803e3d6000fd5b50505050806001019050612339565b73ffffffffffffffffffffffffffffffffffffffff82166124bb576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161250257610528828261255e565b8273ffffffffffffffffffffffffffffffffffffffff163b600003612553576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105288383836127b6565b600080600080600085875af1905080610528576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610ac0565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b8060005b81811015610ad45783838281811061267457612674612f41565b90506020028101906126869190612f70565b61269490602081019061297b565b73ffffffffffffffffffffffffffffffffffffffff1663d2883fbe8585848181106126c1576126c1612f41565b90506020028101906126d39190612f70565b602001358686858181106126e9576126e9612f41565b90506020028101906126fb9190612f70565b6040013587878681811061271157612711612f41565b90506020028101906127239190612f70565b6060013588888781811061273957612739612f41565b905060200281019061274b9190612f70565b612759906080810190613006565b6040518663ffffffff1660e01b815260040161277995949392919061331d565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b5050505080600101905061265a565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610ac0565b73ffffffffffffffffffffffffffffffffffffffff811681146128a757600080fd5b50565b60008083601f8401126128bc57600080fd5b50813567ffffffffffffffff8111156128d457600080fd5b6020830191508360208260051b85010111156128ef57600080fd5b9250929050565b60008060006040848603121561290b57600080fd5b833561291681612885565b9250602084013567ffffffffffffffff81111561293257600080fd5b61293e868287016128aa565b9497909650939450505050565b6000806040838503121561295e57600080fd5b82359150602083013561297081612885565b809150509250929050565b60006020828403121561298d57600080fd5b813561299881612885565b9392505050565b6000806000606084860312156129b457600080fd5b83356129bf81612885565b925060208401356129cf81612885565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b81811015612a18578351835292840192918401916001016129fc565b50909695505050505050565b600080600080600060808688031215612a3c57600080fd5b8535612a4781612885565b94506020860135612a5781612885565b93506040860135612a6781612885565b9250606086013567ffffffffffffffff80821115612a8457600080fd5b818801915088601f830112612a9857600080fd5b813581811115612aa757600080fd5b89602060a083028501011115612abc57600080fd5b9699959850939650602001949392505050565b60008060208385031215612ae257600080fd5b823567ffffffffffffffff811115612af957600080fd5b612b05858286016128aa565b90969095509350505050565b60008060008060408587031215612b2757600080fd5b843567ffffffffffffffff80821115612b3f57600080fd5b612b4b888389016128aa565b90965094506020870135915080821115612b6457600080fd5b50612b71878288016128aa565b95989497509550505050565b6000815180845260005b81811015612ba357602081850181015186830182015201612b87565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015612c5b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452612c49868351612b7d565b95509284019290840190600101612c0f565b509398975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715612cdc57612cdc612c69565b6040525050565b600067ffffffffffffffff821115612cfd57612cfd612c69565b5060051b60200190565b600082601f830112612d1857600080fd5b81356020612d2582612ce3565b604051612d328282612c98565b83815260059390931b8501820192828101915086841115612d5257600080fd5b8286015b848110156119db5780358352918301918301612d56565b60008060408385031215612d8057600080fd5b823567ffffffffffffffff80821115612d9857600080fd5b818501915085601f830112612dac57600080fd5b81356020612db982612ce3565b604051612dc68282612c98565b83815260059390931b8501820192828101915089841115612de657600080fd5b948201945b83861015612e0d578535612dfe81612885565b82529482019490820190612deb565b96505086013592505080821115612e2357600080fd5b50612e3085828601612d07565b9150509250929050565b60008060408385031215612e4d57600080fd5b8235612e5881612885565b9150602083013561297081612885565b600080600080600080600080600060a08a8c031215612e8657600080fd5b8935612e9181612885565b985060208a013567ffffffffffffffff80821115612eae57600080fd5b612eba8d838e016128aa565b909a50985060408c0135915080821115612ed357600080fd5b612edf8d838e016128aa565b909850965060608c0135915080821115612ef857600080fd5b612f048d838e016128aa565b909650945060808c0135915080821115612f1d57600080fd5b50612f2a8c828d016128aa565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112612fa457600080fd5b9190910192915050565b600060208284031215612fc057600080fd5b813563ffffffff8116811461299857600080fd5b600060208284031215612fe657600080fd5b81356fffffffffffffffffffffffffffffffff8116811461299857600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261303b57600080fd5b83018035915067ffffffffffffffff82111561305657600080fd5b6020019150368190038213156128ef57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b85815263ffffffff851660208201526fffffffffffffffffffffffffffffffff841660408201526080606082015260006130f260808301848661306b565b979650505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1833603018112612fa457600080fd5b60208152600061314560208301848661306b565b949350505050565b86815263ffffffff8616602082015260006fffffffffffffffffffffffffffffffff808716604084015280861660608401525060a0608083015261319560a08301848661306b565b98975050505050505050565b6000602082840312156131b357600080fd5b5051919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01833603018112612fa457600080fd5b60006020828403121561320057600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461299857600080fd5b60006020828403121561324257600080fd5b813569ffffffffffffffffffff8116811461299857600080fd5b85815263ffffffff85166020820152600069ffffffffffffffffffff8086511660408401528060208701511660608401528060408701511660808401525060c060a08301526130f260c08301848661306b565b85815263ffffffff851660208201528360408201526080606082015260006130f260808301848661306b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611652576116526132db565b8581528460208201528360408201526080606082015260006130f260808301848661306b565b600060033d111561335c5760046000803e5060005160e01c5b90565b600060443d101561336d5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156133bb57505050505090565b82850191508151818111156133d35750505050505090565b843d87010160208285010111156133ed5750505050505090565b6133fc60208286010187612c98565b509095945050505050565b60208152600061164f6020830184612b7d565b60006020828403121561342c57600080fd5b813567ffffffffffffffff8116811461299857600080fd5b8082028115828204841417611652576116526132db565b80820180821115611652576116526132db565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361349f5761349f6132db565b5060010190565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612fa457600080fd5b8183823760009101908152919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261351f57600080fd5b830160208101925035905067ffffffffffffffff81111561353f57600080fd5b8036038213156128ef57600080fd5b60408152823560408201526020830135606082015260408301356080820152600061357c60608501856134ea565b60a08085015261359060e08501828461306b565b9150506135a060808601866134ea565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c08601526135d583828461306b565b9250505082810360208401528335815260208401356020820152604084013560408201526060840135606082015261361060808501856134ea565b60a060808401526130f260a08401828461306b565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112612fa457600080fd5b84815273ffffffffffffffffffffffffffffffffffffffff8416602082015260606040820152600061368f60608301848661306b565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612fa457600080fd5b85815284602082015273ffffffffffffffffffffffffffffffffffffffff841660408201526080606082015260006130f260808301848661306b56fea264697066735822122033851580707502fec00b2db61147bba7340db1fd418664df84cd7bd7f902a5d364736f6c63430008130033