Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- CapacitorFactory
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 999999
- EVM Version
- default
- Verified at
- 2024-10-23T11:04:15.945735Z
Constructor Arguments
0x00000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c000000000000000000000000000000000000000000000000000000000000000a
Arg [0] (address) : 0x44a44837894b5edc2bde64567fc62599b3b88f4c
Arg [1] (uint256) : 10
contracts/CapacitorFactory.sol
// SPDX-License-Identifier: GPL-3.0-only // Sources flattened with hardhat v2.12.2 https://hardhat.org // File contracts/utils/Ownable.sol pragma solidity 0.8.19; /** * @title Ownable * @dev The Ownable contract provides a simple way to manage ownership of a contract * and allows for ownership to be transferred to a nominated address. */ abstract contract Ownable { address private _owner; address private _nominee; event OwnerNominated(address indexed nominee); event OwnerClaimed(address indexed claimer); error OnlyOwner(); error OnlyNominee(); /** * @dev Sets the contract's owner to the address that is passed to the constructor. */ constructor(address owner_) { _claimOwner(owner_); } /** * @dev Modifier that restricts access to only the contract's owner. * Throws an error if the caller is not the owner. */ modifier onlyOwner() { if (msg.sender != _owner) revert OnlyOwner(); _; } /** * @dev Returns the current owner of the contract. */ function owner() external view returns (address) { return _owner; } /** * @dev Returns the current nominee for ownership of the contract. */ function nominee() external view returns (address) { return _nominee; } /** * @dev Allows the current owner to nominate a new owner for the contract. * Throws an error if the caller is not the owner. * Emits an `OwnerNominated` event with the address of the nominee. */ function nominateOwner(address nominee_) external { if (msg.sender != _owner) revert OnlyOwner(); _nominee = nominee_; emit OwnerNominated(_nominee); } /** * @dev Allows the nominated owner to claim ownership of the contract. * Throws an error if the caller is not the nominee. * Sets the nominated owner as the new owner of the contract. * Emits an `OwnerClaimed` event with the address of the new owner. */ function claimOwner() external { if (msg.sender != _nominee) revert OnlyNominee(); _claimOwner(msg.sender); } /** * @dev Internal function that sets the owner of the contract to the specified address * and sets the nominee to address(0). */ function _claimOwner(address claimer_) internal { _owner = claimer_; _nominee = address(0); emit OwnerClaimed(claimer_); } } // File contracts/utils/AccessControl.sol pragma solidity 0.8.19; /** * @title AccessControl * @dev This abstract contract implements access control mechanism based on roles. * Each role can have one or more addresses associated with it, which are granted * permission to execute functions with the onlyRole modifier. */ abstract contract AccessControl is Ownable { /** * @dev A mapping of roles to a mapping of addresses to boolean values indicating whether or not they have the role. */ mapping(bytes32 => mapping(address => bool)) private _permits; /** * @dev Emitted when a role is granted to an address. */ event RoleGranted(bytes32 indexed role, address indexed grantee); /** * @dev Emitted when a role is revoked from an address. */ event RoleRevoked(bytes32 indexed role, address indexed revokee); /** * @dev Error message thrown when an address does not have permission to execute a function with onlyRole modifier. */ error NoPermit(bytes32 role); /** * @dev Constructor that sets the owner of the contract. */ constructor(address owner_) Ownable(owner_) {} /** * @dev Modifier that restricts access to addresses having roles * Throws an error if the caller do not have permit */ modifier onlyRole(bytes32 role) { if (!_permits[role][msg.sender]) revert NoPermit(role); _; } /** * @dev Checks and reverts if an address do not have a specific role. * @param role_ The role to check. * @param address_ The address to check. */ function _checkRole(bytes32 role_, address address_) internal virtual { if (!_hasRole(role_, address_)) revert NoPermit(role_); } /** * @dev Grants a role to a given address. * @param role_ The role to grant. * @param grantee_ The address to grant the role to. * Emits a RoleGranted event. * Can only be called by the owner of the contract. */ function grantRole( bytes32 role_, address grantee_ ) external virtual onlyOwner { _grantRole(role_, grantee_); } /** * @dev Revokes a role from a given address. * @param role_ The role to revoke. * @param revokee_ The address to revoke the role from. * Emits a RoleRevoked event. * Can only be called by the owner of the contract. */ function revokeRole( bytes32 role_, address revokee_ ) external virtual onlyOwner { _revokeRole(role_, revokee_); } /** * @dev Internal function to grant a role to a given address. * @param role_ The role to grant. * @param grantee_ The address to grant the role to. * Emits a RoleGranted event. */ function _grantRole(bytes32 role_, address grantee_) internal { _permits[role_][grantee_] = true; emit RoleGranted(role_, grantee_); } /** * @dev Internal function to revoke a role from a given address. * @param role_ The role to revoke. * @param revokee_ The address to revoke the role from. * Emits a RoleRevoked event. */ function _revokeRole(bytes32 role_, address revokee_) internal { _permits[role_][revokee_] = false; emit RoleRevoked(role_, revokee_); } /** * @dev Checks whether an address has a specific role. * @param role_ The role to check. * @param address_ The address to check. * @return A boolean value indicating whether or not the address has the role. */ function hasRole( bytes32 role_, address address_ ) external view returns (bool) { return _hasRole(role_, address_); } function _hasRole( bytes32 role_, address address_ ) internal view returns (bool) { return _permits[role_][address_]; } } // File 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/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 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/capacitors/BaseCapacitor.sol pragma solidity 0.8.19; /** * @title BaseCapacitor * @dev Abstract base contract for the Capacitors. Implements shared functionality and provides * access control. */ abstract contract BaseCapacitor is ICapacitor, AccessControl { /// address of socket address public immutable socket; /// an incrementing count for the next packet that is being created uint64 internal _nextPacketCount; /// tracks the count of next packet that will be sealed uint64 internal _nextSealCount; /// maps the packet count with the root hash of that packet mapping(uint64 => bytes32) internal _roots; // Error triggered when not called by socket error OnlySocket(); /** * @dev Throws if called by any account other than the socket. */ modifier onlySocket() { if (msg.sender != socket) revert OnlySocket(); _; } /** * @dev Initializes the contract with the specified socket address. * @param socket_ The address of the socket contract. * @param owner_ The address of the owner of the capacitor contract. */ constructor(address socket_, address owner_) AccessControl(owner_) { socket = socket_; _grantRole(RESCUE_ROLE, owner_); } /** * @dev Returns the count of the latest packet that finished filling. * @dev Returns 0 in case 0 or 1 packets are filled, hence this case should be considered by the caller * @return lastFilledPacket count of the latest packet. */ function getLastFilledPacket() external view returns (uint256 lastFilledPacket) { return _nextPacketCount == 0 ? 0 : _nextPacketCount - 1; } /** * @dev Rescues funds from the contract. * @param token_ The address of the token to rescue. * @param rescueTo_ The address of the user to rescue tokens for. * @param amount_ The amount of tokens to rescue. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyRole(RESCUE_ROLE) { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } } // File contracts/capacitors/SingleCapacitor.sol pragma solidity 0.8.19; /** * @title SingleCapacitor * @notice A capacitor that adds a single message to each packet. * @dev This contract inherits from the `BaseCapacitor` contract, which provides the * basic storage and common function implementations. */ contract SingleCapacitor is BaseCapacitor { // Error triggered when no new packet/message is there to be sealed error NoPendingPacket(); /** * @notice emitted when a new message is added to a packet * @param packedMessage the message packed with payload, fees and config * @param packetCount an incremental id assigned to each new packet created on this capacitor * @param newRootHash Hash of full packet. Same as packedMessage since this capacitor has one message per packet. */ event MessageAdded( bytes32 packedMessage, uint64 packetCount, bytes32 newRootHash ); /** * @dev Initializes the contract with the specified socket address. * @param socket_ The address of the socket contract. * @param owner_ The address of the owner of the capacitor contract. */ constructor( address socket_, address owner_ ) BaseCapacitor(socket_, owner_) {} /** * @inheritdoc ICapacitor */ function getMaxPacketLength() external pure override returns (uint256) { return 1; } /** * @inheritdoc ICapacitor */ function addPackedMessage( bytes32 packedMessage_ ) external override onlySocket { uint64 packetCount = _nextPacketCount++; _roots[packetCount] = packedMessage_; // as it is a single capacitor, here root and packed message are same emit MessageAdded(packedMessage_, packetCount, packedMessage_); } /** * @inheritdoc ICapacitor */ function sealPacket( uint256 ) external override onlySocket returns (bytes32, uint64) { uint64 packetCount = _nextSealCount++; if (_roots[packetCount] == bytes32(0)) revert NoPendingPacket(); bytes32 root = _roots[packetCount]; return (root, packetCount); } /** * @inheritdoc ICapacitor */ function getNextPacketToBeSealed() external view override returns (bytes32, uint64) { uint64 toSeal = _nextSealCount; return (_roots[toSeal], toSeal); } /** * @dev Returns the root hash of the packet with the specified count. * @param count_ The count of the packet. * @return The root hash of the packet. */ function getRootByCount( uint64 count_ ) external view override returns (bytes32) { return _roots[count_]; } } // 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/decapacitors/SingleDecapacitor.sol pragma solidity 0.8.19; /** * @title SingleDecapacitor * @notice A decapacitor that verifies messages by checking if the packed message is equal to the root. * @dev This contract inherits from the `IDecapacitor` interface, which * defines the functions for verifying message inclusion. */ contract SingleDecapacitor is IDecapacitor, AccessControl { /** * @notice Initializes the SingleDecapacitor contract with an owner address. * @param owner_ The address of the contract owner */ constructor(address owner_) AccessControl(owner_) { _grantRole(RESCUE_ROLE, owner_); } /** * @inheritdoc IDecapacitor * @dev Just checks if root equals packed message since each packet has single message. * @dev Proof is ignored in this capacitor. */ function verifyMessageInclusion( bytes32 root_, bytes32 packedMessage_, bytes calldata /* proof */ ) external pure override returns (bool isIncluded) { return root_ == packedMessage_; } /** * @notice Rescues funds from the contract if they are locked by mistake. * @param token_ The address of the token contract. * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyRole(RESCUE_ROLE) { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } } // 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/CapacitorFactory.sol pragma solidity 0.8.19; /** * @title CapacitorFactory * @notice Factory contract for creating capacitor and decapacitor pairs. * @dev The capacitorType_ parameter determines the type of capacitor and decapacitor to deploy. * @dev More types can be introduced by deploying new contract and pointing to it on Socket. */ contract CapacitorFactory is ICapacitorFactory, AccessControl { uint256 private constant SINGLE_CAPACITOR = 1; // min packet length to avoid div by 0 in fee calculations uint256 public constant minAllowedPacketLength = 1; // admin initialized max value for max packet length uint256 public immutable maxAllowedPacketLength; error PacketLengthNotAllowed(); /** * @notice initializes and grants RESCUE_ROLE to owner. * @param owner_ The address of the owner of the contract. * @param maxAllowedPacketLength_ The max length allowed for capacitors */ constructor( address owner_, uint256 maxAllowedPacketLength_ ) AccessControl(owner_) { _grantRole(RESCUE_ROLE, owner_); maxAllowedPacketLength = maxAllowedPacketLength_; } /** * @notice Creates a new capacitor and decapacitor pair based on the given type. * @dev It sets the CapacitorFactory owner as owner of new Capacitor and Decapacitor * @param capacitorType_ The type of capacitor to be created. Can be SINGLE_CAPACITOR or HASH_CHAIN_CAPACITOR. * @dev siblingChainSlug_ sibling chain slug can be used for chain specific capacitors, useful while expanding to non-EVM chains. * @param maxPacketLength_ is not being used with single capacitor system, will be useful with batching. */ function deploy( uint256 capacitorType_, uint32 /** siblingChainSlug_ */, uint256 maxPacketLength_ ) external override returns (ICapacitor, IDecapacitor) { if ( maxPacketLength_ < minAllowedPacketLength || maxPacketLength_ > maxAllowedPacketLength ) revert PacketLengthNotAllowed(); // fetch the capacitor factory owner address owner = this.owner(); if (capacitorType_ == SINGLE_CAPACITOR) { return ( // msg.sender is socket address new SingleCapacitor(msg.sender, owner), new SingleDecapacitor(owner) ); } revert InvalidCapacitorType(); } /** * @notice Rescues funds from the contract if they are locked by mistake. * @param token_ The address of the token contract. * @param rescueTo_ The address where rescued tokens need to be sent. * @param amount_ The amount of tokens to be rescued. */ function rescueFunds( address token_, address rescueTo_, uint256 amount_ ) external onlyRole(RESCUE_ROLE) { RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); } }
Compiler Settings
{"outputSelection":{"*":{"*":["*"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"owner_","internalType":"address"},{"type":"uint256","name":"maxAllowedPacketLength_","internalType":"uint256"}]},{"type":"error","name":"InvalidCapacitorType","inputs":[]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"NoPermit","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"PacketLengthNotAllowed","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":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"grantee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"revokee","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"contract ICapacitor"},{"type":"address","name":"","internalType":"contract IDecapacitor"}],"name":"deploy","inputs":[{"type":"uint256","name":"capacitorType_","internalType":"uint256"},{"type":"uint32","name":"","internalType":"uint32"},{"type":"uint256","name":"maxPacketLength_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"grantee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"address_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxAllowedPacketLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minAllowedPacketLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nominateOwner","inputs":[{"type":"address","name":"nominee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nominee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueFunds","inputs":[{"type":"address","name":"token_","internalType":"address"},{"type":"address","name":"rescueTo_","internalType":"address"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"revokee_","internalType":"address"}]}]
Contract Creation Code
0x60a060405234801561001057600080fd5b506040516126b73803806126b783398101604081905261002f9161011e565b818061003a81610070565b5061006790507fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f29253836100c3565b60805250610158565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000806040838503121561013157600080fd5b82516001600160a01b038116811461014857600080fd5b6020939093015192949293505050565b60805161253d61017a600039600081816102040152610235015261253d6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636ccae05411610081578063d547741f1161005b578063d547741f146101d6578063d6a47312146101e9578063f4ca9b24146101ff57600080fd5b80636ccae054146101825780638da5cb5b1461019557806391d14854146101b357600080fd5b80632f2ff15d116100b25780632f2ff15d146101525780633bd1adec146101675780635b94db271461016f57600080fd5b806320f99c0a146100ce578063284fb36314610112575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610125610120366004610a6b565b610226565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610109565b610165610160366004610ad1565b6103e3565b005b610165610442565b61016561017d366004610b01565b61049e565b610165610190366004610b1e565b61055e565b60005473ffffffffffffffffffffffffffffffffffffffff166100e8565b6101c66101c1366004610ad1565b610601565b6040519015158152602001610109565b6101656101e4366004610ad1565b61063c565b6101f1600181565b604051908152602001610109565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b600080600183108061025757507f000000000000000000000000000000000000000000000000000000000000000083115b1561028e576040517f83d360ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610b4e565b9050600186036103a957338160405161031790610a51565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f080158015610357573d6000803e3d6000fd5b508160405161036590610a5e565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561039e573d6000803e3d6000fd5b5092509250506103db565b6040517f3935408900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610434576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61043e8282610697565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610493576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049c3361071d565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104ef576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166105f0576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6105fb848484610795565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461068d576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61043e828261088a565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff82166107e2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161082e57610829828261090d565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361087f576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610829838383610982565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af1905080610829576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016105e7565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806105fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016105e7565b610edb80610b6c83390190565b610ac180611a4783390190565b600080600060608486031215610a8057600080fd5b83359250602084013563ffffffff81168114610a9b57600080fd5b929592945050506040919091013590565b73ffffffffffffffffffffffffffffffffffffffff81168114610ace57600080fd5b50565b60008060408385031215610ae457600080fd5b823591506020830135610af681610aac565b809150509250929050565b600060208284031215610b1357600080fd5b813561063581610aac565b600080600060608486031215610b3357600080fd5b8335610b3e81610aac565b92506020840135610a9b81610aac565b600060208284031215610b6057600080fd5b815161063581610aac56fe60a060405234801561001057600080fd5b50604051610edb380380610edb83398101604081905261002f91610148565b8181808061003c8161007e565b50506001600160a01b0382166080526100757fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f29253826100d1565b5050505061017b565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b80516001600160a01b038116811461014357600080fd5b919050565b6000806040838503121561015b57600080fd5b6101648361012c565b91506101726020840161012c565b90509250929050565b608051610d376101a4600039600081816101430152818161056301526106cb0152610d376000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80636ccae054116100975780639471651e116100665780639471651e14610215578063d1af313c1461025d578063d547741f14610287578063d7c9eaac1461029a57600080fd5b80636ccae054146101ae5780638da5cb5b146101c157806391d14854146101df578063920ee8a81461020257600080fd5b80632ff9f2c9116100d35780632ff9f2c91461017a5780633bd1adec1461018b5780635b94db27146101935780636afc0f38146101a657600080fd5b806320f99c0a146100fa57806322c8f6cd1461013e5780632f2ff15d14610165575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101147f000000000000000000000000000000000000000000000000000000000000000081565b610178610173366004610bbd565b6102ad565b005b60015b604051908152602001610135565b61017861030c565b6101786101a1366004610be9565b610368565b61017d610428565b6101786101bc366004610c04565b61046d565b60005473ffffffffffffffffffffffffffffffffffffffff16610114565b6101f26101ed366004610bbd565b610510565b6040519015158152602001610135565b610178610210366004610c40565b61054b565b60035468010000000000000000900467ffffffffffffffff16600081815260046020526040902054905b6040805192835267ffffffffffffffff909116602083015201610135565b61017d61026b366004610c59565b67ffffffffffffffff1660009081526004602052604090205490565b610178610295366004610bbd565b610655565b61023f6102a8366004610c40565b6106b0565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102fe576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030882826107da565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461035d576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61036633610860565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103b9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b60035460009067ffffffffffffffff161561045b576003546104569060019067ffffffffffffffff16610cb2565b61045e565b60005b67ffffffffffffffff16905090565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166104ff576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b61050a8484846108d8565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105ba576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805460009167ffffffffffffffff90911690826105d883610cda565b82546101009290920a67ffffffffffffffff818102199093169183160217909155811660008181526004602090815260409182902086905581518681529081019290925281018490529091507f9ed9683bfff0f737f91f20945e98c912976d94e76860b05b48b15bc0d589be1f9060600160405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106a6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030882826109cd565b6000803373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610722576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546000916801000000000000000090910467ffffffffffffffff1690600861074c83610cda565b82546101009290920a67ffffffffffffffff81810219909316918316021790915581166000908152600460205260409020549091506107b7576040517fa902392300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526004602052604090205492509050915091565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff8216610925576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016109715761096c8282610a50565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b6000036109c2576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61096c838383610ac5565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af190508061096c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016104f6565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016104f6565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bb857600080fd5b919050565b60008060408385031215610bd057600080fd5b82359150610be060208401610b94565b90509250929050565b600060208284031215610bfb57600080fd5b61054482610b94565b600080600060608486031215610c1957600080fd5b610c2284610b94565b9250610c3060208501610b94565b9150604084013590509250925092565b600060208284031215610c5257600080fd5b5035919050565b600060208284031215610c6b57600080fd5b813567ffffffffffffffff8116811461054457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff828116828216039080821115610cd357610cd3610c83565b5092915050565b600067ffffffffffffffff808316818103610cf757610cf7610c83565b600101939250505056fea26469706673582212204cb05dc3b3ddf0cdb1ee482aee5d1adcd7c91129c89540c1d8e044cdc99ded4964736f6c63430008130033608060405234801561001057600080fd5b50604051610ac1380380610ac183398101604081905261002f9161011b565b808061003a8161006d565b5061006790507fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f29253826100c0565b5061014b565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b60006020828403121561012d57600080fd5b81516001600160a01b038116811461014457600080fd5b9392505050565b6109678061015a6000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80635b94db27116100765780638da5cb5b1161005b5780638da5cb5b1461015357806391d1485414610171578063d547741f1461018457600080fd5b80635b94db271461012d5780636ccae0541461014057600080fd5b806320f99c0a146100a85780632d095c43146100ec5780632f2ff15d146101105780633bd1adec14610125575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101006100fa366004610805565b50501490565b60405190151581526020016100e3565b61012361011e3660046108ae565b610197565b005b6101236101f6565b61012361013b3660046108da565b610252565b61012361014e3660046108f5565b610312565b60005473ffffffffffffffffffffffffffffffffffffffff166100c2565b61010061017f3660046108ae565b6103b5565b6101236101923660046108ae565b6103f0565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101e8576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101f2828261044b565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610247576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610250336104d1565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102a3576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166103a4576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6103af848484610549565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610441576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101f2828261063e565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff8216610596576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016105e2576105dd82826106c1565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003610633576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105dd838383610736565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af19050806105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c454400000000000000000000000000604482015260640161039b565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806103af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c45440000000000000000000000000000000000604482015260640161039b565b6000806000806060858703121561081b57600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561084157600080fd5b818701915087601f83011261085557600080fd5b81358181111561086457600080fd5b88602082850101111561087657600080fd5b95989497505060200194505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108a957600080fd5b919050565b600080604083850312156108c157600080fd5b823591506108d160208401610885565b90509250929050565b6000602082840312156108ec57600080fd5b6103e982610885565b60008060006060848603121561090a57600080fd5b61091384610885565b925061092160208501610885565b915060408401359050925092509256fea2646970667358221220213393201a839e85462db2d8f36617da0862b897b420ebe6e304d47f19fac99164736f6c63430008130033a26469706673582212203a60fe1018c7f85e79b4b7fe7a880e59ee094b90af0fc5a49d25a05b6017e7a864736f6c6343000813003300000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c000000000000000000000000000000000000000000000000000000000000000a
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80636ccae05411610081578063d547741f1161005b578063d547741f146101d6578063d6a47312146101e9578063f4ca9b24146101ff57600080fd5b80636ccae054146101825780638da5cb5b1461019557806391d14854146101b357600080fd5b80632f2ff15d116100b25780632f2ff15d146101525780633bd1adec146101675780635b94db271461016f57600080fd5b806320f99c0a146100ce578063284fb36314610112575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610125610120366004610a6b565b610226565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610109565b610165610160366004610ad1565b6103e3565b005b610165610442565b61016561017d366004610b01565b61049e565b610165610190366004610b1e565b61055e565b60005473ffffffffffffffffffffffffffffffffffffffff166100e8565b6101c66101c1366004610ad1565b610601565b6040519015158152602001610109565b6101656101e4366004610ad1565b61063c565b6101f1600181565b604051908152602001610109565b6101f17f000000000000000000000000000000000000000000000000000000000000000a81565b600080600183108061025757507f000000000000000000000000000000000000000000000000000000000000000a83115b1561028e576040517f83d360ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610b4e565b9050600186036103a957338160405161031790610a51565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f080158015610357573d6000803e3d6000fd5b508160405161036590610a5e565b73ffffffffffffffffffffffffffffffffffffffff9091168152602001604051809103906000f08015801561039e573d6000803e3d6000fd5b5092509250506103db565b6040517f3935408900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610434576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61043e8282610697565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610493576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049c3361071d565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104ef576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166105f0576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6105fb848484610795565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461068d576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61043e828261088a565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff82166107e2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161082e57610829828261090d565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b60000361087f576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610829838383610982565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af1905080610829576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016105e7565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806105fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016105e7565b610edb80610b6c83390190565b610ac180611a4783390190565b600080600060608486031215610a8057600080fd5b83359250602084013563ffffffff81168114610a9b57600080fd5b929592945050506040919091013590565b73ffffffffffffffffffffffffffffffffffffffff81168114610ace57600080fd5b50565b60008060408385031215610ae457600080fd5b823591506020830135610af681610aac565b809150509250929050565b600060208284031215610b1357600080fd5b813561063581610aac565b600080600060608486031215610b3357600080fd5b8335610b3e81610aac565b92506020840135610a9b81610aac565b600060208284031215610b6057600080fd5b815161063581610aac56fe60a060405234801561001057600080fd5b50604051610edb380380610edb83398101604081905261002f91610148565b8181808061003c8161007e565b50506001600160a01b0382166080526100757fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f29253826100d1565b5050505061017b565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b80516001600160a01b038116811461014357600080fd5b919050565b6000806040838503121561015b57600080fd5b6101648361012c565b91506101726020840161012c565b90509250929050565b608051610d376101a4600039600081816101430152818161056301526106cb0152610d376000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80636ccae054116100975780639471651e116100665780639471651e14610215578063d1af313c1461025d578063d547741f14610287578063d7c9eaac1461029a57600080fd5b80636ccae054146101ae5780638da5cb5b146101c157806391d14854146101df578063920ee8a81461020257600080fd5b80632ff9f2c9116100d35780632ff9f2c91461017a5780633bd1adec1461018b5780635b94db27146101935780636afc0f38146101a657600080fd5b806320f99c0a146100fa57806322c8f6cd1461013e5780632f2ff15d14610165575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101147f000000000000000000000000000000000000000000000000000000000000000081565b610178610173366004610bbd565b6102ad565b005b60015b604051908152602001610135565b61017861030c565b6101786101a1366004610be9565b610368565b61017d610428565b6101786101bc366004610c04565b61046d565b60005473ffffffffffffffffffffffffffffffffffffffff16610114565b6101f26101ed366004610bbd565b610510565b6040519015158152602001610135565b610178610210366004610c40565b61054b565b60035468010000000000000000900467ffffffffffffffff16600081815260046020526040902054905b6040805192835267ffffffffffffffff909116602083015201610135565b61017d61026b366004610c59565b67ffffffffffffffff1660009081526004602052604090205490565b610178610295366004610bbd565b610655565b61023f6102a8366004610c40565b6106b0565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102fe576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030882826107da565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461035d576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61036633610860565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103b9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b60035460009067ffffffffffffffff161561045b576003546104569060019067ffffffffffffffff16610cb2565b61045e565b60005b67ffffffffffffffff16905090565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166104ff576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b61050a8484846108d8565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105ba576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805460009167ffffffffffffffff90911690826105d883610cda565b82546101009290920a67ffffffffffffffff818102199093169183160217909155811660008181526004602090815260409182902086905581518681529081019290925281018490529091507f9ed9683bfff0f737f91f20945e98c912976d94e76860b05b48b15bc0d589be1f9060600160405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106a6576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030882826109cd565b6000803373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610722576040517f503284dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546000916801000000000000000090910467ffffffffffffffff1690600861074c83610cda565b82546101009290920a67ffffffffffffffff81810219909316918316021790915581166000908152600460205260409020549091506107b7576040517fa902392300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526004602052604090205492509050915091565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff8216610925576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016109715761096c8282610a50565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b6000036109c2576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61096c838383610ac5565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af190508061096c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016104f6565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061050a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016104f6565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bb857600080fd5b919050565b60008060408385031215610bd057600080fd5b82359150610be060208401610b94565b90509250929050565b600060208284031215610bfb57600080fd5b61054482610b94565b600080600060608486031215610c1957600080fd5b610c2284610b94565b9250610c3060208501610b94565b9150604084013590509250925092565b600060208284031215610c5257600080fd5b5035919050565b600060208284031215610c6b57600080fd5b813567ffffffffffffffff8116811461054457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff828116828216039080821115610cd357610cd3610c83565b5092915050565b600067ffffffffffffffff808316818103610cf757610cf7610c83565b600101939250505056fea26469706673582212204cb05dc3b3ddf0cdb1ee482aee5d1adcd7c91129c89540c1d8e044cdc99ded4964736f6c63430008130033608060405234801561001057600080fd5b50604051610ac1380380610ac183398101604081905261002f9161011b565b808061003a8161006d565b5061006790507fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f29253826100c0565b5061014b565b600080546001600160a01b0383166001600160a01b0319918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b60008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b60006020828403121561012d57600080fd5b81516001600160a01b038116811461014457600080fd5b9392505050565b6109678061015a6000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80635b94db27116100765780638da5cb5b1161005b5780638da5cb5b1461015357806391d1485414610171578063d547741f1461018457600080fd5b80635b94db271461012d5780636ccae0541461014057600080fd5b806320f99c0a146100a85780632d095c43146100ec5780632f2ff15d146101105780633bd1adec14610125575b600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101006100fa366004610805565b50501490565b60405190151581526020016100e3565b61012361011e3660046108ae565b610197565b005b6101236101f6565b61012361013b3660046108da565b610252565b61012361014e3660046108f5565b610312565b60005473ffffffffffffffffffffffffffffffffffffffff166100c2565b61010061017f3660046108ae565b6103b5565b6101236101923660046108ae565b6103f0565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101e8576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101f2828261044b565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610247576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610250336104d1565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102a3576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f4933f7bec34ee32db93e9f5cd7e0519781b395282211f4f6857489046ea38f7660205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff166103a4576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6103af848484610549565b50505050565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610441576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101f2828261063e565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216811783556001805490921690915560405190917ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8791a250565b73ffffffffffffffffffffffffffffffffffffffff8216610596576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016105e2576105dd82826106c1565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003610633576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105dd838383610736565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af19050806105dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c454400000000000000000000000000604482015260640161039b565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806103af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c45440000000000000000000000000000000000604482015260640161039b565b6000806000806060858703121561081b57600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561084157600080fd5b818701915087601f83011261085557600080fd5b81358181111561086457600080fd5b88602082850101111561087657600080fd5b95989497505060200194505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108a957600080fd5b919050565b600080604083850312156108c157600080fd5b823591506108d160208401610885565b90509250929050565b6000602082840312156108ec57600080fd5b6103e982610885565b60008060006060848603121561090a57600080fd5b61091384610885565b925061092160208501610885565b915060408401359050925092509256fea2646970667358221220213393201a839e85462db2d8f36617da0862b897b420ebe6e304d47f19fac99164736f6c63430008130033a26469706673582212203a60fe1018c7f85e79b4b7fe7a880e59ee094b90af0fc5a49d25a05b6017e7a864736f6c63430008130033