Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
18185633 | 503 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Cooler
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 10 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol"; import {ERC20} from "solmate/tokens/ERC20.sol"; import {Clone} from "clones/Clone.sol"; // Function sig taken from gOHM contract interface IDelegate { function delegate(address to_) external; } import {CoolerFactory} from "./CoolerFactory.sol"; import {CoolerCallback} from "./CoolerCallback.sol"; /// @title Cooler Loans. /// @notice A Cooler is a smart contract escrow that facilitates fixed-duration, peer-to-peer /// loans for a user-defined debt-collateral pair. /// @dev This contract uses Clones (https://github.com/wighawag/clones-with-immutable-args) /// to save gas on deployment. contract Cooler is Clone { using SafeTransferLib for ERC20; // --- ERRORS ---------------------------------------------------- error OnlyApproved(); error Deactivated(); error Default(); error NotExpired(); error NotCoolerCallback(); // --- DATA STRUCTURES ------------------------------------------- /// @notice A loan begins with a borrow request. struct Request { uint256 amount; // Amount to be borrowed. uint256 interest; // Annualized percentage to be paid as interest. uint256 loanToCollateral; // Requested loan-to-collateral ratio. uint256 duration; // Time to repay the loan before it defaults. bool active; // Any lender can clear an active loan request. address requester; // The address that created the request. } /// @notice A request is converted to a loan when a lender clears it. struct Loan { Request request; // Loan terms specified in the request. uint256 principal; // Amount of principal debt owed to the lender. uint256 interestDue; // Interest owed to the lender. uint256 collateral; // Amount of collateral pledged. uint256 expiry; // Time when the loan defaults. address lender; // Lender's address. address recipient; // Recipient of repayments. bool callback; // If this is true, the lender must inherit CoolerCallback. } // --- IMMUTABLES ------------------------------------------------ // This makes the code look prettier. uint256 private constant DECIMALS_INTEREST = 1e18; /// @notice This address owns the collateral in escrow. function owner() public pure returns (address _owner) { return _getArgAddress(0x0); } /// @notice This token is borrowed against. function collateral() public pure returns (ERC20 _collateral) { return ERC20(_getArgAddress(0x14)); } /// @notice This token is lent. function debt() public pure returns (ERC20 _debt) { return ERC20(_getArgAddress(0x28)); } /// @notice This contract created the Cooler function factory() public pure returns (CoolerFactory _factory) { return CoolerFactory(_getArgAddress(0x3c)); } // --- STATE VARIABLES ------------------------------------------- /// @notice Arrays stores all the loan requests. Request[] public requests; /// @notice Arrays stores all the granted loans. Loan[] public loans; /// @notice Facilitates transfer of lender ownership to new addresses mapping(uint256 => address) public approvals; // --- BORROWER -------------------------------------------------- /// @notice Request a loan with given parameters. /// Collateral is taken at time of request. /// @param amount_ of debt tokens to borrow. /// @param interest_ to pay (annualized % of 'amount_'). Expressed in DECIMALS_INTEREST. /// @param loanToCollateral_ debt tokens per collateral token pledged. Expressed in 10**collateral().decimals(). /// @param duration_ of loan tenure in seconds. /// @return reqID of the created request. Equivalent to the index of request in requests[]. function requestLoan( uint256 amount_, uint256 interest_, uint256 loanToCollateral_, uint256 duration_ ) external returns (uint256 reqID) { reqID = requests.length; requests.push( Request({ amount: amount_, interest: interest_, loanToCollateral: loanToCollateral_, duration: duration_, active: true, requester: msg.sender }) ); // The collateral is taken upfront. Will be escrowed // until the loan is repaid or defaulted. collateral().safeTransferFrom( msg.sender, address(this), collateralFor(amount_, loanToCollateral_) ); // Log the event. factory().logRequestLoan(reqID); } /// @notice Cancel a loan request and get the collateral back. /// @param reqID_ index of request in requests[]. function rescindRequest(uint256 reqID_) external { if (msg.sender != owner()) revert OnlyApproved(); Request storage req = requests[reqID_]; if (!req.active) revert Deactivated(); // Update storage and send collateral back to the owner. req.active = false; collateral().safeTransfer(owner(), collateralFor(req.amount, req.loanToCollateral)); // Log the event. factory().logRescindRequest(reqID_); } /// @notice Repay a loan to get the collateral back. /// @dev Despite a malicious lender could reenter with the callback, the /// usage of `msg.sender` prevents any economical benefit to the /// attacker, since they would be repaying the loan themselves. /// @param loanID_ index of loan in loans[]. /// @param repayment_ debt tokens to be repaid. /// @return collateral given back to the borrower. function repayLoan(uint256 loanID_, uint256 repayment_) external returns (uint256) { Loan memory loan = loans[loanID_]; if (block.timestamp > loan.expiry) revert Default(); // Cap the repayment to the total debt of the loan uint256 totalDebt = loan.principal + loan.interestDue; if (repayment_ > totalDebt) repayment_ = totalDebt; // Need to repay interest first, then any extra goes to paying down principal. uint256 interestPaid; uint256 remainder; if (repayment_ >= loan.interestDue) { remainder = repayment_ - loan.interestDue; interestPaid = loan.interestDue; loan.interestDue = 0; } else { loan.interestDue -= repayment_; interestPaid = repayment_; } // We pay back only if user has paid back principal. This can be 0. uint256 decollateralized; if (remainder > 0) { decollateralized = (loan.collateral * remainder) / loan.principal; loan.principal -= remainder; loan.collateral -= decollateralized; } // Save updated loan info in storage. loans[loanID_] = loan; // Transfer repaid debt back to the lender and collateral back to the owner if applicable debt().safeTransferFrom(msg.sender, loan.recipient, repayment_); if (decollateralized > 0) collateral().safeTransfer(owner(), decollateralized); // Log the event. factory().logRepayLoan(loanID_, repayment_); // If necessary, trigger lender callback. if (loan.callback) CoolerCallback(loan.lender).onRepay(loanID_, remainder, interestPaid); return decollateralized; } /// @notice Delegate voting power on collateral. /// @param to_ address to delegate. function delegateVoting(address to_) external { if (msg.sender != owner()) revert OnlyApproved(); IDelegate(address(collateral())).delegate(to_); } // --- LENDER ---------------------------------------------------- /// @notice Fill a requested loan as a lender. /// @param reqID_ index of request in requests[]. /// @param recipient_ address to repay the loan to. /// @param isCallback_ true if the lender implements the CoolerCallback abstract. False otherwise. /// @return loanID of the granted loan. Equivalent to the index of loan in loans[]. function clearRequest( uint256 reqID_, address recipient_, bool isCallback_ ) external returns (uint256 loanID) { Request memory req = requests[reqID_]; // Loan callbacks are only allowed if: // 1. The loan request has been created via a trusted lender. // 2. The lender signals that it implements the CoolerCallback Abstract. bool callback = (isCallback_ && msg.sender == req.requester); // If necessary, ensure lender implements the CoolerCallback abstract. if (callback && !CoolerCallback(msg.sender).isCoolerCallback()) revert NotCoolerCallback(); // Ensure loan request is active. if (!req.active) revert Deactivated(); // Clear the loan request in memory. req.active = false; // Calculate and store loan terms. uint256 interest = interestFor(req.amount, req.interest, req.duration); uint256 collat = collateralFor(req.amount, req.loanToCollateral); loanID = loans.length; loans.push( Loan({ request: req, principal: req.amount, interestDue: interest, collateral: collat, expiry: block.timestamp + req.duration, lender: msg.sender, recipient: recipient_, callback: callback }) ); // Clear the loan request storage. requests[reqID_].active = false; // Transfer debt tokens to the owner of the request. debt().safeTransferFrom(msg.sender, owner(), req.amount); // Log the event. factory().logClearRequest(reqID_, loanID); } /// @notice Allow lender to extend a loan for the borrower. Doesn't require /// borrower permission because it doesn't have a negative impact for them. /// @dev Since this function solely impacts the expiration day, the lender /// should ensure that extension interest payments are done beforehand. /// @param loanID_ index of loan in loans[]. /// @param times_ that the fixed-term loan duration is extended. function extendLoanTerms(uint256 loanID_, uint8 times_) external { Loan memory loan = loans[loanID_]; if (msg.sender != loan.lender) revert OnlyApproved(); if (block.timestamp > loan.expiry) revert Default(); // Update loan terms to reflect the extension. loan.expiry += loan.request.duration * times_; // Save updated loan info in storage. loans[loanID_] = loan; // Log the event. factory().logExtendLoan(loanID_, times_); } /// @notice Claim collateral upon loan default. /// @param loanID_ index of loan in loans[]. /// @return defaulted debt by the borrower, collateral kept by the lender, elapsed time since expiry. function claimDefaulted(uint256 loanID_) external returns (uint256, uint256, uint256, uint256) { Loan memory loan = loans[loanID_]; if (block.timestamp <= loan.expiry) revert NotExpired(); loans[loanID_].principal = 0; loans[loanID_].interestDue = 0; loans[loanID_].collateral = 0; // Transfer defaulted collateral to the lender. collateral().safeTransfer(loan.lender, loan.collateral); // Log the event. factory().logDefaultLoan(loanID_, loan.collateral); // If necessary, trigger lender callback. if (loan.callback) CoolerCallback(loan.lender).onDefault( loanID_, loan.principal, loan.interestDue, loan.collateral ); return (loan.principal, loan.interestDue, loan.collateral, block.timestamp - loan.expiry); } /// @notice Approve transfer of loan ownership rights to a new address. /// @param to_ address to be approved. /// @param loanID_ index of loan in loans[]. function approveTransfer(address to_, uint256 loanID_) external { if (msg.sender != loans[loanID_].lender) revert OnlyApproved(); // Update transfer approvals. approvals[loanID_] = to_; } /// @notice Execute loan ownership transfer. Must be previously approved by the lender. /// @param loanID_ index of loan in loans[]. function transferOwnership(uint256 loanID_) external { if (msg.sender != approvals[loanID_]) revert OnlyApproved(); // Update the load lender and the recipient. loans[loanID_].lender = msg.sender; loans[loanID_].recipient = msg.sender; // Callbacks are disabled when transferring ownership. loans[loanID_].callback = false; // Clear transfer approvals. approvals[loanID_] = address(0); } /// @notice Allow lender to set repayment recipient of a given loan. /// @param loanID_ of lender's loan. /// @param recipient_ reciever of repayments function setRepaymentAddress(uint256 loanID_, address recipient_) external { if (msg.sender != loans[loanID_].lender) revert OnlyApproved(); // Update the repayment method. loans[loanID_].recipient = recipient_; } // --- AUX FUNCTIONS --------------------------------------------- /// @notice Compute collateral needed for a desired loan amount at given loan to collateral ratio. /// @param principal_ amount of debt tokens. /// @param loanToCollateral_ ratio for loan. Expressed in 10**collateral().decimals(). function collateralFor( uint256 principal_, uint256 loanToCollateral_ ) public view returns (uint256) { return (principal_ * (10 ** collateral().decimals())) / loanToCollateral_; } /// @notice Compute interest cost on amount for duration at given annualized rate. /// @param principal_ amount of debt tokens. /// @param rate_ of interest (annualized). /// @param duration_ of the loan in seconds. /// @return Interest in debt token terms. function interestFor( uint256 principal_, uint256 rate_, uint256 duration_ ) public pure returns (uint256) { uint256 interest = (rate_ * duration_) / 365 days; return (principal_ * interest) / DECIMALS_INTEREST; } /// @notice Check if given loan has expired. /// @param loanID_ index of loan in loans[]. /// @return Expiration status. function hasExpired(uint256 loanID_) external view returns (bool) { return block.timestamp > loans[loanID_].expiry; } /// @notice Check if a given request is active. /// @param reqID_ index of request in requests[]. /// @return Active status. function isActive(uint256 reqID_) external view returns (bool) { return requests[reqID_].active; } /// @notice Getter for Request data as a struct. /// @param reqID_ index of request in requests[]. /// @return Request struct. function getRequest(uint256 reqID_) external view returns (Request memory) { return requests[reqID_]; } /// @notice Getter for Loan data as a struct. /// @param loanID_ index of loan in loans[]. /// @return Loan struct. function getLoan(uint256 loanID_) external view returns (Loan memory) { return loans[loanID_]; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @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"); } }
// SPDX-License-Identifier: AGPL-3.0-only 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); } }
// SPDX-License-Identifier: BSD pragma solidity ^0.8.4; /// @title Clone /// @author zefram.eth /// @notice Provides helper functions for reading immutable args from calldata contract Clone { /// @notice Reads an immutable arg with type address /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint256 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads an immutable arg with type uint64 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint8 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata function _getImmutableArgsOffset() internal pure returns (uint256 offset) { // solhint-disable-next-line no-inline-assembly assembly { offset := sub( calldatasize(), add(shr(240, calldataload(sub(calldatasize(), 2))), 2) ) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import {ClonesWithImmutableArgs} from "clones/ClonesWithImmutableArgs.sol"; import {Cooler} from "./Cooler.sol"; /// @title Cooler Loans Factory. /// @notice The Cooler Factory creates new Cooler escrow contracts. /// @dev This contract uses Clones (https://github.com/wighawag/clones-with-immutable-args) /// to save gas on deployment. contract CoolerFactory { using ClonesWithImmutableArgs for address; // --- ERRORS ---------------------------------------------------- error NotFromFactory(); error DecimalsNot18(); // --- EVENTS ---------------------------------------------------- /// @notice A global event when a new loan request is created. event RequestLoan(address indexed cooler, address collateral, address debt, uint256 reqID); /// @notice A global event when a loan request is rescinded. event RescindRequest(address indexed cooler, uint256 reqID); /// @notice A global event when a loan request is fulfilled. event ClearRequest(address indexed cooler, uint256 reqID, uint256 loanID); /// @notice A global event when a loan is repaid. event RepayLoan(address indexed cooler, uint256 loanID, uint256 amount); /// @notice A global event when a loan is extended. event ExtendLoan(address indexed cooler, uint256 loanID, uint8 times); /// @notice A global event when the collateral of defaulted loan is claimed. event DefaultLoan(address indexed cooler, uint256 loanID, uint256 amount); // -- STATE VARIABLES -------------------------------------------- /// @notice Cooler reference implementation (deployed on creation to clone from). Cooler public immutable coolerImplementation; /// @notice Mapping to validate deployed coolers. mapping(address => bool) public created; /// @notice Mapping to prevent duplicate coolers. mapping(address => mapping(ERC20 => mapping(ERC20 => address))) private coolerFor; /// @notice Mapping to query Coolers for Collateral-Debt pair. mapping(ERC20 => mapping(ERC20 => address[])) public coolersFor; // --- INITIALIZATION -------------------------------------------- constructor() { coolerImplementation = new Cooler(); } // --- DEPLOY NEW COOLERS ---------------------------------------- /// @notice creates a new Escrow contract for collateral and debt tokens. /// @param collateral_ the token given as collateral. /// @param debt_ the token to be lent. Interest is denominated in debt tokens. /// @return cooler address of the contract. function generateCooler(ERC20 collateral_, ERC20 debt_) external returns (address cooler) { // Return address if cooler exists. cooler = coolerFor[msg.sender][collateral_][debt_]; // Otherwise generate new cooler. if (cooler == address(0)) { if (collateral_.decimals() != 18 || debt_.decimals() != 18) revert DecimalsNot18(); // Clone the cooler implementation. bytes memory coolerData = abi.encodePacked( msg.sender, // owner address(collateral_), // collateral address(debt_), // debt address(this) // factory ); cooler = address(coolerImplementation).clone(coolerData); // Update storage accordingly. coolerFor[msg.sender][collateral_][debt_] = cooler; coolersFor[collateral_][debt_].push(cooler); created[cooler] = true; } } // --- EMIT EVENTS ----------------------------------------------- /// @notice Ensure that the called is a Cooler. modifier onlyFromFactory { if (!created[msg.sender]) revert NotFromFactory(); _; } /// @notice Emit a global event when a new loan request is created. function logRequestLoan(uint256 reqID_) external onlyFromFactory { emit RequestLoan(msg.sender, address(Cooler(msg.sender).collateral()), address(Cooler(msg.sender).debt()), reqID_); } /// @notice Emit a global event when a loan request is rescinded. function logRescindRequest(uint256 reqID_) external onlyFromFactory { emit RescindRequest(msg.sender, reqID_); } /// @notice Emit a global event when a loan request is fulfilled. function logClearRequest(uint256 reqID_, uint256 loanID_) external onlyFromFactory { emit ClearRequest(msg.sender, reqID_, loanID_); } /// @notice Emit a global event when a loan is repaid. function logRepayLoan(uint256 loanID_, uint256 repayment_) external onlyFromFactory { emit RepayLoan(msg.sender, loanID_, repayment_); } /// @notice Emit a global event when a loan is extended. function logExtendLoan(uint256 loanID_, uint8 times_) external onlyFromFactory { emit ExtendLoan(msg.sender, loanID_, times_); } /// @notice Emit a global event when the collateral of defaulted loan is claimed. function logDefaultLoan(uint256 loanID_, uint256 collateral_) external onlyFromFactory { emit DefaultLoan(msg.sender, loanID_, collateral_); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {CoolerFactory} from "./CoolerFactory.sol"; /// @notice Allows for debt issuers to execute logic when a loan is repaid, rolled, or defaulted. /// @dev The three callback functions must be implemented if `isCoolerCallback()` is set to true. abstract contract CoolerCallback { // --- ERRORS ---------------------------------------------------- error OnlyFromFactory(); // --- INITIALIZATION -------------------------------------------- CoolerFactory public immutable factory; constructor(address coolerFactory_) { factory = CoolerFactory(coolerFactory_); } // --- EXTERNAL FUNCTIONS ------------------------------------------------ /// @notice Informs to Cooler that this contract can handle its callbacks. function isCoolerCallback() external pure returns (bool) { return true; } /// @notice Callback function that handles repayments. function onRepay(uint256 loanID_, uint256 principlePaid_, uint256 interestPaid_) external { if (!factory.created(msg.sender)) revert OnlyFromFactory(); _onRepay(loanID_, principlePaid_, interestPaid_); } /// @notice Callback function that handles defaults. function onDefault( uint256 loanID_, uint256 principle, uint256 interest, uint256 collateral ) external { if (!factory.created(msg.sender)) revert OnlyFromFactory(); _onDefault(loanID_, principle, interest, collateral); } // --- INTERNAL FUNCTIONS ------------------------------------------------ /// @notice Callback function that handles repayments. Override for custom logic. function _onRepay( uint256 loanID_, uint256 principlePaid_, uint256 interestPaid_ ) internal virtual; /// @notice Callback function that handles defaults. function _onDefault( uint256 loanID_, uint256 principle_, uint256 interestDue_, uint256 collateral ) internal virtual; }
// SPDX-License-Identifier: BSD pragma solidity ^0.8.4; /// @title ClonesWithImmutableArgs /// @author wighawag, zefram.eth /// @notice Enables creating clone contracts with immutable args library ClonesWithImmutableArgs { error CreateFail(); /// @notice Creates a clone proxy of the implementation contract, with immutable args /// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length /// @param implementation The implementation contract to clone /// @param data Encoded immutable args /// @return instance The address of the created clone function clone(address implementation, bytes memory data) internal returns (address instance) { // unrealistic for memory ptr or data length to exceed 256 bits unchecked { uint256 extraLength = data.length + 2; // +2 bytes for telling how much data there is appended to the call uint256 creationSize = 0x43 + extraLength; uint256 runSize = creationSize - 11; uint256 dataPtr; uint256 ptr; // solhint-disable-next-line no-inline-assembly assembly { ptr := mload(0x40) // ------------------------------------------------------------------------------------------------------------- // CREATION (11 bytes) // ------------------------------------------------------------------------------------------------------------- // 3d | RETURNDATASIZE | 0 | – // 61 runtime | PUSH2 runtime (r) | r 0 | – mstore( ptr, 0x3d61000000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x02), shl(240, runSize)) // size of the contract running bytecode (16 bits) // creation size = 0b // 80 | DUP1 | r r 0 | – // 60 creation | PUSH1 creation (c) | c r r 0 | – // 3d | RETURNDATASIZE | 0 c r r 0 | – // 39 | CODECOPY | r 0 | [0-2d]: runtime code // 81 | DUP2 | 0 c 0 | [0-2d]: runtime code // f3 | RETURN | 0 | [0-2d]: runtime code mstore( add(ptr, 0x04), 0x80600b3d3981f300000000000000000000000000000000000000000000000000 ) // ------------------------------------------------------------------------------------------------------------- // RUNTIME // ------------------------------------------------------------------------------------------------------------- // 36 | CALLDATASIZE | cds | – // 3d | RETURNDATASIZE | 0 cds | – // 3d | RETURNDATASIZE | 0 0 cds | – // 37 | CALLDATACOPY | – | [0, cds] = calldata // 61 | PUSH2 extra | extra | [0, cds] = calldata mstore( add(ptr, 0x0b), 0x363d3d3761000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x10), shl(240, extraLength)) // 60 0x38 | PUSH1 0x38 | 0x38 extra | [0, cds] = calldata // 0x38 (56) is runtime size - data // 36 | CALLDATASIZE | cds 0x38 extra | [0, cds] = calldata // 39 | CODECOPY | _ | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 0 0 | [0, cds] = calldata // 36 | CALLDATASIZE | cds 0 0 0 | [0, cds] = calldata // 61 extra | PUSH2 extra | extra cds 0 0 0 | [0, cds] = calldata mstore( add(ptr, 0x12), 0x603836393d3d3d36610000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x1b), shl(240, extraLength)) // 01 | ADD | cds+extra 0 0 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 cds 0 0 0 | [0, cds] = calldata // 73 addr | PUSH20 0x123… | addr 0 cds 0 0 0 | [0, cds] = calldata mstore( add(ptr, 0x1d), 0x013d730000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x20), shl(0x60, implementation)) // 5a | GAS | gas addr 0 cds 0 0 0 | [0, cds] = calldata // f4 | DELEGATECALL | success 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | rds success 0 | [0, cds] = calldata // 82 | DUP3 | 0 rds success 0 | [0, cds] = calldata // 80 | DUP1 | 0 0 rds success 0 | [0, cds] = calldata // 3e | RETURNDATACOPY | success 0 | [0, rds] = return data (there might be some irrelevant leftovers in memory [rds, cds] when rds < cds) // 90 | SWAP1 | 0 success | [0, rds] = return data // 3d | RETURNDATASIZE | rds 0 success | [0, rds] = return data // 91 | SWAP2 | success 0 rds | [0, rds] = return data // 60 0x36 | PUSH1 0x36 | 0x36 sucess 0 rds | [0, rds] = return data // 57 | JUMPI | 0 rds | [0, rds] = return data // fd | REVERT | – | [0, rds] = return data // 5b | JUMPDEST | 0 rds | [0, rds] = return data // f3 | RETURN | – | [0, rds] = return data mstore( add(ptr, 0x34), 0x5af43d82803e903d91603657fd5bf30000000000000000000000000000000000 ) } // ------------------------------------------------------------------------------------------------------------- // APPENDED DATA (Accessible from extcodecopy) // (but also send as appended data to the delegatecall) // ------------------------------------------------------------------------------------------------------------- extraLength -= 2; uint256 counter = extraLength; uint256 copyPtr = ptr + 0x43; // solhint-disable-next-line no-inline-assembly assembly { dataPtr := add(data, 32) } for (; counter >= 32; counter -= 32) { // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, mload(dataPtr)) } copyPtr += 32; dataPtr += 32; } uint256 mask = ~(256**(32 - counter) - 1); // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, and(mload(dataPtr), mask)) } copyPtr += counter; // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, shl(240, extraLength)) } // solhint-disable-next-line no-inline-assembly assembly { instance := create(0, ptr, creationSize) } if (instance == address(0)) { revert CreateFail(); } } } }
{ "remappings": [ "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "interfaces/=src/interfaces/", "modules/=src/modules/", "policies/=src/policies/", "libraries/=src/libraries/", "solmate/=lib/solmate/src/", "layer-zero/=lib/solidity-examples/contracts/", "bonds/=lib/bonds/src/", "test/=src/test/", "clones/=lib/clones-with-immutable-args/src/", "cooler/=lib/Cooler/src/", "balancer-v2/=lib/balancer-v2/", "@openzeppelin/=lib/openzeppelin-contracts/", "Cooler/=lib/Cooler/src/", "clones-with-immutable-args/=lib/clones-with-immutable-args/src/", "olympus-v3/=lib/Cooler/lib/olympus-v3/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solidity-examples/=lib/solidity-examples/contracts/" ], "optimizer": { "enabled": true, "runs": 10 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"Deactivated","type":"error"},{"inputs":[],"name":"Default","type":"error"},{"inputs":[],"name":"NotCoolerCallback","type":"error"},{"inputs":[],"name":"NotExpired","type":"error"},{"inputs":[],"name":"OnlyApproved","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"approvals","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"loanID_","type":"uint256"}],"name":"approveTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"}],"name":"claimDefaulted","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reqID_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"bool","name":"isCallback_","type":"bool"}],"name":"clearRequest","outputs":[{"internalType":"uint256","name":"loanID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract ERC20","name":"_collateral","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral_","type":"uint256"}],"name":"collateralFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debt","outputs":[{"internalType":"contract ERC20","name":"_debt","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"}],"name":"delegateVoting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"},{"internalType":"uint8","name":"times_","type":"uint8"}],"name":"extendLoanTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract CoolerFactory","name":"_factory","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"}],"name":"getLoan","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"interest","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"requester","type":"address"}],"internalType":"struct Cooler.Request","name":"request","type":"tuple"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"interestDue","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"callback","type":"bool"}],"internalType":"struct Cooler.Loan","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reqID_","type":"uint256"}],"name":"getRequest","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"interest","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"requester","type":"address"}],"internalType":"struct Cooler.Request","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"}],"name":"hasExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"rate_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"}],"name":"interestFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"reqID_","type":"uint256"}],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"loans","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"interest","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"requester","type":"address"}],"internalType":"struct Cooler.Request","name":"request","type":"tuple"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"interestDue","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"callback","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"},{"internalType":"uint256","name":"repayment_","type":"uint256"}],"name":"repayLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"interest_","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"}],"name":"requestLoan","outputs":[{"internalType":"uint256","name":"reqID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"interest","type":"uint256"},{"internalType":"uint256","name":"loanToCollateral","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"requester","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reqID_","type":"uint256"}],"name":"rescindRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"setRepaymentAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanID_","type":"uint256"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50612118806100206000396000f3fe608060405234801561001057600080fd5b506004361061011d5760003560e01c80630dca59c11461012257806310cf5a1914610140578063206967cf1461016157806349fcbc5414610176578063504006ca1461019957806357e8a2f0146101b957806363035f66146101dc578063753c7ff914610205578063765cb83a1461021857806381d12c581461022b57806382afd23b146102765780638a700b53146102895780638da5cb5b1461029c57806399c6b2ef146102a45780639bcf40a2146102b75780639fdc540c146102ca578063c2c60b72146102dd578063c45a0155146102f0578063c58343ef146102f8578063d23e848914610318578063d8dfeb451461032b578063e1ec3c6814610333578063fa02c4b71461035a575b600080fd5b61012a61036d565b6040516101379190611c10565b60405180910390f35b61015361014e366004611c51565b61037e565b604051908152602001610137565b61017461016f366004611c91565b610724565b005b610189610184366004611c91565b610855565b6040519015158152602001610137565b6101ac6101a7366004611c91565b610885565b6040516101379190611cec565b6101cc6101c7366004611c91565b61096f565b6040516101379493929190611d69565b61012a6101ea366004611c91565b6002602052600090815260409020546001600160a01b031681565b610153610213366004611d84565b610c2a565b610174610226366004611db6565b610deb565b61023e610239366004611c91565b610e8c565b604080519687526020870195909552938501929092526060840152151560808301526001600160a01b031660a082015260c001610137565b610189610284366004611c91565b610ee0565b610153610297366004611dd1565b610f11565b61012a6112f5565b6101536102b2366004611dd1565b611301565b6101536102c5366004611df3565b611393565b6101746102d8366004611e2e565b6113d7565b6101746102eb366004611e5e565b611696565b61012a611732565b61030b610306366004611c91565b61173e565b6040516101379190611e8a565b610174610326366004611c91565b6117c4565b61012a6118ee565b610346610341366004611c91565b6118fa565b604051610137989796959493929190611e98565b610174610368366004611eef565b6119ad565b60006103796028611a2a565b905090565b6000806000858154811061039457610394611f19565b600091825260208083206040805160c081018252600590940290910180548452600181015492840192909252600282015490830152600381015460608301526004015460ff8116151560808301526001600160a01b036101009091041660a0820152915083801561041a57508160a001516001600160a01b0316336001600160a01b0316145b90508080156104885750336001600160a01b0316632a471e256040518163ffffffff1660e01b8152600401602060405180830381865afa158015610462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104869190611f2f565b155b156104a6576040516302e0fdad60e61b815260040160405180910390fd5b81608001516104c857604051630450a9a360e21b815260040160405180910390fd5b6000608083018190528251602084015160608501516104e8929190611393565b905060006104fe84600001518560400151611301565b905060018054905094506001604051806101000160405280868152602001866000015181526020018481526020018381526020018660600151426105429190611f62565b8152336020808301919091526001600160a01b038b8116604080850191909152881515606094850152855460018181018855600097885284882087518051600b909402909101928355808601519183019190915580830151600283015580860151600383015560808082015160048401805460a094850151881661010002610100600160a81b0319931515939093166001600160a81b031991821617929092179055958801516005840155928701516006830155948601516007820155908501516008820155928401516009840180549183166001600160a01b031990921691909117905560c0840151600a909301805460e0909501511515600160a01b0294909216921691909117919091179055805481908a90811061066557610665611f19565b60009182526020909120600590910201600401805460ff19169115159190911790556106ae336106936112f5565b865161069d61036d565b6001600160a01b0316929190611a4f565b6106b6611732565b604051639c6c4a8160e01b8152600481018a9052602481018790526001600160a01b039190911690639c6c4a8190604401600060405180830381600087803b15801561070157600080fd5b505af1158015610715573d6000803e3d6000fd5b50505050505050509392505050565b61072c6112f5565b6001600160a01b0316336001600160a01b03161461075d576040516364759a3360e01b815260040160405180910390fd5b600080828154811061077157610771611f19565b60009182526020909120600590910201600481015490915060ff166107a957604051630450a9a360e21b815260040160405180910390fd5b60048101805460ff191690556107ea6107c06112f5565b6107d283600001548460020154611301565b6107da6118ee565b6001600160a01b03169190611ae9565b6107f2611732565b6001600160a01b0316636763f122836040518263ffffffff1660e01b815260040161081f91815260200190565b600060405180830381600087803b15801561083957600080fd5b505af115801561084d573d6000803e3d6000fd5b505050505050565b60006001828154811061086a5761086a611f19565b90600052602060002090600b02016008015442119050919050565b61088d611b70565b600182815481106108a0576108a0611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a087015291855260058301549585019590955260068201549284019290925260078101546060840152600881015460808401526009810154841660a0840152600a015492831660c0830152600160a01b909204909116151560e082015292915050565b60008060008060006001868154811061098a5761098a611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a0870152918552600583015495850195909552600682015492840192909252600781015460608401526008810154608084018190526009820154851660a0850152600a9091015493841660c0840152600160a01b90930416151560e082015291504211610a765760405163d0404f8560e01b815260040160405180910390fd5b600060018781548110610a8b57610a8b611f19565b90600052602060002090600b020160050181905550600060018781548110610ab557610ab5611f19565b90600052602060002090600b020160060181905550600060018781548110610adf57610adf611f19565b90600052602060002090600b020160070181905550610b098160a0015182606001516107da6118ee565b610b11611732565b6001600160a01b0316630f30e65e8783606001516040518363ffffffff1660e01b8152600401610b4b929190918252602082015260400190565b600060405180830381600087803b158015610b6557600080fd5b505af1158015610b79573d6000803e3d6000fd5b505050508060e0015115610bfc578060a001516001600160a01b0316634b84126a878360200151846040015185606001516040518563ffffffff1660e01b8152600401610bc99493929190611d69565b600060405180830381600087803b158015610be357600080fd5b505af1158015610bf7573d6000803e3d6000fd5b505050505b6020810151604082015160608301516080840151610c1a9042611f7a565b9450945094509450509193509193565b600080546040805160c08101825287815260208101878152918101868152606082018681526001608084018181523360a0860181815292880189559780529351600587027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381019190915594517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56486015591517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565850155517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56684015590517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e567909201805491516001600160a01b031661010002610100600160a81b0319931515939093166001600160a81b03199092169190911791909117905590610d7c9030610d748887611301565b61069d6118ee565b610d84611732565b6001600160a01b0316637447be66826040518263ffffffff1660e01b8152600401610db191815260200190565b600060405180830381600087803b158015610dcb57600080fd5b505af1158015610ddf573d6000803e3d6000fd5b50505050949350505050565b610df36112f5565b6001600160a01b0316336001600160a01b031614610e24576040516364759a3360e01b815260040160405180910390fd5b610e2c6118ee565b6001600160a01b0316635c19a95c826040518263ffffffff1660e01b8152600401610e579190611c10565b600060405180830381600087803b158015610e7157600080fd5b505af1158015610e85573d6000803e3d6000fd5b5050505050565b60008181548110610e9c57600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401549294509092909160ff81169061010090046001600160a01b031686565b6000808281548110610ef457610ef4611f19565b600091825260209091206004600590920201015460ff1692915050565b60008060018481548110610f2757610f27611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a0870152918552600583015495850195909552600682015492840192909252600781015460608401526008810154608084018190526009820154851660a0850152600a9091015493841660c0840152600160a01b90930416151560e082015291504211156110145760405163064e30f160e51b815260040160405180910390fd5b60008160400151826020015161102a9190611f62565b905080841115611038578093505b600080836040015186106110695760408401516110559087611f7a565b604085018051600090915292509050611082565b858460400181815161107b9190611f7a565b9052508591505b600081156110d857846020015182866060015161109f9190611f91565b6110a99190611fb0565b905081856020018181516110bd9190611f7a565b9052506060850180518291906110d4908390611f7a565b9052505b84600189815481106110ec576110ec611f19565b600091825260209182902083518051600b939093029091019182558083015160018301556040808201516002840155606080830151600385015560808084015160048601805460a0968701516001600160a81b0319918216931515610100600160a81b031916939093176101006001600160a01b0394851602179091559688015160058701559287015160068601559086015160078501558501516008840155908401516009830180546001600160a01b03191691831691909117905560c080850151600a909301805460e090960151939092169490931693909317600160a01b91151591909102179091558501516111ea9033908961069d61036d565b8015611204576112046111fb6112f5565b826107da6118ee565b61120c611732565b604051633ddd9f4360e21b8152600481018a9052602481018990526001600160a01b03919091169063f7767d0c90604401600060405180830381600087803b15801561125757600080fd5b505af115801561126b573d6000803e3d6000fd5b505050508460e00151156112e85760a085015160405163b6278e8160e01b8152600481018a905260248101849052604481018590526001600160a01b039091169063b6278e8190606401600060405180830381600087803b1580156112cf57600080fd5b505af11580156112e3573d6000803e3d6000fd5b505050505b9450505050505b92915050565b60006103796000611a2a565b60008161130c6118ee565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611349573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136d9190611fd2565b61137890600a6120d3565b6113829085611f91565b61138c9190611fb0565b9392505050565b6000806301e133806113a58486611f91565b6113af9190611fb0565b9050670de0b6b3a76400006113c48287611f91565b6113ce9190611fb0565b95945050505050565b6000600183815481106113ec576113ec611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a087015291855260058301549585019590955260068201549284019290925260078101546060840152600881015460808401526009810154841660a08401819052600a9091015493841660c0840152600160a01b90930416151560e0820152915033146114d8576040516364759a3360e01b815260040160405180910390fd5b80608001514211156114fd5760405163064e30f160e51b815260040160405180910390fd5b8051606001516115119060ff841690611f91565b816080018181516115229190611f62565b905250600180548291908590811061153c5761153c611f19565b600091825260209182902083518051600b9093029091019182558083015160018301556040808201516002840155606080830151600385015560808084015160048601805460a0968701516001600160a01b0390811661010002610100600160a81b0319941515949094166001600160a81b031992831617939093179091559688015160058701559287015160068601559086015160078501558501516008840155908401516009830180549183166001600160a01b031990921691909117905560c0840151600a909201805460e0909501511515600160a01b029490931691161791909117905561162c611732565b60405163f9b4cb1760e01b81526004810185905260ff841660248201526001600160a01b03919091169063f9b4cb1790604401600060405180830381600087803b15801561167957600080fd5b505af115801561168d573d6000803e3d6000fd5b50505050505050565b600182815481106116a9576116a9611f19565b60009182526020909120600b90910201600901546001600160a01b031633146116e5576040516364759a3360e01b815260040160405180910390fd5b80600183815481106116f9576116f9611f19565b90600052602060002090600b0201600a0160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050565b6000610379603c611a2a565b611746611bcf565b6000828154811061175957611759611f19565b60009182526020918290206040805160c0810182526005909302909101805483526001810154938301939093526002830154908201526003820154606082015260049091015460ff8116151560808301526001600160a01b036101009091041660a082015292915050565b6000818152600260205260409020546001600160a01b031633146117fb576040516364759a3360e01b815260040160405180910390fd5b336001828154811061180f5761180f611f19565b90600052602060002090600b020160090160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550336001828154811061185857611858611f19565b90600052602060002090600b0201600a0160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506000600182815481106118a2576118a2611f19565b60009182526020808320600a600b90930201919091018054931515600160a01b0260ff60a01b1990941693909317909255918252600290526040902080546001600160a01b0319169055565b60006103796014611a2a565b6001818154811061190a57600080fd5b60009182526020918290206040805160c081018252600b9093029091018054835260018101549383019390935260028301549082015260038201546060820152600482015460ff808216151560808401526001600160a01b03610100909204821660a084015260058401546006850154600786015460088701546009880154600a90980154969850929691959094929391831692811691600160a01b9091041688565b600181815481106119c0576119c0611f19565b60009182526020909120600b90910201600901546001600160a01b031633146119fc576040516364759a3360e01b815260040160405180910390fd5b600090815260026020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080611a41600119368181013560f01c90030190565b929092013560601c92915050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610e855760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611b6a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611ae0565b50505050565b604051806101000160405280611b84611bcf565b81526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000151581525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681525090565b6001600160a01b0391909116815260200190565b80356001600160a01b0381168114611c3b57600080fd5b919050565b8015158114611c4e57600080fd5b50565b600080600060608486031215611c6657600080fd5b83359250611c7660208501611c24565b91506040840135611c8681611c40565b809150509250925092565b600060208284031215611ca357600080fd5b5035919050565b8051825260208082015190830152604080820151908301526060808201519083015260808082015115159083015260a0908101516001600160a01b0316910152565b60006101a082019050611d00828451611caa565b602083015160c0830152604083015160e08301526060830151610100830152608083015161012083015260a083015160018060a01b038082166101408501528060c086015116610160850152505060e0830151611d6261018084018215159052565b5092915050565b93845260208401929092526040830152606082015260800190565b60008060008060808587031215611d9a57600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215611dc857600080fd5b61138c82611c24565b60008060408385031215611de457600080fd5b50508035926020909101359150565b600080600060608486031215611e0857600080fd5b505081359360208301359350604090920135919050565b60ff81168114611c4e57600080fd5b60008060408385031215611e4157600080fd5b823591506020830135611e5381611e1f565b809150509250929050565b60008060408385031215611e7157600080fd5b82359150611e8160208401611c24565b90509250929050565b60c081016112ef8284611caa565b6101a08101611ea7828b611caa565b60c082019890985260e08101969096526101008601949094526101208501929092526001600160a01b0390811661014085015216610160830152151561018090910152919050565b60008060408385031215611f0257600080fd5b611f0b83611c24565b946020939093013593505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611f4157600080fd5b815161138c81611c40565b634e487b7160e01b600052601160045260246000fd5b60008219821115611f7557611f75611f4c565b500190565b600082821015611f8c57611f8c611f4c565b500390565b6000816000190483118215151615611fab57611fab611f4c565b500290565b600082611fcd57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611fe457600080fd5b815161138c81611e1f565b600181815b8085111561202a57816000190482111561201057612010611f4c565b8085161561201d57918102915b93841c9390800290611ff4565b509250929050565b600082612041575060016112ef565b8161204e575060006112ef565b8160018114612064576002811461206e5761208a565b60019150506112ef565b60ff84111561207f5761207f611f4c565b50506001821b6112ef565b5060208310610133831016604e8410600b84101617156120ad575081810a6112ef565b6120b78383611fef565b80600019048211156120cb576120cb611f4c565b029392505050565b600061138c60ff84168361203256fea2646970667358221220ceb73d689cb6673c8753824be413f6ca7a447ee12d5484363b89fe7db85ec06264736f6c634300080f0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061011d5760003560e01c80630dca59c11461012257806310cf5a1914610140578063206967cf1461016157806349fcbc5414610176578063504006ca1461019957806357e8a2f0146101b957806363035f66146101dc578063753c7ff914610205578063765cb83a1461021857806381d12c581461022b57806382afd23b146102765780638a700b53146102895780638da5cb5b1461029c57806399c6b2ef146102a45780639bcf40a2146102b75780639fdc540c146102ca578063c2c60b72146102dd578063c45a0155146102f0578063c58343ef146102f8578063d23e848914610318578063d8dfeb451461032b578063e1ec3c6814610333578063fa02c4b71461035a575b600080fd5b61012a61036d565b6040516101379190611c10565b60405180910390f35b61015361014e366004611c51565b61037e565b604051908152602001610137565b61017461016f366004611c91565b610724565b005b610189610184366004611c91565b610855565b6040519015158152602001610137565b6101ac6101a7366004611c91565b610885565b6040516101379190611cec565b6101cc6101c7366004611c91565b61096f565b6040516101379493929190611d69565b61012a6101ea366004611c91565b6002602052600090815260409020546001600160a01b031681565b610153610213366004611d84565b610c2a565b610174610226366004611db6565b610deb565b61023e610239366004611c91565b610e8c565b604080519687526020870195909552938501929092526060840152151560808301526001600160a01b031660a082015260c001610137565b610189610284366004611c91565b610ee0565b610153610297366004611dd1565b610f11565b61012a6112f5565b6101536102b2366004611dd1565b611301565b6101536102c5366004611df3565b611393565b6101746102d8366004611e2e565b6113d7565b6101746102eb366004611e5e565b611696565b61012a611732565b61030b610306366004611c91565b61173e565b6040516101379190611e8a565b610174610326366004611c91565b6117c4565b61012a6118ee565b610346610341366004611c91565b6118fa565b604051610137989796959493929190611e98565b610174610368366004611eef565b6119ad565b60006103796028611a2a565b905090565b6000806000858154811061039457610394611f19565b600091825260208083206040805160c081018252600590940290910180548452600181015492840192909252600282015490830152600381015460608301526004015460ff8116151560808301526001600160a01b036101009091041660a0820152915083801561041a57508160a001516001600160a01b0316336001600160a01b0316145b90508080156104885750336001600160a01b0316632a471e256040518163ffffffff1660e01b8152600401602060405180830381865afa158015610462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104869190611f2f565b155b156104a6576040516302e0fdad60e61b815260040160405180910390fd5b81608001516104c857604051630450a9a360e21b815260040160405180910390fd5b6000608083018190528251602084015160608501516104e8929190611393565b905060006104fe84600001518560400151611301565b905060018054905094506001604051806101000160405280868152602001866000015181526020018481526020018381526020018660600151426105429190611f62565b8152336020808301919091526001600160a01b038b8116604080850191909152881515606094850152855460018181018855600097885284882087518051600b909402909101928355808601519183019190915580830151600283015580860151600383015560808082015160048401805460a094850151881661010002610100600160a81b0319931515939093166001600160a81b031991821617929092179055958801516005840155928701516006830155948601516007820155908501516008820155928401516009840180549183166001600160a01b031990921691909117905560c0840151600a909301805460e0909501511515600160a01b0294909216921691909117919091179055805481908a90811061066557610665611f19565b60009182526020909120600590910201600401805460ff19169115159190911790556106ae336106936112f5565b865161069d61036d565b6001600160a01b0316929190611a4f565b6106b6611732565b604051639c6c4a8160e01b8152600481018a9052602481018790526001600160a01b039190911690639c6c4a8190604401600060405180830381600087803b15801561070157600080fd5b505af1158015610715573d6000803e3d6000fd5b50505050505050509392505050565b61072c6112f5565b6001600160a01b0316336001600160a01b03161461075d576040516364759a3360e01b815260040160405180910390fd5b600080828154811061077157610771611f19565b60009182526020909120600590910201600481015490915060ff166107a957604051630450a9a360e21b815260040160405180910390fd5b60048101805460ff191690556107ea6107c06112f5565b6107d283600001548460020154611301565b6107da6118ee565b6001600160a01b03169190611ae9565b6107f2611732565b6001600160a01b0316636763f122836040518263ffffffff1660e01b815260040161081f91815260200190565b600060405180830381600087803b15801561083957600080fd5b505af115801561084d573d6000803e3d6000fd5b505050505050565b60006001828154811061086a5761086a611f19565b90600052602060002090600b02016008015442119050919050565b61088d611b70565b600182815481106108a0576108a0611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a087015291855260058301549585019590955260068201549284019290925260078101546060840152600881015460808401526009810154841660a0840152600a015492831660c0830152600160a01b909204909116151560e082015292915050565b60008060008060006001868154811061098a5761098a611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a0870152918552600583015495850195909552600682015492840192909252600781015460608401526008810154608084018190526009820154851660a0850152600a9091015493841660c0840152600160a01b90930416151560e082015291504211610a765760405163d0404f8560e01b815260040160405180910390fd5b600060018781548110610a8b57610a8b611f19565b90600052602060002090600b020160050181905550600060018781548110610ab557610ab5611f19565b90600052602060002090600b020160060181905550600060018781548110610adf57610adf611f19565b90600052602060002090600b020160070181905550610b098160a0015182606001516107da6118ee565b610b11611732565b6001600160a01b0316630f30e65e8783606001516040518363ffffffff1660e01b8152600401610b4b929190918252602082015260400190565b600060405180830381600087803b158015610b6557600080fd5b505af1158015610b79573d6000803e3d6000fd5b505050508060e0015115610bfc578060a001516001600160a01b0316634b84126a878360200151846040015185606001516040518563ffffffff1660e01b8152600401610bc99493929190611d69565b600060405180830381600087803b158015610be357600080fd5b505af1158015610bf7573d6000803e3d6000fd5b505050505b6020810151604082015160608301516080840151610c1a9042611f7a565b9450945094509450509193509193565b600080546040805160c08101825287815260208101878152918101868152606082018681526001608084018181523360a0860181815292880189559780529351600587027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381019190915594517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56486015591517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565850155517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56684015590517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e567909201805491516001600160a01b031661010002610100600160a81b0319931515939093166001600160a81b03199092169190911791909117905590610d7c9030610d748887611301565b61069d6118ee565b610d84611732565b6001600160a01b0316637447be66826040518263ffffffff1660e01b8152600401610db191815260200190565b600060405180830381600087803b158015610dcb57600080fd5b505af1158015610ddf573d6000803e3d6000fd5b50505050949350505050565b610df36112f5565b6001600160a01b0316336001600160a01b031614610e24576040516364759a3360e01b815260040160405180910390fd5b610e2c6118ee565b6001600160a01b0316635c19a95c826040518263ffffffff1660e01b8152600401610e579190611c10565b600060405180830381600087803b158015610e7157600080fd5b505af1158015610e85573d6000803e3d6000fd5b5050505050565b60008181548110610e9c57600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401549294509092909160ff81169061010090046001600160a01b031686565b6000808281548110610ef457610ef4611f19565b600091825260209091206004600590920201015460ff1692915050565b60008060018481548110610f2757610f27611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a0870152918552600583015495850195909552600682015492840192909252600781015460608401526008810154608084018190526009820154851660a0850152600a9091015493841660c0840152600160a01b90930416151560e082015291504211156110145760405163064e30f160e51b815260040160405180910390fd5b60008160400151826020015161102a9190611f62565b905080841115611038578093505b600080836040015186106110695760408401516110559087611f7a565b604085018051600090915292509050611082565b858460400181815161107b9190611f7a565b9052508591505b600081156110d857846020015182866060015161109f9190611f91565b6110a99190611fb0565b905081856020018181516110bd9190611f7a565b9052506060850180518291906110d4908390611f7a565b9052505b84600189815481106110ec576110ec611f19565b600091825260209182902083518051600b939093029091019182558083015160018301556040808201516002840155606080830151600385015560808084015160048601805460a0968701516001600160a81b0319918216931515610100600160a81b031916939093176101006001600160a01b0394851602179091559688015160058701559287015160068601559086015160078501558501516008840155908401516009830180546001600160a01b03191691831691909117905560c080850151600a909301805460e090960151939092169490931693909317600160a01b91151591909102179091558501516111ea9033908961069d61036d565b8015611204576112046111fb6112f5565b826107da6118ee565b61120c611732565b604051633ddd9f4360e21b8152600481018a9052602481018990526001600160a01b03919091169063f7767d0c90604401600060405180830381600087803b15801561125757600080fd5b505af115801561126b573d6000803e3d6000fd5b505050508460e00151156112e85760a085015160405163b6278e8160e01b8152600481018a905260248101849052604481018590526001600160a01b039091169063b6278e8190606401600060405180830381600087803b1580156112cf57600080fd5b505af11580156112e3573d6000803e3d6000fd5b505050505b9450505050505b92915050565b60006103796000611a2a565b60008161130c6118ee565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611349573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136d9190611fd2565b61137890600a6120d3565b6113829085611f91565b61138c9190611fb0565b9392505050565b6000806301e133806113a58486611f91565b6113af9190611fb0565b9050670de0b6b3a76400006113c48287611f91565b6113ce9190611fb0565b95945050505050565b6000600183815481106113ec576113ec611f19565b6000918252602091829020604080516101c081018252600b9093029091018054610100808501918252600183015461012086015260028301546101408601526003830154610160860152600483015460ff80821615156101808801526001600160a01b039290910482166101a087015291855260058301549585019590955260068201549284019290925260078101546060840152600881015460808401526009810154841660a08401819052600a9091015493841660c0840152600160a01b90930416151560e0820152915033146114d8576040516364759a3360e01b815260040160405180910390fd5b80608001514211156114fd5760405163064e30f160e51b815260040160405180910390fd5b8051606001516115119060ff841690611f91565b816080018181516115229190611f62565b905250600180548291908590811061153c5761153c611f19565b600091825260209182902083518051600b9093029091019182558083015160018301556040808201516002840155606080830151600385015560808084015160048601805460a0968701516001600160a01b0390811661010002610100600160a81b0319941515949094166001600160a81b031992831617939093179091559688015160058701559287015160068601559086015160078501558501516008840155908401516009830180549183166001600160a01b031990921691909117905560c0840151600a909201805460e0909501511515600160a01b029490931691161791909117905561162c611732565b60405163f9b4cb1760e01b81526004810185905260ff841660248201526001600160a01b03919091169063f9b4cb1790604401600060405180830381600087803b15801561167957600080fd5b505af115801561168d573d6000803e3d6000fd5b50505050505050565b600182815481106116a9576116a9611f19565b60009182526020909120600b90910201600901546001600160a01b031633146116e5576040516364759a3360e01b815260040160405180910390fd5b80600183815481106116f9576116f9611f19565b90600052602060002090600b0201600a0160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050565b6000610379603c611a2a565b611746611bcf565b6000828154811061175957611759611f19565b60009182526020918290206040805160c0810182526005909302909101805483526001810154938301939093526002830154908201526003820154606082015260049091015460ff8116151560808301526001600160a01b036101009091041660a082015292915050565b6000818152600260205260409020546001600160a01b031633146117fb576040516364759a3360e01b815260040160405180910390fd5b336001828154811061180f5761180f611f19565b90600052602060002090600b020160090160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550336001828154811061185857611858611f19565b90600052602060002090600b0201600a0160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506000600182815481106118a2576118a2611f19565b60009182526020808320600a600b90930201919091018054931515600160a01b0260ff60a01b1990941693909317909255918252600290526040902080546001600160a01b0319169055565b60006103796014611a2a565b6001818154811061190a57600080fd5b60009182526020918290206040805160c081018252600b9093029091018054835260018101549383019390935260028301549082015260038201546060820152600482015460ff808216151560808401526001600160a01b03610100909204821660a084015260058401546006850154600786015460088701546009880154600a90980154969850929691959094929391831692811691600160a01b9091041688565b600181815481106119c0576119c0611f19565b60009182526020909120600b90910201600901546001600160a01b031633146119fc576040516364759a3360e01b815260040160405180910390fd5b600090815260026020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600080611a41600119368181013560f01c90030190565b929092013560601c92915050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610e855760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611b6a5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611ae0565b50505050565b604051806101000160405280611b84611bcf565b81526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000151581525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681525090565b6001600160a01b0391909116815260200190565b80356001600160a01b0381168114611c3b57600080fd5b919050565b8015158114611c4e57600080fd5b50565b600080600060608486031215611c6657600080fd5b83359250611c7660208501611c24565b91506040840135611c8681611c40565b809150509250925092565b600060208284031215611ca357600080fd5b5035919050565b8051825260208082015190830152604080820151908301526060808201519083015260808082015115159083015260a0908101516001600160a01b0316910152565b60006101a082019050611d00828451611caa565b602083015160c0830152604083015160e08301526060830151610100830152608083015161012083015260a083015160018060a01b038082166101408501528060c086015116610160850152505060e0830151611d6261018084018215159052565b5092915050565b93845260208401929092526040830152606082015260800190565b60008060008060808587031215611d9a57600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215611dc857600080fd5b61138c82611c24565b60008060408385031215611de457600080fd5b50508035926020909101359150565b600080600060608486031215611e0857600080fd5b505081359360208301359350604090920135919050565b60ff81168114611c4e57600080fd5b60008060408385031215611e4157600080fd5b823591506020830135611e5381611e1f565b809150509250929050565b60008060408385031215611e7157600080fd5b82359150611e8160208401611c24565b90509250929050565b60c081016112ef8284611caa565b6101a08101611ea7828b611caa565b60c082019890985260e08101969096526101008601949094526101208501929092526001600160a01b0390811661014085015216610160830152151561018090910152919050565b60008060408385031215611f0257600080fd5b611f0b83611c24565b946020939093013593505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611f4157600080fd5b815161138c81611c40565b634e487b7160e01b600052601160045260246000fd5b60008219821115611f7557611f75611f4c565b500190565b600082821015611f8c57611f8c611f4c565b500390565b6000816000190483118215151615611fab57611fab611f4c565b500290565b600082611fcd57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611fe457600080fd5b815161138c81611e1f565b600181815b8085111561202a57816000190482111561201057612010611f4c565b8085161561201d57918102915b93841c9390800290611ff4565b509250929050565b600082612041575060016112ef565b8161204e575060006112ef565b8160018114612064576002811461206e5761208a565b60019150506112ef565b60ff84111561207f5761207f611f4c565b50506001821b6112ef565b5060208310610133831016604e8410600b84101617156120ad575081810a6112ef565b6120b78383611fef565b80600019048211156120cb576120cb611f4c565b029392505050565b600061138c60ff84168361203256fea2646970667358221220ceb73d689cb6673c8753824be413f6ca7a447ee12d5484363b89fe7db85ec06264736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.