false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here

Contract Address Details

0x5C4186D343EeF952c9ED886E45F8243edf0A503F

Contract Name
Socket
Creator
0x44a448–b88f4c at 0xc2c333–5a9138
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
1177895
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

Verify & Publish
0x60c06040523480156200001157600080fd5b50604051620047313803806200473183398101604081905262000034916200012d565b84818380806200004481620000a6565b50505063ffffffff9190911660a0528051602090910120608052505060088054600160401b600160e01b031916680100000000000000006001600160a01b0394851602179055600080546001600160a01b031916919092161790555062000257565b600580546001600160a01b0383166001600160a01b031991821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b80516001600160a01b03811681146200011257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156200014657600080fd5b855163ffffffff811681146200015b57600080fd5b945060206200016c878201620000fa565b94506200017c60408801620000fa565b93506200018c60608801620000fa565b60808801519093506001600160401b0380821115620001aa57600080fd5b818901915089601f830112620001bf57600080fd5b815181811115620001d457620001d462000117565b604051601f8201601f19908116603f01168101908382118183101715620001ff57620001ff62000117565b816040528281528c868487010111156200021857600080fd5b600093505b828410156200023c57848401860151818501870152928501926200021d565b60008684830101528096505050505050509295509295909350565b60805160a05161447c620002b56000396000818161090b01528181611392015281816119d701528181611b0b0152818161263e015281816128d70152612fea015260008181610647015281816125dd01526128ac015261447c6000f3fe6080604052600436106102c55760003560e01c806354fd4d501161017957806391d14854116100d6578063c85ce3251161008a578063e992e0ff11610064578063e992e0ff146109d9578063ea93a50914610a13578063ecb9748414610a4357600080fd5b8063c85ce32514610993578063d547741f146109a6578063dc309863146109c657600080fd5b8063b349ba65116100bb578063b349ba65146108f9578063b39691061461092d578063c085c22b1461096657600080fd5b806391d14854146108b95780639ae3f05a146108d957600080fd5b806379cfc0061161012d5780638288a927116101125780638288a927146108205780638da5cb5b146108405780638df132c61461086b57600080fd5b806379cfc006146107d357806381403a021461080057600080fd5b80635febe7e71161015e5780635febe7e7146106895780636ccae054146106c75780636f38f870146106e757600080fd5b806354fd4d50146106355780635b94db271461066957600080fd5b80633386774f1161022757806341805c24116101db578063440406eb116101c0578063440406eb146105a75780634ad701bc146105d75780634afae4021461061557600080fd5b806341805c241461055a57806343fa97ca1461058757600080fd5b80633b1be6781161020c5780633b1be678146104d75780633bd1adec146104f7578063401ae0751461050c57600080fd5b80633386774f1461046e57806335dd06681461048f57600080fd5b806320f99c0a1161027e5780632e7eb258116102635780632e7eb2581461040e5780632f2ff15d1461042e57806330d20f871461044e57600080fd5b806320f99c0a146103d0578063275c41c9146103fb57600080fd5b80631381ba4d116102af5780631381ba4d1461036e5780631ba8e484146103905780631e867311146103b057600080fd5b80626186f7146102ca5780630b04bb4114610321575b600080fd5b3480156102d657600080fd5b50600a546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561032d57600080fd5b5061034161033c366004613720565b610a63565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610318565b34801561037a57600080fd5b5061038e610389366004613768565b610e0c565b005b34801561039c57600080fd5b5061038e6103ab366004613785565b610f19565b3480156103bc57600080fd5b5061038e6103cb366004613811565b610f7a565b3480156103dc57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166102f7565b61038e6104093660046138c3565b611120565b34801561041a57600080fd5b5061038e610429366004613785565b6115d8565b34801561043a57600080fd5b5061038e610449366004613927565b611634565b34801561045a57600080fd5b5061038e610469366004613768565b611693565b61048161047c366004613999565b611793565b604051908152602001610318565b34801561049b57600080fd5b506104c26104aa366004613768565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610318565b3480156104e357600080fd5b5061038e6104f23660046139f8565b611b65565b34801561050357600080fd5b5061038e611d47565b34801561051857600080fd5b506102f7610527366004613a47565b600460209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056657600080fd5b506009546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b34801561059357600080fd5b5061038e6105a2366004613811565b611da3565b3480156105b357600080fd5b506105c76105c2366004613a7c565b611f3f565b6040519015158152602001610318565b3480156105e357600080fd5b506104816105f2366004613a7c565b600c60209081526000938452604080852082529284528284209052825290205481565b34801561062157600080fd5b5061038e610630366004613768565b611f8e565b34801561064157600080fd5b506104817f000000000000000000000000000000000000000000000000000000000000000081565b34801561067557600080fd5b5061038e610684366004613768565b61209c565b34801561069557600080fd5b506104816106a4366004613a7c565b600d60209081526000938452604080852082529284528284209052825290205481565b3480156106d357600080fd5b5061038e6106e2366004613aaa565b61215c565b3480156106f357600080fd5b5061078c610702366004613a47565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020818152604080842063ffffffff95909516845293815291839020835160a081018552815486168082529282015486169381018490526002820154861694810185905260038201548616606082018190526004909201549095166080909501859052909490939290565b6040805173ffffffffffffffffffffffffffffffffffffffff968716815294861660208601529285169284019290925283166060830152909116608082015260a001610318565b3480156107df57600080fd5b506104816107ee366004613aeb565b600e6020526000908152604090205481565b34801561080c57600080fd5b5061038e61081b366004613b04565b6121fa565b34801561082c57600080fd5b5061038e61083b366004613768565b612255565b34801561084c57600080fd5b5060055473ffffffffffffffffffffffffffffffffffffffff166102f7565b34801561087757600080fd5b506102f7610886366004613a47565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108c557600080fd5b506105c76108d4366004613927565b612355565b3480156108e557600080fd5b506104816108f4366004613b30565b612390565b34801561090557600080fd5b506104c27f000000000000000000000000000000000000000000000000000000000000000081565b34801561093957600080fd5b506008546102f79068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561097257600080fd5b506000546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b61038e6109a1366004613b8c565b6124d9565b3480156109b257600080fd5b5061038e6109c1366004613927565b6127e7565b61038e6109d4366004613be8565b612842565b3480156109e557600080fd5b506008546109fa9067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610318565b348015610a1f57600080fd5b506105c7610a2e366004613aeb565b600b6020526000908152604090205460ff1681565b348015610a4f57600080fd5b506105c7610a5e366004613785565b612aa1565b33600081815260036020908152604080832063ffffffff891684529091528120549091829173ffffffffffffffffffffffffffffffffffffffff1615610ad5576040517f2dff855500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546040517f284fb3630000000000000000000000000000000000000000000000000000000081526004810188905263ffffffff8a16602482015260448101899052829173ffffffffffffffffffffffffffffffffffffffff169063284fb3639060640160408051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190613c52565b9150915081945080935088600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548163ffffffff021916908363ffffffff16021790555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fe797daee214784c2b0a3c67d7700cdb94fa243f27a14283eb643ee0fdc520d30838a87878c8c604051610d9c9695949392919073ffffffffffffffffffffffffffffffffffffffff968716815263ffffffff959095166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b60405180910390a16040805173ffffffffffffffffffffffffffffffffffffffff858116825263ffffffff8c16602083015288168183015290517f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b9181900360600190a150505094509492505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16610e9e576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fc7d6b56a07930ef230a86f7fc3ee39eca236764293f0d1a764347ae831252040906020015b60405180910390a15050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610f6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612aae565b505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fcb576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580610fda5750848314155b15611011576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b8181101561111657600086868381811061103157611031613c81565b90506020020160208101906110469190613cb0565b63ffffffff1611156110c6576110c188888381811061106757611067613c81565b9050602002013587878481811061108057611080613c81565b90506020020160208101906110959190613cb0565b8686858181106110a7576110a7613c81565b90506020020160208101906110bc9190613768565b612aae565b61110e565b61110e8888838181106110db576110db613c81565b905060200201358585848181106110f4576110f4613c81565b90506020020160208101906111099190613768565b612aeb565b600101611015565b5050505050505050565b80356000908152600b602052604090205460ff161561116b576040517f7448c64c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356000908152600b60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055808201359083013510156111e6576040517fd38edae000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813561121e576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803560e090811c908335901c8114611262576040517fb39fb5d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a08101825260008082526020808301829052828401828152606084018381526080850184905273ffffffffffffffffffffffffffffffffffffffff8835871c81811686526001855287862063ffffffff8a1687528552878620600281015483169094528354821687526003909301548116825289358552600c84528685208a8501358652845286852091511684529091529290205480611333576040517f1c93605200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085482516040517f02ea143100000000000000000000000000000000000000000000000000000000815260009268010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16916302ea1431916113be9189917f0000000000000000000000000000000000000000000000000000000000000000908a908d90600401613d14565b6020604051808303816000875af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114019190613e01565b600a54909150600090819073ffffffffffffffffffffffffffffffffffffffff1663954d09c98461143560808d018d613e1a565b6040518463ffffffff1660e01b815260040161145393929190613e7f565b6040805180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190613eb2565b91509150806114ce576040517fc32d1d7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546040517fa56d92ce00000000000000000000000000000000000000000000000000000000815260608a0135600482015234602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a56d92ce9060440160006040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506115b489600001358a602001358986888a8f806060019061157a9190613e1a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b6e92505050565b6115cd82878960408d01356115c88d613f85565b612d46565b505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611629576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612eba565b60055473ffffffffffffffffffffffffffffffffffffffff163314611685576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612ef7565b5050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16611720576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527f03d960b6dfd88e82390cc07c64a7a51b63c3b8ecdc888d02d4697995a912cc0590602001610f0d565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290523382526001815283822063ffffffff8b16835290529182205473ffffffffffffffffffffffffffffffffffffffff16808252611826576040517fe741bafb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260016020818152604080842063ffffffff8d168086528184529185209384015473ffffffffffffffffffffffffffffffffffffffff908116878501529190945292905260040154166080820152805161188490612f7d565b91506000611910888686905089898660800151876020015173ffffffffffffffffffffffffffffffffffffffff16632ff9f2c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190613e01565b8f61301d565b905060006040518060a0016040528085815260200183602001516fffffffffffffffffffffffffffffffff1681526020018a815260200189815260200187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508152509050600060088054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166302ea14317f0000000000000000000000000000000000000000000000000000000000000000338e8860000151876040518663ffffffff1660e01b8152600401611a1e9594939291906140cb565b6020604051808303816000875af1158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190613e01565b60208501516040517f920ee8a80000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff169063920ee8a890602401600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050507f45d70e73f9a26cea18d4009d1ad25ffbdc4114ce9d8ceb15959ae9eadb0a3a2c7f0000000000000000000000000000000000000000000000000000000000000000338d8760000151898f8f8f8f8f8d604051611b4f9b9a9998979695949392919061415a565b60405180910390a1505050509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260036020908152604080832063ffffffff89168452909152902054161580611be0575073ffffffffffffffffffffffffffffffffffffffff818116600090815260036020908152604080832063ffffffff8916845290915290205416155b15611c17576040517f63228f2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600081815260016020818152604080842063ffffffff8a1680865290835281852080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8c811691821784558a8116808a526003808952878b20878c528952878b205499860180549a84169a86168b1790558d8316808c526004808b52898d20898e528b529b899020546002880180549190951690871681179094559086018054861682179055998501805490941681179093558551998a5295890193909352928701919091526060860194909452608085015260a084019190915260c0830152907febaba46465001886e6218eb8da227160a320362ee4aab240ead702addafe55ba9060e0015b60405180910390a15050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d98576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611da1336131b0565b565b60055473ffffffffffffffffffffffffffffffffffffffff163314611df4576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580611e035750848314155b15611e3a576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b81811015611116576000868683818110611e5a57611e5a613c81565b9050602002016020810190611e6f9190613cb0565b63ffffffff161115611eef57611eea888883818110611e9057611e90613c81565b90506020020135878784818110611ea957611ea9613c81565b9050602002016020810190611ebe9190613cb0565b868685818110611ed057611ed0613c81565b9050602002016020810190611ee59190613768565b612eba565b611f37565b611f37888883818110611f0457611f04613c81565b90506020020135858584818110611f1d57611f1d613c81565b9050602002016020810190611f329190613768565b612ef7565b600101611e3e565b6000838152600c60209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205415611f83576001611f86565b60005b949350505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff1661201b576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600880547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527fc7238b23787eb9f8aa74c79b27083bb4b8f0db527df90366b487c40fa0ba2d3a90602001610f0d565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120ed576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527fff9a7b11e174fcce811917e5a8f906a450751019d105ceca5d4a7efe2887160660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166121e9576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b6121f4848484613229565b50505050565b6040805133815263ffffffff8416602082015273ffffffffffffffffffffffffffffffffffffffff8316918101919091527f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b90606001610f0d565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff166122e2576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fdd4864dd50be8a1a56c70aebc2953b0890b860197577457ac25fa02f86dadd5590602001610f0d565b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b73ffffffffffffffffffffffffffffffffffffffff808216600090815260016020818152604080842063ffffffff8816855282528084209092015482517f2ff9f2c900000000000000000000000000000000000000000000000000000000815292519394169284928492632ff9f2c9926004808401938290030181865afa15801561241f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124439190613e01565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832063ffffffff8b168452909152812060040154929350918291829161249b918e918e918e918e918e91168a613319565b91945092509050806124ad838561423c565b6124b7919061423c565b6fffffffffffffffffffffffffffffffff169c9b505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602052604081205463ffffffff169081900361253f576040517f73d817fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd7c9eaac00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff87169063d7c9eaac9060240160408051808303816000875af11580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d4919061426c565b600954604080517f000000000000000000000000000000000000000000000000000000000000000060208083019190915263ffffffff89168284015267ffffffffffffffff85168c841b7bffffffffffffffffffffffffffffffffffffffff0000000000000000167f000000000000000000000000000000000000000000000000000000000000000060e01b7fffffffff000000000000000000000000000000000000000000000000000000001617176060830181905260808084018890528451808503909101815260a084019485905280519201919091207fb7ee4eb900000000000000000000000000000000000000000000000000000000909352949650929450600092839273ffffffffffffffffffffffffffffffffffffffff169163b7ee4eb99161270b918a918d908d9060a40161429e565b6040805180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b9190613eb2565b9150915080612786576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828273ffffffffffffffffffffffffffffffffffffffff167f4bf575a0e4ff12a13816954b1ce8b1e53f30e121ea4f107ac086ec29da524abe8c888c8c6040516127d394939291906142ce565b60405180910390a350505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314612838576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612aeb565b84612879576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090819073ffffffffffffffffffffffffffffffffffffffff1663b7ee4eb96128a68960e01c90565b604080517f0000000000000000000000000000000000000000000000000000000000000000602082015263ffffffff7f00000000000000000000000000000000000000000000000000000000000000001691810191909152606081018b9052608081018a905260a0016040516020818303038152906040528051906020012087876040518563ffffffff1660e01b8152600401612946949392919061429e565b6040805180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190613eb2565b91509150806129c1576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000878152600c60209081526040808320600e8084528285208054865291845282852073ffffffffffffffffffffffffffffffffffffffff808c168088529186528487208d90558d8752600d86528487208454885286528487209187529085529285204290558b855290925281548a93918616927f4b8e305abfc214d75df6e3d0b37dc1b2e6e93726d472df847f312d190dcf870492612a60836142ee565b9091555060408051918252602082018b905273ffffffffffffffffffffffffffffffffffffffff8a169082015260600160405180910390a350505050505050565b6000611f8684848461346d565b610f758383604051602001612ad392919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b6060820180516000898152600d602090815260408083208b84528252808320945173ffffffffffffffffffffffffffffffffffffffff908116845294909152908190205490517f4c40818000000000000000000000000000000000000000000000000000000000815260048101879052602481018b9052604481018a905263ffffffff891660648201526084810191909152911690634c4081809060a401602060405180830381865afa158015612c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4d9190614326565b612c83576040517f439cc0cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff16632d095c438486846040518463ffffffff1660e01b8152600401612cc493929190614341565b6020604051808303816000875af1158015612ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d079190614326565b612d3d576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60808101516040517fc41f1f6c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169163c41f1f6c9185913491612da1918991600401614360565b6000604051808303818589803b158015612dba57600080fd5b5088f1158015612dce573d6000803e3d6000fd5b5050600a54602086015186516040517ff1f069d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301526fffffffffffffffffffffffffffffffff909316602482015260448101919091529116945063f1f069d693506064019150612e559050565b600060405180830381600087803b158015612e6f57600080fd5b505af1158015612e83573d6000803e3d6000fd5b505082516040519081527fdc29884a71d2bb98d3c53dc09718be05c7bfd142b7773a5c5cf2517629290ac092506020019050611d38565b610f758383604051602001612edf92919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6008805460009167ffffffffffffffff9091169082612f9b8361437f565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555067ffffffffffffffff1660408373ffffffffffffffffffffffffffffffffffffffff16901b60e07f000000000000000000000000000000000000000000000000000000000000000063ffffffff16901b171760001b9050919050565b604080516060810182526000808252602082018190529181018290529061304483866134fb565b6fffffffffffffffffffffffffffffffff90911660408401819052600a5491925073ffffffffffffffffffffffffffffffffffffffff909116906371c4717b9034908c908c908c908c908a9061309b908d906143a6565b6009546040517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b168152600481019790975260248701959095526044860193909352606485019190915263ffffffff1660848401526fffffffffffffffffffffffffffffffff90811660a4840152861660c483015273ffffffffffffffffffffffffffffffffffffffff90811660e48301528916610104820152610124810188905261014401604080518083038185885af1158015613163573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613188919061441c565b6fffffffffffffffffffffffffffffffff908116845216602083015250979650505050505050565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b73ffffffffffffffffffffffffffffffffffffffff8216613276576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016132bd57610f75828261359e565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361330e576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383613613565b600080600080600061332b88886134fb565b909450915061333a86856143a6565b9350600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aea3d96b8d8d8d8d8d600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518763ffffffff1660e01b81526004016134029695949392919095865260208601949094526040850192909252606084015263ffffffff16608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b6040805180830381865afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613442919061441c565b9550905061345086866143a6565b945061345c828261423c565b925050509750975097945050505050565b6000611f86848460405160200161349492919091825263ffffffff16602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009081526007835281812073ffffffffffffffffffffffffffffffffffffffff8716825290925290205460ff1690565b6040517f06da42e000000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906306da42e0906024016040805180830381865afa15801561356f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613593919061441c565b909590945092505050565b600080600080600085875af1905080610f75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610e95565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806121f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610e95565b803563ffffffff811681146136f657600080fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461371d57600080fd5b50565b6000806000806080858703121561373657600080fd5b61373f856136e2565b93506020850135925060408501359150606085013561375d816136fb565b939692955090935050565b60006020828403121561377a57600080fd5b8135612389816136fb565b60008060006060848603121561379a57600080fd5b833592506137aa602085016136e2565b915060408401356137ba816136fb565b809150509250925092565b60008083601f8401126137d757600080fd5b50813567ffffffffffffffff8111156137ef57600080fd5b6020830191508360208260051b850101111561380a57600080fd5b9250929050565b6000806000806000806060878903121561382a57600080fd5b863567ffffffffffffffff8082111561384257600080fd5b61384e8a838b016137c5565b9098509650602089013591508082111561386757600080fd5b6138738a838b016137c5565b9096509450604089013591508082111561388c57600080fd5b5061389989828a016137c5565b979a9699509497509295939492505050565b600060a082840312156138bd57600080fd5b50919050565b600080604083850312156138d657600080fd5b823567ffffffffffffffff808211156138ee57600080fd5b6138fa868387016138ab565b9350602085013591508082111561391057600080fd5b5061391d858286016138ab565b9150509250929050565b6000806040838503121561393a57600080fd5b82359150602083013561394c816136fb565b809150509250929050565b60008083601f84011261396957600080fd5b50813567ffffffffffffffff81111561398157600080fd5b60208301915083602082850101111561380a57600080fd5b60008060008060008060a087890312156139b257600080fd5b6139bb876136e2565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156139ec57600080fd5b61389989828a01613957565b60008060008060808587031215613a0e57600080fd5b613a17856136e2565b93506020850135613a27816136fb565b92506040850135613a37816136fb565b9150606085013561375d816136fb565b60008060408385031215613a5a57600080fd5b8235613a65816136fb565b9150613a73602084016136e2565b90509250929050565b600080600060608486031215613a9157600080fd5b833592506020840135915060408401356137ba816136fb565b600080600060608486031215613abf57600080fd5b8335613aca816136fb565b92506020840135613ada816136fb565b929592945050506040919091013590565b600060208284031215613afd57600080fd5b5035919050565b60008060408385031215613b1757600080fd5b613b20836136e2565b9150602083013561394c816136fb565b60008060008060008060c08789031215613b4957600080fd5b86359550602087013594506040870135935060608701359250613b6e608088016136e2565b915060a0870135613b7e816136fb565b809150509295509295509295565b60008060008060608587031215613ba257600080fd5b843593506020850135613bb4816136fb565b9250604085013567ffffffffffffffff811115613bd057600080fd5b613bdc87828801613957565b95989497509550505050565b600080600080600060808688031215613c0057600080fd5b85359450602086013593506040860135613c19816136fb565b9250606086013567ffffffffffffffff811115613c3557600080fd5b613c4188828901613957565b969995985093965092949392505050565b60008060408385031215613c6557600080fd5b8251613c70816136fb565b602084015190925061394c816136fb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613cc257600080fd5b612389826136e2565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152823560a0830152602083013560c0830152604083013560e0830152606083013561010083015260808301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db157600080fd5b830160208101903567ffffffffffffffff811115613dce57600080fd5b803603821315613ddd57600080fd5b60a0610120850152613df461014085018284613ccb565b9998505050505050505050565b600060208284031215613e1357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e4f57600080fd5b83018035915067ffffffffffffffff821115613e6a57600080fd5b60200191503681900382131561380a57600080fd5b838152604060208201526000613e99604083018486613ccb565b95945050505050565b805180151581146136f657600080fd5b60008060408385031215613ec557600080fd5b8251613ed0816136fb565b9150613a7360208401613ea2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715613f3057613f30613ede565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f7d57613f7d613ede565b604052919050565b600060a08236031215613f9757600080fd5b613f9f613f0d565b82358152602080840135818301526040840135604083015260608401356060830152608084013567ffffffffffffffff80821115613fdc57600080fd5b9085019036601f830112613fef57600080fd5b81358181111561400157614001613ede565b614031847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f36565b9150808252368482850101111561404757600080fd5b808484018584013760009082019093019290925250608082015292915050565b6000815180845260005b8181101561408d57602081850181015186830182015201614071565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152825160a0830152602083015160c0830152604083015160e08301526060830151610100830152608083015160a061012084015261414e610140840182614067565b98975050505050505050565b600061018063ffffffff808f16845273ffffffffffffffffffffffffffffffffffffffff808f166020860152818e166040860152808d16606086015250508960808401528860a08401528760c08401528660e0840152806101008401526141c48184018688613ccb565b9150506fffffffffffffffffffffffffffffffff808451166101208401528060208501511661014084015280604085015116610160840152509c9b505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff8181168382160190808211156142655761426561420d565b5092915050565b6000806040838503121561427f57600080fd5b82519150602083015167ffffffffffffffff8116811461394c57600080fd5b63ffffffff851681528360208201526060604082015260006142c4606083018486613ccb565b9695505050505050565b8481528360208201526060604082015260006142c4606083018486613ccb565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361431f5761431f61420d565b5060010190565b60006020828403121561433857600080fd5b61238982613ea2565b838152826020820152606060408201526000613e996060830184614067565b63ffffffff83168152604060208201526000611f866040830184614067565b600067ffffffffffffffff80831681810361439c5761439c61420d565b6001019392505050565b60006fffffffffffffffffffffffffffffffff808416806143f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b80516fffffffffffffffffffffffffffffffff811681146136f657600080fd5b6000806040838503121561442f57600080fd5b614438836143fc565b9150613a73602084016143fc56fea26469706673582212208b207b6ea0b17a8c1b971aded8aa3d712bdaff7e0e0f033fdd5c848b561a579564736f6c634300081300330000000000000000000000000000000000000000000000000000000000028c61000000000000000000000000941f0ef5258604fe10c76ae3858984ce0452b5f2000000000000000000000000fe9dcb3daba382f46f2ce69ddeb3b5df86d96f0400000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004494d4c4900000000000000000000000000000000000000000000000000000000

Deployed ByteCode

0x6080604052600436106102c55760003560e01c806354fd4d501161017957806391d14854116100d6578063c85ce3251161008a578063e992e0ff11610064578063e992e0ff146109d9578063ea93a50914610a13578063ecb9748414610a4357600080fd5b8063c85ce32514610993578063d547741f146109a6578063dc309863146109c657600080fd5b8063b349ba65116100bb578063b349ba65146108f9578063b39691061461092d578063c085c22b1461096657600080fd5b806391d14854146108b95780639ae3f05a146108d957600080fd5b806379cfc0061161012d5780638288a927116101125780638288a927146108205780638da5cb5b146108405780638df132c61461086b57600080fd5b806379cfc006146107d357806381403a021461080057600080fd5b80635febe7e71161015e5780635febe7e7146106895780636ccae054146106c75780636f38f870146106e757600080fd5b806354fd4d50146106355780635b94db271461066957600080fd5b80633386774f1161022757806341805c24116101db578063440406eb116101c0578063440406eb146105a75780634ad701bc146105d75780634afae4021461061557600080fd5b806341805c241461055a57806343fa97ca1461058757600080fd5b80633b1be6781161020c5780633b1be678146104d75780633bd1adec146104f7578063401ae0751461050c57600080fd5b80633386774f1461046e57806335dd06681461048f57600080fd5b806320f99c0a1161027e5780632e7eb258116102635780632e7eb2581461040e5780632f2ff15d1461042e57806330d20f871461044e57600080fd5b806320f99c0a146103d0578063275c41c9146103fb57600080fd5b80631381ba4d116102af5780631381ba4d1461036e5780631ba8e484146103905780631e867311146103b057600080fd5b80626186f7146102ca5780630b04bb4114610321575b600080fd5b3480156102d657600080fd5b50600a546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561032d57600080fd5b5061034161033c366004613720565b610a63565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610318565b34801561037a57600080fd5b5061038e610389366004613768565b610e0c565b005b34801561039c57600080fd5b5061038e6103ab366004613785565b610f19565b3480156103bc57600080fd5b5061038e6103cb366004613811565b610f7a565b3480156103dc57600080fd5b5060065473ffffffffffffffffffffffffffffffffffffffff166102f7565b61038e6104093660046138c3565b611120565b34801561041a57600080fd5b5061038e610429366004613785565b6115d8565b34801561043a57600080fd5b5061038e610449366004613927565b611634565b34801561045a57600080fd5b5061038e610469366004613768565b611693565b61048161047c366004613999565b611793565b604051908152602001610318565b34801561049b57600080fd5b506104c26104aa366004613768565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610318565b3480156104e357600080fd5b5061038e6104f23660046139f8565b611b65565b34801561050357600080fd5b5061038e611d47565b34801561051857600080fd5b506102f7610527366004613a47565b600460209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056657600080fd5b506009546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b34801561059357600080fd5b5061038e6105a2366004613811565b611da3565b3480156105b357600080fd5b506105c76105c2366004613a7c565b611f3f565b6040519015158152602001610318565b3480156105e357600080fd5b506104816105f2366004613a7c565b600c60209081526000938452604080852082529284528284209052825290205481565b34801561062157600080fd5b5061038e610630366004613768565b611f8e565b34801561064157600080fd5b506104817f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e35681565b34801561067557600080fd5b5061038e610684366004613768565b61209c565b34801561069557600080fd5b506104816106a4366004613a7c565b600d60209081526000938452604080852082529284528284209052825290205481565b3480156106d357600080fd5b5061038e6106e2366004613aaa565b61215c565b3480156106f357600080fd5b5061078c610702366004613a47565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020818152604080842063ffffffff95909516845293815291839020835160a081018552815486168082529282015486169381018490526002820154861694810185905260038201548616606082018190526004909201549095166080909501859052909490939290565b6040805173ffffffffffffffffffffffffffffffffffffffff968716815294861660208601529285169284019290925283166060830152909116608082015260a001610318565b3480156107df57600080fd5b506104816107ee366004613aeb565b600e6020526000908152604090205481565b34801561080c57600080fd5b5061038e61081b366004613b04565b6121fa565b34801561082c57600080fd5b5061038e61083b366004613768565b612255565b34801561084c57600080fd5b5060055473ffffffffffffffffffffffffffffffffffffffff166102f7565b34801561087757600080fd5b506102f7610886366004613a47565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108c557600080fd5b506105c76108d4366004613927565b612355565b3480156108e557600080fd5b506104816108f4366004613b30565b612390565b34801561090557600080fd5b506104c27f0000000000000000000000000000000000000000000000000000000000028c6181565b34801561093957600080fd5b506008546102f79068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561097257600080fd5b506000546102f79073ffffffffffffffffffffffffffffffffffffffff1681565b61038e6109a1366004613b8c565b6124d9565b3480156109b257600080fd5b5061038e6109c1366004613927565b6127e7565b61038e6109d4366004613be8565b612842565b3480156109e557600080fd5b506008546109fa9067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610318565b348015610a1f57600080fd5b506105c7610a2e366004613aeb565b600b6020526000908152604090205460ff1681565b348015610a4f57600080fd5b506105c7610a5e366004613785565b612aa1565b33600081815260036020908152604080832063ffffffff891684529091528120549091829173ffffffffffffffffffffffffffffffffffffffff1615610ad5576040517f2dff855500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546040517f284fb3630000000000000000000000000000000000000000000000000000000081526004810188905263ffffffff8a16602482015260448101899052829173ffffffffffffffffffffffffffffffffffffffff169063284fb3639060640160408051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190613c52565b9150915081945080935088600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548163ffffffff021916908363ffffffff16021790555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b63ffffffff1663ffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fe797daee214784c2b0a3c67d7700cdb94fa243f27a14283eb643ee0fdc520d30838a87878c8c604051610d9c9695949392919073ffffffffffffffffffffffffffffffffffffffff968716815263ffffffff959095166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b60405180910390a16040805173ffffffffffffffffffffffffffffffffffffffff858116825263ffffffff8c16602083015288168183015290517f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b9181900360600190a150505094509492505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16610e9e576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fc7d6b56a07930ef230a86f7fc3ee39eca236764293f0d1a764347ae831252040906020015b60405180910390a15050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610f6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612aae565b505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fcb576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580610fda5750848314155b15611011576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b8181101561111657600086868381811061103157611031613c81565b90506020020160208101906110469190613cb0565b63ffffffff1611156110c6576110c188888381811061106757611067613c81565b9050602002013587878481811061108057611080613c81565b90506020020160208101906110959190613cb0565b8686858181106110a7576110a7613c81565b90506020020160208101906110bc9190613768565b612aae565b61110e565b61110e8888838181106110db576110db613c81565b905060200201358585848181106110f4576110f4613c81565b90506020020160208101906111099190613768565b612aeb565b600101611015565b5050505050505050565b80356000908152600b602052604090205460ff161561116b576040517f7448c64c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356000908152600b60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055808201359083013510156111e6576040517fd38edae000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813561121e576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803560e090811c908335901c8114611262576040517fb39fb5d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a08101825260008082526020808301829052828401828152606084018381526080850184905273ffffffffffffffffffffffffffffffffffffffff8835871c81811686526001855287862063ffffffff8a1687528552878620600281015483169094528354821687526003909301548116825289358552600c84528685208a8501358652845286852091511684529091529290205480611333576040517f1c93605200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085482516040517f02ea143100000000000000000000000000000000000000000000000000000000815260009268010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16916302ea1431916113be9189917f0000000000000000000000000000000000000000000000000000000000028c61908a908d90600401613d14565b6020604051808303816000875af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114019190613e01565b600a54909150600090819073ffffffffffffffffffffffffffffffffffffffff1663954d09c98461143560808d018d613e1a565b6040518463ffffffff1660e01b815260040161145393929190613e7f565b6040805180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190613eb2565b91509150806114ce576040517fc32d1d7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546040517fa56d92ce00000000000000000000000000000000000000000000000000000000815260608a0135600482015234602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a56d92ce9060440160006040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506115b489600001358a602001358986888a8f806060019061157a9190613e1a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b6e92505050565b6115cd82878960408d01356115c88d613f85565b612d46565b505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314611629576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383612eba565b60055473ffffffffffffffffffffffffffffffffffffffff163314611685576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612ef7565b5050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff16611720576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527f03d960b6dfd88e82390cc07c64a7a51b63c3b8ecdc888d02d4697995a912cc0590602001610f0d565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290523382526001815283822063ffffffff8b16835290529182205473ffffffffffffffffffffffffffffffffffffffff16808252611826576040517fe741bafb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260016020818152604080842063ffffffff8d168086528184529185209384015473ffffffffffffffffffffffffffffffffffffffff908116878501529190945292905260040154166080820152805161188490612f7d565b91506000611910888686905089898660800151876020015173ffffffffffffffffffffffffffffffffffffffff16632ff9f2c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190613e01565b8f61301d565b905060006040518060a0016040528085815260200183602001516fffffffffffffffffffffffffffffffff1681526020018a815260200189815260200187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508152509050600060088054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166302ea14317f0000000000000000000000000000000000000000000000000000000000028c61338e8860000151876040518663ffffffff1660e01b8152600401611a1e9594939291906140cb565b6020604051808303816000875af1158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190613e01565b60208501516040517f920ee8a80000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff169063920ee8a890602401600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050507f45d70e73f9a26cea18d4009d1ad25ffbdc4114ce9d8ceb15959ae9eadb0a3a2c7f0000000000000000000000000000000000000000000000000000000000028c61338d8760000151898f8f8f8f8f8d604051611b4f9b9a9998979695949392919061415a565b60405180910390a1505050509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260036020908152604080832063ffffffff89168452909152902054161580611be0575073ffffffffffffffffffffffffffffffffffffffff818116600090815260036020908152604080832063ffffffff8916845290915290205416155b15611c17576040517f63228f2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600081815260016020818152604080842063ffffffff8a1680865290835281852080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8c811691821784558a8116808a526003808952878b20878c528952878b205499860180549a84169a86168b1790558d8316808c526004808b52898d20898e528b529b899020546002880180549190951690871681179094559086018054861682179055998501805490941681179093558551998a5295890193909352928701919091526060860194909452608085015260a084019190915260c0830152907febaba46465001886e6218eb8da227160a320362ee4aab240ead702addafe55ba9060e0015b60405180910390a15050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d98576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611da1336131b0565b565b60055473ffffffffffffffffffffffffffffffffffffffff163314611df4576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8481141580611e035750848314155b15611e3a576040517f11e86f7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b81811015611116576000868683818110611e5a57611e5a613c81565b9050602002016020810190611e6f9190613cb0565b63ffffffff161115611eef57611eea888883818110611e9057611e90613c81565b90506020020135878784818110611ea957611ea9613c81565b9050602002016020810190611ebe9190613cb0565b868685818110611ed057611ed0613c81565b9050602002016020810190611ee59190613768565b612eba565b611f37565b611f37888883818110611f0457611f04613c81565b90506020020135858584818110611f1d57611f1d613c81565b9050602002016020810190611f329190613768565b612ef7565b600101611e3e565b6000838152600c60209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205415611f83576001611f86565b60005b949350505050565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff1661201b576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600880547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527fc7238b23787eb9f8aa74c79b27083bb4b8f0db527df90366b487c40fa0ba2d3a90602001610f0d565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120ed576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527fff9a7b11e174fcce811917e5a8f906a450751019d105ceca5d4a7efe2887160660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166121e9576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b6121f4848484613229565b50505050565b6040805133815263ffffffff8416602082015273ffffffffffffffffffffffffffffffffffffffff8316918101919091527f2a53ef9531d7243776a776fb7d718a6c9ebe2818f1a875f06df1f39af0bf599b90606001610f0d565b3360009081527f45f9541cf4ad029f180498070b7e92d865c32641a6f46018a578b750f26cde3760205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19060ff166122e2576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610e95565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fdd4864dd50be8a1a56c70aebc2953b0890b860197577457ac25fa02f86dadd5590602001610f0d565b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b73ffffffffffffffffffffffffffffffffffffffff808216600090815260016020818152604080842063ffffffff8816855282528084209092015482517f2ff9f2c900000000000000000000000000000000000000000000000000000000815292519394169284928492632ff9f2c9926004808401938290030181865afa15801561241f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124439190613e01565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832063ffffffff8b168452909152812060040154929350918291829161249b918e918e918e918e918e91168a613319565b91945092509050806124ad838561423c565b6124b7919061423c565b6fffffffffffffffffffffffffffffffff169c9b505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602052604081205463ffffffff169081900361253f576040517f73d817fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd7c9eaac00000000000000000000000000000000000000000000000000000000815260048101869052600090819073ffffffffffffffffffffffffffffffffffffffff87169063d7c9eaac9060240160408051808303816000875af11580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d4919061426c565b600954604080517f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e35660208083019190915263ffffffff89168284015267ffffffffffffffff85168c841b7bffffffffffffffffffffffffffffffffffffffff0000000000000000167f0000000000000000000000000000000000000000000000000000000000028c6160e01b7fffffffff000000000000000000000000000000000000000000000000000000001617176060830181905260808084018890528451808503909101815260a084019485905280519201919091207fb7ee4eb900000000000000000000000000000000000000000000000000000000909352949650929450600092839273ffffffffffffffffffffffffffffffffffffffff169163b7ee4eb99161270b918a918d908d9060a40161429e565b6040805180830381865afa158015612727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274b9190613eb2565b9150915080612786576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828273ffffffffffffffffffffffffffffffffffffffff167f4bf575a0e4ff12a13816954b1ce8b1e53f30e121ea4f107ac086ec29da524abe8c888c8c6040516127d394939291906142ce565b60405180910390a350505050505050505050565b60055473ffffffffffffffffffffffffffffffffffffffff163314612838576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61168f8282612aeb565b84612879576040517fb21147c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090819073ffffffffffffffffffffffffffffffffffffffff1663b7ee4eb96128a68960e01c90565b604080517f484f1c5889188a0a81068ce8c49d8f7c3b3f1b0c1723b50ebd656a8d4f99e356602082015263ffffffff7f0000000000000000000000000000000000000000000000000000000000028c611691810191909152606081018b9052608081018a905260a0016040516020818303038152906040528051906020012087876040518563ffffffff1660e01b8152600401612946949392919061429e565b6040805180830381865afa158015612962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129869190613eb2565b91509150806129c1576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000878152600c60209081526040808320600e8084528285208054865291845282852073ffffffffffffffffffffffffffffffffffffffff808c168088529186528487208d90558d8752600d86528487208454885286528487209187529085529285204290558b855290925281548a93918616927f4b8e305abfc214d75df6e3d0b37dc1b2e6e93726d472df847f312d190dcf870492612a60836142ee565b9091555060408051918252602082018b905273ffffffffffffffffffffffffffffffffffffffff8a169082015260600160405180910390a350505050505050565b6000611f8684848461346d565b610f758383604051602001612ad392919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b6060820180516000898152600d602090815260408083208b84528252808320945173ffffffffffffffffffffffffffffffffffffffff908116845294909152908190205490517f4c40818000000000000000000000000000000000000000000000000000000000815260048101879052602481018b9052604481018a905263ffffffff891660648201526084810191909152911690634c4081809060a401602060405180830381865afa158015612c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4d9190614326565b612c83576040517f439cc0cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816040015173ffffffffffffffffffffffffffffffffffffffff16632d095c438486846040518463ffffffff1660e01b8152600401612cc493929190614341565b6020604051808303816000875af1158015612ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d079190614326565b612d3d576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60808101516040517fc41f1f6c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169163c41f1f6c9185913491612da1918991600401614360565b6000604051808303818589803b158015612dba57600080fd5b5088f1158015612dce573d6000803e3d6000fd5b5050600a54602086015186516040517ff1f069d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301526fffffffffffffffffffffffffffffffff909316602482015260448101919091529116945063f1f069d693506064019150612e559050565b600060405180830381600087803b158015612e6f57600080fd5b505af1158015612e83573d6000803e3d6000fd5b505082516040519081527fdc29884a71d2bb98d3c53dc09718be05c7bfd142b7773a5c5cf2517629290ac092506020019050611d38565b610f758383604051602001612edf92919091825263ffffffff16602082015260400190565b60405160208183030381529060405280519060200120825b600082815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6008805460009167ffffffffffffffff9091169082612f9b8361437f565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555067ffffffffffffffff1660408373ffffffffffffffffffffffffffffffffffffffff16901b60e07f0000000000000000000000000000000000000000000000000000000000028c6163ffffffff16901b171760001b9050919050565b604080516060810182526000808252602082018190529181018290529061304483866134fb565b6fffffffffffffffffffffffffffffffff90911660408401819052600a5491925073ffffffffffffffffffffffffffffffffffffffff909116906371c4717b9034908c908c908c908c908a9061309b908d906143a6565b6009546040517fffffffff0000000000000000000000000000000000000000000000000000000060e08b901b168152600481019790975260248701959095526044860193909352606485019190915263ffffffff1660848401526fffffffffffffffffffffffffffffffff90811660a4840152861660c483015273ffffffffffffffffffffffffffffffffffffffff90811660e48301528916610104820152610124810188905261014401604080518083038185885af1158015613163573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613188919061441c565b6fffffffffffffffffffffffffffffffff908116845216602083015250979650505050505050565b6005805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556006805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b73ffffffffffffffffffffffffffffffffffffffff8216613276576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016132bd57610f75828261359e565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361330e576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f75838383613613565b600080600080600061332b88886134fb565b909450915061333a86856143a6565b9350600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aea3d96b8d8d8d8d8d600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518763ffffffff1660e01b81526004016134029695949392919095865260208601949094526040850192909252606084015263ffffffff16608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b6040805180830381865afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613442919061441c565b9550905061345086866143a6565b945061345c828261423c565b925050509750975097945050505050565b6000611f86848460405160200161349492919091825263ffffffff16602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009081526007835281812073ffffffffffffffffffffffffffffffffffffffff8716825290925290205460ff1690565b6040517f06da42e000000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152600090819073ffffffffffffffffffffffffffffffffffffffff8416906306da42e0906024016040805180830381865afa15801561356f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613593919061441c565b909590945092505050565b600080600080600085875af1905080610f75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610e95565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806121f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610e95565b803563ffffffff811681146136f657600080fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461371d57600080fd5b50565b6000806000806080858703121561373657600080fd5b61373f856136e2565b93506020850135925060408501359150606085013561375d816136fb565b939692955090935050565b60006020828403121561377a57600080fd5b8135612389816136fb565b60008060006060848603121561379a57600080fd5b833592506137aa602085016136e2565b915060408401356137ba816136fb565b809150509250925092565b60008083601f8401126137d757600080fd5b50813567ffffffffffffffff8111156137ef57600080fd5b6020830191508360208260051b850101111561380a57600080fd5b9250929050565b6000806000806000806060878903121561382a57600080fd5b863567ffffffffffffffff8082111561384257600080fd5b61384e8a838b016137c5565b9098509650602089013591508082111561386757600080fd5b6138738a838b016137c5565b9096509450604089013591508082111561388c57600080fd5b5061389989828a016137c5565b979a9699509497509295939492505050565b600060a082840312156138bd57600080fd5b50919050565b600080604083850312156138d657600080fd5b823567ffffffffffffffff808211156138ee57600080fd5b6138fa868387016138ab565b9350602085013591508082111561391057600080fd5b5061391d858286016138ab565b9150509250929050565b6000806040838503121561393a57600080fd5b82359150602083013561394c816136fb565b809150509250929050565b60008083601f84011261396957600080fd5b50813567ffffffffffffffff81111561398157600080fd5b60208301915083602082850101111561380a57600080fd5b60008060008060008060a087890312156139b257600080fd5b6139bb876136e2565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156139ec57600080fd5b61389989828a01613957565b60008060008060808587031215613a0e57600080fd5b613a17856136e2565b93506020850135613a27816136fb565b92506040850135613a37816136fb565b9150606085013561375d816136fb565b60008060408385031215613a5a57600080fd5b8235613a65816136fb565b9150613a73602084016136e2565b90509250929050565b600080600060608486031215613a9157600080fd5b833592506020840135915060408401356137ba816136fb565b600080600060608486031215613abf57600080fd5b8335613aca816136fb565b92506020840135613ada816136fb565b929592945050506040919091013590565b600060208284031215613afd57600080fd5b5035919050565b60008060408385031215613b1757600080fd5b613b20836136e2565b9150602083013561394c816136fb565b60008060008060008060c08789031215613b4957600080fd5b86359550602087013594506040870135935060608701359250613b6e608088016136e2565b915060a0870135613b7e816136fb565b809150509295509295509295565b60008060008060608587031215613ba257600080fd5b843593506020850135613bb4816136fb565b9250604085013567ffffffffffffffff811115613bd057600080fd5b613bdc87828801613957565b95989497509550505050565b600080600080600060808688031215613c0057600080fd5b85359450602086013593506040860135613c19816136fb565b9250606086013567ffffffffffffffff811115613c3557600080fd5b613c4188828901613957565b969995985093965092949392505050565b60008060408385031215613c6557600080fd5b8251613c70816136fb565b602084015190925061394c816136fb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613cc257600080fd5b612389826136e2565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152823560a0830152602083013560c0830152604083013560e0830152606083013561010083015260808301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db157600080fd5b830160208101903567ffffffffffffffff811115613dce57600080fd5b803603821315613ddd57600080fd5b60a0610120850152613df461014085018284613ccb565b9998505050505050505050565b600060208284031215613e1357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e4f57600080fd5b83018035915067ffffffffffffffff821115613e6a57600080fd5b60200191503681900382131561380a57600080fd5b838152604060208201526000613e99604083018486613ccb565b95945050505050565b805180151581146136f657600080fd5b60008060408385031215613ec557600080fd5b8251613ed0816136fb565b9150613a7360208401613ea2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715613f3057613f30613ede565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f7d57613f7d613ede565b604052919050565b600060a08236031215613f9757600080fd5b613f9f613f0d565b82358152602080840135818301526040840135604083015260608401356060830152608084013567ffffffffffffffff80821115613fdc57600080fd5b9085019036601f830112613fef57600080fd5b81358181111561400157614001613ede565b614031847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f36565b9150808252368482850101111561404757600080fd5b808484018584013760009082019093019290925250608082015292915050565b6000815180845260005b8181101561408d57602081850181015186830182015201614071565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808816835273ffffffffffffffffffffffffffffffffffffffff808816602085015281871660408501528086166060850152505060a06080830152825160a0830152602083015160c0830152604083015160e08301526060830151610100830152608083015160a061012084015261414e610140840182614067565b98975050505050505050565b600061018063ffffffff808f16845273ffffffffffffffffffffffffffffffffffffffff808f166020860152818e166040860152808d16606086015250508960808401528860a08401528760c08401528660e0840152806101008401526141c48184018688613ccb565b9150506fffffffffffffffffffffffffffffffff808451166101208401528060208501511661014084015280604085015116610160840152509c9b505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff8181168382160190808211156142655761426561420d565b5092915050565b6000806040838503121561427f57600080fd5b82519150602083015167ffffffffffffffff8116811461394c57600080fd5b63ffffffff851681528360208201526060604082015260006142c4606083018486613ccb565b9695505050505050565b8481528360208201526060604082015260006142c4606083018486613ccb565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361431f5761431f61420d565b5060010190565b60006020828403121561433857600080fd5b61238982613ea2565b838152826020820152606060408201526000613e996060830184614067565b63ffffffff83168152604060208201526000611f866040830184614067565b600067ffffffffffffffff80831681810361439c5761439c61420d565b6001019392505050565b60006fffffffffffffffffffffffffffffffff808416806143f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b80516fffffffffffffffffffffffffffffffff811681146136f657600080fd5b6000806040838503121561442f57600080fd5b614438836143fc565b9150613a73602084016143fc56fea26469706673582212208b207b6ea0b17a8c1b971aded8aa3d712bdaff7e0e0f033fdd5c848b561a579564736f6c63430008130033