Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multi Chain
Multichain Addresses
3 addresses found via
Latest 10 from a total of 10 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Create Market | 8815204 | 166 days 17 hrs ago | IN | 0 ETH | 0.00231437 | ||||
Create Market | 8790104 | 171 days 4 hrs ago | IN | 0 ETH | 0.01053448 | ||||
Create Market | 8787921 | 171 days 13 hrs ago | IN | 0 ETH | 0.00608967 | ||||
Create Market | 8787918 | 171 days 13 hrs ago | IN | 0 ETH | 0.08092423 | ||||
Create Market | 8787913 | 171 days 13 hrs ago | IN | 0 ETH | 0.00604549 | ||||
Create Market | 8787908 | 171 days 13 hrs ago | IN | 0 ETH | 0.00632096 | ||||
Create Market | 8787472 | 171 days 15 hrs ago | IN | 0 ETH | 0.0041954 | ||||
Create Market | 8784674 | 172 days 3 hrs ago | IN | 0 ETH | 0.02979687 | ||||
Close Market | 8777903 | 173 days 7 hrs ago | IN | 0 ETH | 0.00092675 | ||||
Create Market | 8776524 | 173 days 13 hrs ago | IN | 0 ETH | 0.01962034 |
Latest 13 internal transactions
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
8787918 | 171 days 13 hrs ago | 0 ETH | ||||
8787918 | 171 days 13 hrs ago | 0 ETH | ||||
8787918 | 171 days 13 hrs ago | 0 ETH | ||||
8787918 | 171 days 13 hrs ago | 0 ETH | ||||
8784674 | 172 days 3 hrs ago | 0 ETH | ||||
8784674 | 172 days 3 hrs ago | 0 ETH | ||||
8784674 | 172 days 3 hrs ago | 0 ETH | ||||
8784674 | 172 days 3 hrs ago | 0 ETH | ||||
8776524 | 173 days 13 hrs ago | 0 ETH | ||||
8776524 | 173 days 13 hrs ago | 0 ETH | ||||
8776524 | 173 days 13 hrs ago | 0 ETH | ||||
8776524 | 173 days 13 hrs ago | 0 ETH | ||||
8774506 | 173 days 21 hrs ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
BondFixedExpiryFPA
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 100000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.8.15; import {BondBaseFPA, IBondAggregator, Authority} from "./bases/BondBaseFPA.sol"; import {IBondTeller} from "./interfaces/IBondTeller.sol"; import {IBondFixedExpiryTeller} from "./interfaces/IBondFixedExpiryTeller.sol"; /// @title Bond Fixed-Expiry Fixed Price Auctioneer /// @notice Bond Fixed-Expiry Fixed Price Auctioneer Contract /// @dev Bond Protocol is a permissionless system to create bond markets /// for any token pair. Bond issuers create BondMarkets that pay out /// a Payout Token in exchange for deposited Quote Tokens. Users can purchase /// future-dated Payout Tokens with Quote Tokens at the current market price and /// receive Bond Tokens to represent their position while their bond vests. /// Once the Bond Tokens vest, they can redeem it for the Quote Tokens. /// /// @dev An Auctioneer contract allows users to create and manage bond markets. /// All bond pricing logic and market data is stored in the Auctioneer. /// An Auctioneer is dependent on a Teller to serve external users and /// an Aggregator to register new markets. Th Fixed Price Auctioneer /// lets issuers set a Fixed Price to buy a target amount of quote tokens or sell /// a target amount of payout tokens over the duration of a market. /// See IBondFPA.sol for price format details. /// /// @dev The Fixed-Expiry Fixed Price Auctioneer is an implementation of the /// Bond Base Fixed Price Auctioneer contract specific to creating bond markets where /// all purchases on that market vest at a certain timestamp. /// /// @author Oighty contract BondFixedExpiryFPA is BondBaseFPA { /* ========== CONSTRUCTOR ========== */ constructor( IBondTeller teller_, IBondAggregator aggregator_, address guardian_, Authority authority_ ) BondBaseFPA(teller_, aggregator_, guardian_, authority_) {} /// @inheritdoc BondBaseFPA function createMarket(bytes calldata params_) external override returns (uint256) { // Decode params into the struct type expected by this auctioneer MarketParams memory params = abi.decode(params_, (MarketParams)); // Vesting is rounded to the nearest day at 0000 UTC (in seconds) since bond tokens // are only unique to a day, not a specific timestamp. params.vesting = (params.vesting / 1 days) * 1 days; // Get conclusion from start time and duration // Don't need to check valid start time or duration here since it will be checked in _createMarket uint48 start = params.start == 0 ? uint48(block.timestamp) : params.start; uint48 conclusion = start + params.duration; // Check that the vesting parameter is valid for a fixed-expiry market if (params.vesting != 0 && params.vesting < conclusion) revert Auctioneer_InvalidParams(); // Create market with provided params uint256 marketId = _createMarket(params); // Create bond token (ERC20 for fixed expiry) if not instant swap if (params.vesting != 0) IBondFixedExpiryTeller(address(_teller)).deploy(params.payoutToken, params.vesting); // Return market ID return marketId; } }
// 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: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) abstract contract Auth { event OwnerUpdated(address indexed user, address indexed newOwner); event AuthorityUpdated(address indexed user, Authority indexed newAuthority); address public owner; Authority public authority; constructor(address _owner, Authority _authority) { owner = _owner; authority = _authority; emit OwnerUpdated(msg.sender, _owner); emit AuthorityUpdated(msg.sender, _authority); } modifier requiresAuth() { require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); _; } function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be // aware that this makes protected functions uncallable even to the owner if the authority is out of order. return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; } function setAuthority(Authority newAuthority) public virtual { // We check if the caller is the owner first because we want to ensure they can // always swap out the authority even if it's reverting or using up a lot of gas. require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); authority = newAuthority; emit AuthorityUpdated(msg.sender, newAuthority); } function setOwner(address newOwner) public virtual requiresAuth { owner = newOwner; emit OwnerUpdated(msg.sender, newOwner); } } /// @notice A generic interface for a contract which provides authorization data to an Auth instance. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) interface Authority { function canCall( address user, address target, bytes4 functionSig ) external view returns (bool); }
// 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/Rari-Capital/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 //////////////////////////////////////////////////////////////*/ bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 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 { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, 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: AGPL-3.0-or-later pragma solidity 0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import {CloneERC20} from "./lib/CloneERC20.sol"; /// @title ERC20 Bond Token /// @notice ERC20 Bond Token Contract /// @dev Bond Protocol is a permissionless system to create Olympus-style bond markets /// for any token pair. The markets do not require maintenance and will manage /// bond prices based on activity. Bond issuers create BondMarkets that pay out /// a Payout Token in exchange for deposited Quote Tokens. Users can purchase /// future-dated Payout Tokens with Quote Tokens at the current market price and /// receive Bond Tokens to represent their position while their bond vests. /// Once the Bond Tokens vest, they can redeem it for the Quote Tokens. /// /// @dev The ERC20 Bond Token contract is issued by a Fixed Expiry Teller to /// represent bond positions until they vest. Bond tokens can be redeemed for // the underlying token 1:1 at or after expiry. /// /// @dev This contract uses Clones (https://github.com/wighawag/clones-with-immutable-args) /// to save gas on deployment and is based on VestedERC20 (https://github.com/ZeframLou/vested-erc20) /// /// @author Oighty, Zeus, Potted Meat, indigo contract ERC20BondToken is CloneERC20 { /* ========== ERRORS ========== */ error BondToken_OnlyTeller(); /* ========== IMMUTABLE PARAMETERS ========== */ /// @notice The token to be redeemed when the bond vests /// @return _underlying The address of the underlying token function underlying() external pure returns (ERC20 _underlying) { return ERC20(_getArgAddress(0x41)); } /// @notice Timestamp at which the BondToken can be redeemed for the underlying /// @return _expiry The vest start timestamp function expiry() external pure returns (uint48 _expiry) { return uint48(_getArgUint256(0x55)); } /// @notice Address of the Teller that created the token function teller() public pure returns (address _teller) { return _getArgAddress(0x75); } /* ========== MINT/BURN ========== */ function mint(address to, uint256 amount) external { if (msg.sender != teller()) revert BondToken_OnlyTeller(); _mint(to, amount); } function burn(address from, uint256 amount) external { if (msg.sender != teller()) revert BondToken_OnlyTeller(); _burn(from, amount); } }
/// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import {Auth, Authority} from "solmate/auth/Auth.sol"; import {IBondFPA, IBondAuctioneer} from "../interfaces/IBondFPA.sol"; import {IBondTeller} from "../interfaces/IBondTeller.sol"; import {IBondCallback} from "../interfaces/IBondCallback.sol"; import {IBondAggregator} from "../interfaces/IBondAggregator.sol"; import {TransferHelper} from "../lib/TransferHelper.sol"; import {FullMath} from "../lib/FullMath.sol"; /// @title Bond Fixed Price Auctioneer /// @notice Bond Fixed Price Auctioneer Base Contract /// @dev Bond Protocol is a system to create markets for any token pair. /// Bond issuers create BondMarkets that pay out a Payout Token in exchange /// for deposited Quote Tokens. Users can purchase future-dated Payout Tokens /// with Quote Tokens at the current market price and receive Bond Tokens to /// represent their position while their bond vests. Once the Bond Tokens vest, /// they can redeem it for the Quote Tokens. Alternatively, markets can be /// instant swap and payouts are made immediately to the user. /// /// @dev An Auctioneer contract allows users to create and manage bond markets. /// All bond pricing logic and market data is stored in the Auctioneer. /// An Auctioneer is dependent on a Teller to serve external users and /// an Aggregator to register new markets. The Fixed Price Auctioneer /// lets issuers set a Fixed Price to buy a target amount of quote tokens or sell /// a target amount of payout tokens over the duration of a market. /// See IBondFPA.sol for price format details. /// /// @author Oighty abstract contract BondBaseFPA is IBondFPA, Auth { using TransferHelper for ERC20; using FullMath for uint256; /* ========== ERRORS ========== */ error Auctioneer_OnlyMarketOwner(); error Auctioneer_MarketNotActive(); error Auctioneer_MaxPayoutExceeded(); error Auctioneer_AmountLessThanMinimum(); error Auctioneer_NotEnoughCapacity(); error Auctioneer_InvalidCallback(); error Auctioneer_BadExpiry(); error Auctioneer_InvalidParams(); error Auctioneer_NotAuthorized(); error Auctioneer_NewMarketsNotAllowed(); /* ========== EVENTS ========== */ event MarketCreated( uint256 indexed id, address indexed payoutToken, address indexed quoteToken, uint48 vesting, uint256 fixedPrice ); event MarketClosed(uint256 indexed id); /* ========== STATE VARIABLES ========== */ /// @notice Information pertaining to bond markets mapping(uint256 => BondMarket) public markets; /// @notice Information pertaining to market vesting and duration mapping(uint256 => BondTerms) public terms; /// @notice New address to designate as market owner. They must accept ownership to transfer permissions. mapping(uint256 => address) public newOwners; /// @notice Whether or not the auctioneer allows new markets to be created /// @dev Changing to false will sunset the auctioneer after all active markets end bool public allowNewMarkets; // Minimum time parameter values. Can be updated by admin. /// @notice Minimum deposit interval for a market uint48 public minDepositInterval; /// @notice Minimum market duration in seconds uint48 public minMarketDuration; /// @notice Whether or not the market creator is authorized to use a callback address mapping(address => bool) public callbackAuthorized; // A 'vesting' param longer than 50 years is considered a timestamp for fixed expiry. uint48 internal constant MAX_FIXED_TERM = 52 weeks * 50; uint48 internal constant ONE_HUNDRED_PERCENT = 1e5; // one percent equals 1000. // BondAggregator contract with utility functions IBondAggregator internal immutable _aggregator; // BondTeller contract that handles interactions with users and issues tokens IBondTeller internal immutable _teller; constructor( IBondTeller teller_, IBondAggregator aggregator_, address guardian_, Authority authority_ ) Auth(guardian_, authority_) { _aggregator = aggregator_; _teller = teller_; minDepositInterval = 1 hours; minMarketDuration = 1 days; allowNewMarkets = true; } /* ========== MARKET FUNCTIONS ========== */ /// @inheritdoc IBondAuctioneer function createMarket(bytes calldata params_) external virtual returns (uint256); /// @notice core market creation logic, see IBondFPA.MarketParams documentation function _createMarket(MarketParams memory params_) internal returns (uint256) { { // Check that the auctioneer is allowing new markets to be created if (!allowNewMarkets) revert Auctioneer_NewMarketsNotAllowed(); // Ensure params are in bounds uint8 payoutTokenDecimals = params_.payoutToken.decimals(); uint8 quoteTokenDecimals = params_.quoteToken.decimals(); if (payoutTokenDecimals < 6 || payoutTokenDecimals > 18) revert Auctioneer_InvalidParams(); if (quoteTokenDecimals < 6 || quoteTokenDecimals > 18) revert Auctioneer_InvalidParams(); if (params_.scaleAdjustment < -24 || params_.scaleAdjustment > 24) revert Auctioneer_InvalidParams(); // Restrict the use of a callback address unless allowed if (!callbackAuthorized[msg.sender] && params_.callbackAddr != address(0)) revert Auctioneer_NotAuthorized(); // Start time must be zero or in the future if (params_.start > 0 && params_.start < block.timestamp) revert Auctioneer_InvalidParams(); } // Unit to scale calculation for this market by to ensure reasonable values. // See IBondFPA for more details. // // scaleAdjustment should be equal to (payoutDecimals - quoteDecimals) - ((payoutPriceDecimals - quotePriceDecimals) / 2) uint256 scale; unchecked { scale = 10**uint8(36 + params_.scaleAdjustment); } // Check that price is not zero if (params_.formattedPrice == 0) revert Auctioneer_InvalidParams(); // Check time bounds if ( params_.duration < minMarketDuration || params_.depositInterval < minDepositInterval || params_.depositInterval > params_.duration ) revert Auctioneer_InvalidParams(); // Calculate the maximum payout amount for this market uint256 _maxPayout = ( params_.capacityInQuote ? params_.capacity.mulDiv(scale, params_.formattedPrice) : params_.capacity ).mulDiv(uint256(params_.depositInterval), uint256(params_.duration)); // Register new market on aggregator and get marketId uint256 marketId = _aggregator.registerMarket(params_.payoutToken, params_.quoteToken); markets[marketId] = BondMarket({ owner: msg.sender, payoutToken: params_.payoutToken, quoteToken: params_.quoteToken, callbackAddr: params_.callbackAddr, capacityInQuote: params_.capacityInQuote, capacity: params_.capacity, maxPayout: _maxPayout, price: params_.formattedPrice, scale: scale, purchased: 0, sold: 0 }); // Calculate and store time terms uint48 start = params_.start == 0 ? uint48(block.timestamp) : params_.start; terms[marketId] = BondTerms({ start: start, conclusion: start + params_.duration, vesting: params_.vesting }); emit MarketCreated( marketId, address(params_.payoutToken), address(params_.quoteToken), params_.vesting, params_.formattedPrice ); return marketId; } /// @inheritdoc IBondAuctioneer function pushOwnership(uint256 id_, address newOwner_) external override { if (msg.sender != markets[id_].owner) revert Auctioneer_OnlyMarketOwner(); newOwners[id_] = newOwner_; } /// @inheritdoc IBondAuctioneer function pullOwnership(uint256 id_) external override { if (msg.sender != newOwners[id_]) revert Auctioneer_NotAuthorized(); markets[id_].owner = newOwners[id_]; } /// @inheritdoc IBondFPA function setMinMarketDuration(uint48 duration_) external override requiresAuth { // Restricted to authorized addresses // Require duration to be greater than minimum deposit interval and at least 1 day if (duration_ < minDepositInterval || duration_ < 1 days) revert Auctioneer_InvalidParams(); minMarketDuration = duration_; } /// @inheritdoc IBondFPA function setMinDepositInterval(uint48 depositInterval_) external override requiresAuth { // Restricted to authorized addresses // Require min deposit interval to be less than minimum market duration and at least 1 hour if (depositInterval_ > minMarketDuration || depositInterval_ < 1 hours) revert Auctioneer_InvalidParams(); minDepositInterval = depositInterval_; } // Unused, but required by interface function setIntervals(uint256 id_, uint32[3] calldata intervals_) external override {} // Unused, but required by interface function setDefaults(uint32[6] memory defaults_) external override {} /// @inheritdoc IBondAuctioneer function setAllowNewMarkets(bool status_) external override requiresAuth { // Restricted to authorized addresses allowNewMarkets = status_; } /// @inheritdoc IBondAuctioneer function setCallbackAuthStatus(address creator_, bool status_) external override requiresAuth { // Restricted to authorized addresses callbackAuthorized[creator_] = status_; } /// @inheritdoc IBondAuctioneer function closeMarket(uint256 id_) external override { if (msg.sender != markets[id_].owner) revert Auctioneer_OnlyMarketOwner(); terms[id_].conclusion = uint48(block.timestamp); markets[id_].capacity = 0; emit MarketClosed(id_); } /* ========== TELLER FUNCTIONS ========== */ /// @inheritdoc IBondAuctioneer function purchaseBond( uint256 id_, uint256 amount_, uint256 minAmountOut_ ) external override returns (uint256 payout) { if (msg.sender != address(_teller)) revert Auctioneer_NotAuthorized(); BondMarket storage market = markets[id_]; // If market uses a callback, check that owner is still callback authorized if (market.callbackAddr != address(0) && !callbackAuthorized[market.owner]) revert Auctioneer_NotAuthorized(); // Check if market is live, if not revert if (!isLive(id_)) revert Auctioneer_MarketNotActive(); // Calculate payout amount from fixed price payout = amount_.mulDiv(market.scale, market.price); // Payout must be greater than user inputted minimum if (payout < minAmountOut_) revert Auctioneer_AmountLessThanMinimum(); // Markets have a max payout amount per transaction if (payout > market.maxPayout) revert Auctioneer_MaxPayoutExceeded(); // Update Capacity // Capacity is either the number of payout tokens that the market can sell // (if capacity in quote is false), // // or the number of quote tokens that the market can buy // (if capacity in quote is true) // If amount/payout is greater than capacity remaining, revert if (market.capacityInQuote ? amount_ > market.capacity : payout > market.capacity) revert Auctioneer_NotEnoughCapacity(); // Capacity is decreased by the deposited or paid amount market.capacity -= market.capacityInQuote ? amount_ : payout; // Markets keep track of how many quote tokens have been // purchased, and how many payout tokens have been sold market.purchased += amount_; market.sold += payout; } /* ========== VIEW FUNCTIONS ========== */ /* ========== EXTERNAL VIEW FUNCTIONS ========== */ /// @inheritdoc IBondAuctioneer function getMarketInfoForPurchase(uint256 id_) external view returns ( address owner, address callbackAddr, ERC20 payoutToken, ERC20 quoteToken, uint48 vesting, uint256 maxPayout_ ) { BondMarket memory market = markets[id_]; return ( market.owner, market.callbackAddr, market.payoutToken, market.quoteToken, terms[id_].vesting, maxPayout(id_) ); } /// @inheritdoc IBondAuctioneer function marketPrice(uint256 id_) public view override returns (uint256) { return markets[id_].price; } /// @inheritdoc IBondAuctioneer function marketScale(uint256 id_) external view override returns (uint256) { return markets[id_].scale; } /// @inheritdoc IBondAuctioneer function payoutFor( uint256 amount_, uint256 id_, address referrer_ ) public view override returns (uint256) { // Calculate the payout for the given amount of tokens uint256 fee = amount_.mulDiv(_teller.getFee(referrer_), ONE_HUNDRED_PERCENT); uint256 payout = (amount_ - fee).mulDiv(markets[id_].scale, marketPrice(id_)); // Check that the payout is less than or equal to the maximum payout, // Revert if not, otherwise return the payout if (payout > maxPayout(id_)) { revert Auctioneer_MaxPayoutExceeded(); } else { return payout; } } /// @inheritdoc IBondAuctioneer function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256) { // Calculate maximum amount of quote tokens that correspond to max bond size // Maximum of the maxPayout and the remaining capacity converted to quote tokens BondMarket memory market = markets[id_]; uint256 price = marketPrice(id_); uint256 quoteCapacity = market.capacityInQuote ? market.capacity : market.capacity.mulDiv(price, market.scale); uint256 maxQuote = market.maxPayout.mulDiv(price, market.scale); uint256 amountAccepted = quoteCapacity < maxQuote ? quoteCapacity : maxQuote; // Take into account teller fees and return // Estimate fee based on amountAccepted. Fee taken will be slightly larger than // this given it will be taken off the larger amount, but this avoids rounding // errors with trying to calculate the exact amount. // Therefore, the maxAmountAccepted is slightly conservative. uint256 estimatedFee = amountAccepted.mulDiv( _teller.getFee(referrer_), ONE_HUNDRED_PERCENT ); return amountAccepted + estimatedFee; } /// @inheritdoc IBondFPA function maxPayout(uint256 id_) public view override returns (uint256) { // Get current price uint256 price = marketPrice(id_); BondMarket memory market = markets[id_]; // Convert capacity to payout token units for comparison with max payout uint256 capacity = market.capacityInQuote ? market.capacity.mulDiv(market.scale, price) : market.capacity; // Cap max payout at the remaining capacity return market.maxPayout > capacity ? capacity : market.maxPayout; } /// @inheritdoc IBondAuctioneer function isInstantSwap(uint256 id_) public view returns (bool) { uint256 vesting = terms[id_].vesting; return (vesting <= MAX_FIXED_TERM) ? vesting == 0 : vesting <= block.timestamp; } /// @inheritdoc IBondAuctioneer function isLive(uint256 id_) public view override returns (bool) { return (markets[id_].capacity != 0 && terms[id_].conclusion > uint48(block.timestamp) && terms[id_].start <= uint48(block.timestamp)); } /// @inheritdoc IBondAuctioneer function ownerOf(uint256 id_) external view override returns (address) { return markets[id_].owner; } /// @inheritdoc IBondAuctioneer function getTeller() external view override returns (IBondTeller) { return _teller; } /// @inheritdoc IBondAuctioneer function getAggregator() external view override returns (IBondAggregator) { return _aggregator; } /// @inheritdoc IBondAuctioneer function currentCapacity(uint256 id_) external view override returns (uint256) { return markets[id_].capacity; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondAuctioneer} from "../interfaces/IBondAuctioneer.sol"; import {IBondTeller} from "../interfaces/IBondTeller.sol"; interface IBondAggregator { /// @notice Register a auctioneer with the aggregator /// @notice Only Guardian /// @param auctioneer_ Address of the Auctioneer to register /// @dev A auctioneer must be registered with an aggregator to create markets function registerAuctioneer(IBondAuctioneer auctioneer_) external; /// @notice Register a new market with the aggregator /// @notice Only registered depositories /// @param payoutToken_ Token to be paid out by the market /// @param quoteToken_ Token to be accepted by the market /// @param marketId ID of the market being created function registerMarket(ERC20 payoutToken_, ERC20 quoteToken_) external returns (uint256 marketId); /// @notice Get the auctioneer for the provided market ID /// @param id_ ID of Market function getAuctioneer(uint256 id_) external view returns (IBondAuctioneer); /// @notice Calculate current market price of payout token in quote tokens /// @dev Accounts for debt and control variable decay since last deposit (vs _marketPrice()) /// @param id_ ID of market /// @return Price for market (see the specific auctioneer for units) // // if price is below minimum price, minimum price is returned // this is enforced on deposits by manipulating total debt (see _decay()) function marketPrice(uint256 id_) external view returns (uint256); /// @notice Scale value to use when converting between quote token and payout token amounts with marketPrice() /// @param id_ ID of market /// @return Scaling factor for market in configured decimals function marketScale(uint256 id_) external view returns (uint256); /// @notice Payout due for amount of quote tokens /// @dev Accounts for debt and control variable decay so it is up to date /// @param amount_ Amount of quote tokens to spend /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. /// @return amount of payout tokens to be paid function payoutFor( uint256 amount_, uint256 id_, address referrer_ ) external view returns (uint256); /// @notice Returns maximum amount of quote token accepted by the market /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256); /// @notice Does market send payout immediately /// @param id_ Market ID to search for function isInstantSwap(uint256 id_) external view returns (bool); /// @notice Is a given market accepting deposits /// @param id_ ID of market function isLive(uint256 id_) external view returns (bool); /// @notice Returns array of active market IDs within a range /// @dev Should be used if length exceeds max to query entire array function liveMarketsBetween(uint256 firstIndex_, uint256 lastIndex_) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given quote token /// @param token_ Address of token to query by /// @param isPayout_ If true, search by payout token, else search for quote token function liveMarketsFor(address token_, bool isPayout_) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given owner /// @param owner_ Address of owner to query by /// @param firstIndex_ Market ID to start at /// @param lastIndex_ Market ID to end at (non-inclusive) function liveMarketsBy( address owner_, uint256 firstIndex_, uint256 lastIndex_ ) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given payout and quote token /// @param payout_ Address of payout token /// @param quote_ Address of quote token function marketsFor(address payout_, address quote_) external view returns (uint256[] memory); /// @notice Returns the market ID with the highest current payoutToken payout for depositing quoteToken /// @param payout_ Address of payout token /// @param quote_ Address of quote token /// @param amountIn_ Amount of quote tokens to deposit /// @param minAmountOut_ Minimum amount of payout tokens to receive as payout /// @param maxExpiry_ Latest acceptable vesting timestamp for bond /// Inputting the zero address will take into account just the protocol fee. function findMarketFor( address payout_, address quote_, uint256 amountIn_, uint256 minAmountOut_, uint256 maxExpiry_ ) external view returns (uint256 id); /// @notice Returns the Teller that services the market ID function getTeller(uint256 id_) external view returns (IBondTeller); /// @notice Returns current capacity of a market function currentCapacity(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondTeller} from "../interfaces/IBondTeller.sol"; import {IBondAggregator} from "../interfaces/IBondAggregator.sol"; interface IBondAuctioneer { /// @notice Creates a new bond market /// @param params_ Configuration data needed for market creation, encoded in a bytes array /// @dev See specific auctioneer implementations for details on encoding the parameters. /// @return id ID of new bond market function createMarket(bytes memory params_) external returns (uint256); /// @notice Disable existing bond market /// @notice Must be market owner /// @param id_ ID of market to close function closeMarket(uint256 id_) external; /// @notice Exchange quote tokens for a bond in a specified market /// @notice Must be teller /// @param id_ ID of the Market the bond is being purchased from /// @param amount_ Amount to deposit in exchange for bond (after fee has been deducted) /// @param minAmountOut_ Minimum acceptable amount of bond to receive. Prevents frontrunning /// @return payout Amount of payout token to be received from the bond function purchaseBond( uint256 id_, uint256 amount_, uint256 minAmountOut_ ) external returns (uint256 payout); /// @notice Set market intervals to different values than the defaults /// @notice Must be market owner /// @dev Changing the intervals could cause markets to behave in unexpected way /// tuneInterval should be greater than tuneAdjustmentDelay /// @param id_ Market ID /// @param intervals_ Array of intervals (3) /// 1. Tune interval - Frequency of tuning /// 2. Tune adjustment delay - Time to implement downward tuning adjustments /// 3. Debt decay interval - Interval over which debt should decay completely function setIntervals(uint256 id_, uint32[3] calldata intervals_) external; /// @notice Designate a new owner of a market /// @notice Must be market owner /// @dev Doesn't change permissions until newOwner calls pullOwnership /// @param id_ Market ID /// @param newOwner_ New address to give ownership to function pushOwnership(uint256 id_, address newOwner_) external; /// @notice Accept ownership of a market /// @notice Must be market newOwner /// @dev The existing owner must call pushOwnership prior to the newOwner calling this function /// @param id_ Market ID function pullOwnership(uint256 id_) external; /// @notice Set the auctioneer defaults /// @notice Must be policy /// @param defaults_ Array of default values /// 1. Tune interval - amount of time between tuning adjustments /// 2. Tune adjustment delay - amount of time to apply downward tuning adjustments /// 3. Minimum debt decay interval - minimum amount of time to let debt decay to zero /// 4. Minimum deposit interval - minimum amount of time to wait between deposits /// 5. Minimum market duration - minimum amount of time a market can be created for /// 6. Minimum debt buffer - the minimum amount of debt over the initial debt to trigger a market shutdown /// @dev The defaults set here are important to avoid edge cases in market behavior, e.g. a very short market reacts doesn't tune well /// @dev Only applies to new markets that are created after the change function setDefaults(uint32[6] memory defaults_) external; /// @notice Change the status of the auctioneer to allow creation of new markets /// @dev Setting to false and allowing active markets to end will sunset the auctioneer /// @param status_ Allow market creation (true) : Disallow market creation (false) function setAllowNewMarkets(bool status_) external; /// @notice Change whether a market creator is allowed to use a callback address in their markets or not /// @notice Must be guardian /// @dev Callback is believed to be safe, but a whitelist is implemented to prevent abuse /// @param creator_ Address of market creator /// @param status_ Allow callback (true) : Disallow callback (false) function setCallbackAuthStatus(address creator_, bool status_) external; /* ========== VIEW FUNCTIONS ========== */ /// @notice Provides information for the Teller to execute purchases on a Market /// @param id_ Market ID /// @return owner Address of the market owner (tokens transferred from this address if no callback) /// @return callbackAddr Address of the callback contract to get tokens for payouts /// @return payoutToken Payout Token (token paid out) for the Market /// @return quoteToken Quote Token (token received) for the Market /// @return vesting Timestamp or duration for vesting, implementation-dependent /// @return maxPayout Maximum amount of payout tokens you can purchase in one transaction function getMarketInfoForPurchase(uint256 id_) external view returns ( address owner, address callbackAddr, ERC20 payoutToken, ERC20 quoteToken, uint48 vesting, uint256 maxPayout ); /// @notice Calculate current market price of payout token in quote tokens /// @param id_ ID of market /// @return Price for market in configured decimals // // if price is below minimum price, minimum price is returned function marketPrice(uint256 id_) external view returns (uint256); /// @notice Scale value to use when converting between quote token and payout token amounts with marketPrice() /// @param id_ ID of market /// @return Scaling factor for market in configured decimals function marketScale(uint256 id_) external view returns (uint256); /// @notice Payout due for amount of quote tokens /// @dev Accounts for debt and control variable decay so it is up to date /// @param amount_ Amount of quote tokens to spend /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. /// @return amount of payout tokens to be paid function payoutFor( uint256 amount_, uint256 id_, address referrer_ ) external view returns (uint256); /// @notice Returns maximum amount of quote token accepted by the market /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256); /// @notice Does market send payout immediately /// @param id_ Market ID to search for function isInstantSwap(uint256 id_) external view returns (bool); /// @notice Is a given market accepting deposits /// @param id_ ID of market function isLive(uint256 id_) external view returns (bool); /// @notice Returns the address of the market owner /// @param id_ ID of market function ownerOf(uint256 id_) external view returns (address); /// @notice Returns the Teller that services the Auctioneer function getTeller() external view returns (IBondTeller); /// @notice Returns the Aggregator that services the Auctioneer function getAggregator() external view returns (IBondAggregator); /// @notice Returns current capacity of a market function currentCapacity(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; interface IBondCallback { /// @notice Send payout tokens to Teller while allowing market owners to perform custom logic on received or paid out tokens /// @notice Market ID on Teller must be whitelisted /// @param id_ ID of the market /// @param inputAmount_ Amount of quote tokens bonded to the market /// @param outputAmount_ Amount of payout tokens to be paid out to the market /// @dev Must transfer the output amount of payout tokens back to the Teller /// @dev Should check that the quote tokens have been transferred to the contract in the _callback function function callback( uint256 id_, uint256 inputAmount_, uint256 outputAmount_ ) external; /// @notice Returns the number of quote tokens received and payout tokens paid out for a market /// @param id_ ID of the market /// @return in_ Amount of quote tokens bonded to the market /// @return out_ Amount of payout tokens paid out to the market function amountsForMarket(uint256 id_) external view returns (uint256 in_, uint256 out_); /// @notice Whitelist a teller and market ID combination /// @notice Must be callback owner /// @param teller_ Address of the Teller contract which serves the market /// @param id_ ID of the market function whitelist(address teller_, uint256 id_) external; /// @notice Remove a market ID on a teller from the whitelist /// @dev Shutdown function in case there's an issue with the teller /// @param teller_ Address of the Teller contract which serves the market /// @param id_ ID of the market to remove from whitelist function blacklist(address teller_, uint256 id_) external; /// @notice Withdraw tokens from the callback and update balances /// @notice Only callback owner /// @param to_ Address of the recipient /// @param token_ Address of the token to withdraw /// @param amount_ Amount of tokens to withdraw function withdraw( address to_, ERC20 token_, uint256 amount_ ) external; /// @notice Deposit tokens to the callback and update balances /// @notice Only callback owner /// @param token_ Address of the token to deposit /// @param amount_ Amount of tokens to deposit function deposit(ERC20 token_, uint256 amount_) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondAuctioneer} from "../interfaces/IBondAuctioneer.sol"; interface IBondFPA is IBondAuctioneer { /// @notice Information pertaining to bond market struct BondMarket { address owner; // market owner. sends payout tokens, receives quote tokens (defaults to creator) ERC20 payoutToken; // token to pay depositors with ERC20 quoteToken; // token to accept as payment address callbackAddr; // address to call for any operations on bond purchase. Must inherit to IBondCallback. bool capacityInQuote; // capacity limit is in payment token (true) or in payout (false, default) uint256 capacity; // capacity remaining uint256 maxPayout; // max payout tokens out in one order uint256 price; // fixed price of the market (see MarketParams struct) uint256 scale; // scaling factor for the market (see MarketParams struct) uint256 sold; // payout tokens out uint256 purchased; // quote tokens in } /// @notice Information pertaining to market duration and vesting struct BondTerms { uint48 start; // timestamp when market starts uint48 conclusion; // timestamp when market no longer offered uint48 vesting; // length of time from deposit to expiry if fixed-term, vesting timestamp if fixed-expiry } /// @notice Parameters to create a new bond market /// @dev Note price should be passed in a specific format: /// formatted price = (payoutPriceCoefficient / quotePriceCoefficient) /// * 10**(36 + scaleAdjustment + quoteDecimals - payoutDecimals + payoutPriceDecimals - quotePriceDecimals) /// where: /// payoutDecimals - Number of decimals defined for the payoutToken in its ERC20 contract /// quoteDecimals - Number of decimals defined for the quoteToken in its ERC20 contract /// payoutPriceCoefficient - The coefficient of the payoutToken price in scientific notation (also known as the significant digits) /// payoutPriceDecimals - The significand of the payoutToken price in scientific notation (also known as the base ten exponent) /// quotePriceCoefficient - The coefficient of the quoteToken price in scientific notation (also known as the significant digits) /// quotePriceDecimals - The significand of the quoteToken price in scientific notation (also known as the base ten exponent) /// scaleAdjustment - see below /// * In the above definitions, the "prices" need to have the same unit of account (i.e. both in OHM, $, ETH, etc.) /// If price is not provided in this format, the market will not behave as intended. /// @param params_ Encoded bytes array, with the following elements /// @dev 0. Payout Token (token paid out) /// @dev 1. Quote Token (token to be received) /// @dev 2. Callback contract address, should conform to IBondCallback. If 0x00, tokens will be transferred from market.owner /// @dev 3. Is Capacity in Quote Token? /// @dev 4. Capacity (amount in quoteDecimals or amount in payoutDecimals) /// @dev 5. Formatted price (see note above) /// @dev 6. Deposit interval (seconds). Desired frequency of bonds. Used to calculate max payout of market (maxPayout = length / depositInterval * capacity). /// @dev 7. Is fixed term ? Vesting length (seconds) : Vesting expiry (timestamp). /// @dev A 'vesting' param longer than 50 years is considered a timestamp for fixed expiry. /// @dev 8. Start Time of the Market (timestamp) - Allows starting a market in the future. /// @dev If a start time is provided, the txn must be sent prior to the start time (functions as a deadline). /// @dev If start time is not provided (i.e. 0), the market will start immediately. /// @dev 9. Market Duration (seconds) - Duration of the market in seconds. /// @dev 10. Market scaling factor adjustment, ranges from -24 to +24 within the configured market bounds. /// @dev Should be calculated as: (payoutDecimals - quoteDecimals) - ((payoutPriceDecimals - quotePriceDecimals) / 2) /// @dev Providing a scaling factor adjustment that doesn't follow this formula could lead to under or overflow errors in the market. /// @return ID of new bond market struct MarketParams { ERC20 payoutToken; ERC20 quoteToken; address callbackAddr; bool capacityInQuote; uint256 capacity; uint256 formattedPrice; uint48 depositInterval; uint48 vesting; uint48 start; uint48 duration; int8 scaleAdjustment; } /// @notice Set the minimum market duration /// @notice Access controlled /// @param duration_ Minimum market duration in seconds function setMinMarketDuration(uint48 duration_) external; /// @notice Set the minimum deposit interval /// @notice Access controlled /// @param depositInterval_ Minimum deposit interval in seconds function setMinDepositInterval(uint48 depositInterval_) external; /* ========== VIEW FUNCTIONS ========== */ /// @notice Calculate current market price of payout token in quote tokens /// @param id_ ID of market /// @return Price for market in configured decimals (see MarketParams) /// @dev price is derived from the equation: // // p = f_p // // where // p = price // f_p = fixed price provided on creation // function marketPrice(uint256 id_) external view override returns (uint256); /// @notice Calculate max payout of the market in payout tokens /// @dev Returns a dynamically calculated payout or the maximum set by the creator, whichever is less. /// @param id_ ID of market /// @return Current max payout for the market in payout tokens function maxPayout(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20BondToken} from "../ERC20BondToken.sol"; import {ERC20} from "solmate/tokens/ERC20.sol"; interface IBondFixedExpiryTeller { /// @notice Redeem a fixed-expiry bond token for the underlying token (bond token must have matured) /// @param token_ Token to redeem /// @param amount_ Amount to redeem function redeem(ERC20BondToken token_, uint256 amount_) external; /// @notice Deposit an ERC20 token and mint a future-dated ERC20 bond token /// @param underlying_ ERC20 token redeemable when the bond token vests /// @param expiry_ Timestamp at which the bond token can be redeemed for the underlying token /// @param amount_ Amount of underlying tokens to deposit /// @return Address of the ERC20 bond token received /// @return Amount of the ERC20 bond token received function create( ERC20 underlying_, uint48 expiry_, uint256 amount_ ) external returns (ERC20BondToken, uint256); /// @notice Deploy a new ERC20 bond token for an (underlying, expiry) pair and return its address /// @dev ERC20 used for fixed-expiry /// @dev If a bond token exists for the (underlying, expiry) pair, it returns that address /// @param underlying_ ERC20 token redeemable when the bond token vests /// @param expiry_ Timestamp at which the bond token can be redeemed for the underlying token /// @return Address of the ERC20 bond token being created function deploy(ERC20 underlying_, uint48 expiry_) external returns (ERC20BondToken); /// @notice Get the ERC20BondToken contract corresponding to a market /// @param id_ ID of the market /// @return ERC20BondToken contract address function getBondTokenForMarket(uint256 id_) external view returns (ERC20BondToken); /// @notice Get the ERC20BondToken contract corresponding to an (underlying, expiry) pair, reverts if no token exists /// @param underlying_ ERC20 token redeemable when the bond token vests /// @param expiry_ Timestamp at which the bond token can be redeemed for the underlying token (this is rounded to the nearest day) /// @return ERC20BondToken contract address function getBondToken(ERC20 underlying_, uint48 expiry_) external view returns (ERC20BondToken); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; interface IBondTeller { /// @notice Exchange quote tokens for a bond in a specified market /// @param recipient_ Address of recipient of bond. Allows deposits for other addresses /// @param referrer_ Address of referrer who will receive referral fee. For frontends to fill. /// Direct calls can use the zero address for no referrer fee. /// @param id_ ID of the Market the bond is being purchased from /// @param amount_ Amount to deposit in exchange for bond /// @param minAmountOut_ Minimum acceptable amount of bond to receive. Prevents frontrunning /// @return Amount of payout token to be received from the bond /// @return Timestamp at which the bond token can be redeemed for the underlying token function purchase( address recipient_, address referrer_, uint256 id_, uint256 amount_, uint256 minAmountOut_ ) external returns (uint256, uint48); /// @notice Get current fee charged by the teller based on the combined protocol and referrer fee /// @param referrer_ Address of the referrer /// @return Fee in basis points (3 decimal places) function getFee(address referrer_) external view returns (uint48); /// @notice Set protocol fee /// @notice Must be guardian /// @param fee_ Protocol fee in basis points (3 decimal places) function setProtocolFee(uint48 fee_) external; /// @notice Set the discount for creating bond tokens from the base protocol fee /// @dev The discount is subtracted from the protocol fee to determine the fee /// when using create() to mint bond tokens without using an Auctioneer /// @param discount_ Create Fee Discount in basis points (3 decimal places) function setCreateFeeDiscount(uint48 discount_) external; /// @notice Set your fee as a referrer to the protocol /// @notice Fee is set for sending address /// @param fee_ Referrer fee in basis points (3 decimal places) function setReferrerFee(uint48 fee_) external; /// @notice Claim fees accrued by sender in the input tokens and sends them to the provided address /// @param tokens_ Array of tokens to claim fees for /// @param to_ Address to send fees to function claimFees(ERC20[] memory tokens_, address to_) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {Clone} from "clones/Clone.sol"; /// @notice Modern and gas efficient ERC20 implementation. /// @author Solmate (https://github.com/Rari-Capital/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 CloneERC20 is Clone { /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*/////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*/////////////////////////////////////////////////////////////// METADATA //////////////////////////////////////////////////////////////*/ function name() external pure returns (string memory) { return string(abi.encodePacked(_getArgUint256(0))); } function symbol() external pure returns (string memory) { return string(abi.encodePacked(_getArgUint256(0x20))); } function decimals() external pure returns (uint8) { return _getArgUint8(0x40); } /*/////////////////////////////////////////////////////////////// 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 increaseAllowance(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] += amount; emit Approval(msg.sender, spender, allowance[msg.sender][spender]); return true; } function decreaseAllowance(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] -= amount; emit Approval(msg.sender, spender, allowance[msg.sender][spender]); 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; } /*/////////////////////////////////////////////////////////////// INTERNAL 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); } function _getImmutableVariablesOffset() internal pure returns (uint256 offset) { assembly { offset := sub(calldatasize(), add(shr(240, calldataload(sub(calldatasize(), 2))), 2)) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = (type(uint256).max - denominator + 1) & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); unchecked { if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; /// @notice Safe ERC20 and ETH transfer library that safely handles missing return values. /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/TransferHelper.sol) /// @author Taken from Solmate. library TransferHelper { function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(ERC20.transferFrom.selector, from, to, amount) ); require( success && (data.length == 0 || abi.decode(data, (bool))) && address(token).code.length > 0, "TRANSFER_FROM_FAILED" ); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(ERC20.transfer.selector, to, amount) ); require( success && (data.length == 0 || abi.decode(data, (bool))) && address(token).code.length > 0, "TRANSFER_FAILED" ); } // function safeApprove( // ERC20 token, // address to, // uint256 amount // ) internal { // (bool success, bytes memory data) = address(token).call( // abi.encodeWithSelector(ERC20.approve.selector, to, amount) // ); // require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED"); // } // function safeTransferETH(address to, uint256 amount) internal { // (bool success, ) = to.call{value: amount}(new bytes(0)); // require(success, "ETH_TRANSFER_FAILED"); // } }
{ "remappings": [ "clones-with-immutable-args/=lib/clones-with-immutable-args/src/", "clones/=lib/clones-with-immutable-args/src/", "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "prb-math/=lib/prb-math/src/'/", "solmate/=lib/solmate/src/", "src/=src/", "weird-erc20/=lib/solmate/lib/weird-erc20/src/" ], "optimizer": { "enabled": true, "runs": 100000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
[{"inputs":[{"internalType":"contract IBondTeller","name":"teller_","type":"address"},{"internalType":"contract IBondAggregator","name":"aggregator_","type":"address"},{"internalType":"address","name":"guardian_","type":"address"},{"internalType":"contract Authority","name":"authority_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Auctioneer_AmountLessThanMinimum","type":"error"},{"inputs":[],"name":"Auctioneer_BadExpiry","type":"error"},{"inputs":[],"name":"Auctioneer_InvalidCallback","type":"error"},{"inputs":[],"name":"Auctioneer_InvalidParams","type":"error"},{"inputs":[],"name":"Auctioneer_MarketNotActive","type":"error"},{"inputs":[],"name":"Auctioneer_MaxPayoutExceeded","type":"error"},{"inputs":[],"name":"Auctioneer_NewMarketsNotAllowed","type":"error"},{"inputs":[],"name":"Auctioneer_NotAuthorized","type":"error"},{"inputs":[],"name":"Auctioneer_NotEnoughCapacity","type":"error"},{"inputs":[],"name":"Auctioneer_OnlyMarketOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"MarketClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"payoutToken","type":"address"},{"indexed":true,"internalType":"address","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"uint48","name":"vesting","type":"uint48"},{"indexed":false,"internalType":"uint256","name":"fixedPrice","type":"uint256"}],"name":"MarketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"inputs":[],"name":"allowNewMarkets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"callbackAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"closeMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"params_","type":"bytes"}],"name":"createMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"currentCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggregator","outputs":[{"internalType":"contract IBondAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"getMarketInfoForPurchase","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"callbackAddr","type":"address"},{"internalType":"contract ERC20","name":"payoutToken","type":"address"},{"internalType":"contract ERC20","name":"quoteToken","type":"address"},{"internalType":"uint48","name":"vesting","type":"uint48"},{"internalType":"uint256","name":"maxPayout_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTeller","outputs":[{"internalType":"contract IBondTeller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"isInstantSwap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"isLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"marketPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"marketScale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"markets","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"contract ERC20","name":"payoutToken","type":"address"},{"internalType":"contract ERC20","name":"quoteToken","type":"address"},{"internalType":"address","name":"callbackAddr","type":"address"},{"internalType":"bool","name":"capacityInQuote","type":"bool"},{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"maxPayout","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"scale","type":"uint256"},{"internalType":"uint256","name":"sold","type":"uint256"},{"internalType":"uint256","name":"purchased","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"address","name":"referrer_","type":"address"}],"name":"maxAmountAccepted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"maxPayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositInterval","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minMarketDuration","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"newOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"address","name":"referrer_","type":"address"}],"name":"payoutFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"pullOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"minAmountOut_","type":"uint256"}],"name":"purchaseBond","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"address","name":"newOwner_","type":"address"}],"name":"pushOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status_","type":"bool"}],"name":"setAllowNewMarkets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creator_","type":"address"},{"internalType":"bool","name":"status_","type":"bool"}],"name":"setCallbackAuthStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[6]","name":"defaults_","type":"uint32[6]"}],"name":"setDefaults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint32[3]","name":"intervals_","type":"uint32[3]"}],"name":"setIntervals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"depositInterval_","type":"uint48"}],"name":"setMinDepositInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"duration_","type":"uint48"}],"name":"setMinMarketDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"terms","outputs":[{"internalType":"uint48","name":"start","type":"uint48"},{"internalType":"uint48","name":"conclusion","type":"uint48"},{"internalType":"uint48","name":"vesting","type":"uint48"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162002d9d38038062002d9d833981016040819052620000349162000125565b600080546001600160a01b03199081166001600160a01b0385811691821784556001805490931690851617909155604051869286928692869284928492909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a3505050506001600160a01b039081166080521660a0525050600580546001600160681b03191669015180000000000e1001179055506200018d9050565b6001600160a01b03811681146200012257600080fd5b50565b600080600080608085870312156200013c57600080fd5b845162000149816200010c565b60208601519094506200015c816200010c565b60408601519093506200016f816200010c565b606086015190925062000182816200010c565b939692955090935050565b60805160a051612bc7620001d66000396000818161046e01528181610c2c015281816114260152818161169f01526117520152600081816102ae01526120d30152612bc76000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c8063946824cd1161012a578063bd1f3a5e116100bd578063c7bf8ca01161008c578063d2bee32311610071578063d2bee3231461073f578063e007fa971461075c578063f61338f61461076f57600080fd5b8063c7bf8ca0146106fe578063d20406871461071157600080fd5b8063bd1f3a5e14610647578063bf48582b14610658578063bf7e214f1461066b578063c0aa0e8a1461068b57600080fd5b8063afa9d3b0116100f9578063afa9d3b01461050e578063b1283e771461051b578063bbbdd95a14610621578063bcf6cde81461063457600080fd5b8063946824cd146104495780639787d1071461046c578063acc5570c14610492578063ae418095146104fb57600080fd5b806357e333ba116101bd5780636729a41e1161018c5780637a9e5e4b116101715780637a9e5e4b146104035780638b098db3146104165780638da5cb5b1461042957600080fd5b80636729a41e146103bb578063699e17d9146103f157600080fd5b806357e333ba1461033c5780635dc4d16b1461034f5780635f77274e146103725780636352211e1461038557600080fd5b80633ad59dbc116101f95780633ad59dbc146102ac5780633adec5a7146102f357806344ee01721461031657806353c7f8e01461032957600080fd5b806310b053171461022b57806313af4035146102405780631c063a6c146102535780632750745814610289575b600080fd5b61023e6102393660046125f2565b610782565b005b61023e61024e36600461263d565b61083d565b6102766102613660046125f2565b60009081526002602052604090206004015490565b6040519081526020015b60405180910390f35b61029c6102973660046125f2565b610946565b6040519015158152602001610280565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b6102766103013660046125f2565b60009081526002602052604090206006015490565b61023e610324366004612679565b6109b3565b610276610337366004612696565b610aed565b61027661034a3660046125f2565b610cd7565b61029c61035d36600461263d565b60066020526000908152604090205460ff1681565b61023e610380366004612721565b610de5565b6102ce6103933660046125f2565b60009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6102ce6103c93660046125f2565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61023e6103ff36600461273e565b5050565b61023e61041136600461263d565b610eaa565b61029c6104243660046125f2565b611007565b6000546102ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6102766104573660046125f2565b60009081526002602052604090206007015490565b7f00000000000000000000000000000000000000000000000000000000000000006102ce565b6104a56104a03660046125f2565b61104d565b6040805173ffffffffffffffffffffffffffffffffffffffff97881681529587166020870152938616938501939093529316606083015265ffffffffffff909216608082015260a081019190915260c001610280565b61023e6105093660046125f2565b611160565b60055461029c9060ff1681565b6105ad6105293660046125f2565b6002602081905260009182526040909120805460018201549282015460038301546004840154600585015460068601546007870154600888015460099098015473ffffffffffffffffffffffffffffffffffffffff97881699881698968816978616967401000000000000000000000000000000000000000090960460ff1695908b565b6040805173ffffffffffffffffffffffffffffffffffffffff9c8d1681529a8c1660208c0152988b16988a0198909852989095166060880152921515608087015260a086019190915260c085015260e084015261010083015261012082019290925261014081019190915261016001610280565b61023e61062f366004612771565b61123e565b61023e6106423660046127aa565b611328565b61023e610655366004612828565b50565b6102766106663660046128b9565b6113d8565b6001546102ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6106d56106993660046125f2565b60036020526000908152604090205465ffffffffffff80821691660100000000000081048216916c010000000000000000000000009091041683565b6040805165ffffffffffff94851681529284166020840152921691810191909152606001610280565b61027661070c3660046127aa565b611527565b60055461072890610100900465ffffffffffff1681565b60405165ffffffffffff9091168152602001610280565b60055461072890670100000000000000900465ffffffffffff1681565b61027661076a3660046128f2565b611738565b61023e61077d366004612679565b6119fe565b60008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146107df576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600090815260046020908152604080832054600290925290912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b61086b336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b6108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60008181526002602052604081206004015415801590610988575060008281526003602052604090205465ffffffffffff428116660100000000000090920416115b80156109ad575060008281526003602052604090205465ffffffffffff428116911611155b92915050565b6109e1336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b60055465ffffffffffff61010090910481169082161080610a725750620151808165ffffffffffff16105b15610aa9576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805465ffffffffffff909216670100000000000000027fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff909216919091179055565b600080610afc83850185612930565b9050620151808160e00151610b119190612a2b565b610b1e9062015180612a77565b65ffffffffffff90811660e08301526101008201516000911615610b4757816101000151610b49565b425b9050600082610120015182610b5e9190612aa5565b90508260e0015165ffffffffffff16600014158015610b9057508065ffffffffffff168360e0015165ffffffffffff16105b15610bc7576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bd284611c48565b90508360e0015165ffffffffffff16600014610ccd57835160e08501516040517fc6e38a4b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263c6e38a4b92610c889260040173ffffffffffffffffffffffffffffffffffffffff92909216825265ffffffffffff16602082015260400190565b6020604051808303816000875af1158015610ca7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccb9190612acf565b505b9695505050505050565b60008181526002602081815260408084206006810154825161016081018452825473ffffffffffffffffffffffffffffffffffffffff9081168252600184015481169582019590955294820154841692850192909252600381015492831660608501527401000000000000000000000000000000000000000090920460ff16151560808401819052600483015460a0850152600583015460c085015260e084018290526007830154610100850152600883015461012085015260099092015461014084015291908390610dae578160a00151610dc3565b61010082015160a0830151610dc39185612526565b9050808260c0015111610dda578160c00151610ddc565b805b95945050505050565b610e13336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b610e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610f8d57506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff0000000000000000000000000000000000000000000000000000000016604482015273ffffffffffffffffffffffffffffffffffffffff9091169063b700961390606401602060405180830381865afa158015610f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8d9190612aec565b610f9657600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b6000818152600360205260408120546c01000000000000000000000000900465ffffffffffff16635dba24008111156110435742811115611046565b80155b9392505050565b6000818152600260208181526040808420815161016081018352815473ffffffffffffffffffffffffffffffffffffffff90811680835260018401548216838701819052968401548216838601819052600380860154938416606086018190527401000000000000000000000000000000000000000090940460ff1615156080860152600486015460a0860152600586015460c0860152600686015460e08601526007860154610100860152600886015461012086015260099095015461014085015289895293909552928620548695869586958695869594929391926c01000000000000000000000000900465ffffffffffff1661114b8d610cd7565b949d939c50919a509850965090945092505050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146111bd576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff1666010000000000004265ffffffffffff160217905560029091528082206004018290555182917f9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa615591a250565b61126c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b6112d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b60008281526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611385576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60009182526004602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182916114a6917f00000000000000000000000000000000000000000000000000000000000000009091169063b88c914890602401602060405180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190612b09565b869065ffffffffffff16620186a0612526565b6000858152600260205260408120600781015460069091015492935090916114da91906114d3858a612b26565b9190612526565b90506114e585610cd7565b81111561151e576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91506110469050565b6000828152600260208181526040808420815161016081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015481168286015282860154811693820193909352600382015492831660608201527401000000000000000000000000000000000000000090920460ff1615156080830152600481015460a0830152600581015460c0830152600681015460e08301819052600782015461010084015260088201546101208401526009909101546101408301528685529290915290600082608001516116155761010083015160a0840151611610918490612526565b61161b565b8260a001515b9050600061163d838561010001518660c001516125269092919063ffffffff16565b9050600081831061164e5781611650565b825b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015291925060009161171f917f00000000000000000000000000000000000000000000000000000000000000009091169063b88c914890602401602060405180830381865afa1580156116e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170c9190612b09565b839065ffffffffffff16620186a0612526565b905061172b8183612b3d565b9998505050505050505050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146117a9576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600260205260409020600381015473ffffffffffffffffffffffffffffffffffffffff16158015906118075750805473ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205460ff16155b1561183e576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61184785610946565b61187d576040517fa24c407400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078101546006820154611892918691612526565b9150828210156118ce576040517f74ec9d5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806005015482111561190c576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015474010000000000000000000000000000000000000000900460ff1661193c5780600401548211611944565b806004015484115b1561197b576040517ff3383dc900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015474010000000000000000000000000000000000000000900460ff166119a557816119a7565b835b8160040160008282546119ba9190612b26565b92505081905550838160090160008282546119d59190612b3d565b92505081905550818160080160008282546119f09190612b3d565b909155509195945050505050565b611a2c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b611a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b60055465ffffffffffff67010000000000000090910481169082161180611ac25750610e108165ffffffffffff16105b15611af9576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805465ffffffffffff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff909216919091179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff168015801590611c1b57506040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b700961390606401602060405180830381865afa158015611bf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1b9190612aec565b80611c40575060005473ffffffffffffffffffffffffffffffffffffffff8581169116145b949350505050565b60055460009060ff16611c87576040517f64be3ffa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826000015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190612b55565b90506000836020015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d739190612b55565b905060068260ff161080611d8a575060128260ff16115b15611dc1576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068160ff161080611dd6575060128160ff16115b15611e0d576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe884610140015160000b1280611e4b5750601884610140015160000b135b15611e82576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526006602052604090205460ff16158015611ebb5750604084015173ffffffffffffffffffffffffffffffffffffffff1615155b15611ef2576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084610100015165ffffffffffff16118015611f1b57504284610100015165ffffffffffff16105b15611f52576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600082610140015160240160ff16600a0a90508260a00151600003611fa5576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055461012084015165ffffffffffff670100000000000000909204821691161080611fe7575060055460c084015165ffffffffffff61010090920482169116105b8061200a575082610120015165ffffffffffff168360c0015165ffffffffffff16115b15612041576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120898460c0015165ffffffffffff1685610120015165ffffffffffff1686606001516120745786608001516114d3565b60a087015160808801516114d3918790612526565b845160208601516040517fb435914300000000000000000000000000000000000000000000000000000000815292935060009273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263b4359143926121289260040173ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b6020604051808303816000875af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b9190612b78565b90506040518061016001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015115158152602001866080015181526020018381526020018660a0015181526020018481526020016000815260200160008152506002600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160030160146101000a81548160ff02191690831515021790555060a0820151816004015560c0820151816005015560e08201518160060155610100820151816007015561012082015181600801556101408201518160090155905050600085610100015165ffffffffffff166000146123e0578561010001516123e2565b425b905060405180606001604052808265ffffffffffff1681526020018761012001518361240e9190612aa5565b65ffffffffffff908116825260e089018051821660209384015260008681526003845260409081902085518154878701519784015186166c01000000000000000000000000027fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff9887166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090921692871692909217179690961695909517909455828a01518a51915160a08c015186519190941681529384019290925273ffffffffffffffffffffffffffffffffffffffff9182169391169185917f8235b14cd272b4e791960fe1118559bb7fed86934fcffeeae9b1175103b0756d910160405180910390a450949350505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060000361257d576000841161257257600080fd5b508290049050611046565b80841161258957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006020828403121561260457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461065557600080fd5b80356126388161260b565b919050565b60006020828403121561264f57600080fd5b81356110468161260b565b65ffffffffffff8116811461065557600080fd5b80356126388161265a565b60006020828403121561268b57600080fd5b81356110468161265a565b600080602083850312156126a957600080fd5b823567ffffffffffffffff808211156126c157600080fd5b818501915085601f8301126126d557600080fd5b8135818111156126e457600080fd5b8660208285010111156126f657600080fd5b60209290920196919550909350505050565b801515811461065557600080fd5b803561263881612708565b60006020828403121561273357600080fd5b813561104681612708565b6000806080838503121561275157600080fd5b823591508360808401111561276557600080fd5b50926020919091019150565b6000806040838503121561278457600080fd5b823561278f8161260b565b9150602083013561279f81612708565b809150509250929050565b600080604083850312156127bd57600080fd5b82359150602083013561279f8161260b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715612822576128226127cf565b60405290565b600060c0828403121561283a57600080fd5b82601f83011261284957600080fd5b60405160c0810181811067ffffffffffffffff8211171561286c5761286c6127cf565b6040528060c084018581111561288157600080fd5b845b818110156128ae57803563ffffffff811681146128a05760008081fd5b835260209283019201612883565b509195945050505050565b6000806000606084860312156128ce57600080fd5b833592506020840135915060408401356128e78161260b565b809150509250925092565b60008060006060848603121561290757600080fd5b505081359360208301359350604090920135919050565b8035600081900b811461263857600080fd5b6000610160828403121561294357600080fd5b61294b6127fe565b6129548361262d565b81526129626020840161262d565b60208201526129736040840161262d565b604082015261298460608401612716565b60608201526080830135608082015260a083013560a08201526129a960c0840161266e565b60c08201526129ba60e0840161266e565b60e08201526101006129cd81850161266e565b908201526101206129df84820161266e565b908201526101406129f184820161291e565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600065ffffffffffff80841680612a6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600065ffffffffffff80831681851681830481118215151615612a9c57612a9c6129fc565b02949350505050565b600065ffffffffffff808316818516808303821115612ac657612ac66129fc565b01949350505050565b600060208284031215612ae157600080fd5b81516110468161260b565b600060208284031215612afe57600080fd5b815161104681612708565b600060208284031215612b1b57600080fd5b81516110468161265a565b600082821015612b3857612b386129fc565b500390565b60008219821115612b5057612b506129fc565b500190565b600060208284031215612b6757600080fd5b815160ff8116811461104657600080fd5b600060208284031215612b8a57600080fd5b505191905056fea2646970667358221220f92297a9e1aff74c3a75db2a5293fb44d86ebf71128c6480091bddeaa253cf0764736f6c634300080f0033000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc95000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1000000000000000000000000007bd11fca0daaeadd455b51826f9a015f2f0969000000000000000000000000007a0f48a4e3d74ab4234adf9ea9eb32f87b4b14
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102265760003560e01c8063946824cd1161012a578063bd1f3a5e116100bd578063c7bf8ca01161008c578063d2bee32311610071578063d2bee3231461073f578063e007fa971461075c578063f61338f61461076f57600080fd5b8063c7bf8ca0146106fe578063d20406871461071157600080fd5b8063bd1f3a5e14610647578063bf48582b14610658578063bf7e214f1461066b578063c0aa0e8a1461068b57600080fd5b8063afa9d3b0116100f9578063afa9d3b01461050e578063b1283e771461051b578063bbbdd95a14610621578063bcf6cde81461063457600080fd5b8063946824cd146104495780639787d1071461046c578063acc5570c14610492578063ae418095146104fb57600080fd5b806357e333ba116101bd5780636729a41e1161018c5780637a9e5e4b116101715780637a9e5e4b146104035780638b098db3146104165780638da5cb5b1461042957600080fd5b80636729a41e146103bb578063699e17d9146103f157600080fd5b806357e333ba1461033c5780635dc4d16b1461034f5780635f77274e146103725780636352211e1461038557600080fd5b80633ad59dbc116101f95780633ad59dbc146102ac5780633adec5a7146102f357806344ee01721461031657806353c7f8e01461032957600080fd5b806310b053171461022b57806313af4035146102405780631c063a6c146102535780632750745814610289575b600080fd5b61023e6102393660046125f2565b610782565b005b61023e61024e36600461263d565b61083d565b6102766102613660046125f2565b60009081526002602052604090206004015490565b6040519081526020015b60405180910390f35b61029c6102973660046125f2565b610946565b6040519015158152602001610280565b7f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d15b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b6102766103013660046125f2565b60009081526002602052604090206006015490565b61023e610324366004612679565b6109b3565b610276610337366004612696565b610aed565b61027661034a3660046125f2565b610cd7565b61029c61035d36600461263d565b60066020526000908152604090205460ff1681565b61023e610380366004612721565b610de5565b6102ce6103933660046125f2565b60009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6102ce6103c93660046125f2565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61023e6103ff36600461273e565b5050565b61023e61041136600461263d565b610eaa565b61029c6104243660046125f2565b611007565b6000546102ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6102766104573660046125f2565b60009081526002602052604090206007015490565b7f000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc956102ce565b6104a56104a03660046125f2565b61104d565b6040805173ffffffffffffffffffffffffffffffffffffffff97881681529587166020870152938616938501939093529316606083015265ffffffffffff909216608082015260a081019190915260c001610280565b61023e6105093660046125f2565b611160565b60055461029c9060ff1681565b6105ad6105293660046125f2565b6002602081905260009182526040909120805460018201549282015460038301546004840154600585015460068601546007870154600888015460099098015473ffffffffffffffffffffffffffffffffffffffff97881699881698968816978616967401000000000000000000000000000000000000000090960460ff1695908b565b6040805173ffffffffffffffffffffffffffffffffffffffff9c8d1681529a8c1660208c0152988b16988a0198909852989095166060880152921515608087015260a086019190915260c085015260e084015261010083015261012082019290925261014081019190915261016001610280565b61023e61062f366004612771565b61123e565b61023e6106423660046127aa565b611328565b61023e610655366004612828565b50565b6102766106663660046128b9565b6113d8565b6001546102ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6106d56106993660046125f2565b60036020526000908152604090205465ffffffffffff80821691660100000000000081048216916c010000000000000000000000009091041683565b6040805165ffffffffffff94851681529284166020840152921691810191909152606001610280565b61027661070c3660046127aa565b611527565b60055461072890610100900465ffffffffffff1681565b60405165ffffffffffff9091168152602001610280565b60055461072890670100000000000000900465ffffffffffff1681565b61027661076a3660046128f2565b611738565b61023e61077d366004612679565b6119fe565b60008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146107df576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600090815260046020908152604080832054600290925290912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b61086b336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b6108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60008181526002602052604081206004015415801590610988575060008281526003602052604090205465ffffffffffff428116660100000000000090920416115b80156109ad575060008281526003602052604090205465ffffffffffff428116911611155b92915050565b6109e1336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b60055465ffffffffffff61010090910481169082161080610a725750620151808165ffffffffffff16105b15610aa9576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805465ffffffffffff909216670100000000000000027fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff909216919091179055565b600080610afc83850185612930565b9050620151808160e00151610b119190612a2b565b610b1e9062015180612a77565b65ffffffffffff90811660e08301526101008201516000911615610b4757816101000151610b49565b425b9050600082610120015182610b5e9190612aa5565b90508260e0015165ffffffffffff16600014158015610b9057508065ffffffffffff168360e0015165ffffffffffff16105b15610bc7576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bd284611c48565b90508360e0015165ffffffffffff16600014610ccd57835160e08501516040517fc6e38a4b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc95169263c6e38a4b92610c889260040173ffffffffffffffffffffffffffffffffffffffff92909216825265ffffffffffff16602082015260400190565b6020604051808303816000875af1158015610ca7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccb9190612acf565b505b9695505050505050565b60008181526002602081815260408084206006810154825161016081018452825473ffffffffffffffffffffffffffffffffffffffff9081168252600184015481169582019590955294820154841692850192909252600381015492831660608501527401000000000000000000000000000000000000000090920460ff16151560808401819052600483015460a0850152600583015460c085015260e084018290526007830154610100850152600883015461012085015260099092015461014084015291908390610dae578160a00151610dc3565b61010082015160a0830151610dc39185612526565b9050808260c0015111610dda578160c00151610ddc565b805b95945050505050565b610e13336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b610e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610f8d57506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff0000000000000000000000000000000000000000000000000000000016604482015273ffffffffffffffffffffffffffffffffffffffff9091169063b700961390606401602060405180830381865afa158015610f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8d9190612aec565b610f9657600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b6000818152600360205260408120546c01000000000000000000000000900465ffffffffffff16635dba24008111156110435742811115611046565b80155b9392505050565b6000818152600260208181526040808420815161016081018352815473ffffffffffffffffffffffffffffffffffffffff90811680835260018401548216838701819052968401548216838601819052600380860154938416606086018190527401000000000000000000000000000000000000000090940460ff1615156080860152600486015460a0860152600586015460c0860152600686015460e08601526007860154610100860152600886015461012086015260099095015461014085015289895293909552928620548695869586958695869594929391926c01000000000000000000000000900465ffffffffffff1661114b8d610cd7565b949d939c50919a509850965090945092505050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146111bd576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff1666010000000000004265ffffffffffff160217905560029091528082206004018290555182917f9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa615591a250565b61126c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b6112d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b60008281526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611385576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60009182526004602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182916114a6917f000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc959091169063b88c914890602401602060405180830381865afa15801561146f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114939190612b09565b869065ffffffffffff16620186a0612526565b6000858152600260205260408120600781015460069091015492935090916114da91906114d3858a612b26565b9190612526565b90506114e585610cd7565b81111561151e576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91506110469050565b6000828152600260208181526040808420815161016081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015481168286015282860154811693820193909352600382015492831660608201527401000000000000000000000000000000000000000090920460ff1615156080830152600481015460a0830152600581015460c0830152600681015460e08301819052600782015461010084015260088201546101208401526009909101546101408301528685529290915290600082608001516116155761010083015160a0840151611610918490612526565b61161b565b8260a001515b9050600061163d838561010001518660c001516125269092919063ffffffff16565b9050600081831061164e5781611650565b825b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015291925060009161171f917f000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc959091169063b88c914890602401602060405180830381865afa1580156116e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170c9190612b09565b839065ffffffffffff16620186a0612526565b905061172b8183612b3d565b9998505050505050505050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc9516146117a9576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600260205260409020600381015473ffffffffffffffffffffffffffffffffffffffff16158015906118075750805473ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205460ff16155b1561183e576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61184785610946565b61187d576040517fa24c407400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078101546006820154611892918691612526565b9150828210156118ce576040517f74ec9d5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806005015482111561190c576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015474010000000000000000000000000000000000000000900460ff1661193c5780600401548211611944565b806004015484115b1561197b576040517ff3383dc900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015474010000000000000000000000000000000000000000900460ff166119a557816119a7565b835b8160040160008282546119ba9190612b26565b92505081905550838160090160008282546119d59190612b3d565b92505081905550818160080160008282546119f09190612b3d565b909155509195945050505050565b611a2c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611b37565b611a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016108cd565b60055465ffffffffffff67010000000000000090910481169082161180611ac25750610e108165ffffffffffff16105b15611af9576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805465ffffffffffff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff909216919091179055565b60015460009073ffffffffffffffffffffffffffffffffffffffff168015801590611c1b57506040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b700961390606401602060405180830381865afa158015611bf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1b9190612aec565b80611c40575060005473ffffffffffffffffffffffffffffffffffffffff8581169116145b949350505050565b60055460009060ff16611c87576040517f64be3ffa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826000015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190612b55565b90506000836020015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d739190612b55565b905060068260ff161080611d8a575060128260ff16115b15611dc1576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068160ff161080611dd6575060128160ff16115b15611e0d576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe884610140015160000b1280611e4b5750601884610140015160000b135b15611e82576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526006602052604090205460ff16158015611ebb5750604084015173ffffffffffffffffffffffffffffffffffffffff1615155b15611ef2576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084610100015165ffffffffffff16118015611f1b57504284610100015165ffffffffffff16105b15611f52576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600082610140015160240160ff16600a0a90508260a00151600003611fa5576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055461012084015165ffffffffffff670100000000000000909204821691161080611fe7575060055460c084015165ffffffffffff61010090920482169116105b8061200a575082610120015165ffffffffffff168360c0015165ffffffffffff16115b15612041576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120898460c0015165ffffffffffff1685610120015165ffffffffffff1686606001516120745786608001516114d3565b60a087015160808801516114d3918790612526565b845160208601516040517fb435914300000000000000000000000000000000000000000000000000000000815292935060009273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1169263b4359143926121289260040173ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b6020604051808303816000875af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b9190612b78565b90506040518061016001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015115158152602001866080015181526020018381526020018660a0015181526020018481526020016000815260200160008152506002600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160030160146101000a81548160ff02191690831515021790555060a0820151816004015560c0820151816005015560e08201518160060155610100820151816007015561012082015181600801556101408201518160090155905050600085610100015165ffffffffffff166000146123e0578561010001516123e2565b425b905060405180606001604052808265ffffffffffff1681526020018761012001518361240e9190612aa5565b65ffffffffffff908116825260e089018051821660209384015260008681526003845260409081902085518154878701519784015186166c01000000000000000000000000027fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff9887166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090921692871692909217179690961695909517909455828a01518a51915160a08c015186519190941681529384019290925273ffffffffffffffffffffffffffffffffffffffff9182169391169185917f8235b14cd272b4e791960fe1118559bb7fed86934fcffeeae9b1175103b0756d910160405180910390a450949350505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060000361257d576000841161257257600080fd5b508290049050611046565b80841161258957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006020828403121561260457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461065557600080fd5b80356126388161260b565b919050565b60006020828403121561264f57600080fd5b81356110468161260b565b65ffffffffffff8116811461065557600080fd5b80356126388161265a565b60006020828403121561268b57600080fd5b81356110468161265a565b600080602083850312156126a957600080fd5b823567ffffffffffffffff808211156126c157600080fd5b818501915085601f8301126126d557600080fd5b8135818111156126e457600080fd5b8660208285010111156126f657600080fd5b60209290920196919550909350505050565b801515811461065557600080fd5b803561263881612708565b60006020828403121561273357600080fd5b813561104681612708565b6000806080838503121561275157600080fd5b823591508360808401111561276557600080fd5b50926020919091019150565b6000806040838503121561278457600080fd5b823561278f8161260b565b9150602083013561279f81612708565b809150509250929050565b600080604083850312156127bd57600080fd5b82359150602083013561279f8161260b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715612822576128226127cf565b60405290565b600060c0828403121561283a57600080fd5b82601f83011261284957600080fd5b60405160c0810181811067ffffffffffffffff8211171561286c5761286c6127cf565b6040528060c084018581111561288157600080fd5b845b818110156128ae57803563ffffffff811681146128a05760008081fd5b835260209283019201612883565b509195945050505050565b6000806000606084860312156128ce57600080fd5b833592506020840135915060408401356128e78161260b565b809150509250925092565b60008060006060848603121561290757600080fd5b505081359360208301359350604090920135919050565b8035600081900b811461263857600080fd5b6000610160828403121561294357600080fd5b61294b6127fe565b6129548361262d565b81526129626020840161262d565b60208201526129736040840161262d565b604082015261298460608401612716565b60608201526080830135608082015260a083013560a08201526129a960c0840161266e565b60c08201526129ba60e0840161266e565b60e08201526101006129cd81850161266e565b908201526101206129df84820161266e565b908201526101406129f184820161291e565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600065ffffffffffff80841680612a6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600065ffffffffffff80831681851681830481118215151615612a9c57612a9c6129fc565b02949350505050565b600065ffffffffffff808316818516808303821115612ac657612ac66129fc565b01949350505050565b600060208284031215612ae157600080fd5b81516110468161260b565b600060208284031215612afe57600080fd5b815161104681612708565b600060208284031215612b1b57600080fd5b81516110468161265a565b600082821015612b3857612b386129fc565b500390565b60008219821115612b5057612b506129fc565b500190565b600060208284031215612b6757600080fd5b815160ff8116811461104657600080fd5b600060208284031215612b8a57600080fd5b505191905056fea2646970667358221220f92297a9e1aff74c3a75db2a5293fb44d86ebf71128c6480091bddeaa253cf0764736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc95000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1000000000000000000000000007bd11fca0daaeadd455b51826f9a015f2f0969000000000000000000000000007a0f48a4e3d74ab4234adf9ea9eb32f87b4b14
-----Decoded View---------------
Arg [0] : teller_ (address): 0x007FE70dc9797C4198528aE43d8195ffF82Bdc95
Arg [1] : aggregator_ (address): 0x007A66A2a13415DB3613C1a4dd1C942A285902d1
Arg [2] : guardian_ (address): 0x007BD11FCa0dAaeaDD455b51826F9a015f2f0969
Arg [3] : authority_ (address): 0x007A0F48A4e3d74Ab4234adf9eA9EB32f87b4b14
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc95
Arg [1] : 000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1
Arg [2] : 000000000000000000000000007bd11fca0daaeadd455b51826f9a015f2f0969
Arg [3] : 000000000000000000000000007a0f48a4e3d74ab4234adf9ea9eb32f87b4b14
Loading...
Loading
[ Download: CSV Export ]
[ 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.