Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Socket
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 999999
- EVM Version
- default
- Verified at
- 2024-10-23T11:04:20.396447Z
Constructor Arguments
0x0000000000000000000000000000000000000000000000000000000000028c61000000000000000000000000941f0ef5258604fe10c76ae3858984ce0452b5f2000000000000000000000000fe9dcb3daba382f46f2ce69ddeb3b5df86d96f0400000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004494d4c4900000000000000000000000000000000000000000000000000000000
Arg [0] (uint32) : 167009
Arg [1] (address) : 0x941f0ef5258604fe10c76ae3858984ce0452b5f2
Arg [2] (address) : 0xfe9dcb3daba382f46f2ce69ddeb3b5df86d96f04
Arg [3] (address) : 0x44a44837894b5edc2bde64567fc62599b3b88f4c
Arg [4] (string) : IMLI
contracts/socket/Socket.sol
// SPDX-License-Identifier: GPL-3.0-only // Sources flattened with hardhat v2.12.2 https://hardhat.org // File contracts/interfaces/IPlug.sol pragma solidity 0.8.19; /** * @title IPlug * @notice Interface for a plug contract that executes the message received from a source chain. */ interface IPlug { /** * @dev this should be only executable by socket * @notice executes the message received from source chain * @notice It is expected to have original sender checks in the destination plugs using payload * @param srcChainSlug_ chain slug of source * @param payload_ the data which is needed by plug at inbound call on remote */ function inbound( uint32 srcChainSlug_, bytes calldata payload_ ) 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/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/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/IHasher.sol pragma solidity 0.8.19; /** * @title IHasher * @notice Interface for hasher contract that calculates the packed message */ interface IHasher { /** * @notice returns the bytes32 hash of the message packed * @param srcChainSlug src chain slug * @param srcPlug address of plug at source * @param dstChainSlug remote chain slug * @param dstPlug address of plug at remote * @param messageDetails contains message details, see ISocket for more details */ function packMessage( uint32 srcChainSlug, address srcPlug, uint32 dstChainSlug, address dstPlug, ISocket.MessageDetails memory messageDetails ) external returns (bytes32); } // 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/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/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/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/interfaces/IDecapacitor.sol pragma solidity 0.8.19; /** * @title IDecapacitor interface * @notice Interface for a contract that verifies if a packed message is part of a packet or not */ interface IDecapacitor { /** * @notice Returns true if packed message is part of root. * @param root_ root hash of the packet. * @param packedMessage_ packed message which needs to be verified. * @param proof_ proof used to determine the inclusion * @dev This function is kept as view instead of pure, as in future we may have stateful decapacitors * @return isIncluded boolean indicating whether the message is included in the packet or not. */ function verifyMessageInclusion( bytes32 root_, bytes32 packedMessage_, bytes calldata proof_ ) external returns (bool isIncluded); } // File contracts/interfaces/ICapacitorFactory.sol pragma solidity 0.8.19; /** * @title ICapacitorFactory * @notice Interface for a factory contract that deploys new instances of `ICapacitor` and `IDecapacitor` contracts. */ interface ICapacitorFactory { /** * @dev Emitted when an invalid capacitor type is requested during deployment. */ error InvalidCapacitorType(); /** * @notice Deploys a new instance of an `ICapacitor` and `IDecapacitor` contract with the specified parameters. * @param capacitorType The type of the capacitor to be deployed. * @param siblingChainSlug The identifier of the sibling chain. * @param maxPacketLength The maximum length of a packet. * @return Returns the deployed `ICapacitor` and `IDecapacitor` contract instances. */ function deploy( uint256 capacitorType, uint32 siblingChainSlug, uint256 maxPacketLength ) external returns (ICapacitor, IDecapacitor); } // 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/socket/SocketConfig.sol pragma solidity 0.8.19; /** * @title SocketConfig * @notice An abstract contract for configuring socket connections for plugs between different chains, * manages plug configs and switchboard registrations * @dev This contract is meant to be inherited by other contracts that require socket configuration functionality */ abstract contract SocketConfig is ISocket { // factory contract that can deploy capacitors and decapacitors ICapacitorFactory public capacitorFactory__; /** * @dev Struct to store the configuration for a plug connection */ struct PlugConfig { // address of the sibling plug on the remote chain address siblingPlug; // capacitor instance for the outbound plug connection ICapacitor capacitor__; // decapacitor instance for the inbound plug connection IDecapacitor decapacitor__; // inbound switchboard instance for the plug connection ISwitchboard inboundSwitchboard__; // outbound switchboard instance for the plug connection ISwitchboard outboundSwitchboard__; } // plug => remoteChainSlug => (siblingPlug, capacitor__, decapacitor__, inboundSwitchboard__, outboundSwitchboard__) mapping(address => mapping(uint32 => PlugConfig)) internal _plugConfigs; // It is used to maintain record of capacitors in the system registered for a slug and also used in seal for verification // capacitor address => siblingChainSlug mapping(address => uint32) public capacitorToSlug; // switchboard => siblingChainSlug => ICapacitor mapping(address => mapping(uint32 => ICapacitor)) public capacitors__; // switchboard => siblingChainSlug => IDecapacitor mapping(address => mapping(uint32 => IDecapacitor)) public decapacitors__; // Event triggered when a new switchboard is added event SwitchboardAdded( address switchboard, uint32 siblingChainSlug, address capacitor, address decapacitor, uint256 maxPacketLength, uint256 capacitorType ); // Event triggered when a new switchboard is added event SiblingSwitchboardUpdated( address switchboard, uint32 siblingChainSlug, address siblingSwitchboard ); // Error triggered when a switchboard already exists error SwitchboardExists(); // Error triggered when a connection is invalid error InvalidConnection(); /** * @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 override returns (address capacitor, address decapacitor) { address switchboardAddress = msg.sender; // only capacitor checked, decapacitor assumed will exist if capacitor does if ( address(capacitors__[switchboardAddress][siblingChainSlug_]) != address(0) ) revert SwitchboardExists(); ( ICapacitor capacitor__, IDecapacitor decapacitor__ ) = capacitorFactory__.deploy( capacitorType_, siblingChainSlug_, maxPacketLength_ ); capacitor = address(capacitor__); decapacitor = address(decapacitor__); capacitorToSlug[capacitor] = siblingChainSlug_; capacitors__[switchboardAddress][siblingChainSlug_] = capacitor__; decapacitors__[switchboardAddress][siblingChainSlug_] = decapacitor__; emit SwitchboardAdded( switchboardAddress, siblingChainSlug_, capacitor, decapacitor, maxPacketLength_, capacitorType_ ); emit SiblingSwitchboardUpdated( switchboardAddress, siblingChainSlug_, siblingSwitchboard_ ); } /** * @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 { emit SiblingSwitchboardUpdated( msg.sender, siblingChainSlug_, siblingSwitchboard_ ); } /** * @notice connects Plug to Socket and sets the config for given `siblingChainSlug_` * @notice msg.sender is stored as plug address against given configuration * @param siblingChainSlug_ the sibling chain slug * @param siblingPlug_ address of plug present at siblingChainSlug_ to call at inbound * @param inboundSwitchboard_ the address of switchboard to use for verifying messages at inbound * @param outboundSwitchboard_ the address of switchboard to use for sending messages */ function connect( uint32 siblingChainSlug_, address siblingPlug_, address inboundSwitchboard_, address outboundSwitchboard_ ) external override { // only capacitor checked, decapacitor assumed will exist if capacitor does // as they both are deployed together always if ( address(capacitors__[inboundSwitchboard_][siblingChainSlug_]) == address(0) || address(capacitors__[outboundSwitchboard_][siblingChainSlug_]) == address(0) ) revert InvalidConnection(); PlugConfig storage _plugConfig = _plugConfigs[msg.sender][ siblingChainSlug_ ]; _plugConfig.siblingPlug = siblingPlug_; _plugConfig.capacitor__ = capacitors__[outboundSwitchboard_][ siblingChainSlug_ ]; _plugConfig.decapacitor__ = decapacitors__[inboundSwitchboard_][ siblingChainSlug_ ]; _plugConfig.inboundSwitchboard__ = ISwitchboard(inboundSwitchboard_); _plugConfig.outboundSwitchboard__ = ISwitchboard(outboundSwitchboard_); emit PlugConnected( msg.sender, siblingChainSlug_, siblingPlug_, inboundSwitchboard_, outboundSwitchboard_, address(_plugConfig.capacitor__), address(_plugConfig.decapacitor__) ); } /** * @notice returns the config for given `plugAddress_` and `siblingChainSlug_` * @param siblingChainSlug_ the sibling chain slug * @param plugAddress_ address of plug present at current chain */ function getPlugConfig( address plugAddress_, uint32 siblingChainSlug_ ) external view returns ( address siblingPlug, address inboundSwitchboard__, address outboundSwitchboard__, address capacitor__, address decapacitor__ ) { PlugConfig memory _plugConfig = _plugConfigs[plugAddress_][ siblingChainSlug_ ]; return ( _plugConfig.siblingPlug, address(_plugConfig.inboundSwitchboard__), address(_plugConfig.outboundSwitchboard__), address(_plugConfig.capacitor__), address(_plugConfig.decapacitor__) ); } } // File contracts/socket/SocketBase.sol pragma solidity 0.8.19; /** * @title SocketBase * @notice A contract that is responsible for common storage for src and dest contracts, governance * setters and inherits SocketConfig */ abstract contract SocketBase is SocketConfig, AccessControlExtended { // Version string for this socket instance bytes32 public immutable version; // ChainSlug for this deployed socket instance uint32 public immutable chainSlug; // Counter for messages going outbound from current chain uint64 public globalMessageCount; /** * @dev constructs a new Socket contract instance. * @param chainSlug_ the chain slug of the contract. * @param version_ the string to identify current version. */ constructor(uint32 chainSlug_, string memory version_) { chainSlug = chainSlug_; version = keccak256(bytes(version_)); } //////////////////////////////////////////////////////// //////////// PERIPHERY CONTRACT CONNECTORS //////////// //////////////////////////////////////////////////////// // Hasher contract IHasher public hasher__; // Transmit Manager contract ITransmitManager public override transmitManager__; // Execution Manager contract IExecutionManager public override executionManager__; //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// /** * @dev Error thrown when non-transmitter tries to seal/propose */ error InvalidTransmitter(); //////////////////////////////////////////////////////// ////////////////////// EVENTS ////////////////////////// //////////////////////////////////////////////////////// /** * @notice An event that is emitted when the capacitor factory is updated. * @param capacitorFactory The address of the new capacitorFactory. */ event CapacitorFactorySet(address capacitorFactory); /** * @notice An event that is emitted when the hasher is updated. * @param hasher The address of the new hasher. */ event HasherSet(address hasher); /** * @notice An event that is emitted when the executionManager is updated. * @param executionManager The address of the new executionManager. */ event ExecutionManagerSet(address executionManager); /** * @notice An event that is emitted when a new transmitManager contract is set * @param transmitManager address of new transmitManager contract */ event TransmitManagerSet(address transmitManager); ////////////////////////////////////////////////// //////////// GOV Permissioned setters //////////// ////////////////////////////////////////////////// /** * @dev Set the capacitor factory contract * @dev Only governance can call this function * @param capacitorFactory_ The address of the capacitor factory contract */ function setCapacitorFactory( address capacitorFactory_ ) external onlyRole(GOVERNANCE_ROLE) { capacitorFactory__ = ICapacitorFactory(capacitorFactory_); emit CapacitorFactorySet(capacitorFactory_); } /** * @notice updates hasher__ * @dev Only governance can call this function * @param hasher_ address of hasher */ function setHasher(address hasher_) external onlyRole(GOVERNANCE_ROLE) { hasher__ = IHasher(hasher_); emit HasherSet(hasher_); } /** * @notice updates executionManager__ * @dev Only governance can call this function * @param executionManager_ address of Execution Manager */ function setExecutionManager( address executionManager_ ) external onlyRole(GOVERNANCE_ROLE) { executionManager__ = IExecutionManager(executionManager_); emit ExecutionManagerSet(executionManager_); } /** * @notice updates transmitManager__ * @param transmitManager_ address of Transmit Manager * @dev Only governance can call this function * @dev This function sets the transmitManager address. If it is ever upgraded, * remove the fees from executionManager first, and then upgrade address at socket. */ function setTransmitManager( address transmitManager_ ) external onlyRole(GOVERNANCE_ROLE) { transmitManager__ = ITransmitManager(transmitManager_); emit TransmitManagerSet(transmitManager_); } ////////////////////////////////////////////// //////////// Rescue role actions //////////// ///////////////////////////////////////////// /** * @notice Rescues funds from the contract if they are locked by mistake. This contract does not * theoretically need this function but it is added for safety. * @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_); } } // File contracts/socket/SocketDst.sol pragma solidity 0.8.19; /** * @title SocketDst * @dev SocketDst is an abstract contract that inherits from SocketBase and * provides functionality for message execution, packet proposal, and verification. * It manages the mapping of message execution status, packet ID roots, and root proposed * timestamps. It emits events for packet proposal and root updates. * It also includes functions for message execution and verification */ abstract contract SocketDst is SocketBase { //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// /* * @dev Error emitted when a packet has not been proposed */ error PacketNotProposed(); /* * @dev Error emitted when a packet id is invalid */ error InvalidPacketId(); /** * @dev Error emitted when proof is invalid */ error InvalidProof(); /** * @dev Error emitted when a message has already been executed */ error MessageAlreadyExecuted(); /** * @dev Error emitted when the executor is not valid */ error NotExecutor(); /** * @dev Error emitted when verification fails */ error VerificationFailed(); /** * @dev Error emitted when source slugs deduced from packet id and msg id don't match */ error ErrInSourceValidation(); /** * @dev Error emitted when less gas limit is provided for execution than expected */ error LowGasLimit(); //////////////////////////////////////////////////////////// ////////////////////// State Vars ////////////////////////// //////////////////////////////////////////////////////////// /** * @dev keeps track of whether a message has been executed or not using message id */ mapping(bytes32 => bool) public messageExecuted; /** * @dev capacitorAddr|chainSlug|packetId => proposalCount => switchboard => packetIdRoots */ mapping(bytes32 => mapping(uint256 => mapping(address => bytes32))) public override packetIdRoots; /** * @dev packetId => proposalCount => switchboard => proposalTimestamp */ mapping(bytes32 => mapping(uint256 => mapping(address => uint256))) public rootProposedAt; /** * @dev packetId => proposalCount */ mapping(bytes32 => uint256) public proposalCount; //////////////////////////////////////////////////////// ////////////////////// EVENTS ////////////////////////// //////////////////////////////////////////////////////// /** * @notice emits the packet details when proposed at remote * @param transmitter address of transmitter * @param packetId packet id * @param proposalCount proposal id * @param root packet root */ event PacketProposed( address indexed transmitter, bytes32 indexed packetId, uint256 proposalCount, bytes32 root, address switchboard ); //////////////////////////////////////////////////////// ////////////////////// OPERATIONS ////////////////////////// //////////////////////////////////////////////////////// /** * @dev Function to propose a packet * @notice the signature is validated if it belongs to transmitter or not * @param packetId_ packet id * @param root_ packet root * @param switchboard_ The address of switchboard for which this packet is proposed * @param signature_ signature */ function proposeForSwitchboard( bytes32 packetId_, bytes32 root_, address switchboard_, bytes calldata signature_ ) external payable override { if (packetId_ == bytes32(0)) revert InvalidPacketId(); (address transmitter, bool isTransmitter) = transmitManager__ .checkTransmitter( _decodeChainSlug(packetId_), keccak256(abi.encode(version, chainSlug, packetId_, root_)), signature_ ); if (!isTransmitter) revert InvalidTransmitter(); packetIdRoots[packetId_][proposalCount[packetId_]][ switchboard_ ] = root_; rootProposedAt[packetId_][proposalCount[packetId_]][ switchboard_ ] = block.timestamp; emit PacketProposed( transmitter, packetId_, proposalCount[packetId_]++, root_, switchboard_ ); } /** * @notice Executes a message that has been delivered by transmitters and authenticated by switchboards * @param executionDetails_ all inputs needed from the executor for executing this particular message * @param messageDetails_ the details needed for message verification */ function execute( ISocket.ExecutionDetails calldata executionDetails_, ISocket.MessageDetails calldata messageDetails_ ) external payable override { // make sure message is not executed already if (messageExecuted[messageDetails_.msgId]) revert MessageAlreadyExecuted(); // update state to make sure no reentrancy messageExecuted[messageDetails_.msgId] = true; // make sure caller is calling with right gas limits // we also make sure to give executors the ability to execute with higher gas limits // than the minimum required if ( executionDetails_.executionGasLimit < messageDetails_.minMsgGasLimit ) revert LowGasLimit(); if (executionDetails_.packetId == bytes32(0)) revert InvalidPacketId(); // extract chain slug from msgID uint32 remoteSlug = _decodeChainSlug(messageDetails_.msgId); // make sure packet and msg are for the same chain if (_decodeChainSlug(executionDetails_.packetId) != remoteSlug) revert ErrInSourceValidation(); // extract plug address from msgID address localPlug = _decodePlug(messageDetails_.msgId); // fetch required vars from plug config PlugConfig memory plugConfig; plugConfig.decapacitor__ = _plugConfigs[localPlug][remoteSlug] .decapacitor__; plugConfig.siblingPlug = _plugConfigs[localPlug][remoteSlug] .siblingPlug; plugConfig.inboundSwitchboard__ = _plugConfigs[localPlug][remoteSlug] .inboundSwitchboard__; // fetch packet root bytes32 packetRoot = packetIdRoots[executionDetails_.packetId][ executionDetails_.proposalCount ][address(plugConfig.inboundSwitchboard__)]; if (packetRoot == bytes32(0)) revert PacketNotProposed(); // create packed message bytes32 packedMessage = hasher__.packMessage( remoteSlug, plugConfig.siblingPlug, chainSlug, localPlug, messageDetails_ ); // make sure caller is executor (address executor, bool isValidExecutor) = executionManager__ .isExecutor(packedMessage, executionDetails_.signature); if (!isValidExecutor) revert NotExecutor(); // finally make sure executor params were respected by the executor executionManager__.verifyParams( messageDetails_.executionParams, msg.value ); // verify message was part of the packet and // authenticated by respective switchboard _verify( executionDetails_.packetId, executionDetails_.proposalCount, remoteSlug, packedMessage, packetRoot, plugConfig, executionDetails_.decapacitorProof ); // execute message _execute( executor, localPlug, remoteSlug, executionDetails_.executionGasLimit, messageDetails_ ); } //////////////////////////////////////////////////////// ////////////////// INTERNAL FUNCS ////////////////////// //////////////////////////////////////////////////////// function _verify( bytes32 packetId_, uint256 proposalCount_, uint32 remoteChainSlug_, bytes32 packedMessage_, bytes32 packetRoot_, PlugConfig memory plugConfig_, bytes memory decapacitorProof_ ) internal { // NOTE: is the the first un-trusted call in the system, another one is Plug.inbound if ( !ISwitchboard(plugConfig_.inboundSwitchboard__).allowPacket( packetRoot_, packetId_, proposalCount_, remoteChainSlug_, rootProposedAt[packetId_][proposalCount_][ address(plugConfig_.inboundSwitchboard__) ] ) ) revert VerificationFailed(); if ( !plugConfig_.decapacitor__.verifyMessageInclusion( packetRoot_, packedMessage_, decapacitorProof_ ) ) revert InvalidProof(); } /** * This function assumes localPlug_ will have code while executing. As the message * execution failure is not blocking the system, it is not necessary to check if * code exists in the given address. */ function _execute( address executor_, address localPlug_, uint32 remoteChainSlug_, uint256 executionGasLimit_, ISocket.MessageDetails memory messageDetails_ ) internal { // NOTE: external un-trusted call IPlug(localPlug_).inbound{gas: executionGasLimit_, value: msg.value}( remoteChainSlug_, messageDetails_.payload ); executionManager__.updateExecutionFees( executor_, uint128(messageDetails_.executionFee), messageDetails_.msgId ); emit ExecutionSuccess(messageDetails_.msgId); } /** * @dev Checks whether the specified packet has been proposed. * @param packetId_ The ID of the packet to check. * @param proposalCount_ The proposal ID of the packetId to check. * @param switchboard_ The address of switchboard for which this packet is proposed * @return A boolean indicating whether the packet has been proposed or not. */ function isPacketProposed( bytes32 packetId_, uint256 proposalCount_, address switchboard_ ) external view returns (bool) { return packetIdRoots[packetId_][proposalCount_][switchboard_] == bytes32(0) ? false : true; } /** * @dev Decodes the plug address from a given message id. * @param id_ The ID of the msg to decode the plug from. * @return plug_ The address of sibling plug decoded from the message ID. */ function _decodePlug(bytes32 id_) internal pure returns (address plug_) { plug_ = address(uint160(uint256(id_) >> 64)); } /** * @dev Decodes the chain ID from a given packet/message ID. * @param id_ The ID of the packet/msg to decode the chain slug from. * @return chainSlug_ The chain slug decoded from the packet/message ID. */ function _decodeChainSlug( bytes32 id_ ) internal pure returns (uint32 chainSlug_) { chainSlug_ = uint32(uint256(id_) >> 224); } } // File contracts/socket/SocketSrc.sol pragma solidity 0.8.19; /** * @title SocketSrc * @dev The SocketSrc contract inherits from SocketBase and handles all the operations that * happen on the source side. Provides the following functions * 1. Sending messages from the local chain to a remote chain * 2. Estimating minFees for message transmission, verification and execution * 3. Sealing packets and making them ready to be transmitted */ abstract contract SocketSrc is SocketBase { //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// /** * @dev Error triggerred when invalid capacitor address is provided */ error InvalidCapacitorAddress(); /** * @dev Error triggerred when siblingPlug is not found */ error PlugDisconnected(); //////////////////////////////////////////////////////// ////////////////////// EVENTS ////////////////////////// //////////////////////////////////////////////////////// /** * @notice Emits as soon as a capacitor is sealed * @param transmitter address of transmitter that sealed this packet(recovered from sig) * @param packetId packed-packet id * @param root root of the packet * @param signature signature of transmitter */ event Sealed( address indexed transmitter, bytes32 indexed packetId, uint256 batchSize, bytes32 root, bytes signature ); /** * @notice emits the message details when a new message arrives at outbound * @param localChainSlug local chain slug * @param localPlug local plug address * @param dstChainSlug remote chain slug * @param dstPlug remote plug address * @param msgId message id packed with remoteChainSlug and nonce * @param minMsgGasLimit gas limit needed to execute the inbound at remote * @param payload the data which will be used by inbound at remote */ event MessageOutbound( uint32 localChainSlug, address localPlug, uint32 dstChainSlug, address dstPlug, bytes32 msgId, uint256 minMsgGasLimit, bytes32 executionParams, bytes32 transmissionParams, bytes payload, Fees fees ); /** * @notice To send message to a connected remote chain. Should only be called by a plug. * @param siblingChainSlug_ the remote chain slug * @param minMsgGasLimit_ the minimum gas-limit needed to execute the payload on remote * @param executionParams_ a 32 bytes param to add details for execution, for eg: fees to be paid for execution * @param transmissionParams_ a 32 bytes param to add extra details for transmission * @param payload_ bytes to be delivered to the Plug on the siblingChainSlug_ */ function outbound( uint32 siblingChainSlug_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_, bytes calldata payload_ ) external payable override returns (bytes32 msgId) { PlugConfig memory plugConfig; // looks up the sibling plug address using the msg.sender as the local plug address plugConfig.siblingPlug = _plugConfigs[msg.sender][siblingChainSlug_] .siblingPlug; // if no sibling plug is found for the given chain slug, revert if (plugConfig.siblingPlug == address(0)) revert PlugDisconnected(); // fetches auxillary details for the message from the plug config plugConfig.capacitor__ = _plugConfigs[msg.sender][siblingChainSlug_] .capacitor__; plugConfig.outboundSwitchboard__ = _plugConfigs[msg.sender][ siblingChainSlug_ ].outboundSwitchboard__; // creates a unique ID for the message msgId = _encodeMsgId(plugConfig.siblingPlug); // validate if caller has send enough fees, if yes, send fees to execution manager // for parties to claim later ISocket.Fees memory fees = _validateAndSendFees( minMsgGasLimit_, uint256(payload_.length), executionParams_, transmissionParams_, plugConfig.outboundSwitchboard__, plugConfig.capacitor__.getMaxPacketLength(), siblingChainSlug_ ); ISocket.MessageDetails memory messageDetails = ISocket.MessageDetails({ msgId: msgId, minMsgGasLimit: minMsgGasLimit_, executionParams: executionParams_, payload: payload_, executionFee: fees.executionFee }); // create a compressed data-struct called PackedMessage // which has the message payload and some configuration details bytes32 packedMessage = hasher__.packMessage( chainSlug, msg.sender, siblingChainSlug_, plugConfig.siblingPlug, messageDetails ); // finally add packedMessage to the capacitor to generate new root plugConfig.capacitor__.addPackedMessage(packedMessage); emit MessageOutbound( chainSlug, msg.sender, siblingChainSlug_, plugConfig.siblingPlug, msgId, minMsgGasLimit_, executionParams_, transmissionParams_, payload_, fees ); } /** * @notice Validates if enough fee is provided for message execution. If yes, fees is sent and stored in execution manager. * @param minMsgGasLimit_ the min gas-limit of the message. * @param payloadSize_ The byte length of payload of the message. * @param executionParams_ The extraParams required for execution. * @param transmissionParams_ The extraParams required for transmission. * @param switchboard_ The address of the switchboard through which the message is sent. * @param maxPacketLength_ The maxPacketLength for the capacitor used. Used for calculating transmission Fees. * @param siblingChainSlug_ The slug of the destination chain for the message. */ function _validateAndSendFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, ISwitchboard switchboard_, uint256 maxPacketLength_, uint32 siblingChainSlug_ ) internal returns (ISocket.Fees memory fees) { uint128 verificationFeePerMessage; // switchboard is plug configured and this is an external untrusted call ( fees.switchboardFees, verificationFeePerMessage ) = _getSwitchboardMinFees(siblingChainSlug_, switchboard_); // deposits msg.value to execution manager and checks if enough fees is provided (fees.executionFee, fees.transmissionFees) = executionManager__ .payAndCheckFees{value: msg.value}( minMsgGasLimit_, payloadSize_, executionParams_, transmissionParams_, siblingChainSlug_, fees.switchboardFees / uint128(maxPacketLength_), verificationFeePerMessage, address(transmitManager__), address(switchboard_), maxPacketLength_ ); } /** * @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 payloadSize_ The byte length of payload of the message. * @param executionParams_ The extraParams required for execution. * @param siblingChainSlug_ 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 siblingChainSlug_, address plug_ ) external view override returns (uint256 totalFees) { ICapacitor capacitor__ = _plugConfigs[plug_][siblingChainSlug_] .capacitor__; uint256 maxPacketLength = capacitor__.getMaxPacketLength(); ( uint128 transmissionFees, uint128 switchboardFees, uint128 executionFees ) = _getAllMinFees( minMsgGasLimit_, payloadSize_, executionParams_, transmissionParams_, siblingChainSlug_, _plugConfigs[plug_][siblingChainSlug_].outboundSwitchboard__, maxPacketLength ); totalFees = transmissionFees + switchboardFees + executionFees; } /** * @notice Retrieves the minimum fees required for switchboard. * @param siblingChainSlug_ The slug of the destination chain for the message. * @param switchboard__ The switchboard address for which fees is retrieved. * @return switchboardFees fees required for message verification */ function _getSwitchboardMinFees( uint32 siblingChainSlug_, ISwitchboard switchboard__ ) internal view returns (uint128 switchboardFees, uint128 verificationOverheadFees) { (switchboardFees, verificationOverheadFees) = switchboard__.getMinFees( siblingChainSlug_ ); } /** * @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 payloadSize_ The byte length of payload of the message. * @param executionParams_ The extraParams required for execution. * @param siblingChainSlug_ The slug of the destination chain for the message. * @param switchboard__ The address of the switchboard through which the message is sent. */ function _getAllMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 siblingChainSlug_, ISwitchboard switchboard__, uint256 maxPacketLength_ ) internal view returns ( uint128 transmissionFees, uint128 switchboardFees, uint128 executionFees ) { uint128 verificationOverheadFees; uint128 msgExecutionFee; (switchboardFees, verificationOverheadFees) = _getSwitchboardMinFees( siblingChainSlug_, switchboard__ ); switchboardFees /= uint128(maxPacketLength_); (msgExecutionFee, transmissionFees) = executionManager__ .getExecutionTransmissionMinFees( minMsgGasLimit_, payloadSize_, executionParams_, transmissionParams_, siblingChainSlug_, address(transmitManager__) ); transmissionFees /= uint128(maxPacketLength_); executionFees = msgExecutionFee + verificationOverheadFees; } /** * @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 override { uint32 siblingChainSlug = capacitorToSlug[capacitorAddress_]; if (siblingChainSlug == 0) revert InvalidCapacitorAddress(); (bytes32 root, uint64 packetCount) = ICapacitor(capacitorAddress_) .sealPacket(batchSize_); bytes32 packetId = _encodePacketId(capacitorAddress_, packetCount); (address transmitter, bool isTransmitter) = transmitManager__ .checkTransmitter( siblingChainSlug, keccak256( abi.encode(version, siblingChainSlug, packetId, root) ), signature_ ); if (!isTransmitter) revert InvalidTransmitter(); emit Sealed(transmitter, packetId, batchSize_, root, signature_); } // Packs the local plug, local chain slug, remote chain slug and nonce // globalMessageCount++ will take care of msg id overflow as well // msgId(256) = localChainSlug(32) | siblingPlug_(160) | nonce(64) function _encodeMsgId(address siblingPlug_) internal returns (bytes32) { return bytes32( (uint256(chainSlug) << 224) | (uint256(uint160(siblingPlug_)) << 64) | globalMessageCount++ ); } function _encodePacketId( address capacitorAddress_, uint64 packetCount_ ) internal view returns (bytes32) { return bytes32( (uint256(chainSlug) << 224) | (uint256(uint160(capacitorAddress_)) << 64) | packetCount_ ); } } // File contracts/socket/Socket.sol pragma solidity 0.8.19; /** * @title Socket * @notice Core-contract containing all the core-socket utilities. * @dev This contract inherits from SocketSrc and SocketDst */ contract Socket is SocketSrc, SocketDst { /* * @notice constructor for creating a new Socket contract instance. * @param chainSlug_ The unique identifier of the chain this socket is deployed on. * @param hasher_ The address of the Hasher contract used to pack the message before transmitting them. * @param capacitorFactory_ The address of the CapacitorFactory contract used to create new Capacitor and DeCapacitor contracts. * @param owner_ The address of the owner who has the initial admin role. * @param version_ The version string which is hashed and stored in socket. */ constructor( uint32 chainSlug_, address hasher_, address capacitorFactory_, address owner_, string memory version_ ) AccessControlExtended(owner_) SocketBase(chainSlug_, version_) { hasher__ = IHasher(hasher_); capacitorFactory__ = ICapacitorFactory(capacitorFactory_); } }
Compiler Settings
{"outputSelection":{"*":{"*":["*"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"type":"address","name":"hasher_","internalType":"address"},{"type":"address","name":"capacitorFactory_","internalType":"address"},{"type":"address","name":"owner_","internalType":"address"},{"type":"string","name":"version_","internalType":"string"}]},{"type":"error","name":"ErrInSourceValidation","inputs":[]},{"type":"error","name":"InvalidCapacitorAddress","inputs":[]},{"type":"error","name":"InvalidConnection","inputs":[]},{"type":"error","name":"InvalidPacketId","inputs":[]},{"type":"error","name":"InvalidProof","inputs":[]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"InvalidTransmitter","inputs":[]},{"type":"error","name":"LowGasLimit","inputs":[]},{"type":"error","name":"MessageAlreadyExecuted","inputs":[]},{"type":"error","name":"NoPermit","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"error","name":"NotExecutor","inputs":[]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"PacketNotProposed","inputs":[]},{"type":"error","name":"PlugDisconnected","inputs":[]},{"type":"error","name":"SwitchboardExists","inputs":[]},{"type":"error","name":"UnequalArrayLengths","inputs":[]},{"type":"error","name":"VerificationFailed","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"CapacitorFactorySet","inputs":[{"type":"address","name":"capacitorFactory","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionManagerSet","inputs":[{"type":"address","name":"executionManager","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionSuccess","inputs":[{"type":"bytes32","name":"msgId","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"HasherSet","inputs":[{"type":"address","name":"hasher","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"MessageOutbound","inputs":[{"type":"uint32","name":"localChainSlug","internalType":"uint32","indexed":false},{"type":"address","name":"localPlug","internalType":"address","indexed":false},{"type":"uint32","name":"dstChainSlug","internalType":"uint32","indexed":false},{"type":"address","name":"dstPlug","internalType":"address","indexed":false},{"type":"bytes32","name":"msgId","internalType":"bytes32","indexed":false},{"type":"uint256","name":"minMsgGasLimit","internalType":"uint256","indexed":false},{"type":"bytes32","name":"executionParams","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"transmissionParams","internalType":"bytes32","indexed":false},{"type":"bytes","name":"payload","internalType":"bytes","indexed":false},{"type":"tuple","name":"fees","internalType":"struct ISocket.Fees","indexed":false,"components":[{"type":"uint128","name":"transmissionFees","internalType":"uint128"},{"type":"uint128","name":"executionFee","internalType":"uint128"},{"type":"uint128","name":"switchboardFees","internalType":"uint128"}]}],"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":"PacketProposed","inputs":[{"type":"address","name":"transmitter","internalType":"address","indexed":true},{"type":"bytes32","name":"packetId","internalType":"bytes32","indexed":true},{"type":"uint256","name":"proposalCount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"root","internalType":"bytes32","indexed":false},{"type":"address","name":"switchboard","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"PlugConnected","inputs":[{"type":"address","name":"plug","internalType":"address","indexed":false},{"type":"uint32","name":"siblingChainSlug","internalType":"uint32","indexed":false},{"type":"address","name":"siblingPlug","internalType":"address","indexed":false},{"type":"address","name":"inboundSwitchboard","internalType":"address","indexed":false},{"type":"address","name":"outboundSwitchboard","internalType":"address","indexed":false},{"type":"address","name":"capacitor","internalType":"address","indexed":false},{"type":"address","name":"decapacitor","internalType":"address","indexed":false}],"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":"event","name":"Sealed","inputs":[{"type":"address","name":"transmitter","internalType":"address","indexed":true},{"type":"bytes32","name":"packetId","internalType":"bytes32","indexed":true},{"type":"uint256","name":"batchSize","internalType":"uint256","indexed":false},{"type":"bytes32","name":"root","internalType":"bytes32","indexed":false},{"type":"bytes","name":"signature","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"SiblingSwitchboardUpdated","inputs":[{"type":"address","name":"switchboard","internalType":"address","indexed":false},{"type":"uint32","name":"siblingChainSlug","internalType":"uint32","indexed":false},{"type":"address","name":"siblingSwitchboard","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SwitchboardAdded","inputs":[{"type":"address","name":"switchboard","internalType":"address","indexed":false},{"type":"uint32","name":"siblingChainSlug","internalType":"uint32","indexed":false},{"type":"address","name":"capacitor","internalType":"address","indexed":false},{"type":"address","name":"decapacitor","internalType":"address","indexed":false},{"type":"uint256","name":"maxPacketLength","internalType":"uint256","indexed":false},{"type":"uint256","name":"capacitorType","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TransmitManagerSet","inputs":[{"type":"address","name":"transmitManager","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICapacitorFactory"}],"name":"capacitorFactory__","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"capacitorToSlug","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICapacitor"}],"name":"capacitors__","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint32","name":"","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"chainSlug","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"connect","inputs":[{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"address","name":"siblingPlug_","internalType":"address"},{"type":"address","name":"inboundSwitchboard_","internalType":"address"},{"type":"address","name":"outboundSwitchboard_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IDecapacitor"}],"name":"decapacitors__","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint32","name":"","internalType":"uint32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"execute","inputs":[{"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":"address","name":"","internalType":"contract IExecutionManager"}],"name":"executionManager__","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"totalFees","internalType":"uint256"}],"name":"getMinFees","inputs":[{"type":"uint256","name":"minMsgGasLimit_","internalType":"uint256"},{"type":"uint256","name":"payloadSize_","internalType":"uint256"},{"type":"bytes32","name":"executionParams_","internalType":"bytes32"},{"type":"bytes32","name":"transmissionParams_","internalType":"bytes32"},{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"address","name":"plug_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"siblingPlug","internalType":"address"},{"type":"address","name":"inboundSwitchboard__","internalType":"address"},{"type":"address","name":"outboundSwitchboard__","internalType":"address"},{"type":"address","name":"capacitor__","internalType":"address"},{"type":"address","name":"decapacitor__","internalType":"address"}],"name":"getPlugConfig","inputs":[{"type":"address","name":"plugAddress_","internalType":"address"},{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"globalMessageCount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantBatchRole","inputs":[{"type":"bytes32[]","name":"roleNames_","internalType":"bytes32[]"},{"type":"uint32[]","name":"slugs_","internalType":"uint32[]"},{"type":"address[]","name":"grantees_","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"grantee_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRoleWithSlug","inputs":[{"type":"bytes32","name":"roleName_","internalType":"bytes32"},{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"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":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRoleWithSlug","inputs":[{"type":"bytes32","name":"roleName_","internalType":"bytes32"},{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"type":"address","name":"address_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IHasher"}],"name":"hasher__","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPacketProposed","inputs":[{"type":"bytes32","name":"packetId_","internalType":"bytes32"},{"type":"uint256","name":"proposalCount_","internalType":"uint256"},{"type":"address","name":"switchboard_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"messageExecuted","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"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":"payable","outputs":[{"type":"bytes32","name":"msgId","internalType":"bytes32"}],"name":"outbound","inputs":[{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"uint256","name":"minMsgGasLimit_","internalType":"uint256"},{"type":"bytes32","name":"executionParams_","internalType":"bytes32"},{"type":"bytes32","name":"transmissionParams_","internalType":"bytes32"},{"type":"bytes","name":"payload_","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"packetIdRoots","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"proposalCount","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"proposeForSwitchboard","inputs":[{"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":[{"type":"address","name":"capacitor","internalType":"address"},{"type":"address","name":"decapacitor","internalType":"address"}],"name":"registerSwitchboardForSibling","inputs":[{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"uint256","name":"maxPacketLength_","internalType":"uint256"},{"type":"uint256","name":"capacitorType_","internalType":"uint256"},{"type":"address","name":"siblingSwitchboard_","internalType":"address"}]},{"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":"revokeBatchRole","inputs":[{"type":"bytes32[]","name":"roleNames_","internalType":"bytes32[]"},{"type":"uint32[]","name":"slugs_","internalType":"uint32[]"},{"type":"address[]","name":"grantees_","internalType":"address[]"}]},{"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":"revokeRoleWithSlug","inputs":[{"type":"bytes32","name":"roleName_","internalType":"bytes32"},{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"type":"address","name":"grantee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rootProposedAt","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"seal","inputs":[{"type":"uint256","name":"batchSize_","internalType":"uint256"},{"type":"address","name":"capacitorAddress_","internalType":"address"},{"type":"bytes","name":"signature_","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCapacitorFactory","inputs":[{"type":"address","name":"capacitorFactory_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExecutionManager","inputs":[{"type":"address","name":"executionManager_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setHasher","inputs":[{"type":"address","name":"hasher_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTransmitManager","inputs":[{"type":"address","name":"transmitManager_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ITransmitManager"}],"name":"transmitManager__","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"useSiblingSwitchboard","inputs":[{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"address","name":"siblingSwitchboard_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"version","inputs":[]}]
Contract Creation Code
0x60c06040523480156200001157600080fd5b50604051620047313803806200473183398101604081905262000034916200012d565b84818380806200004481620000a6565b50505063ffffffff9190911660a0528051602090910120608052505060088054600160401b600160e01b031916680100000000000000006001600160a01b0394851602179055600080546001600160a01b031916919092161790555062000257565b600580546001600160a01b0383166001600160a01b031991821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b80516001600160a01b03811681146200011257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156200014657600080fd5b855163ffffffff811681146200015b57600080fd5b945060206200016c878201620000fa565b94506200017c60408801620000fa565b93506200018c60608801620000fa565b60808801519093506001600160401b0380821115620001aa57600080fd5b818901915089601f830112620001bf57600080fd5b815181811115620001d457620001d462000117565b604051601f8201601f19908116603f01168101908382118183101715620001ff57620001ff62000117565b816040528281528c868487010111156200021857600080fd5b600093505b828410156200023c57848401860151818501870152928501926200021d565b60008684830101528096505050505050509295509295909350565b60805160a05161447c620002b56000396000818161090b01528181611392015281816119d701528181611b0b0152818161263e015281816128d70152612fea015260008181610647015281816125dd01526128ac015261447c6000f3fe6080604052600436106102c55760003560e01c806354fd4d501161017957806391d14854116100d6578063c85ce3251161008a578063e992e0ff11610064578063e992e0ff146109d9578063ea93a50914610a13578063ecb9748414610a4357600080fd5b8063c85ce32514610993578063d547741f146109a6578063dc309863146109c657600080fd5b8063b349ba65116100bb578063b349ba65146108f9578063b39691061461092d578063c085c22b1461096657600080fd5b806391d14854146108b95780639ae3f05a146108d957600080fd5b806379cfc0061161012d5780638288a927116101125780638288a927146108205780638da5cb5b146108405780638df132c61461086b57600080fd5b806379cfc006146107d357806381403a021461080057600080fd5b80635febe7e71161015e5780635febe7e7146106895780636ccae054146106c75780636f38f870146106e757600080fd5b806354fd4d50146106355780635b94db271461066957600080fd5b80633386774f1161022757806341805c24116101db578063440406eb116101c0578063440406eb146105a75780634ad701bc146105d75780634afae4021461061557600080fd5b806341805c241461055a57806343fa97ca1461058757600080fd5b80633b1be6781161020c5780633b1be678146104d75780633bd1adec146104f7578063401ae0751461050c57600080fd5b80633386774f1461046e57806335dd06681461048f57600080fd5b806320f99c0a1161027e5780632e7eb258116102635780632e7eb2581461040e5780632f2ff15d1461042e57806330d20f871461044e57600080fd5b806320f99c0a146103d0578063275c41c9146103fb57600080fd5b80631381ba4d116102af5780631381ba4d1461036e5780631ba8e484146103905780631e867311146103b057600080fd5b80626186f7146102ca5780630b04bb4114610321575b600080fd5b3480156102d657600080fd5b50600a546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561032d57600080fd5b5061034161033c366004613720565b610a63565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610318565b34801561037a57600080fd5b5061038e610389366004613768565b610e0c565b005b34801561039c57600080fd5b5061038e6103ab366004613785565b610f19565b3480156103bc57600080fd5b5061038e6103cb366004613811565b610f7a565b3480156103dc57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166102f7565b61038e6104093660046138c3565b611120565b34801561041a57600080fd5b5061038e610429366004613785565b6115d8565b34801561043a57600080fd5b5061038e610449366004613927565b611634565b34801561045a57600080fd5b5061038e610469366004613768565b611693565b61048161047c366004613999565b611793565b604051908152602001610318565b34801561049b57600080fd5b506104c26104aa366004613768565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610318565b3480156104e357600080fd5b5061038e6104f23660046139f8565b611b65565b34801561050357600080fd5b5061038e611d47565b34801561051857600080fd5b506102f7610527366004613a47565b600460209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056657600080fd5b506009546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b34801561059357600080fd5b5061038e6105a2366004613811565b611da3565b3480156105b357600080fd5b506105c76105c2366004613a7c565b611f3f565b6040519015158152602001610318565b3480156105e357600080fd5b506104816105f2366004613a7c565b600c60209081526000938452604080852082529284528284209052825290205481565b34801561062157600080fd5b5061038e610630366004613768565b611f8e565b34801561064157600080fd5b506104817f000000000000000000000000000000000000000000000000000000000000000081565b34801561067557600080fd5b5061038e610684366004613768565b61209c565b34801561069557600080fd5b506104816106a4366004613a7c565b600d60209081526000938452604080852082529284528284209052825290205481565b3480156106d357600080fd5b5061038e6106e2366004613aaa565b61215c565b3480156106f357600080fd5b5061078c610702366004613a47565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020818152604080842063ffffffff95909516845293815291839020835160a081018552815486168082529282015486169381018490526002820154861694810185905260038201548616606082018190526004909201549095166080909501859052909490939290565b6040805173ffffffffffffffffffffffffffffffffffffffff968716815294861660208601529285169284019290925283166060830152909116608082015260a001610318565b3480156107df57600080fd5b506104816107ee366004613aeb565b600e6020526000908152604090205481565b34801561080c57600080fd5b5061038e61081b366004613b04565b6121fa565b34801561082c57600080fd5b5061038e61083b366004613768565b612255565b34801561084c57600080fd5b5060055473ffffffffffffffffffffffffffffffffffffffff166102f7565b34801561087757600080fd5b506102f7610886366004613a47565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108c557600080fd5b506105c76108d4366004613927565b612355565b3480156108e557600080fd5b506104816108f4366004613b30565b612390565b34801561090557600080fd5b506104c27f000000000000000000000000000000000000000000000000000000000000000081565b34801561093957600080fd5b506008546102f79068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561097257600080fd5b506000546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b61038e6109a1366004613b8c565b6124d9565b3480156109b257600080fd5b5061038e6109c1366004613927565b6127e7565b61038e6109d4366004613be8565b612842565b3480156109e557600080fd5b506008546109fa9067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610318565b348015610a1f57600080fd5b506105c7610a2e366004613aeb565b600b6020526000908152604090205460ff1681565b348015610a4f57600080fd5b506105c7610a5e366004613785565b612aa1565b33600081815260036020908152604080832063ffffffff891684529091528120549091829173ffffffffffffffffffffffffffffffffffffffff1615610ad5576040517f2dff855500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546040517f284fb3630000000000000000000000000000000000000000000000000000000081526004810188905263ffffffff8a16602482015260448101899052829173ffffffffffffffffffffffffffffffffffffffff169063284fb3639060640160408051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190613c52565b9150915081945080935088600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548163ffffffff021916908363ffffffff16021790555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fe797daee214784c2b0a3c67d7700cdb94fa243f27a14283eb643ee0fdc520d30838a87878c8c604051610d9c9695949392919073ffffffffffffffffffffffffffffffffffffffff968716815263ffffffff959095166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b60405180910390a16040805173ffffffffffffffffffffffffffffffffffffffff858116825263ffffffff8c16602083015288168183015290517f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b9181900360600190a150505094509492505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16610e9e576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fc7d6b56a07930ef230a86f7fc3ee39eca236764293f0d1a764347ae831252040906020015b60405180910390a15050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610f6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612aae565b505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fcb576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580610fda5750848314155b15611011576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b8181101561111657600086868381811061103157611031613c81565b90506020020160208101906110469190613cb0565b63ffffffff1611156110c6576110c188888381811061106757611067613c81565b9050602002013587878481811061108057611080613c81565b90506020020160208101906110959190613cb0565b8686858181106110a7576110a7613c81565b90506020020160208101906110bc9190613768565b612aae565b61110e565b61110e8888838181106110db576110db613c81565b905060200201358585848181106110f4576110f4613c81565b90506020020160208101906111099190613768565b612aeb565b600101611015565b5050505050505050565b80356000908152600b602052604090205460ff161561116b576040517f7448c64c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356000908152600b60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055808201359083013510156111e6576040517fd38edae000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813561121e576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803560e090811c908335901c8114611262576040517fb39fb5d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a08101825260008082526020808301829052828401828152606084018381526080850184905273ffffffffffffffffffffffffffffffffffffffff8835871c81811686526001855287862063ffffffff8a1687528552878620600281015483169094528354821687526003909301548116825289358552600c84528685208a8501358652845286852091511684529091529290205480611333576040517f1c93605200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085482516040517f02ea143100000000000000000000000000000000000000000000000000000000815260009268010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16916302ea1431916113be9189917f0000000000000000000000000000000000000000000000000000000000000000908a908d90600401613d14565b6020604051808303816000875af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114019190613e01565b600a54909150600090819073ffffffffffffffffffffffffffffffffffffffff1663954d09c98461143560808d018d613e1a565b6040518463ffffffff1660e01b815260040161145393929190613e7f565b6040805180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190613eb2565b91509150806114ce576040517fc32d1d7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546040517fa56d92ce00000000000000000000000000000000000000000000000000000000815260608a0135600482015234602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a56d92ce9060440160006040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506115b489600001358a602001358986888a8f806060019061157a9190613e1a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b6e92505050565b6115cd82878960408d01356115c88d613f85565b612d46565b505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611629576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612eba565b60055473ffffffffffffffffffffffffffffffffffffffff163314611685576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612ef7565b5050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16611720576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527f03d960b6dfd88e82390cc07c64a7a51b63c3b8ecdc888d02d4697995a912cc0590602001610f0d565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290523382526001815283822063ffffffff8b16835290529182205473ffffffffffffffffffffffffffffffffffffffff16808252611826576040517fe741bafb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260016020818152604080842063ffffffff8d168086528184529185209384015473ffffffffffffffffffffffffffffffffffffffff908116878501529190945292905260040154166080820152805161188490612f7d565b91506000611910888686905089898660800151876020015173ffffffffffffffffffffffffffffffffffffffff16632ff9f2c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190613e01565b8f61301d565b905060006040518060a0016040528085815260200183602001516fffffffffffffffffffffffffffffffff1681526020018a815260200189815260200187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508152509050600060088054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166302ea14317f0000000000000000000000000000000000000000000000000000000000000000338e8860000151876040518663ffffffff1660e01b8152600401611a1e9594939291906140cb565b6020604051808303816000875af1158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190613e01565b60208501516040517f920ee8a80000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff169063920ee8a890602401600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050507f45d70e73f9a26cea18d4009d1ad25ffbdc4114ce9d8ceb15959ae9eadb0a3a2c7f0000000000000000000000000000000000000000000000000000000000000000338d8760000151898f8f8f8f8f8d604051611b4f9b9a9998979695949392919061415a565b60405180910390a1505050509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260036020908152604080832063ffffffff89168452909152902054161580611be0575073ffffffffffffffffffffffffffffffffffffffff818116600090815260036020908152604080832063ffffffff8916845290915290205416155b15611c17576040517f63228f2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600081815260016020818152604080842063ffffffff8a1680865290835281852080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8c811691821784558a8116808a526003808952878b20878c528952878b205499860180549a84169a86168b1790558d8316808c526004808b52898d20898e528b529b899020546002880180549190951690871681179094559086018054861682179055998501805490941681179093558551998a5295890193909352928701919091526060860194909452608085015260a084019190915260c0830152907febaba46465001886e6218eb8da227160a320362ee4aab240ead702addafe55ba9060e0015b60405180910390a15050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d98576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611da1336131b0565b565b60055473ffffffffffffffffffffffffffffffffffffffff163314611df4576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580611e035750848314155b15611e3a576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b81811015611116576000868683818110611e5a57611e5a613c81565b9050602002016020810190611e6f9190613cb0565b63ffffffff161115611eef57611eea888883818110611e9057611e90613c81565b90506020020135878784818110611ea957611ea9613c81565b9050602002016020810190611ebe9190613cb0565b868685818110611ed057611ed0613c81565b9050602002016020810190611ee59190613768565b612eba565b611f37565b611f37888883818110611f0457611f04613c81565b90506020020135858584818110611f1d57611f1d613c81565b9050602002016020810190611f329190613768565b612ef7565b600101611e3e565b6000838152600c60209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205415611f83576001611f86565b60005b949350505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff1661201b576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600880547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527fc7238b23787eb9f8aa74c79b27083bb4b8f0db527df90366b487c40fa0ba2d3a90602001610f0d565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120ed576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527fff9a7b11e174fcce811917e5a8f906a450751019d105ceca5d4a7efe2887160660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166121e9576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b6121f4848484613229565b50505050565b6040805133815263ffffffff8416602082015273ffffffffffffffffffffffffffffffffffffffff8316918101919091527f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b90606001610f0d565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff166122e2576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fdd4864dd50be8a1a56c70aebc2953b0890b860197577457ac25fa02f86dadd5590602001610f0d565b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b73ffffffffffffffffffffffffffffffffffffffff808216600090815260016020818152604080842063ffffffff8816855282528084209092015482517f2ff9f2c900000000000000000000000000000000000000000000000000000000815292519394169284928492632ff9f2c9926004808401938290030181865afa15801561241f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124439190613e01565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832063ffffffff8b168452909152812060040154929350918291829161249b918e918e918e918e918e91168a613319565b91945092509050806124ad838561423c565b6124b7919061423c565b6fffffffffffffffffffffffffffffffff169c9b505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602052604081205463ffffffff169081900361253f576040517f73d817fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd7c9eaac00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff87169063d7c9eaac9060240160408051808303816000875af11580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d4919061426c565b600954604080517f000000000000000000000000000000000000000000000000000000000000000060208083019190915263ffffffff89168284015267ffffffffffffffff85168c841b7bffffffffffffffffffffffffffffffffffffffff0000000000000000167f000000000000000000000000000000000000000000000000000000000000000060e01b7fffffffff000000000000000000000000000000000000000000000000000000001617176060830181905260808084018890528451808503909101815260a084019485905280519201919091207fb7ee4eb900000000000000000000000000000000000000000000000000000000909352949650929450600092839273ffffffffffffffffffffffffffffffffffffffff169163b7ee4eb99161270b918a918d908d9060a40161429e565b6040805180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b9190613eb2565b9150915080612786576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828273ffffffffffffffffffffffffffffffffffffffff167f4bf575a0e4ff12a13816954b1ce8b1e53f30e121ea4f107ac086ec29da524abe8c888c8c6040516127d394939291906142ce565b60405180910390a350505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314612838576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612aeb565b84612879576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090819073ffffffffffffffffffffffffffffffffffffffff1663b7ee4eb96128a68960e01c90565b604080517f0000000000000000000000000000000000000000000000000000000000000000602082015263ffffffff7f00000000000000000000000000000000000000000000000000000000000000001691810191909152606081018b9052608081018a905260a0016040516020818303038152906040528051906020012087876040518563ffffffff1660e01b8152600401612946949392919061429e565b6040805180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190613eb2565b91509150806129c1576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000878152600c60209081526040808320600e8084528285208054865291845282852073ffffffffffffffffffffffffffffffffffffffff808c168088529186528487208d90558d8752600d86528487208454885286528487209187529085529285204290558b855290925281548a93918616927f4b8e305abfc214d75df6e3d0b37dc1b2e6e93726d472df847f312d190dcf870492612a60836142ee565b9091555060408051918252602082018b905273ffffffffffffffffffffffffffffffffffffffff8a169082015260600160405180910390a350505050505050565b6000611f8684848461346d565b610f758383604051602001612ad392919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b6060820180516000898152600d602090815260408083208b84528252808320945173ffffffffffffffffffffffffffffffffffffffff908116845294909152908190205490517f4c40818000000000000000000000000000000000000000000000000000000000815260048101879052602481018b9052604481018a905263ffffffff891660648201526084810191909152911690634c4081809060a401602060405180830381865afa158015612c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4d9190614326565b612c83576040517f439cc0cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff16632d095c438486846040518463ffffffff1660e01b8152600401612cc493929190614341565b6020604051808303816000875af1158015612ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d079190614326565b612d3d576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60808101516040517fc41f1f6c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169163c41f1f6c9185913491612da1918991600401614360565b6000604051808303818589803b158015612dba57600080fd5b5088f1158015612dce573d6000803e3d6000fd5b5050600a54602086015186516040517ff1f069d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301526fffffffffffffffffffffffffffffffff909316602482015260448101919091529116945063f1f069d693506064019150612e559050565b600060405180830381600087803b158015612e6f57600080fd5b505af1158015612e83573d6000803e3d6000fd5b505082516040519081527fdc29884a71d2bb98d3c53dc09718be05c7bfd142b7773a5c5cf2517629290ac092506020019050611d38565b610f758383604051602001612edf92919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6008805460009167ffffffffffffffff9091169082612f9b8361437f565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555067ffffffffffffffff1660408373ffffffffffffffffffffffffffffffffffffffff16901b60e07f000000000000000000000000000000000000000000000000000000000000000063ffffffff16901b171760001b9050919050565b604080516060810182526000808252602082018190529181018290529061304483866134fb565b6fffffffffffffffffffffffffffffffff90911660408401819052600a5491925073ffffffffffffffffffffffffffffffffffffffff909116906371c4717b9034908c908c908c908c908a9061309b908d906143a6565b6009546040517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b168152600481019790975260248701959095526044860193909352606485019190915263ffffffff1660848401526fffffffffffffffffffffffffffffffff90811660a4840152861660c483015273ffffffffffffffffffffffffffffffffffffffff90811660e48301528916610104820152610124810188905261014401604080518083038185885af1158015613163573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613188919061441c565b6fffffffffffffffffffffffffffffffff908116845216602083015250979650505050505050565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b73ffffffffffffffffffffffffffffffffffffffff8216613276576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016132bd57610f75828261359e565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361330e576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383613613565b600080600080600061332b88886134fb565b909450915061333a86856143a6565b9350600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aea3d96b8d8d8d8d8d600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518763ffffffff1660e01b81526004016134029695949392919095865260208601949094526040850192909252606084015263ffffffff16608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b6040805180830381865afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613442919061441c565b9550905061345086866143a6565b945061345c828261423c565b925050509750975097945050505050565b6000611f86848460405160200161349492919091825263ffffffff16602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009081526007835281812073ffffffffffffffffffffffffffffffffffffffff8716825290925290205460ff1690565b6040517f06da42e000000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906306da42e0906024016040805180830381865afa15801561356f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613593919061441c565b909590945092505050565b600080600080600085875af1905080610f75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610e95565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806121f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610e95565b803563ffffffff811681146136f657600080fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461371d57600080fd5b50565b6000806000806080858703121561373657600080fd5b61373f856136e2565b93506020850135925060408501359150606085013561375d816136fb565b939692955090935050565b60006020828403121561377a57600080fd5b8135612389816136fb565b60008060006060848603121561379a57600080fd5b833592506137aa602085016136e2565b915060408401356137ba816136fb565b809150509250925092565b60008083601f8401126137d757600080fd5b50813567ffffffffffffffff8111156137ef57600080fd5b6020830191508360208260051b850101111561380a57600080fd5b9250929050565b6000806000806000806060878903121561382a57600080fd5b863567ffffffffffffffff8082111561384257600080fd5b61384e8a838b016137c5565b9098509650602089013591508082111561386757600080fd5b6138738a838b016137c5565b9096509450604089013591508082111561388c57600080fd5b5061389989828a016137c5565b979a9699509497509295939492505050565b600060a082840312156138bd57600080fd5b50919050565b600080604083850312156138d657600080fd5b823567ffffffffffffffff808211156138ee57600080fd5b6138fa868387016138ab565b9350602085013591508082111561391057600080fd5b5061391d858286016138ab565b9150509250929050565b6000806040838503121561393a57600080fd5b82359150602083013561394c816136fb565b809150509250929050565b60008083601f84011261396957600080fd5b50813567ffffffffffffffff81111561398157600080fd5b60208301915083602082850101111561380a57600080fd5b60008060008060008060a087890312156139b257600080fd5b6139bb876136e2565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156139ec57600080fd5b61389989828a01613957565b60008060008060808587031215613a0e57600080fd5b613a17856136e2565b93506020850135613a27816136fb565b92506040850135613a37816136fb565b9150606085013561375d816136fb565b60008060408385031215613a5a57600080fd5b8235613a65816136fb565b9150613a73602084016136e2565b90509250929050565b600080600060608486031215613a9157600080fd5b833592506020840135915060408401356137ba816136fb565b600080600060608486031215613abf57600080fd5b8335613aca816136fb565b92506020840135613ada816136fb565b929592945050506040919091013590565b600060208284031215613afd57600080fd5b5035919050565b60008060408385031215613b1757600080fd5b613b20836136e2565b9150602083013561394c816136fb565b60008060008060008060c08789031215613b4957600080fd5b86359550602087013594506040870135935060608701359250613b6e608088016136e2565b915060a0870135613b7e816136fb565b809150509295509295509295565b60008060008060608587031215613ba257600080fd5b843593506020850135613bb4816136fb565b9250604085013567ffffffffffffffff811115613bd057600080fd5b613bdc87828801613957565b95989497509550505050565b600080600080600060808688031215613c0057600080fd5b85359450602086013593506040860135613c19816136fb565b9250606086013567ffffffffffffffff811115613c3557600080fd5b613c4188828901613957565b969995985093965092949392505050565b60008060408385031215613c6557600080fd5b8251613c70816136fb565b602084015190925061394c816136fb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613cc257600080fd5b612389826136e2565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152823560a0830152602083013560c0830152604083013560e0830152606083013561010083015260808301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db157600080fd5b830160208101903567ffffffffffffffff811115613dce57600080fd5b803603821315613ddd57600080fd5b60a0610120850152613df461014085018284613ccb565b9998505050505050505050565b600060208284031215613e1357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e4f57600080fd5b83018035915067ffffffffffffffff821115613e6a57600080fd5b60200191503681900382131561380a57600080fd5b838152604060208201526000613e99604083018486613ccb565b95945050505050565b805180151581146136f657600080fd5b60008060408385031215613ec557600080fd5b8251613ed0816136fb565b9150613a7360208401613ea2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715613f3057613f30613ede565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f7d57613f7d613ede565b604052919050565b600060a08236031215613f9757600080fd5b613f9f613f0d565b82358152602080840135818301526040840135604083015260608401356060830152608084013567ffffffffffffffff80821115613fdc57600080fd5b9085019036601f830112613fef57600080fd5b81358181111561400157614001613ede565b614031847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f36565b9150808252368482850101111561404757600080fd5b808484018584013760009082019093019290925250608082015292915050565b6000815180845260005b8181101561408d57602081850181015186830182015201614071565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152825160a0830152602083015160c0830152604083015160e08301526060830151610100830152608083015160a061012084015261414e610140840182614067565b98975050505050505050565b600061018063ffffffff808f16845273ffffffffffffffffffffffffffffffffffffffff808f166020860152818e166040860152808d16606086015250508960808401528860a08401528760c08401528660e0840152806101008401526141c48184018688613ccb565b9150506fffffffffffffffffffffffffffffffff808451166101208401528060208501511661014084015280604085015116610160840152509c9b505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff8181168382160190808211156142655761426561420d565b5092915050565b6000806040838503121561427f57600080fd5b82519150602083015167ffffffffffffffff8116811461394c57600080fd5b63ffffffff851681528360208201526060604082015260006142c4606083018486613ccb565b9695505050505050565b8481528360208201526060604082015260006142c4606083018486613ccb565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361431f5761431f61420d565b5060010190565b60006020828403121561433857600080fd5b61238982613ea2565b838152826020820152606060408201526000613e996060830184614067565b63ffffffff83168152604060208201526000611f866040830184614067565b600067ffffffffffffffff80831681810361439c5761439c61420d565b6001019392505050565b60006fffffffffffffffffffffffffffffffff808416806143f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b80516fffffffffffffffffffffffffffffffff811681146136f657600080fd5b6000806040838503121561442f57600080fd5b614438836143fc565b9150613a73602084016143fc56fea26469706673582212208b207b6ea0b17a8c1b971aded8aa3d712bdaff7e0e0f033fdd5c848b561a579564736f6c634300081300330000000000000000000000000000000000000000000000000000000000028c61000000000000000000000000941f0ef5258604fe10c76ae3858984ce0452b5f2000000000000000000000000fe9dcb3daba382f46f2ce69ddeb3b5df86d96f0400000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004494d4c4900000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x6080604052600436106102c55760003560e01c806354fd4d501161017957806391d14854116100d6578063c85ce3251161008a578063e992e0ff11610064578063e992e0ff146109d9578063ea93a50914610a13578063ecb9748414610a4357600080fd5b8063c85ce32514610993578063d547741f146109a6578063dc309863146109c657600080fd5b8063b349ba65116100bb578063b349ba65146108f9578063b39691061461092d578063c085c22b1461096657600080fd5b806391d14854146108b95780639ae3f05a146108d957600080fd5b806379cfc0061161012d5780638288a927116101125780638288a927146108205780638da5cb5b146108405780638df132c61461086b57600080fd5b806379cfc006146107d357806381403a021461080057600080fd5b80635febe7e71161015e5780635febe7e7146106895780636ccae054146106c75780636f38f870146106e757600080fd5b806354fd4d50146106355780635b94db271461066957600080fd5b80633386774f1161022757806341805c24116101db578063440406eb116101c0578063440406eb146105a75780634ad701bc146105d75780634afae4021461061557600080fd5b806341805c241461055a57806343fa97ca1461058757600080fd5b80633b1be6781161020c5780633b1be678146104d75780633bd1adec146104f7578063401ae0751461050c57600080fd5b80633386774f1461046e57806335dd06681461048f57600080fd5b806320f99c0a1161027e5780632e7eb258116102635780632e7eb2581461040e5780632f2ff15d1461042e57806330d20f871461044e57600080fd5b806320f99c0a146103d0578063275c41c9146103fb57600080fd5b80631381ba4d116102af5780631381ba4d1461036e5780631ba8e484146103905780631e867311146103b057600080fd5b80626186f7146102ca5780630b04bb4114610321575b600080fd5b3480156102d657600080fd5b50600a546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561032d57600080fd5b5061034161033c366004613720565b610a63565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610318565b34801561037a57600080fd5b5061038e610389366004613768565b610e0c565b005b34801561039c57600080fd5b5061038e6103ab366004613785565b610f19565b3480156103bc57600080fd5b5061038e6103cb366004613811565b610f7a565b3480156103dc57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166102f7565b61038e6104093660046138c3565b611120565b34801561041a57600080fd5b5061038e610429366004613785565b6115d8565b34801561043a57600080fd5b5061038e610449366004613927565b611634565b34801561045a57600080fd5b5061038e610469366004613768565b611693565b61048161047c366004613999565b611793565b604051908152602001610318565b34801561049b57600080fd5b506104c26104aa366004613768565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610318565b3480156104e357600080fd5b5061038e6104f23660046139f8565b611b65565b34801561050357600080fd5b5061038e611d47565b34801561051857600080fd5b506102f7610527366004613a47565b600460209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056657600080fd5b506009546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b34801561059357600080fd5b5061038e6105a2366004613811565b611da3565b3480156105b357600080fd5b506105c76105c2366004613a7c565b611f3f565b6040519015158152602001610318565b3480156105e357600080fd5b506104816105f2366004613a7c565b600c60209081526000938452604080852082529284528284209052825290205481565b34801561062157600080fd5b5061038e610630366004613768565b611f8e565b34801561064157600080fd5b506104817f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e35681565b34801561067557600080fd5b5061038e610684366004613768565b61209c565b34801561069557600080fd5b506104816106a4366004613a7c565b600d60209081526000938452604080852082529284528284209052825290205481565b3480156106d357600080fd5b5061038e6106e2366004613aaa565b61215c565b3480156106f357600080fd5b5061078c610702366004613a47565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020818152604080842063ffffffff95909516845293815291839020835160a081018552815486168082529282015486169381018490526002820154861694810185905260038201548616606082018190526004909201549095166080909501859052909490939290565b6040805173ffffffffffffffffffffffffffffffffffffffff968716815294861660208601529285169284019290925283166060830152909116608082015260a001610318565b3480156107df57600080fd5b506104816107ee366004613aeb565b600e6020526000908152604090205481565b34801561080c57600080fd5b5061038e61081b366004613b04565b6121fa565b34801561082c57600080fd5b5061038e61083b366004613768565b612255565b34801561084c57600080fd5b5060055473ffffffffffffffffffffffffffffffffffffffff166102f7565b34801561087757600080fd5b506102f7610886366004613a47565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108c557600080fd5b506105c76108d4366004613927565b612355565b3480156108e557600080fd5b506104816108f4366004613b30565b612390565b34801561090557600080fd5b506104c27f0000000000000000000000000000000000000000000000000000000000028c6181565b34801561093957600080fd5b506008546102f79068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561097257600080fd5b506000546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b61038e6109a1366004613b8c565b6124d9565b3480156109b257600080fd5b5061038e6109c1366004613927565b6127e7565b61038e6109d4366004613be8565b612842565b3480156109e557600080fd5b506008546109fa9067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610318565b348015610a1f57600080fd5b506105c7610a2e366004613aeb565b600b6020526000908152604090205460ff1681565b348015610a4f57600080fd5b506105c7610a5e366004613785565b612aa1565b33600081815260036020908152604080832063ffffffff891684529091528120549091829173ffffffffffffffffffffffffffffffffffffffff1615610ad5576040517f2dff855500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546040517f284fb3630000000000000000000000000000000000000000000000000000000081526004810188905263ffffffff8a16602482015260448101899052829173ffffffffffffffffffffffffffffffffffffffff169063284fb3639060640160408051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190613c52565b9150915081945080935088600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548163ffffffff021916908363ffffffff16021790555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fe797daee214784c2b0a3c67d7700cdb94fa243f27a14283eb643ee0fdc520d30838a87878c8c604051610d9c9695949392919073ffffffffffffffffffffffffffffffffffffffff968716815263ffffffff959095166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b60405180910390a16040805173ffffffffffffffffffffffffffffffffffffffff858116825263ffffffff8c16602083015288168183015290517f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b9181900360600190a150505094509492505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16610e9e576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fc7d6b56a07930ef230a86f7fc3ee39eca236764293f0d1a764347ae831252040906020015b60405180910390a15050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610f6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612aae565b505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fcb576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580610fda5750848314155b15611011576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b8181101561111657600086868381811061103157611031613c81565b90506020020160208101906110469190613cb0565b63ffffffff1611156110c6576110c188888381811061106757611067613c81565b9050602002013587878481811061108057611080613c81565b90506020020160208101906110959190613cb0565b8686858181106110a7576110a7613c81565b90506020020160208101906110bc9190613768565b612aae565b61110e565b61110e8888838181106110db576110db613c81565b905060200201358585848181106110f4576110f4613c81565b90506020020160208101906111099190613768565b612aeb565b600101611015565b5050505050505050565b80356000908152600b602052604090205460ff161561116b576040517f7448c64c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356000908152600b60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055808201359083013510156111e6576040517fd38edae000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813561121e576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803560e090811c908335901c8114611262576040517fb39fb5d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a08101825260008082526020808301829052828401828152606084018381526080850184905273ffffffffffffffffffffffffffffffffffffffff8835871c81811686526001855287862063ffffffff8a1687528552878620600281015483169094528354821687526003909301548116825289358552600c84528685208a8501358652845286852091511684529091529290205480611333576040517f1c93605200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085482516040517f02ea143100000000000000000000000000000000000000000000000000000000815260009268010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16916302ea1431916113be9189917f0000000000000000000000000000000000000000000000000000000000028c61908a908d90600401613d14565b6020604051808303816000875af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114019190613e01565b600a54909150600090819073ffffffffffffffffffffffffffffffffffffffff1663954d09c98461143560808d018d613e1a565b6040518463ffffffff1660e01b815260040161145393929190613e7f565b6040805180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190613eb2565b91509150806114ce576040517fc32d1d7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546040517fa56d92ce00000000000000000000000000000000000000000000000000000000815260608a0135600482015234602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a56d92ce9060440160006040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506115b489600001358a602001358986888a8f806060019061157a9190613e1a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b6e92505050565b6115cd82878960408d01356115c88d613f85565b612d46565b505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611629576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612eba565b60055473ffffffffffffffffffffffffffffffffffffffff163314611685576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612ef7565b5050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16611720576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527f03d960b6dfd88e82390cc07c64a7a51b63c3b8ecdc888d02d4697995a912cc0590602001610f0d565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290523382526001815283822063ffffffff8b16835290529182205473ffffffffffffffffffffffffffffffffffffffff16808252611826576040517fe741bafb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260016020818152604080842063ffffffff8d168086528184529185209384015473ffffffffffffffffffffffffffffffffffffffff908116878501529190945292905260040154166080820152805161188490612f7d565b91506000611910888686905089898660800151876020015173ffffffffffffffffffffffffffffffffffffffff16632ff9f2c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190613e01565b8f61301d565b905060006040518060a0016040528085815260200183602001516fffffffffffffffffffffffffffffffff1681526020018a815260200189815260200187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508152509050600060088054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166302ea14317f0000000000000000000000000000000000000000000000000000000000028c61338e8860000151876040518663ffffffff1660e01b8152600401611a1e9594939291906140cb565b6020604051808303816000875af1158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190613e01565b60208501516040517f920ee8a80000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff169063920ee8a890602401600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050507f45d70e73f9a26cea18d4009d1ad25ffbdc4114ce9d8ceb15959ae9eadb0a3a2c7f0000000000000000000000000000000000000000000000000000000000028c61338d8760000151898f8f8f8f8f8d604051611b4f9b9a9998979695949392919061415a565b60405180910390a1505050509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260036020908152604080832063ffffffff89168452909152902054161580611be0575073ffffffffffffffffffffffffffffffffffffffff818116600090815260036020908152604080832063ffffffff8916845290915290205416155b15611c17576040517f63228f2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600081815260016020818152604080842063ffffffff8a1680865290835281852080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8c811691821784558a8116808a526003808952878b20878c528952878b205499860180549a84169a86168b1790558d8316808c526004808b52898d20898e528b529b899020546002880180549190951690871681179094559086018054861682179055998501805490941681179093558551998a5295890193909352928701919091526060860194909452608085015260a084019190915260c0830152907febaba46465001886e6218eb8da227160a320362ee4aab240ead702addafe55ba9060e0015b60405180910390a15050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d98576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611da1336131b0565b565b60055473ffffffffffffffffffffffffffffffffffffffff163314611df4576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580611e035750848314155b15611e3a576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b81811015611116576000868683818110611e5a57611e5a613c81565b9050602002016020810190611e6f9190613cb0565b63ffffffff161115611eef57611eea888883818110611e9057611e90613c81565b90506020020135878784818110611ea957611ea9613c81565b9050602002016020810190611ebe9190613cb0565b868685818110611ed057611ed0613c81565b9050602002016020810190611ee59190613768565b612eba565b611f37565b611f37888883818110611f0457611f04613c81565b90506020020135858584818110611f1d57611f1d613c81565b9050602002016020810190611f329190613768565b612ef7565b600101611e3e565b6000838152600c60209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205415611f83576001611f86565b60005b949350505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff1661201b576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600880547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527fc7238b23787eb9f8aa74c79b27083bb4b8f0db527df90366b487c40fa0ba2d3a90602001610f0d565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120ed576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527fff9a7b11e174fcce811917e5a8f906a450751019d105ceca5d4a7efe2887160660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166121e9576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b6121f4848484613229565b50505050565b6040805133815263ffffffff8416602082015273ffffffffffffffffffffffffffffffffffffffff8316918101919091527f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b90606001610f0d565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff166122e2576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fdd4864dd50be8a1a56c70aebc2953b0890b860197577457ac25fa02f86dadd5590602001610f0d565b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b73ffffffffffffffffffffffffffffffffffffffff808216600090815260016020818152604080842063ffffffff8816855282528084209092015482517f2ff9f2c900000000000000000000000000000000000000000000000000000000815292519394169284928492632ff9f2c9926004808401938290030181865afa15801561241f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124439190613e01565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832063ffffffff8b168452909152812060040154929350918291829161249b918e918e918e918e918e91168a613319565b91945092509050806124ad838561423c565b6124b7919061423c565b6fffffffffffffffffffffffffffffffff169c9b505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602052604081205463ffffffff169081900361253f576040517f73d817fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd7c9eaac00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff87169063d7c9eaac9060240160408051808303816000875af11580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d4919061426c565b600954604080517f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e35660208083019190915263ffffffff89168284015267ffffffffffffffff85168c841b7bffffffffffffffffffffffffffffffffffffffff0000000000000000167f0000000000000000000000000000000000000000000000000000000000028c6160e01b7fffffffff000000000000000000000000000000000000000000000000000000001617176060830181905260808084018890528451808503909101815260a084019485905280519201919091207fb7ee4eb900000000000000000000000000000000000000000000000000000000909352949650929450600092839273ffffffffffffffffffffffffffffffffffffffff169163b7ee4eb99161270b918a918d908d9060a40161429e565b6040805180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b9190613eb2565b9150915080612786576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828273ffffffffffffffffffffffffffffffffffffffff167f4bf575a0e4ff12a13816954b1ce8b1e53f30e121ea4f107ac086ec29da524abe8c888c8c6040516127d394939291906142ce565b60405180910390a350505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314612838576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612aeb565b84612879576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090819073ffffffffffffffffffffffffffffffffffffffff1663b7ee4eb96128a68960e01c90565b604080517f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e356602082015263ffffffff7f0000000000000000000000000000000000000000000000000000000000028c611691810191909152606081018b9052608081018a905260a0016040516020818303038152906040528051906020012087876040518563ffffffff1660e01b8152600401612946949392919061429e565b6040805180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190613eb2565b91509150806129c1576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000878152600c60209081526040808320600e8084528285208054865291845282852073ffffffffffffffffffffffffffffffffffffffff808c168088529186528487208d90558d8752600d86528487208454885286528487209187529085529285204290558b855290925281548a93918616927f4b8e305abfc214d75df6e3d0b37dc1b2e6e93726d472df847f312d190dcf870492612a60836142ee565b9091555060408051918252602082018b905273ffffffffffffffffffffffffffffffffffffffff8a169082015260600160405180910390a350505050505050565b6000611f8684848461346d565b610f758383604051602001612ad392919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b6060820180516000898152600d602090815260408083208b84528252808320945173ffffffffffffffffffffffffffffffffffffffff908116845294909152908190205490517f4c40818000000000000000000000000000000000000000000000000000000000815260048101879052602481018b9052604481018a905263ffffffff891660648201526084810191909152911690634c4081809060a401602060405180830381865afa158015612c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4d9190614326565b612c83576040517f439cc0cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff16632d095c438486846040518463ffffffff1660e01b8152600401612cc493929190614341565b6020604051808303816000875af1158015612ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d079190614326565b612d3d576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60808101516040517fc41f1f6c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169163c41f1f6c9185913491612da1918991600401614360565b6000604051808303818589803b158015612dba57600080fd5b5088f1158015612dce573d6000803e3d6000fd5b5050600a54602086015186516040517ff1f069d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301526fffffffffffffffffffffffffffffffff909316602482015260448101919091529116945063f1f069d693506064019150612e559050565b600060405180830381600087803b158015612e6f57600080fd5b505af1158015612e83573d6000803e3d6000fd5b505082516040519081527fdc29884a71d2bb98d3c53dc09718be05c7bfd142b7773a5c5cf2517629290ac092506020019050611d38565b610f758383604051602001612edf92919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6008805460009167ffffffffffffffff9091169082612f9b8361437f565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555067ffffffffffffffff1660408373ffffffffffffffffffffffffffffffffffffffff16901b60e07f0000000000000000000000000000000000000000000000000000000000028c6163ffffffff16901b171760001b9050919050565b604080516060810182526000808252602082018190529181018290529061304483866134fb565b6fffffffffffffffffffffffffffffffff90911660408401819052600a5491925073ffffffffffffffffffffffffffffffffffffffff909116906371c4717b9034908c908c908c908c908a9061309b908d906143a6565b6009546040517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b168152600481019790975260248701959095526044860193909352606485019190915263ffffffff1660848401526fffffffffffffffffffffffffffffffff90811660a4840152861660c483015273ffffffffffffffffffffffffffffffffffffffff90811660e48301528916610104820152610124810188905261014401604080518083038185885af1158015613163573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613188919061441c565b6fffffffffffffffffffffffffffffffff908116845216602083015250979650505050505050565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b73ffffffffffffffffffffffffffffffffffffffff8216613276576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016132bd57610f75828261359e565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361330e576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383613613565b600080600080600061332b88886134fb565b909450915061333a86856143a6565b9350600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aea3d96b8d8d8d8d8d600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518763ffffffff1660e01b81526004016134029695949392919095865260208601949094526040850192909252606084015263ffffffff16608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b6040805180830381865afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613442919061441c565b9550905061345086866143a6565b945061345c828261423c565b925050509750975097945050505050565b6000611f86848460405160200161349492919091825263ffffffff16602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009081526007835281812073ffffffffffffffffffffffffffffffffffffffff8716825290925290205460ff1690565b6040517f06da42e000000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906306da42e0906024016040805180830381865afa15801561356f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613593919061441c565b909590945092505050565b600080600080600085875af1905080610f75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610e95565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806121f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610e95565b803563ffffffff811681146136f657600080fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461371d57600080fd5b50565b6000806000806080858703121561373657600080fd5b61373f856136e2565b93506020850135925060408501359150606085013561375d816136fb565b939692955090935050565b60006020828403121561377a57600080fd5b8135612389816136fb565b60008060006060848603121561379a57600080fd5b833592506137aa602085016136e2565b915060408401356137ba816136fb565b809150509250925092565b60008083601f8401126137d757600080fd5b50813567ffffffffffffffff8111156137ef57600080fd5b6020830191508360208260051b850101111561380a57600080fd5b9250929050565b6000806000806000806060878903121561382a57600080fd5b863567ffffffffffffffff8082111561384257600080fd5b61384e8a838b016137c5565b9098509650602089013591508082111561386757600080fd5b6138738a838b016137c5565b9096509450604089013591508082111561388c57600080fd5b5061389989828a016137c5565b979a9699509497509295939492505050565b600060a082840312156138bd57600080fd5b50919050565b600080604083850312156138d657600080fd5b823567ffffffffffffffff808211156138ee57600080fd5b6138fa868387016138ab565b9350602085013591508082111561391057600080fd5b5061391d858286016138ab565b9150509250929050565b6000806040838503121561393a57600080fd5b82359150602083013561394c816136fb565b809150509250929050565b60008083601f84011261396957600080fd5b50813567ffffffffffffffff81111561398157600080fd5b60208301915083602082850101111561380a57600080fd5b60008060008060008060a087890312156139b257600080fd5b6139bb876136e2565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156139ec57600080fd5b61389989828a01613957565b60008060008060808587031215613a0e57600080fd5b613a17856136e2565b93506020850135613a27816136fb565b92506040850135613a37816136fb565b9150606085013561375d816136fb565b60008060408385031215613a5a57600080fd5b8235613a65816136fb565b9150613a73602084016136e2565b90509250929050565b600080600060608486031215613a9157600080fd5b833592506020840135915060408401356137ba816136fb565b600080600060608486031215613abf57600080fd5b8335613aca816136fb565b92506020840135613ada816136fb565b929592945050506040919091013590565b600060208284031215613afd57600080fd5b5035919050565b60008060408385031215613b1757600080fd5b613b20836136e2565b9150602083013561394c816136fb565b60008060008060008060c08789031215613b4957600080fd5b86359550602087013594506040870135935060608701359250613b6e608088016136e2565b915060a0870135613b7e816136fb565b809150509295509295509295565b60008060008060608587031215613ba257600080fd5b843593506020850135613bb4816136fb565b9250604085013567ffffffffffffffff811115613bd057600080fd5b613bdc87828801613957565b95989497509550505050565b600080600080600060808688031215613c0057600080fd5b85359450602086013593506040860135613c19816136fb565b9250606086013567ffffffffffffffff811115613c3557600080fd5b613c4188828901613957565b969995985093965092949392505050565b60008060408385031215613c6557600080fd5b8251613c70816136fb565b602084015190925061394c816136fb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613cc257600080fd5b612389826136e2565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152823560a0830152602083013560c0830152604083013560e0830152606083013561010083015260808301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db157600080fd5b830160208101903567ffffffffffffffff811115613dce57600080fd5b803603821315613ddd57600080fd5b60a0610120850152613df461014085018284613ccb565b9998505050505050505050565b600060208284031215613e1357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e4f57600080fd5b83018035915067ffffffffffffffff821115613e6a57600080fd5b60200191503681900382131561380a57600080fd5b838152604060208201526000613e99604083018486613ccb565b95945050505050565b805180151581146136f657600080fd5b60008060408385031215613ec557600080fd5b8251613ed0816136fb565b9150613a7360208401613ea2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715613f3057613f30613ede565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f7d57613f7d613ede565b604052919050565b600060a08236031215613f9757600080fd5b613f9f613f0d565b82358152602080840135818301526040840135604083015260608401356060830152608084013567ffffffffffffffff80821115613fdc57600080fd5b9085019036601f830112613fef57600080fd5b81358181111561400157614001613ede565b614031847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f36565b9150808252368482850101111561404757600080fd5b808484018584013760009082019093019290925250608082015292915050565b6000815180845260005b8181101561408d57602081850181015186830182015201614071565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152825160a0830152602083015160c0830152604083015160e08301526060830151610100830152608083015160a061012084015261414e610140840182614067565b98975050505050505050565b600061018063ffffffff808f16845273ffffffffffffffffffffffffffffffffffffffff808f166020860152818e166040860152808d16606086015250508960808401528860a08401528760c08401528660e0840152806101008401526141c48184018688613ccb565b9150506fffffffffffffffffffffffffffffffff808451166101208401528060208501511661014084015280604085015116610160840152509c9b505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff8181168382160190808211156142655761426561420d565b5092915050565b6000806040838503121561427f57600080fd5b82519150602083015167ffffffffffffffff8116811461394c57600080fd5b63ffffffff851681528360208201526060604082015260006142c4606083018486613ccb565b9695505050505050565b8481528360208201526060604082015260006142c4606083018486613ccb565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361431f5761431f61420d565b5060010190565b60006020828403121561433857600080fd5b61238982613ea2565b838152826020820152606060408201526000613e996060830184614067565b63ffffffff83168152604060208201526000611f866040830184614067565b600067ffffffffffffffff80831681810361439c5761439c61420d565b6001019392505050565b60006fffffffffffffffffffffffffffffffff808416806143f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b80516fffffffffffffffffffffffffffffffff811681146136f657600080fd5b6000806040838503121561442f57600080fd5b614438836143fc565b9150613a73602084016143fc56fea26469706673582212208b207b6ea0b17a8c1b971aded8aa3d712bdaff7e0e0f033fdd5c848b561a579564736f6c63430008130033