Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Counter
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 999999
- EVM Version
- default
- Verified at
- 2024-10-23T11:04:31.825684Z
Constructor Arguments
0x0000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f
Arg [0] (address) : 0x5c4186d343eef952c9ed886e45f8243edf0a503f
contracts/examples/Counter.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/ITransmitManager.sol pragma solidity 0.8.19; /** * @title ITransmitManager * @dev The interface for a transmit manager contract */ interface ITransmitManager { /** * @notice Checks if a given transmitter is authorized to send transactions to the destination chain. * @param siblingSlug The unique identifier for the sibling chain. * @param digest The digest of the message being signed. * @param signature The signature of the message being signed. * @return The address of the transmitter and a boolean indicating whether the transmitter is authorized or not. */ function checkTransmitter( uint32 siblingSlug, bytes32 digest, bytes calldata signature ) external view returns (address, bool); /** * @notice sets the transmission fee needed to transmit message to given `siblingSlug_` * @dev recovered address should add have feeUpdater role for `siblingSlug_` * @param nonce_ The incremental nonce to prevent signature replay * @param siblingSlug_ sibling id for which fee updater is registered * @param transmissionFees_ digest which is signed by transmitter * @param signature_ signature */ function setTransmissionFees( uint256 nonce_, uint32 siblingSlug_, uint128 transmissionFees_, bytes calldata signature_ ) external; /** * @notice receives fees from Execution manager * @dev this function can be used to keep track of fees received for each slug * @param siblingSlug_ sibling id for which fee updater is registered */ function receiveFees(uint32 siblingSlug_) external payable; } // File contracts/interfaces/IExecutionManager.sol pragma solidity 0.8.19; /** * @title Execution Manager Interface * @dev This interface defines the functions for managing and executing transactions on external chains * @dev It is also responsible for collecting all the socket fees, which can then be pulled by others */ interface IExecutionManager { struct ExecutionFeesParam { // for calculating perGasCost * gasLimit uint80 perGasCost; // for calculating cost for executing payload (needed for rollups) uint80 perByteCost; // additional cost (differs based on chain) uint80 overhead; } /** * @notice Returns the executor of the packed message and whether the executor is authorized * @param packedMessage The message packed with payload, fees and config * @param sig The signature of the message * @return The address of the executor and a boolean indicating if the executor is authorized */ function isExecutor( bytes32 packedMessage, bytes memory sig ) external view returns (address, bool); /** * @notice Pays the fees for executing a transaction on the external chain * @dev This function is payable and assumes the socket is going to send correct amount of fees. * @param minMsgGasLimit_ The minimum gas limit for the transaction * @param payloadSize_ The payload size in bytes * @param executionParams_ Extra params for execution * @param transmissionParams_ Extra params for transmission * @param siblingChainSlug_ Sibling chain identifier * @param switchboardFees_ fee charged by switchboard for processing transaction * @param verificationOverheadFees_ fee charged for verifying transaction * @param transmitManager_ The transmitManager address * @param switchboard_ The switchboard address * @param maxPacketLength_ The maxPacketLength for the capacitor */ function payAndCheckFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 siblingChainSlug_, uint128 switchboardFees_, uint128 verificationOverheadFees_, address transmitManager_, address switchboard_, uint256 maxPacketLength_ ) external payable returns (uint128, uint128); /** * @notice Returns the minimum fees required for executing a transaction on the external chain * @param minMsgGasLimit_ minMsgGasLimit_ * @param siblingChainSlug_ The destination slug * @return The minimum fees required for executing the transaction */ function getMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, uint32 siblingChainSlug_ ) external view returns (uint128); /** * @notice function for getting the minimum fees required for executing and transmitting a cross-chain transaction * @dev this function is called at source to calculate the execution cost. * @param payloadSize_ byte length of payload. Currently only used to check max length, later on will be used for fees calculation. * @param executionParams_ Can be used for providing extra information. Currently used for msgValue * @param siblingChainSlug_ Sibling chain identifier * @return minExecutionFee : Minimum fees required for executing the transaction */ function getExecutionTransmissionMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 siblingChainSlug_, address transmitManager_ ) external view returns (uint128, uint128); /** * @notice Updates the execution fees for an executor and message ID * @param executor The executor address * @param executionFees The execution fees to update * @param msgId The ID of the message */ function updateExecutionFees( address executor, uint128 executionFees, bytes32 msgId ) external; /** * @notice updates the transmission fee * @param remoteChainSlug_ sibling chain identifier * @param transmitMinFees_ transmission fees collected */ function setTransmissionMinFees( uint32 remoteChainSlug_, uint128 transmitMinFees_ ) external; /** * @notice sets the minimum execution fees required for executing at `siblingChainSlug_` * @dev this function currently sets the price for a constant msg gas limit and payload size * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param executionFees_ total fees where price in destination native token is converted to source native tokens * @param signature_ signature of fee updater */ function setExecutionFees( uint256 nonce_, uint32 siblingChainSlug_, ExecutionFeesParam calldata executionFees_, bytes calldata signature_ ) external; /** * @notice sets the min limit for msg value for `siblingChainSlug_` * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param msgValueMinThreshold_ min msg value * @param signature_ signature of fee updater */ function setMsgValueMinThreshold( uint256 nonce_, uint32 siblingChainSlug_, uint256 msgValueMinThreshold_, bytes calldata signature_ ) external; /** * @notice sets the max limit for msg value for `siblingChainSlug_` * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param msgValueMaxThreshold_ max msg value * @param signature_ signature of fee updater */ function setMsgValueMaxThreshold( uint256 nonce_, uint32 siblingChainSlug_, uint256 msgValueMaxThreshold_, bytes calldata signature_ ) external; /** * @notice sets the relative token price for `siblingChainSlug_` * @dev this function is expected to be called frequently to match the original prices * @param nonce_ incremental id to prevent signature replay * @param siblingChainSlug_ sibling chain identifier * @param relativeNativeTokenPrice_ relative price * @param signature_ signature of fee updater */ function setRelativeNativeTokenPrice( uint256 nonce_, uint32 siblingChainSlug_, uint256 relativeNativeTokenPrice_, bytes calldata signature_ ) external; /** * @notice called by socket while executing message to validate if the msg value provided is enough * @param executionParams_ a bytes32 string where first byte gives param type (if value is 0 or not) * and remaining bytes give the msg value needed * @param msgValue_ msg.value to be sent with inbound */ function verifyParams( bytes32 executionParams_, uint256 msgValue_ ) external view; /** * @notice withdraws switchboard fees from contract * @param siblingChainSlug_ withdraw fees corresponding to this slug * @param amount_ withdraw amount */ function withdrawSwitchboardFees( uint32 siblingChainSlug_, address switchboard_, uint128 amount_ ) external; /** * @dev this function gets the transmitManager address from the socket contract. If it is ever upgraded in socket, * @dev remove the fees from executionManager first, and then upgrade address at socket. * @notice withdraws transmission fees from contract * @param siblingChainSlug_ withdraw fees corresponding to this slug * @param amount_ withdraw amount */ function withdrawTransmissionFees( uint32 siblingChainSlug_, uint128 amount_ ) external; } // File contracts/interfaces/ISocket.sol pragma solidity 0.8.19; /** * @title ISocket * @notice An interface for a cross-chain communication contract * @dev This interface provides methods for transmitting and executing messages between chains, * connecting a plug to a remote chain and setting up switchboards for the message transmission * This interface also emits events for important operations such as message transmission, execution status, * and plug connection */ interface ISocket { /** * @notice A struct containing fees required for message transmission and execution * @param transmissionFees fees needed for transmission * @param switchboardFees fees needed by switchboard * @param executionFee fees needed for execution */ struct Fees { uint128 transmissionFees; uint128 executionFee; uint128 switchboardFees; } /** * @title MessageDetails * @dev This struct defines the details of a message to be executed in a Decapacitor contract. */ struct MessageDetails { // A unique identifier for the message. bytes32 msgId; // The fee to be paid for executing the message. uint256 executionFee; // The min amount of gas that can be used to execute the message. uint256 minMsgGasLimit; // The extra params which might provide msg value and additional info needed for message exec bytes32 executionParams; // The payload data to be executed in the message. bytes payload; } /** * @title ExecutionDetails * @dev This struct defines the execution details */ struct ExecutionDetails { // packet id bytes32 packetId; // proposal count uint256 proposalCount; // gas limit needed to execute inbound uint256 executionGasLimit; // proof data required by the Decapacitor contract to verify the message's authenticity bytes decapacitorProof; // signature of executor bytes signature; } /** * @notice emits the status of message after inbound call * @param msgId msg id which is executed */ event ExecutionSuccess(bytes32 msgId); /** * @notice emits the config set by a plug for a remoteChainSlug * @param plug address of plug on current chain * @param siblingChainSlug sibling chain slug * @param siblingPlug address of plug on sibling chain * @param inboundSwitchboard inbound switchboard (select from registered options) * @param outboundSwitchboard outbound switchboard (select from registered options) * @param capacitor capacitor selected based on outbound switchboard * @param decapacitor decapacitor selected based on inbound switchboard */ event PlugConnected( address plug, uint32 siblingChainSlug, address siblingPlug, address inboundSwitchboard, address outboundSwitchboard, address capacitor, address decapacitor ); /** * @notice registers a message * @dev Packs the message and includes it in a packet with capacitor * @param remoteChainSlug_ the remote chain slug * @param minMsgGasLimit_ the gas limit needed to execute the payload on remote * @param payload_ the data which is needed by plug at inbound call on remote */ function outbound( uint32 remoteChainSlug_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_, bytes calldata payload_ ) external payable returns (bytes32 msgId); /** * @notice executes a message * @param executionDetails_ the packet details, proof and signature needed for message execution * @param messageDetails_ the message details */ function execute( ISocket.ExecutionDetails calldata executionDetails_, ISocket.MessageDetails calldata messageDetails_ ) external payable; /** * @notice seals data in capacitor for specific batchSize * @param batchSize_ size of batch to be sealed * @param capacitorAddress_ address of capacitor * @param signature_ signed Data needed for verification */ function seal( uint256 batchSize_, address capacitorAddress_, bytes calldata signature_ ) external payable; /** * @notice proposes a packet * @param packetId_ packet id * @param root_ root data * @param switchboard_ The address of switchboard for which this packet is proposed * @param signature_ signed Data needed for verification */ function proposeForSwitchboard( bytes32 packetId_, bytes32 root_, address switchboard_, bytes calldata signature_ ) external payable; /** * @notice sets the config specific to the plug * @param siblingChainSlug_ the sibling chain slug * @param siblingPlug_ address of plug present at sibling chain to call inbound * @param inboundSwitchboard_ the address of switchboard to use for receiving messages * @param outboundSwitchboard_ the address of switchboard to use for sending messages */ function connect( uint32 siblingChainSlug_, address siblingPlug_, address inboundSwitchboard_, address outboundSwitchboard_ ) external; /** * @notice deploy capacitor and decapacitor for a switchboard with a specified max packet length, sibling chain slug, and capacitor type. * @param siblingChainSlug_ The slug of the sibling chain that the switchboard is registered with. * @param maxPacketLength_ The maximum length of a packet allowed by the switchboard. * @param capacitorType_ The type of capacitor that the switchboard uses. * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function registerSwitchboardForSibling( uint32 siblingChainSlug_, uint256 maxPacketLength_, uint256 capacitorType_, address siblingSwitchboard_ ) external returns (address capacitor, address decapacitor); /** * @notice Emits the sibling switchboard for given `siblingChainSlug_`. * @dev This function is expected to be only called by switchboard. * @dev the event emitted is tracked by transmitters to decide which switchboard a packet should be proposed on * @param siblingChainSlug_ The slug of the sibling chain * @param siblingSwitchboard_ The switchboard address deployed on `siblingChainSlug_` */ function useSiblingSwitchboard( uint32 siblingChainSlug_, address siblingSwitchboard_ ) external; /** * @notice Retrieves the packet id roots for a specified packet id. * @param packetId_ The packet id for which to retrieve the root. * @param proposalCount_ The proposal id for packetId_ for which to retrieve the root. * @param switchboard_ The address of switchboard for which this packet is proposed * @return The packet id roots for the specified packet id. */ function packetIdRoots( bytes32 packetId_, uint256 proposalCount_, address switchboard_ ) external view returns (bytes32); /** * @notice Retrieves the latest proposalCount for a packet id. * @return The proposal count for the specified packet id. */ function proposalCount(bytes32 packetId_) external view returns (uint256); /** * @notice Retrieves the minimum fees required for a message with a specified gas limit and destination chain. * @param minMsgGasLimit_ The gas limit of the message. * @param remoteChainSlug_ The slug of the destination chain for the message. * @param plug_ The address of the plug through which the message is sent. * @return totalFees The minimum fees required for the specified message. */ function getMinFees( uint256 minMsgGasLimit_, uint256 payloadSize_, bytes32 executionParams_, bytes32 transmissionParams_, uint32 remoteChainSlug_, address plug_ ) external view returns (uint256 totalFees); /// return instance of transmit manager function transmitManager__() external view returns (ITransmitManager); /// return instance of execution manager function executionManager__() external view returns (IExecutionManager); } // File contracts/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 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/examples/Counter.sol pragma solidity 0.8.19; contract Counter is IPlug, Ownable(msg.sender) { // immutables address public immutable socket; // application state uint256 public counter; // application ops bytes32 public constant OP_ADD = keccak256("OP_ADD"); bytes32 public constant OP_SUB = keccak256("OP_SUB"); error OnlySocket(); error InvalidAmount(); constructor(address socket_) { socket = socket_; } function localAddOperation(uint256 amount_) external { _addOperation(amount_); } function localSubOperation(uint256 amount_) external { _subOperation(amount_); } function remoteAddOperation( uint32 chainSlug_, uint256 amount_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_ ) external payable { bytes memory payload = abi.encode(OP_ADD, amount_, msg.sender); _outbound( chainSlug_, minMsgGasLimit_, executionParams_, transmissionParams_, payload ); } function remoteSubOperation( uint32 chainSlug_, uint256 amount_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_ ) external payable { bytes memory payload = abi.encode(OP_SUB, amount_, msg.sender); _outbound( chainSlug_, minMsgGasLimit_, executionParams_, transmissionParams_, payload ); } function inbound( uint32, bytes calldata payload_ ) external payable override { if (msg.sender != socket) revert OnlySocket(); (bytes32 operationType, uint256 amount, ) = abi.decode( payload_, (bytes32, uint256, address) ); if (operationType == OP_ADD) { _addOperation(amount); } else if (operationType == OP_SUB) { _subOperation(amount); } else { revert("CounterMock: Invalid Operation"); } } function _outbound( uint32 targetChain_, uint256 minMsgGasLimit_, bytes32 executionParams_, bytes32 transmissionParams_, bytes memory payload_ ) private { ISocket(socket).outbound{value: msg.value}( targetChain_, minMsgGasLimit_, executionParams_, transmissionParams_, payload_ ); } // // base ops // function _addOperation(uint256 amount_) private { counter += amount_; } function _subOperation(uint256 amount_) private { if (counter < amount_) revert InvalidAmount(); counter -= amount_; } // settings function setSocketConfig( uint32 remoteChainSlug_, address remotePlug_, address switchboard_ ) external onlyOwner { ISocket(socket).connect( remoteChainSlug_, remotePlug_, switchboard_, switchboard_ ); } /** * @notice Rescues funds from the contract if they are locked by mistake. * @param token_ The address of the token contract. * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyOwner { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } }
Compiler Settings
{"outputSelection":{"*":{"*":["*"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"socket_","internalType":"address"}]},{"type":"error","name":"InvalidAmount","inputs":[]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"OnlySocket","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"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":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"OP_ADD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"OP_SUB","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"counter","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"inbound","inputs":[{"type":"uint32","name":"","internalType":"uint32"},{"type":"bytes","name":"payload_","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"localAddOperation","inputs":[{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"localSubOperation","inputs":[{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nominateOwner","inputs":[{"type":"address","name":"nominee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nominee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"remoteAddOperation","inputs":[{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"type":"uint256","name":"amount_","internalType":"uint256"},{"type":"uint256","name":"minMsgGasLimit_","internalType":"uint256"},{"type":"bytes32","name":"executionParams_","internalType":"bytes32"},{"type":"bytes32","name":"transmissionParams_","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"remoteSubOperation","inputs":[{"type":"uint32","name":"chainSlug_","internalType":"uint32"},{"type":"uint256","name":"amount_","internalType":"uint256"},{"type":"uint256","name":"minMsgGasLimit_","internalType":"uint256"},{"type":"bytes32","name":"executionParams_","internalType":"bytes32"},{"type":"bytes32","name":"transmissionParams_","internalType":"bytes32"}]},{"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":"setSocketConfig","inputs":[{"type":"uint32","name":"remoteChainSlug_","internalType":"uint32"},{"type":"address","name":"remotePlug_","internalType":"address"},{"type":"address","name":"switchboard_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"socket","inputs":[]}]
Contract Creation Code
0x60a060405234801561001057600080fd5b50604051610fbc380380610fbc83398101604081905261002f9161009e565b336100398161004b565b506001600160a01b03166080526100ce565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b6000602082840312156100b057600080fd5b81516001600160a01b03811681146100c757600080fd5b9392505050565b608051610ebe6100fe600039600081816101920152818161056701528181610756015261086c0152610ebe6000f3fe6080604052600436106100e85760003560e01c8063664c38f31161008a578063ae2cb7a711610059578063ae2cb7a7146102a6578063b9ffcc34146102c6578063c41f1f6c146102e6578063fcb32712146102f957600080fd5b8063664c38f3146102355780636ccae054146102485780637f63bce9146102685780638da5cb5b1461027b57600080fd5b80632602c01e116100c65780632602c01e146101b45780633bd1adec146101e85780635b94db27146101ff57806361bc221a1461021f57600080fd5b80630548a9e7146100ed57806320f99c0a1461013457806322c8f6cd14610180575b600080fd5b3480156100f957600080fd5b506101217fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d39074661281565b6040519081526020015b60405180910390f35b34801561014057600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161012b565b34801561018c57600080fd5b5061015b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101c057600080fd5b506101217fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99781565b3480156101f457600080fd5b506101fd610319565b005b34801561020b57600080fd5b506101fd61021a366004610bb2565b610375565b34801561022b57600080fd5b5061012160025481565b6101fd610243366004610bef565b610435565b34801561025457600080fd5b506101fd610263366004610c31565b610498565b6101fd610276366004610bef565b6104f9565b34801561028757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661015b565b3480156102b257600080fd5b506101fd6102c1366004610c72565b61053a565b3480156102d257600080fd5b506101fd6102e1366004610c72565b610546565b6101fd6102f4366004610c8b565b61054f565b34801561030557600080fd5b506101fd610314366004610d0e565b6106a5565b60015473ffffffffffffffffffffffffffffffffffffffff16331461036a576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610373336107b7565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103c6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b604080517fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99760208201529081018590523360608201526000906080015b6040516020818303038152906040529050610490868585858561082f565b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104e9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f48383836108ee565b505050565b604080517fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d3907466126020820152908101859052336060820152600090608001610472565b610543816109de565b50565b61054381610a34565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105be576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806105cd83850185610d57565b50915091507fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99782036106075761060281610a34565b61069e565b7fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d390746612820361063757610602816109de565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f436f756e7465724d6f636b3a20496e76616c6964204f7065726174696f6e000060448201526064015b60405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106f6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f3b1be67800000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301528281166044830181905260648301527f00000000000000000000000000000000000000000000000000000000000000001690633b1be67890608401600060405180830381600087803b15801561079a57600080fd5b505af11580156107ae573d6000803e3d6000fd5b50505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b6040517f3386774f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690633386774f9034906108ab9089908990899089908990600401610d85565b60206040518083038185885af11580156108c9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104909190610e14565b73ffffffffffffffffffffffffffffffffffffffff821661093b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff841601610982576104f48282610a46565b8273ffffffffffffffffffffffffffffffffffffffff163b6000036109d3576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f4838383610abb565b806002541015610a1a576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060026000828254610a2c9190610e5c565b909155505050565b8060026000828254610a2c9190610e75565b600080600080600085875af19050806104f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610695565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610b8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610695565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461054357600080fd5b600060208284031215610bc457600080fd5b8135610bcf81610b90565b9392505050565b803563ffffffff81168114610bea57600080fd5b919050565b600080600080600060a08688031215610c0757600080fd5b610c1086610bd6565b97602087013597506040870135966060810135965060800135945092505050565b600080600060608486031215610c4657600080fd5b8335610c5181610b90565b92506020840135610c6181610b90565b929592945050506040919091013590565b600060208284031215610c8457600080fd5b5035919050565b600080600060408486031215610ca057600080fd5b610ca984610bd6565b9250602084013567ffffffffffffffff80821115610cc657600080fd5b818601915086601f830112610cda57600080fd5b813581811115610ce957600080fd5b876020828501011115610cfb57600080fd5b6020830194508093505050509250925092565b600080600060608486031215610d2357600080fd5b610d2c84610bd6565b92506020840135610d3c81610b90565b91506040840135610d4c81610b90565b809150509250925092565b600080600060608486031215610d6c57600080fd5b83359250602084013591506040840135610d4c81610b90565b63ffffffff8616815260006020868184015285604084015284606084015260a0608084015283518060a085015260005b81811015610dd15785810183015185820160c001528201610db5565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509695505050505050565b600060208284031215610e2657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610e6f57610e6f610e2d565b92915050565b80820180821115610e6f57610e6f610e2d56fea2646970667358221220c9995baf7a5e9cf0741bc1d34151f3f0900939e27f587b2985c5b22f785f306f64736f6c634300081300330000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f
Deployed ByteCode
0x6080604052600436106100e85760003560e01c8063664c38f31161008a578063ae2cb7a711610059578063ae2cb7a7146102a6578063b9ffcc34146102c6578063c41f1f6c146102e6578063fcb32712146102f957600080fd5b8063664c38f3146102355780636ccae054146102485780637f63bce9146102685780638da5cb5b1461027b57600080fd5b80632602c01e116100c65780632602c01e146101b45780633bd1adec146101e85780635b94db27146101ff57806361bc221a1461021f57600080fd5b80630548a9e7146100ed57806320f99c0a1461013457806322c8f6cd14610180575b600080fd5b3480156100f957600080fd5b506101217fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d39074661281565b6040519081526020015b60405180910390f35b34801561014057600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161012b565b34801561018c57600080fd5b5061015b7f0000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f81565b3480156101c057600080fd5b506101217fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99781565b3480156101f457600080fd5b506101fd610319565b005b34801561020b57600080fd5b506101fd61021a366004610bb2565b610375565b34801561022b57600080fd5b5061012160025481565b6101fd610243366004610bef565b610435565b34801561025457600080fd5b506101fd610263366004610c31565b610498565b6101fd610276366004610bef565b6104f9565b34801561028757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661015b565b3480156102b257600080fd5b506101fd6102c1366004610c72565b61053a565b3480156102d257600080fd5b506101fd6102e1366004610c72565b610546565b6101fd6102f4366004610c8b565b61054f565b34801561030557600080fd5b506101fd610314366004610d0e565b6106a5565b60015473ffffffffffffffffffffffffffffffffffffffff16331461036a576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610373336107b7565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103c6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b604080517fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99760208201529081018590523360608201526000906080015b6040516020818303038152906040529050610490868585858561082f565b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104e9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f48383836108ee565b505050565b604080517fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d3907466126020820152908101859052336060820152600090608001610472565b610543816109de565b50565b61054381610a34565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f16146105be576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806105cd83850185610d57565b50915091507fbad314e77c9e165fb6cdad2b69ae15ea10f47a976480a84ea0ef9a8b8817b99782036106075761060281610a34565b61069e565b7fde6ce4bedbca0651358aef7b21343405a14691bbef1508653f9f01d390746612820361063757610602816109de565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f436f756e7465724d6f636b3a20496e76616c6964204f7065726174696f6e000060448201526064015b60405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106f6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f3b1be67800000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301528281166044830181905260648301527f0000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f1690633b1be67890608401600060405180830381600087803b15801561079a57600080fd5b505af11580156107ae573d6000803e3d6000fd5b50505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b6040517f3386774f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005c4186d343eef952c9ed886e45f8243edf0a503f1690633386774f9034906108ab9089908990899089908990600401610d85565b60206040518083038185885af11580156108c9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906104909190610e14565b73ffffffffffffffffffffffffffffffffffffffff821661093b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff841601610982576104f48282610a46565b8273ffffffffffffffffffffffffffffffffffffffff163b6000036109d3576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f4838383610abb565b806002541015610a1a576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060026000828254610a2c9190610e5c565b909155505050565b8060026000828254610a2c9190610e75565b600080600080600085875af19050806104f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610695565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610b8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610695565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461054357600080fd5b600060208284031215610bc457600080fd5b8135610bcf81610b90565b9392505050565b803563ffffffff81168114610bea57600080fd5b919050565b600080600080600060a08688031215610c0757600080fd5b610c1086610bd6565b97602087013597506040870135966060810135965060800135945092505050565b600080600060608486031215610c4657600080fd5b8335610c5181610b90565b92506020840135610c6181610b90565b929592945050506040919091013590565b600060208284031215610c8457600080fd5b5035919050565b600080600060408486031215610ca057600080fd5b610ca984610bd6565b9250602084013567ffffffffffffffff80821115610cc657600080fd5b818601915086601f830112610cda57600080fd5b813581811115610ce957600080fd5b876020828501011115610cfb57600080fd5b6020830194508093505050509250925092565b600080600060608486031215610d2357600080fd5b610d2c84610bd6565b92506020840135610d3c81610b90565b91506040840135610d4c81610b90565b809150509250925092565b600080600060608486031215610d6c57600080fd5b83359250602084013591506040840135610d4c81610b90565b63ffffffff8616815260006020868184015285604084015284606084015260a0608084015283518060a085015260005b81811015610dd15785810183015185820160c001528201610db5565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509695505050505050565b600060208284031215610e2657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610e6f57610e6f610e2d565b92915050565b80820180821115610e6f57610e6f610e2d56fea2646970667358221220c9995baf7a5e9cf0741bc1d34151f3f0900939e27f587b2985c5b22f785f306f64736f6c63430008130033