Contract 0x007FEA32545a39Ff558a1367BBbC1A22bc7ABEfD 9

Contract Overview

Balance:
0 ETH
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xd80eeb25244e076abf4045695841d32cfa6e258017075439e5c2a152df4a8f48Create Market21161842022-12-02 9:51:12292 days 23 hrs ago0x24ef8c193e02c0d952ec56c0097df33b7947b7f6 IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.00006244 0.1
0x24e76f6ebde0cb14c2df8f226d8f63cb6ecd0589dca12f2a292d2383ca8b4802Create Market21041012022-12-02 5:21:24293 days 3 hrs ago0x24ef8c193e02c0d952ec56c0097df33b7947b7f6 IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.00006245 0.1
0xc5b73c14a0ad412b14a6a830d9c2a603400a918f2af433d331bb6bf701898bbfCreate Market21029372022-12-02 4:41:32293 days 4 hrs ago0xda8b43d5da504a3a418aeedce1ece868536807fa IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.00005041 0.1
0xcefcdd415e2cddd51a0f569205e059d39a3260d3af1ef09178f3b0ef61ff2788Create Market21022632022-12-02 4:16:08293 days 5 hrs ago0xda8b43d5da504a3a418aeedce1ece868536807fa IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.00006249 0.1
0xb29289014d47e24f64c03291df0542c60f05132eb042744c503893dc6d26d929Create Market19342132022-11-28 20:07:53296 days 13 hrs ago0x19518e4d4e542f4b0fc27366c23fac7a0ba491da IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.000083910.1
0x4ab17aed67e3955bc930a942db0c14ace92fefec699b47cf568024212e79c7c9Set Callback Aut...19310732022-11-28 18:29:44296 days 14 hrs ago0x1a5309f208f161a393e8b5a253de8ab894a67188 IN  0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH0.000015830.1
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x421082e82138479231b59e896dbc16927a74a0513959b062eb290ebcd1b05ca521284052022-12-02 13:59:54292 days 19 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x421082e82138479231b59e896dbc16927a74a0513959b062eb290ebcd1b05ca521284052022-12-02 13:59:54292 days 19 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x421082e82138479231b59e896dbc16927a74a0513959b062eb290ebcd1b05ca521284052022-12-02 13:59:54292 days 19 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0xd80eeb25244e076abf4045695841d32cfa6e258017075439e5c2a152df4a8f4821161842022-12-02 9:51:12292 days 23 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007fe70dc9797c4198528ae43d8195fff82bdc950 ETH
0xd80eeb25244e076abf4045695841d32cfa6e258017075439e5c2a152df4a8f4821161842022-12-02 9:51:12292 days 23 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007a66a2a13415db3613c1a4dd1c942a285902d10 ETH
0xd80eeb25244e076abf4045695841d32cfa6e258017075439e5c2a152df4a8f4821161842022-12-02 9:51:12292 days 23 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x6cec0ba158fd0c8bc48eafa11f8560318b32258d0 ETH
0xd80eeb25244e076abf4045695841d32cfa6e258017075439e5c2a152df4a8f4821161842022-12-02 9:51:12292 days 23 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0xca93c9bfac39efc5b069066a0970c3036c3029c90 ETH
0x24e76f6ebde0cb14c2df8f226d8f63cb6ecd0589dca12f2a292d2383ca8b480221041012022-12-02 5:21:24293 days 3 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007fe70dc9797c4198528ae43d8195fff82bdc950 ETH
0x24e76f6ebde0cb14c2df8f226d8f63cb6ecd0589dca12f2a292d2383ca8b480221041012022-12-02 5:21:24293 days 3 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007a66a2a13415db3613c1a4dd1c942a285902d10 ETH
0x24e76f6ebde0cb14c2df8f226d8f63cb6ecd0589dca12f2a292d2383ca8b480221041012022-12-02 5:21:24293 days 3 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0xca93c9bfac39efc5b069066a0970c3036c3029c90 ETH
0x24e76f6ebde0cb14c2df8f226d8f63cb6ecd0589dca12f2a292d2383ca8b480221041012022-12-02 5:21:24293 days 3 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x6cec0ba158fd0c8bc48eafa11f8560318b32258d0 ETH
0xc5b73c14a0ad412b14a6a830d9c2a603400a918f2af433d331bb6bf701898bbf21029372022-12-02 4:41:32293 days 4 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007fe70dc9797c4198528ae43d8195fff82bdc950 ETH
0xc5b73c14a0ad412b14a6a830d9c2a603400a918f2af433d331bb6bf701898bbf21029372022-12-02 4:41:32293 days 4 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007a66a2a13415db3613c1a4dd1c942a285902d10 ETH
0xc5b73c14a0ad412b14a6a830d9c2a603400a918f2af433d331bb6bf701898bbf21029372022-12-02 4:41:32293 days 4 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0xca93c9bfac39efc5b069066a0970c3036c3029c90 ETH
0xc5b73c14a0ad412b14a6a830d9c2a603400a918f2af433d331bb6bf701898bbf21029372022-12-02 4:41:32293 days 4 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x6cec0ba158fd0c8bc48eafa11f8560318b32258d0 ETH
0xcefcdd415e2cddd51a0f569205e059d39a3260d3af1ef09178f3b0ef61ff278821022632022-12-02 4:16:08293 days 5 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007fe70dc9797c4198528ae43d8195fff82bdc950 ETH
0xcefcdd415e2cddd51a0f569205e059d39a3260d3af1ef09178f3b0ef61ff278821022632022-12-02 4:16:08293 days 5 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x007a66a2a13415db3613c1a4dd1c942a285902d10 ETH
0xcefcdd415e2cddd51a0f569205e059d39a3260d3af1ef09178f3b0ef61ff278821022632022-12-02 4:16:08293 days 5 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0xca93c9bfac39efc5b069066a0970c3036c3029c90 ETH
0xcefcdd415e2cddd51a0f569205e059d39a3260d3af1ef09178f3b0ef61ff278821022632022-12-02 4:16:08293 days 5 hrs ago 0x007fea32545a39ff558a1367bbbc1a22bc7abefd 0x6cec0ba158fd0c8bc48eafa11f8560318b32258d0 ETH
0x62a8d0068499a5d313802c2fce281563f49424ee79ba7dcbe4995167f00371fd20051252022-11-30 8:07:54295 days 1 hr ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x62a8d0068499a5d313802c2fce281563f49424ee79ba7dcbe4995167f00371fd20051252022-11-30 8:07:54295 days 1 hr ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x62a8d0068499a5d313802c2fce281563f49424ee79ba7dcbe4995167f00371fd20051252022-11-30 8:07:54295 days 1 hr ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x48b6cb1940c76ad616214bc22f039a3492f7fd71a50f12fd5dac26c674df85f219804042022-11-29 18:15:18295 days 15 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x48b6cb1940c76ad616214bc22f039a3492f7fd71a50f12fd5dac26c674df85f219804042022-11-29 18:15:18295 days 15 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
0x48b6cb1940c76ad616214bc22f039a3492f7fd71a50f12fd5dac26c674df85f219804042022-11-29 18:15:18295 days 15 hrs ago 0x007fe70dc9797c4198528ae43d8195fff82bdc95 0x007fea32545a39ff558a1367bbbc1a22bc7abefd0 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BondFixedExpirySDA

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 16 : Clone.sol
// 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)
            )
        }
    }
}

File 2 of 16 : Auth.sol
// 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);
}

File 3 of 16 : ERC20.sol
// 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);
    }
}

File 4 of 16 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 5 of 16 : BondFixedExpirySDA.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.15;

import {BondBaseSDA, IBondAggregator, Authority} from "./bases/BondBaseSDA.sol";
import {IBondTeller} from "./interfaces/IBondTeller.sol";
import {IBondFixedExpiryTeller} from "./interfaces/IBondFixedExpiryTeller.sol";

/// @title Bond Fixed-Expiry Sequential Dutch Auctioneer
/// @notice Bond Fixed-Expiry Sequential Dutch Auctioneer 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 Fixed-Expiry Auctioneer is an implementation of the
///      Bond Base Sequential Dutch Auctioneer contract specific to creating bond markets where
///      all purchases on that market vest at a certain timestamp.
///
/// @author Oighty, Zeus, Potted Meat, indigo
contract BondFixedExpirySDA is BondBaseSDA {
    /* ========== CONSTRUCTOR ========== */
    constructor(
        IBondTeller teller_,
        IBondAggregator aggregator_,
        address guardian_,
        Authority authority_
    ) BondBaseSDA(teller_, aggregator_, guardian_, authority_) {}

    /// @inheritdoc BondBaseSDA
    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;

        // Check that the vesting parameter is valid for a fixed-expiry market
        if (params.vesting != 0 && params.vesting < params.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;
    }
}

File 6 of 16 : ERC20BondToken.sol
// 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);
    }
}

File 7 of 16 : BondBaseSDA.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.15;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol";
import {Auth, Authority} from "solmate/auth/Auth.sol";

import {IBondSDA, IBondAuctioneer} from "../interfaces/IBondSDA.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 Sequential Dutch Auctioneer (SDA)
/// @notice Bond Sequential Dutch Auctioneer Base Contract
/// @dev Bond Protocol is a 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 Auctioneer contract allows users to create and manage bond markets.
///      All bond pricing logic and market data is stored in the Auctioneer.
///      A Auctioneer is dependent on a Teller to serve external users and
///      an Aggregator to register new markets. This implementation of the Auctioneer
///      uses a Sequential Dutch Auction pricing system to buy a target amount of quote
///      tokens or sell a target amount of payout tokens over the duration of a market.
///
/// @author Oighty, Zeus, Potted Meat, indigo
abstract contract BondBaseSDA is IBondSDA, Auth {
    using TransferHelper for ERC20;
    using FullMath for uint256;

    /* ========== ERRORS ========== */

    error Auctioneer_OnlyMarketOwner();
    error Auctioneer_InitialPriceLessThanMin();
    error Auctioneer_MarketConcluded(uint256 conclusion_);
    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 initialPrice
    );
    event MarketClosed(uint256 indexed id);
    event Tuned(uint256 indexed id, uint256 oldControlVariable, uint256 newControlVariable);
    event DefaultsUpdated(
        uint32 defaultTuneInterval,
        uint32 defaultTuneAdjustment,
        uint32 minDebtDecayInterval,
        uint32 minDepositInterval,
        uint32 minMarketDuration,
        uint32 minDebtBuffer
    );

    /* ========== STATE VARIABLES ========== */

    /// @notice Main information pertaining to bond market
    mapping(uint256 => BondMarket) public markets;

    /// @notice Information used to control how a bond market changes
    mapping(uint256 => BondTerms) public terms;

    /// @notice Data needed for tuning bond market
    mapping(uint256 => BondMetadata) public metadata;

    /// @notice Control variable changes
    mapping(uint256 => Adjustment) public adjustments;

    /// @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;

    /// @notice Whether or not the market creator is authorized to use a callback address
    mapping(address => bool) public callbackAuthorized;

    /// Sane defaults for tuning. Can be adjusted for a specific market via setters.
    uint32 public defaultTuneInterval;
    uint32 public defaultTuneAdjustment;
    /// Minimum values for decay, deposit interval, market duration and debt buffer.
    uint32 public minDebtDecayInterval;
    uint32 public minDepositInterval;
    uint32 public minMarketDuration;
    uint32 public minDebtBuffer;

    // 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 FEE_DECIMALS = 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_;

        defaultTuneInterval = 24 hours;
        defaultTuneAdjustment = 1 hours;
        minDebtDecayInterval = 3 days;
        minDepositInterval = 1 hours;
        minMarketDuration = 1 days;
        minDebtBuffer = 10000; // 10%

        allowNewMarkets = true;
    }

    /* ========== MARKET FUNCTIONS ========== */

    /// @inheritdoc IBondAuctioneer
    function createMarket(bytes calldata params_) external virtual returns (uint256);

    /// @notice core market creation logic, see IBondSDA.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();
        }

        // Unit to scale calculation for this market by to ensure reasonable values
        // for price, debt, and control variable without under/overflows.
        // See IBondSDA for more details.
        //
        // scaleAdjustment should be equal to (payoutDecimals - quoteDecimals) - ((payoutPriceDecimals - quotePriceDecimals) / 2)
        uint256 scale;
        unchecked {
            scale = 10**uint8(36 + params_.scaleAdjustment);
        }

        if (params_.formattedInitialPrice < params_.formattedMinimumPrice)
            revert Auctioneer_InitialPriceLessThanMin();

        // Register new market on aggregator and get marketId
        uint256 marketId = _aggregator.registerMarket(params_.payoutToken, params_.quoteToken);

        uint32 secondsToConclusion;
        uint32 debtDecayInterval;
        {
            // Conclusion must be later than the current block timestamp or will revert
            secondsToConclusion = uint32(params_.conclusion - block.timestamp);
            if (
                secondsToConclusion < minMarketDuration ||
                params_.depositInterval < minDepositInterval ||
                params_.depositInterval > secondsToConclusion
            ) revert Auctioneer_InvalidParams();

            // The debt decay interval is how long it takes for price to drop to 0 from the last decay timestamp.
            // In reality, a 50% drop is likely a guaranteed bond sale. Therefore, debt decay interval needs to be
            // long enough to allow a bond to adjust if oversold. It also needs to be some multiple of deposit interval
            // because you don't want to go from 100 to 0 during the time frame you expected to sell a single bond.
            // A multiple of 5 is a sane default observed from running OP v1 bond markets.
            uint32 userDebtDecay = params_.depositInterval * 5;
            debtDecayInterval = minDebtDecayInterval > userDebtDecay
                ? minDebtDecayInterval
                : userDebtDecay;

            uint256 tuneIntervalCapacity = params_.capacity.mulDiv(
                uint256(
                    params_.depositInterval > defaultTuneInterval
                        ? params_.depositInterval
                        : defaultTuneInterval
                ),
                uint256(secondsToConclusion)
            );

            metadata[marketId] = BondMetadata({
                lastTune: uint48(block.timestamp),
                lastDecay: uint48(block.timestamp),
                length: secondsToConclusion,
                depositInterval: params_.depositInterval,
                tuneInterval: params_.depositInterval > defaultTuneInterval
                    ? params_.depositInterval
                    : defaultTuneInterval,
                tuneAdjustmentDelay: defaultTuneAdjustment,
                debtDecayInterval: debtDecayInterval,
                tuneIntervalCapacity: tuneIntervalCapacity,
                tuneBelowCapacity: params_.capacity - tuneIntervalCapacity,
                lastTuneDebt: (
                    params_.capacityInQuote
                        ? params_.capacity.mulDiv(scale, params_.formattedInitialPrice)
                        : params_.capacity
                ).mulDiv(uint256(debtDecayInterval), uint256(secondsToConclusion))
            });
        }

        // Initial target debt is equal to capacity scaled by the ratio of the debt decay interval and the length of the market.
        // This is the amount of debt that should be decayed over the decay interval if no purchases are made.
        // Note price should be passed in a specific format:
        // price = (payoutPriceCoefficient / quotePriceCoefficient)
        //         * 10**(36 + scaleAdjustment + quoteDecimals - payoutDecimals + payoutPriceDecimals - quotePriceDecimals)
        // See IBondSDA for more details and variable definitions.
        uint256 targetDebt;
        uint256 maxPayout;
        {
            uint256 capacity = params_.capacityInQuote
                ? params_.capacity.mulDiv(scale, params_.formattedInitialPrice)
                : params_.capacity;

            targetDebt = capacity.mulDiv(uint256(debtDecayInterval), uint256(secondsToConclusion));

            // Max payout is the amount of capacity that should be utilized in a deposit
            // interval. for example, if capacity is 1,000 TOKEN, there are 10 days to conclusion,
            // and the preferred deposit interval is 1 day, max payout would be 100 TOKEN.
            // Additionally, max payout is the maximum amount that a user can receive from a single
            // purchase at that moment in time.
            maxPayout = capacity.mulDiv(
                uint256(params_.depositInterval),
                uint256(secondsToConclusion)
            );
        }

        markets[marketId] = BondMarket({
            owner: msg.sender,
            payoutToken: params_.payoutToken,
            quoteToken: params_.quoteToken,
            callbackAddr: params_.callbackAddr,
            capacityInQuote: params_.capacityInQuote,
            capacity: params_.capacity,
            totalDebt: targetDebt,
            minPrice: params_.formattedMinimumPrice,
            maxPayout: maxPayout,
            purchased: 0,
            sold: 0,
            scale: scale
        });

        // Max debt serves as a circuit breaker for the market. let's say the quote token is a stablecoin,
        // and that stablecoin depegs. without max debt, the market would continue to buy until it runs
        // out of capacity. this is configurable with a 3 decimal buffer (1000 = 1% above initial price).
        // Note that its likely advisable to keep this buffer wide.
        // Note that the buffer is above 100%. i.e. 10% buffer = initial debt * 1.1
        // 1e5 = 100,000. 10,000 / 100,000 = 10%.
        // See IBondSDA.MarketParams for more information on determining a reasonable debt buffer.
        uint256 minDebtBuffer_ = maxPayout.mulDiv(FEE_DECIMALS, targetDebt) > minDebtBuffer
            ? maxPayout.mulDiv(FEE_DECIMALS, targetDebt)
            : minDebtBuffer;
        uint256 maxDebt = targetDebt +
            targetDebt.mulDiv(
                uint256(params_.debtBuffer > minDebtBuffer_ ? params_.debtBuffer : minDebtBuffer_),
                1e5
            );

        // The control variable is set as the ratio of price to the initial targetDebt, scaled to prevent under/overflows.
        // It determines the price of the market as the debt decays and is tuned by the market based on user activity.
        // See _tune() for more information.
        //
        // price = control variable * debt / scale
        // therefore, control variable = price * scale / debt
        uint256 controlVariable = params_.formattedInitialPrice.mulDiv(scale, targetDebt);

        terms[marketId] = BondTerms({
            controlVariable: controlVariable,
            maxDebt: maxDebt,
            vesting: params_.vesting,
            conclusion: params_.conclusion
        });

        emit MarketCreated(
            marketId,
            address(params_.payoutToken),
            address(params_.quoteToken),
            params_.vesting,
            params_.formattedInitialPrice
        );

        return marketId;
    }

    /// @inheritdoc IBondAuctioneer
    function setIntervals(uint256 id_, uint32[3] calldata intervals_) external override {
        // Check that the market is live
        if (!isLive(id_)) revert Auctioneer_InvalidParams();

        // Check that the intervals are non-zero
        if (intervals_[0] == 0 || intervals_[1] == 0 || intervals_[2] == 0)
            revert Auctioneer_InvalidParams();

        // Check that tuneInterval >= tuneAdjustmentDelay
        if (intervals_[0] < intervals_[1]) revert Auctioneer_InvalidParams();

        BondMetadata storage meta = metadata[id_];
        // Check that tuneInterval >= depositInterval
        if (intervals_[0] < meta.depositInterval) revert Auctioneer_InvalidParams();

        // Check that debtDecayInterval >= minDebtDecayInterval
        if (intervals_[2] < minDebtDecayInterval) revert Auctioneer_InvalidParams();

        // Check that sender is market owner
        BondMarket memory market = markets[id_];
        if (msg.sender != market.owner) revert Auctioneer_OnlyMarketOwner();

        // Update intervals
        meta.tuneInterval = intervals_[0];
        meta.tuneIntervalCapacity = market.capacity.mulDiv(
            uint256(intervals_[0]),
            uint256(terms[id_].conclusion) - block.timestamp
        ); // don't have a stored value for market duration, this will update tuneIntervalCapacity based on time remaining
        meta.tuneBelowCapacity = market.capacity > meta.tuneIntervalCapacity
            ? market.capacity - meta.tuneIntervalCapacity
            : 0;
        meta.tuneAdjustmentDelay = intervals_[1];
        meta.debtDecayInterval = intervals_[2];
    }

    /// @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 IBondAuctioneer
    function setDefaults(uint32[6] memory defaults_) external override requiresAuth {
        // Restricted to authorized addresses

        // Validate inputs
        // Check that defaultTuneInterval >= defaultTuneAdjustment
        if (defaults_[0] < defaults_[1]) revert Auctioneer_InvalidParams();

        // Check that defaultTuneInterval >= minDepositInterval
        if (defaults_[0] < defaults_[3]) revert Auctioneer_InvalidParams();

        // Check that minDepositInterval <= minMarketDuration
        if (defaults_[3] > defaults_[4]) revert Auctioneer_InvalidParams();

        // Check that minDebtDecayInterval >= 5 * minDepositInterval
        if (defaults_[2] < defaults_[3] * 5) revert Auctioneer_InvalidParams();

        // Update defaults
        defaultTuneInterval = defaults_[0];
        defaultTuneAdjustment = defaults_[1];
        minDebtDecayInterval = defaults_[2];
        minDepositInterval = defaults_[3];
        minMarketDuration = defaults_[4];
        minDebtBuffer = defaults_[5];

        emit DefaultsUpdated(
            defaultTuneInterval,
            defaultTuneAdjustment,
            minDebtDecayInterval,
            minDepositInterval,
            minMarketDuration,
            minDebtBuffer
        );
    }

    /// @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();
        _close(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_];
        BondTerms memory term = terms[id_];

        // If market uses a callback, check that owner is still callback authorized
        if (market.callbackAddr != address(0) && !callbackAuthorized[market.owner])
            revert Auctioneer_NotAuthorized();

        // Markets end at a defined timestamp
        uint48 currentTime = uint48(block.timestamp);
        if (currentTime >= term.conclusion) revert Auctioneer_MarketConcluded(term.conclusion);

        uint256 price;
        (price, payout) = _decayAndGetPrice(id_, amount_, uint48(block.timestamp)); // Debt and the control variable decay over time

        // Payout must be greater than user inputted minimum
        if (payout < minAmountOut_) revert Auctioneer_AmountLessThanMinimum();

        // Markets have a max payout amount, capping size because deposits
        // do not experience slippage. max payout is recalculated upon tuning
        if (payout > market.maxPayout) revert Auctioneer_MaxPayoutExceeded();

        // Update Capacity and Debt values

        // 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;

        // Circuit breaker. If max debt is breached, the market is closed
        if (term.maxDebt < market.totalDebt) {
            _close(id_);
        } else {
            // If market will continue, the control variable is tuned to to expend remaining capacity over remaining market duration
            _tune(id_, currentTime, price);
        }
    }

    /* ========== INTERNAL DEPO FUNCTIONS ========== */

    /// @notice          Close a market
    /// @dev             Closing a market sets capacity to 0 and immediately stops bonding
    function _close(uint256 id_) internal {
        terms[id_].conclusion = uint48(block.timestamp);
        markets[id_].capacity = 0;

        emit MarketClosed(id_);
    }

    /// @notice                 Decay debt, and adjust control variable if there is an active change
    /// @param id_              ID of market
    /// @param amount_          Amount of quote tokens being purchased
    /// @param time_            Current timestamp (saves gas when passed in)
    /// @return marketPrice_    Current market price of bond, accounting for decay
    /// @return payout_         Amount of payout tokens received at current price
    function _decayAndGetPrice(
        uint256 id_,
        uint256 amount_,
        uint48 time_
    ) internal returns (uint256 marketPrice_, uint256 payout_) {
        BondMarket memory market = markets[id_];

        // Debt is a time-decayed sum of tokens spent in a market
        // Debt is added when deposits occur and removed over time
        // |
        // |    debt falls with
        // |   / \  inactivity        / \
        // | /     \              /\ /   \
        // |         \           /        \ / \
        // |           \      /\/
        // |             \  /  and rises
        // |                with deposits
        // |
        // |------------------------------------| t

        // Decay debt by the amount of time since the last decay
        uint256 decayedDebt = currentDebt(id_);
        markets[id_].totalDebt = decayedDebt;

        // Control variable decay

        // The bond control variable is continually tuned. When it is lowered (which
        // lowers the market price), the change is carried out smoothly over time.
        if (adjustments[id_].active) {
            Adjustment storage adjustment = adjustments[id_];

            (uint256 adjustBy, uint48 secondsSince, bool stillActive) = _controlDecay(id_);
            terms[id_].controlVariable -= adjustBy;

            if (stillActive) {
                adjustment.change -= adjustBy;
                adjustment.timeToAdjusted -= secondsSince;
                adjustment.lastAdjustment = time_;
            } else {
                adjustment.active = false;
            }
        }

        // Price is not allowed to be lower than the minimum price
        marketPrice_ = _currentMarketPrice(id_);
        uint256 minPrice = market.minPrice;
        if (marketPrice_ < minPrice) marketPrice_ = minPrice;

        // Payout for the deposit = amount / price
        //
        // where:
        // payout = payout tokens out
        // amount = quote tokens in
        // price = quote tokens : payout token (i.e. 200 QUOTE : BASE), adjusted for scaling
        payout_ = amount_.mulDiv(market.scale, marketPrice_);

        // Cache storage variables to memory
        uint256 debtDecayInterval = uint256(metadata[id_].debtDecayInterval);
        uint256 lastTuneDebt = metadata[id_].lastTuneDebt;
        uint256 lastDecay = uint256(metadata[id_].lastDecay);

        // Set last decay timestamp based on size of purchase to linearize decay
        uint256 lastDecayIncrement = debtDecayInterval.mulDivUp(payout_, lastTuneDebt);
        metadata[id_].lastDecay += uint48(lastDecayIncrement);

        // Update total debt following the purchase
        // Goal is to have the same decayed debt post-purchase as pre-purchase so that price is the same as before purchase and then add new debt to increase price
        // 1. Adjust total debt so that decayed debt is equal to the current debt after updating the last decay timestamp.
        //    This is the currentDebt function solved for totalDebt and adding lastDecayIncrement (the number of seconds lastDecay moves forward in time)
        //    to the number of seconds used to calculate the previous currentDebt.
        // 2. Add the payout to the total debt to increase the price.
        uint256 decayOffset = time_ > lastDecay
            ? (
                debtDecayInterval > (time_ - lastDecay)
                    ? debtDecayInterval - (time_ - lastDecay)
                    : 0
            )
            : debtDecayInterval + (lastDecay - time_);
        markets[id_].totalDebt =
            decayedDebt.mulDiv(debtDecayInterval, decayOffset + lastDecayIncrement) +
            payout_ +
            1; // add 1 to satisfy price inequality
    }

    /// @notice             Auto-adjust control variable to hit capacity/spend target
    /// @param id_          ID of market
    /// @param time_        Timestamp (saves gas when passed in)
    /// @param price_       Current price of the market
    function _tune(
        uint256 id_,
        uint48 time_,
        uint256 price_
    ) internal {
        BondMetadata memory meta = metadata[id_];
        BondMarket memory market = markets[id_];

        // Market tunes in 2 situations:
        // 1. If capacity has exceeded target since last tune adjustment and the market is oversold
        // 2. If a tune interval has passed since last tune adjustment and the market is undersold
        //
        // Markets are created with a target capacity with the expectation that capacity will
        // be utilized evenly over the duration of the market.
        // The intuition with tuning is:
        // - When the market is ahead of target capacity, we should tune based on capacity.
        // - When the market is behind target capacity, we should tune based on time.

        // Compute seconds remaining until market will conclude
        uint256 timeRemaining = uint256(terms[id_].conclusion - time_);

        // Standardize capacity into an payout token amount
        uint256 capacity = market.capacityInQuote
            ? market.capacity.mulDiv(market.scale, price_)
            : market.capacity;
        // Calculate initial capacity based on remaining capacity and amount sold/purchased up to this point
        uint256 initialCapacity = capacity +
            (market.capacityInQuote ? market.purchased.mulDiv(market.scale, price_) : market.sold);

        // Calculate timeNeutralCapacity as the capacity expected to be sold up to this point and the current capacity
        // Higher than initial capacity means the market is undersold, lower than initial capacity means the market is oversold
        uint256 timeNeutralCapacity = initialCapacity.mulDiv(
            uint256(meta.length) - timeRemaining,
            uint256(meta.length)
        ) + capacity;

        if (
            (market.capacity < meta.tuneBelowCapacity && timeNeutralCapacity < initialCapacity) ||
            (time_ >= meta.lastTune + meta.tuneInterval && timeNeutralCapacity > initialCapacity)
        ) {
            // Calculate the correct payout to complete on time assuming each bond
            // will be max size in the desired deposit interval for the remaining time
            //
            // i.e. market has 10 days remaining. deposit interval is 1 day. capacity
            // is 10,000 TOKEN. max payout would be 1,000 TOKEN (10,000 * 1 / 10).
            markets[id_].maxPayout = capacity.mulDiv(uint256(meta.depositInterval), timeRemaining);

            // Calculate ideal target debt to satisty capacity in the remaining time
            // The target debt is based on whether the market is under or oversold at this point in time
            // This target debt will ensure price is reactive while ensuring the magnitude of being over/undersold
            // doesn't cause larger fluctuations towards the end of the market.
            //
            // Calculate target debt from the timeNeutralCapacity and the ratio of debt decay interval and the length of the market
            uint256 targetDebt = timeNeutralCapacity.mulDiv(
                uint256(meta.debtDecayInterval),
                uint256(meta.length)
            );

            // Derive a new control variable from the target debt
            uint256 controlVariable = terms[id_].controlVariable;
            uint256 newControlVariable = price_.mulDivUp(market.scale, targetDebt);

            emit Tuned(id_, controlVariable, newControlVariable);

            if (newControlVariable < controlVariable) {
                // If decrease, control variable change will be carried out over the tune interval
                // this is because price will be lowered
                uint256 change = controlVariable - newControlVariable;
                adjustments[id_] = Adjustment(change, time_, meta.tuneAdjustmentDelay, true);
            } else {
                // Tune up immediately
                terms[id_].controlVariable = newControlVariable;
                // Set current adjustment to inactive (e.g. if we are re-tuning early)
                adjustments[id_].active = false;
            }

            metadata[id_].lastTune = time_;
            metadata[id_].tuneBelowCapacity = market.capacity > meta.tuneIntervalCapacity
                ? market.capacity - meta.tuneIntervalCapacity
                : 0;
            metadata[id_].lastTuneDebt = targetDebt;
        }
    }

    /* ========== INTERNAL VIEW FUNCTIONS ========== */

    /// @notice             Calculate current market price of payout token in quote tokens
    /// @dev                See marketPrice() in IBondSDA for explanation of price computation
    /// @dev                Uses info from storage because data has been updated before call (vs marketPrice())
    /// @param id_          Market ID
    /// @return             Price for market in payout token decimals
    function _currentMarketPrice(uint256 id_) internal view returns (uint256) {
        BondMarket memory market = markets[id_];
        return terms[id_].controlVariable.mulDivUp(market.totalDebt, market.scale);
    }

    /// @notice                 Amount to decay control variable by
    /// @param id_              ID of market
    /// @return decay           change in control variable
    /// @return secondsSince    seconds since last change in control variable
    /// @return active          whether or not change remains active
    function _controlDecay(uint256 id_)
        internal
        view
        returns (
            uint256 decay,
            uint48 secondsSince,
            bool active
        )
    {
        Adjustment memory info = adjustments[id_];
        if (!info.active) return (0, 0, false);

        secondsSince = uint48(block.timestamp) - info.lastAdjustment;
        active = secondsSince < info.timeToAdjusted;
        decay = active
            ? info.change.mulDiv(uint256(secondsSince), uint256(info.timeToAdjusted))
            : info.change;
    }

    /* ========== 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,
            market.maxPayout
        );
    }

    /// @inheritdoc IBondSDA
    function marketPrice(uint256 id_) public view override returns (uint256) {
        uint256 price = currentControlVariable(id_).mulDivUp(currentDebt(id_), markets[id_].scale);

        return (price > markets[id_].minPrice) ? price : markets[id_].minPrice;
    }

    /// @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_), 1e5);
        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 > markets[id_].maxPayout) {
            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_), 1e5);

        return amountAccepted + estimatedFee;
    }

    /// @inheritdoc IBondSDA
    function currentDebt(uint256 id_) public view override returns (uint256) {
        BondMetadata memory meta = metadata[id_];
        uint256 lastDecay = uint256(meta.lastDecay);
        uint256 currentTime = block.timestamp;

        // Determine if decay should increase or decrease debt based on last decay time
        // If last decay time is in the future, then debt should be increased
        // If last decay time is in the past, then debt should be decreased
        if (lastDecay > currentTime) {
            uint256 secondsUntil;
            unchecked {
                secondsUntil = lastDecay - currentTime;
            }
            return
                markets[id_].totalDebt.mulDiv(
                    uint256(meta.debtDecayInterval) + secondsUntil,
                    uint256(meta.debtDecayInterval)
                );
        } else {
            uint256 secondsSince;
            unchecked {
                secondsSince = currentTime - lastDecay;
            }
            return
                secondsSince > meta.debtDecayInterval
                    ? 0
                    : markets[id_].totalDebt.mulDiv(
                        uint256(meta.debtDecayInterval) - secondsSince,
                        uint256(meta.debtDecayInterval)
                    );
        }
    }

    /// @inheritdoc IBondSDA
    function currentControlVariable(uint256 id_) public view override returns (uint256) {
        (uint256 decay, , ) = _controlDecay(id_);
        return terms[id_].controlVariable - decay;
    }

    /// @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 > 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;
    }
}

File 8 of 16 : IBondAggregator.sol
// 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);
}

File 9 of 16 : IBondAuctioneer.sol
// 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);
}

File 10 of 16 : IBondCallback.sol
// 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;
}

File 11 of 16 : IBondFixedExpiryTeller.sol
// 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);
}

File 12 of 16 : IBondSDA.sol
// 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 IBondSDA is IBondAuctioneer {
    /// @notice Main 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 totalDebt; // total payout token debt from market
        uint256 minPrice; // minimum price (hard floor for the market)
        uint256 maxPayout; // max payout tokens out in one order
        uint256 sold; // payout tokens out
        uint256 purchased; // quote tokens in
        uint256 scale; // scaling factor for the market (see MarketParams struct)
    }

    /// @notice Information used to control how a bond market changes
    struct BondTerms {
        uint256 controlVariable; // scaling variable for price
        uint256 maxDebt; // max payout token debt accrued
        uint48 vesting; // length of time from deposit to expiry if fixed-term, vesting timestamp if fixed-expiry
        uint48 conclusion; // timestamp when market no longer offered
    }

    /// @notice Data needed for tuning bond market
    /// @dev Durations are stored in uint32 (not int32) and timestamps are stored in uint48, so is not subject to Y2K38 overflow
    struct BondMetadata {
        uint48 lastTune; // last timestamp when control variable was tuned
        uint48 lastDecay; // last timestamp when market was created and debt was decayed
        uint32 length; // time from creation to conclusion.
        uint32 depositInterval; // target frequency of deposits
        uint32 tuneInterval; // frequency of tuning
        uint32 tuneAdjustmentDelay; // time to implement downward tuning adjustments
        uint32 debtDecayInterval; // interval over which debt should decay completely
        uint256 tuneIntervalCapacity; // capacity expected to be used during a tuning interval
        uint256 tuneBelowCapacity; // capacity that the next tuning will occur at
        uint256 lastTuneDebt; // target debt calculated at last tuning
    }

    /// @notice Control variable adjustment data
    struct Adjustment {
        uint256 change;
        uint48 lastAdjustment;
        uint48 timeToAdjusted; // how long until adjustment happens
        bool active;
    }

    /// @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 initial price (see note above)
    /// @dev                    6. Formatted minimum price (see note above)
    /// @dev                    7. Debt buffer. Percent with 3 decimals. Percentage over the initial debt to allow the market to accumulate at anyone time.
    /// @dev                       Works as a circuit breaker for the market in case external conditions incentivize massive buying (e.g. stablecoin depeg).
    /// @dev                       Minimum is the greater of 10% or initial max payout as a percentage of capacity.
    /// @dev                       If the value is too small, the market will not be able function normally and close prematurely.
    /// @dev                       If the value is too large, the market will not circuit break when intended. The value must be > 10% but can exceed 100% if desired.
    /// @dev                       A good heuristic to calculate a debtBuffer with is to determine the amount of capacity that you think is reasonable to be expended
    /// @dev                       in a short duration as a percent, e.g. 25%. Then a reasonable debtBuffer would be: 0.25 * 1e3 * decayInterval / marketDuration
    /// @dev                       where decayInterval = max(3 days, 5 * depositInterval) and marketDuration = conclusion - creation time.
    /// @dev                    8. 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                    9. Conclusion (timestamp)
    /// @dev                    10. Deposit interval (seconds)
    /// @dev                    11. 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 formattedInitialPrice;
        uint256 formattedMinimumPrice;
        uint32 debtBuffer;
        uint48 vesting;
        uint48 conclusion;
        uint32 depositInterval;
        int8 scaleAdjustment;
    }

    /* ========== VIEW FUNCTIONS ========== */

    /// @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 in configured decimals (see MarketParams)
    //
    // price is derived from the equation
    //
    // p = c * d
    //
    // where
    // p = price
    // c = control variable
    // d = debt
    //
    // d -= ( d * (dt / l) )
    //
    // where
    // dt = change in time
    // l = length of program
    //
    // 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 override returns (uint256);

    /// @notice             Calculate debt factoring in decay
    /// @dev                Accounts for debt decay since last deposit
    /// @param id_          ID of market
    /// @return             Current debt for market in payout token decimals
    function currentDebt(uint256 id_) external view returns (uint256);

    /// @notice             Up to date control variable
    /// @dev                Accounts for control variable adjustment
    /// @param id_          ID of market
    /// @return             Control variable for market in payout token decimals
    function currentControlVariable(uint256 id_) external view returns (uint256);
}

File 13 of 16 : IBondTeller.sol
// 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;
}

File 14 of 16 : CloneERC20.sol
// 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))
        }
    }
}

File 15 of 16 : FullMath.sol
// 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++;
            }
        }
    }
}

File 16 of 16 : TransferHelper.sol
// 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");
    // }
}

Settings
{
  "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/",
    "solidity-code-metrics/=node_modules/solidity-code-metrics/",
    "solmate/=lib/solmate/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": {}
}

Contract ABI

[{"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_InitialPriceLessThanMin","type":"error"},{"inputs":[],"name":"Auctioneer_InvalidCallback","type":"error"},{"inputs":[],"name":"Auctioneer_InvalidParams","type":"error"},{"inputs":[{"internalType":"uint256","name":"conclusion_","type":"uint256"}],"name":"Auctioneer_MarketConcluded","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":false,"internalType":"uint32","name":"defaultTuneInterval","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"defaultTuneAdjustment","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"minDebtDecayInterval","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"minDepositInterval","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"minMarketDuration","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"minDebtBuffer","type":"uint32"}],"name":"DefaultsUpdated","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":"initialPrice","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldControlVariable","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newControlVariable","type":"uint256"}],"name":"Tuned","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"adjustments","outputs":[{"internalType":"uint256","name":"change","type":"uint256"},{"internalType":"uint48","name":"lastAdjustment","type":"uint48"},{"internalType":"uint48","name":"timeToAdjusted","type":"uint48"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"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":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"currentControlVariable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"currentDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultTuneAdjustment","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultTuneInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":"totalDebt","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"maxPayout","type":"uint256"},{"internalType":"uint256","name":"sold","type":"uint256"},{"internalType":"uint256","name":"purchased","type":"uint256"},{"internalType":"uint256","name":"scale","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":"","type":"uint256"}],"name":"metadata","outputs":[{"internalType":"uint48","name":"lastTune","type":"uint48"},{"internalType":"uint48","name":"lastDecay","type":"uint48"},{"internalType":"uint32","name":"length","type":"uint32"},{"internalType":"uint32","name":"depositInterval","type":"uint32"},{"internalType":"uint32","name":"tuneInterval","type":"uint32"},{"internalType":"uint32","name":"tuneAdjustmentDelay","type":"uint32"},{"internalType":"uint32","name":"debtDecayInterval","type":"uint32"},{"internalType":"uint256","name":"tuneIntervalCapacity","type":"uint256"},{"internalType":"uint256","name":"tuneBelowCapacity","type":"uint256"},{"internalType":"uint256","name":"lastTuneDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDebtBuffer","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDebtDecayInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minMarketDuration","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"terms","outputs":[{"internalType":"uint256","name":"controlVariable","type":"uint256"},{"internalType":"uint256","name":"maxDebt","type":"uint256"},{"internalType":"uint48","name":"vesting","type":"uint48"},{"internalType":"uint48","name":"conclusion","type":"uint48"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b506040516200497f3803806200497f83398101604081905262000034916200013d565b600080546001600160a01b03199081166001600160a01b0385811691821784556001805490931690851617909155604051869286928692869284928492909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a3505050506001600160a01b039081166080521660a0525050600980546001600160c01b0319167527100001518000000e100003f48000000e100001518017905550506007805460ff19166001179055620001a5565b6001600160a01b03811681146200013a57600080fd5b50565b600080600080608085870312156200015457600080fd5b8451620001618162000124565b6020860151909450620001748162000124565b6040860151909350620001878162000124565b60608601519092506200019a8162000124565b939692955090935050565b60805160a051614791620001ee6000396000818161051001528181610eca01528181611e860152818161211801526121cb0152600081816103480152612aab01526147916000f3fe608060405234801561001057600080fd5b50600436106102ad5760003560e01c8063acc5570c1161017b578063bf7e214f116100d8578063d9ccdc931161008c578063e3684e3911610071578063e3684e39146109af578063e922067314610aed578063ea0aca3314610b0957600080fd5b8063d9ccdc931461098c578063e007fa971461099c57600080fd5b8063c7bf8ca0116100bd578063c7bf8ca014610935578063d204068714610948578063d2bee3231461096857600080fd5b8063bf7e214f146108a2578063c0aa0e8a146108c257600080fd5b8063bc3b2b121161012f578063bcf6cde811610114578063bcf6cde814610869578063bd1f3a5e1461087c578063bf48582b1461088f57600080fd5b8063bc3b2b12146107d2578063bcb296671461085657600080fd5b8063afa9d3b011610160578063afa9d3b0146106a1578063b1283e77146106ae578063bbbdd95a146107bf57600080fd5b8063acc5570c14610534578063ae4180951461068e57600080fd5b80635f77274e116102295780638973082c116101dd5780638da5cb5b116101c25780638da5cb5b146104cb578063946824cd146104eb5780639787d1071461050e57600080fd5b80638973082c1461047b5780638b098db3146104b857600080fd5b80636729a41e1161020e5780636729a41e1461041f578063699e17d9146104555780637a9e5e4b1461046857600080fd5b80635f77274e146103d65780636352211e146103e957600080fd5b806327507458116102805780633adec5a7116102655780633adec5a71461038d57806353c7f8e0146103a05780635dc4d16b146103b357600080fd5b806327507458146103235780633ad59dbc1461034657600080fd5b80630a9d85eb146102b257806310b05317146102d857806313af4035146102ed5780631c063a6c14610300575b600080fd5b6102c56102c0366004614132565b610b21565b6040519081526020015b60405180910390f35b6102eb6102e6366004614132565b610b53565b005b6102eb6102fb36600461417d565b610c0e565b6102c561030e366004614132565b60009081526002602052604090206004015490565b610336610331366004614132565b610d17565b60405190151581526020016102cf565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102cf565b6102c561039b366004614132565b610d60565b6102c56103ae36600461419a565b610dc3565b6103366103c136600461417d565b60086020526000908152604090205460ff1681565b6102eb6103e4366004614225565b610f73565b6103686103f7366004614132565b60009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b61036861042d366004614132565b60066020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6102eb610463366004614242565b611038565b6102eb61047636600461417d565b6114df565b6009546104a39074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016102cf565b6103366104c6366004614132565b61163c565b6000546103689073ffffffffffffffffffffffffffffffffffffffff1681565b6102c56104f9366004614132565b6000908152600260205260409020600a015490565b7f0000000000000000000000000000000000000000000000000000000000000000610368565b610638610542366004614132565b6000818152600260208181526040808420815161018081018352815473ffffffffffffffffffffffffffffffffffffffff90811680835260018401548216838701819052848801548316848701819052600380870154948516606087018190527401000000000000000000000000000000000000000090950460ff1615156080870152600487015460a0870152600587015460c0870152600687015460e08701526007870154610100870190815260088801546101208801526009880154610140880152600a90970154610160909601959095529989529290955292909520909301549251919590949265ffffffffffff169190565b6040805173ffffffffffffffffffffffffffffffffffffffff97881681529587166020870152938616938501939093529316606083015265ffffffffffff909216608082015260a081019190915260c0016102cf565b6102eb61069c366004614132565b611672565b6007546103369060ff1681565b6107456106bc366004614132565b600260208190526000918252604090912080546001820154928201546003830154600484015460058501546006860154600787015460088801546009890154600a9099015473ffffffffffffffffffffffffffffffffffffffff9889169a891699978916988716977401000000000000000000000000000000000000000090970460ff1696908c565b6040805173ffffffffffffffffffffffffffffffffffffffff9d8e1681529b8d1660208d0152998c16998b0199909952999096166060890152931515608088015260a087019290925260c086015260e0850152610100840152610120830152610140820192909252610160810191909152610180016102cf565b6102eb6107cd366004614275565b6116db565b6108256107e0366004614132565b6005602052600090815260409020805460019091015465ffffffffffff8082169166010000000000008104909116906c01000000000000000000000000900460ff1684565b6040516102cf949392919093845265ffffffffffff9283166020850152911660408301521515606082015260800190565b6102c5610864366004614132565b6117c5565b6102eb6108773660046142ae565b611959565b6102eb61088a366004614340565b611a09565b6102c561089d3660046143c5565b611e38565b6001546103689073ffffffffffffffffffffffffffffffffffffffff1681565b6109076108d0366004614132565b60036020526000908152604090208054600182015460029092015490919065ffffffffffff80821691660100000000000090041684565b60408051948552602085019390935265ffffffffffff918216928401929092521660608201526080016102cf565b6102c56109433660046142ae565b611f91565b6009546104a3906c01000000000000000000000000900463ffffffff1681565b6009546104a390700100000000000000000000000000000000900463ffffffff1681565b6009546104a39063ffffffff1681565b6102c56109aa3660046143fe565b6121b1565b610a876109bd366004614132565b600460205260009081526040902080546001820154600283015460039093015465ffffffffffff80841694660100000000000085049091169363ffffffff6c0100000000000000000000000082048116947001000000000000000000000000000000008304821694740100000000000000000000000000000000000000008404831694780100000000000000000000000000000000000000000000000085048416947c0100000000000000000000000000000000000000000000000000000000900490931692908a565b6040805165ffffffffffff9b8c1681529a90991660208b015263ffffffff978816988a01989098529486166060890152928516608088015290841660a08701529290921660c085015260e0840191909152610100830152610120820152610140016102cf565b6009546104a39068010000000000000000900463ffffffff1681565b6009546104a390640100000000900463ffffffff1681565b600080610b2d8361250a565b5050600084815260036020526040902054909150610b4c908290614459565b9392505050565b60008181526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610bb0576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600090815260066020908152604080832054600290925290912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b610c3c336000357fffffffff00000000000000000000000000000000000000000000000000000000166125e5565b610ca7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60008181526002602052604081206004015415801590610d5a575060008281526003602052604090206002015442660100000000000090910465ffffffffffff16115b92915050565b600080610d91610d6f846117c5565b6000858152600260205260409020600a0154610d8a86610b21565b91906126f5565b6000848152600260205260409020600601549091508111610d5a57600083815260026020526040902060060154610b4c565b600080610dd2838501856144a1565b905062015180816101000151610de891906145a7565b610df590620151806145f3565b65ffffffffffff16610100820181905215801590610e2c575080610120015165ffffffffffff1681610100015165ffffffffffff16105b15610e63576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e6e82612753565b905081610100015165ffffffffffff16600014610f6b5781516101008301516040517fc6e38a4b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263c6e38a4b92610f269260040173ffffffffffffffffffffffffffffffffffffffff92909216825265ffffffffffff16602082015260400190565b6020604051808303816000875af1158015610f45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f699190614621565b505b949350505050565b610fa1336000357fffffffff00000000000000000000000000000000000000000000000000000000166125e5565b611007576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610c9e565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b61104182610d17565b611077576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611084602082018261463e565b63ffffffff1615806110a957506110a1604082016020830161463e565b63ffffffff16155b806110c757506110bf606082016040830161463e565b63ffffffff16155b156110fe576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61110e604082016020830161463e565b63ffffffff16611121602083018361463e565b63ffffffff16101561115f576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526004602090815260409091208054909170010000000000000000000000000000000090910463ffffffff169061119c9084018461463e565b63ffffffff1610156111da576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095468010000000000000000900463ffffffff166111ff606084016040850161463e565b63ffffffff16101561123d576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260026020818152604092839020835161018081018552815473ffffffffffffffffffffffffffffffffffffffff908116808352600184015482169483019490945293820154841694810194909452600381015492831660608501527401000000000000000000000000000000000000000090920460ff1615156080840152600482015460a0840152600582015460c0840152600682015460e0840152600782015461010084015260088201546101208401526009820154610140840152600a909101546101608301523314611343576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611350602084018461463e565b825463ffffffff9190911674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161782556113ee6113a9602085018561463e565b60008681526003602052604090206002015463ffffffff91909116906113e29042906601000000000000900465ffffffffffff16614459565b60a0840151919061343c565b6001830181905560a08201511161140657600061141a565b81600101548160a0015161141a9190614459565b600283015561142f604084016020850161463e565b825463ffffffff919091167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff90911617825561148c606084016040850161463e565b825463ffffffff919091167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911617909155505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806115c257506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff0000000000000000000000000000000000000000000000000000000016604482015273ffffffffffffffffffffffffffffffffffffffff9091169063b700961390606401602060405180830381865afa15801561159e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c29190614659565b6115cb57600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b60008181526003602052604081206002015465ffffffffffff16635dba240081111561166b5742811115610b4c565b1592915050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146116cf576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116d881613508565b50565b611709336000357fffffffff00000000000000000000000000000000000000000000000000000000166125e5565b61176f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610c9e565b73ffffffffffffffffffffffffffffffffffffffff91909116600090815260086020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6000818152600460209081526040808320815161014081018352815465ffffffffffff8082168352660100000000000082041694820185905263ffffffff6c0100000000000000000000000082048116948301949094527001000000000000000000000000000000008104841660608301527401000000000000000000000000000000000000000081048416608083015278010000000000000000000000000000000000000000000000008104841660a08301527c0100000000000000000000000000000000000000000000000000000000900490921660c0830152600181015460e083015260028101546101008301526003015461012082015290428082111561191a5760c083015181830390611910906118e890839063ffffffff16614676565b60c0860151600089815260026020526040902060050154919063ffffffff9081169061343c16565b9695505050505050565b60c08301518282039063ffffffff16811161194d57611948818560c0015163ffffffff166118e89190614459565b611910565b60009695505050505050565b60008281526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146119b6576040517f4e1c8b5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60009182526006602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b611a37336000357fffffffff00000000000000000000000000000000000000000000000000000000166125e5565b611a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610c9e565b6020810151815163ffffffff91821691161015611ae6576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060810151815163ffffffff91821691161015611b2f576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151606082015163ffffffff91821691161115611b7b576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060810151611b8b90600561468e565b63ffffffff16816002602002015163ffffffff161015611bd7576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060006020020151600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90921691909117905580600160200201516009805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117905580600260200201516009805463ffffffff90921668010000000000000000027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff90921691909117905580600360200201516009805463ffffffff9092166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff90921691909117905580600460200201516009805463ffffffff909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff90921691909117905580600560209081029190910151600980547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff81167401000000000000000000000000000000000000000063ffffffff9485168102918217938490556040805193861692861692909217835264010000000084048516958301959095526801000000000000000083048416908201526c010000000000000000000000008204831660608201527001000000000000000000000000000000008204831660808201529290041660a08201527fbbc02fa2138d26ec5ecb379612618d1b291bf5140167f3028178080953459c5a9060c00160405180910390a150565b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000918291611f06917f00000000000000000000000000000000000000000000000000000000000000009091169063b88c914890602401602060405180830381865afa158015611ecf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef391906146b1565b869065ffffffffffff16620186a061343c565b6000858152600260205260408120600a015491925090611f3a90611f2987610d60565b611f33858a614459565b919061343c565b600086815260026020526040902060070154909150811115611f88576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9150610b4c9050565b6000828152600260208181526040808420815161018081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015481169482019490945293810154831691840191909152600381015491821660608401527401000000000000000000000000000000000000000090910460ff1615156080830152600481015460a0830152600581015460c0830152600681015460e0830152600781015461010083015260088101546101208301526009810154610140830152600a01546101608201528161206585610d60565b90506000826080015161208d5761016083015160a084015161208891849061343c565b612093565b8260a001515b905060006120b68385610160015186610100015161343c9092919063ffffffff16565b905060008183106120c757816120c9565b825b6040517fb88c914800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8981166004830152919250600091612198917f00000000000000000000000000000000000000000000000000000000000000009091169063b88c914890602401602060405180830381865afa158015612161573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218591906146b1565b839065ffffffffffff16620186a061343c565b90506121a48183614676565b9998505050505050505050565b60003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612222576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526002602081815260408084206003808452948290208251608081018452815481526001820154948101949094529093015465ffffffffffff80821692840192909252660100000000000090041660608201529181015490919073ffffffffffffffffffffffffffffffffffffffff16158015906122cb5750815473ffffffffffffffffffffffffffffffffffffffff1660009081526008602052604090205460ff16155b15612302576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000429050816060015165ffffffffffff168165ffffffffffff16106123645760608201516040517f07fc4a7000000000000000000000000000000000000000000000000000000000815265ffffffffffff9091166004820152602401610c9e565b600061237188884261358c565b95509050858510156123af576040517f74ec9d5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600701548511156123ed576040517f5c430eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600384015474010000000000000000000000000000000000000000900460ff1661241d5783600401548511612425565b836004015487115b1561245c576040517ff3383dc900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600384015474010000000000000000000000000000000000000000900460ff166124865784612488565b865b84600401600082825461249b9190614459565b92505081905550868460090160008282546124b69190614676565b92505081905550848460080160008282546124d19190614676565b90915550506005840154602084015110156124f4576124ef88613508565b6124ff565b6124ff88838361395b565b505050509392505050565b600081815260056020908152604080832081516080810183528154815260019091015465ffffffffffff8082169483019490945266010000000000008104909316918101919091526c0100000000000000000000000090910460ff1615156060820181905282918291612588576000806000935093509350506125de565b602081015161259790426146ce565b9250806040015165ffffffffffff168365ffffffffffff16109150816125be5780516125da565b604081015181516125da9165ffffffffffff808716911661343c565b9350505b9193909250565b60015460009073ffffffffffffffffffffffffffffffffffffffff1680158015906126c957506040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b700961390606401602060405180830381865afa1580156126a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c99190614659565b80610f6b575060005473ffffffffffffffffffffffffffffffffffffffff858116911614949350505050565b600061270284848461343c565b90506000828061271457612714614578565b8486091115610b4c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811061274957600080fd5b6001019392505050565b60075460009060ff16612792576040517f64be3ffa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826000015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280791906146f5565b90506000836020015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561285a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287e91906146f5565b905060068260ff161080612895575060128260ff16115b156128cc576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068160ff1610806128e1575060128160ff16115b15612918576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe884610160015160000b12806129565750601884610160015160000b135b1561298d576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526008602052604090205460ff161580156129c65750604084015173ffffffffffffffffffffffffffffffffffffffff1615155b156129fd576040517f2c47703200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600082610160015160240160ff16600a0a90508260c001518360a001511015612a54576040517f4496547d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160208401516040517fb435914300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316600482015290821660248201526000917f0000000000000000000000000000000000000000000000000000000000000000169063b4359143906044016020604051808303816000875af1158015612af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b189190614718565b90506000804286610120015165ffffffffffff16612b369190614459565b60095490925063ffffffff70010000000000000000000000000000000090910481169083161080612b87575060095461014087015163ffffffff6c0100000000000000000000000090920482169116105b80612ba257508163ffffffff1686610140015163ffffffff16115b15612bd9576040517f3b596f5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008661014001516005612bed919061468e565b60095490915063ffffffff808316680100000000000000009092041611612c145780612c2a565b60095468010000000000000000900463ffffffff165b600954610140890151919350600091612c829163ffffffff908116911611612c5a5760095463ffffffff16612c61565b8861014001515b63ffffffff168563ffffffff168a6080015161343c9092919063ffffffff16565b60408051610140808201835265ffffffffffff4216808352602083015263ffffffff808916938301939093528b01805183166060830152600954905193945090926080840192918216911611612ce05760095463ffffffff16612ce7565b8961014001515b63ffffffff9081168252600954640100000000900481166020830152851660408201526060810183905260808a810151910190612d25908490614459565b8152602001612d638563ffffffff168763ffffffff168c60600151612d4e578c60800151611f33565b60a08d015160808e0151611f33918d9061343c565b90526000868152600460209081526040808320845181549386015192860151606080880151608089015160a08a015160c08b015165ffffffffffff9687167fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909a169990991766010000000000009690981695909502969096177fffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff948516027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff161770010000000000000000000000000000000091841691909102177fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000958316959095027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1694909417780100000000000000000000000000000000000000000000000092821692909202919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000919094160292909217825560e08401516001830155610100840151600283015561012090930151600390910155908901519092508291508190612f60578860800151612f75565b60a089015160808a0151612f7591899061343c565b9050612f8e8163ffffffff808716908881169061343c16565b9250612fb689610140015163ffffffff168663ffffffff168361343c9092919063ffffffff16565b9150506040518061018001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001896000015173ffffffffffffffffffffffffffffffffffffffff168152602001896020015173ffffffffffffffffffffffffffffffffffffffff168152602001896040015173ffffffffffffffffffffffffffffffffffffffff168152602001896060015115158152602001896080015181526020018381526020018960c0015181526020018281526020016000815260200160008152602001878152506002600087815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060608201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160030160146101000a81548160ff02191690831515021790555060a0820151816004015560c0820151816005015560e0820151816006015561010082015181600701556101208201518160080155610140820151816009015561016082015181600a01559050506000600960149054906101000a900463ffffffff1663ffffffff16613256620186a065ffffffffffff16858561343c9092919063ffffffff16565b116132815760095474010000000000000000000000000000000000000000900463ffffffff1661328f565b61328f82620186a08561343c565b905060006132c4828b60e0015163ffffffff16116132ad57826132b9565b8a60e0015163ffffffff165b8590620186a061343c565b6132ce9085614676565b60a08b01519091506000906132e4908a8761343c565b905060405180608001604052808281526020018381526020018c610100015165ffffffffffff1681526020018c610120015165ffffffffffff16815250600360008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020160006101000a81548165ffffffffffff021916908365ffffffffffff16021790555060608201518160020160066101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050508a6020015173ffffffffffffffffffffffffffffffffffffffff168b6000015173ffffffffffffffffffffffffffffffffffffffff16897f8235b14cd272b4e791960fe1118559bb7fed86934fcffeeae9b1175103b0756d8e61010001518f60a0015160405161342592919065ffffffffffff929092168252602082015260400190565b60405180910390a450959998505050505050505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003613493576000841161348857600080fd5b508290049050610b4c565b80841161349f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000818152600360209081526040808320600290810180547fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff1666010000000000004265ffffffffffff16021790559091528082206004018290555182917f9dc30b8eda31a6a144e092e5de600955523a6a925cc15cc1d1b9b4872cfa615591a250565b6000838152600260208181526040808420815161018081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015481169482019490945293810154831691840191909152600381015491821660608401527401000000000000000000000000000000000000000090910460ff1615156080830152600481015460a0830152600581015460c0830152600681015460e0830152600781015461010083015260088101546101208301526009810154610140830152600a0154610160820152819081613662876117c5565b600088815260026020908152604080832060059081018590559091529020600101549091506c01000000000000000000000000900460ff16156137aa5760008781526005602052604081209080806136b98b61250a565b60008e8152600360205260408120805494975092955090935085926136df908490614459565b9091555050801561377a57828460000160008282546136fe9190614459565b909155505060018401805483919060069061372c9084906601000000000000900465ffffffffffff166146ce565b92506101000a81548165ffffffffffff021916908365ffffffffffff160217905550888460010160006101000a81548165ffffffffffff021916908365ffffffffffff1602179055506137a5565b6001840180547fffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff1690555b505050505b6137b38761404f565b60e0830151909450808510156137c7578094505b6101608301516137d99088908761343c565b600089815260046020526040812080546003909101549296507c0100000000000000000000000000000000000000000000000000000000810463ffffffff9081169392660100000000000090920465ffffffffffff1691906138419085908a9086906126f516565b60008d8152600460205260409020805491925082916006906138769084906601000000000000900465ffffffffffff16614731565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055506000828b65ffffffffffff16116138ca576138bb65ffffffffffff8c1684614459565b6138c59086614676565b613905565b6138dc8365ffffffffffff8d16614459565b85116138e9576000613905565b6138fb8365ffffffffffff8d16614459565b6139059086614459565b90508861391e866139168585614676565b8a919061343c565b6139289190614676565b613933906001614676565b60009d8e5260026020526040909d206005019c909c5550969a95995094975050505050505050565b600060046000858152602001908152602001600020604051806101400160405290816000820160009054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016000820160069054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160189054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160018201548152602001600282015481526020016003820154815250509050600060026000868152602001908152602001600020604051806101800160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820160149054906101000a900460ff16151515158152602001600482015481526020016005820154815260200160068201548152602001600782015481526020016008820154815260200160098201548152602001600a8201548152505090506000846003600088815260200190815260200160002060020160069054906101000a900465ffffffffffff16613cc491906146ce565b65ffffffffffff16905060008260800151613ce3578260a00151613cf8565b61016083015160a0840151613cf8918761343c565b905060008360800151613d1057836101200151613d26565b610160840151610140850151613d26918861343c565b613d309083614676565b9050600082613d6985886040015163ffffffff16613d4e9190614459565b886040015163ffffffff168561343c9092919063ffffffff16565b613d739190614676565b90508561010001518560a00151108015613d8c57508181105b80613dc7575060808601518651613da99163ffffffff1690614731565b65ffffffffffff168865ffffffffffff1610158015613dc757508181115b1561404457613deb866060015163ffffffff16858561343c9092919063ffffffff16565b60008a8152600260205260408082206007019290925560c0880151918801519091613e2491849163ffffffff9081169181169061343c16565b60008b81526003602052604081205461016089015192935091613e49908b90856126f5565b60408051848152602081018390529192508d917f78f9c01d72705dba80d6ce051d36a1f987bf2a3800fee938c111a2ae741e57d1910160405180910390a281811015613f77576000613e9b8284614459565b905060405180608001604052808281526020018d65ffffffffffff1681526020018b60a0015163ffffffff1665ffffffffffff16815260200160011515815250600560008f81526020019081526020016000206000820151816000015560208201518160010160006101000a81548165ffffffffffff021916908365ffffffffffff16021790555060408201518160010160066101000a81548165ffffffffffff021916908365ffffffffffff160217905550606082015181600101600c6101000a81548160ff02191690831515021790555090505050613fbc565b60008c81526003602090815260408083208490556005909152902060010180547fffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffff1690555b60008c815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001665ffffffffffff8d1617905560e089015160a089015111614010576000614024565b8860e001518860a001516140249190614459565b60008d815260046020526040902060028101919091556003019290925550505b505050505050505050565b6000818152600260208181526040808420815161018081018352815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116828601529482015485168184015260038083015495861660608301527401000000000000000000000000000000000000000090950460ff1615156080820152600482015460a0820152600582015460c08201819052600683015460e0830152600783015461010083015260088301546101208301526009830154610140830152600a90920154610160820181905287875294909352908420549192610b4c9291906126f5565b60006020828403121561414457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146116d857600080fd5b80356141788161414b565b919050565b60006020828403121561418f57600080fd5b8135610b4c8161414b565b600080602083850312156141ad57600080fd5b823567ffffffffffffffff808211156141c557600080fd5b818501915085601f8301126141d957600080fd5b8135818111156141e857600080fd5b8660208285010111156141fa57600080fd5b60209290920196919550909350505050565b80151581146116d857600080fd5b80356141788161420c565b60006020828403121561423757600080fd5b8135610b4c8161420c565b6000806080838503121561425557600080fd5b823591508360808401111561426957600080fd5b50926020919091019150565b6000806040838503121561428857600080fd5b82356142938161414b565b915060208301356142a38161420c565b809150509250929050565b600080604083850312156142c157600080fd5b8235915060208301356142a38161414b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614326576143266142d3565b60405290565b803563ffffffff8116811461417857600080fd5b600060c0828403121561435257600080fd5b82601f83011261436157600080fd5b60405160c0810181811067ffffffffffffffff82111715614384576143846142d3565b6040528060c084018581111561439957600080fd5b845b818110156143ba576143ac8161432c565b83526020928301920161439b565b509195945050505050565b6000806000606084860312156143da57600080fd5b833592506020840135915060408401356143f38161414b565b809150509250925092565b60008060006060848603121561441357600080fd5b505081359360208301359350604090920135919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561446b5761446b61442a565b500390565b65ffffffffffff811681146116d857600080fd5b803561417881614470565b8035600081900b811461417857600080fd5b600061018082840312156144b457600080fd5b6144bc614302565b6144c58361416d565b81526144d36020840161416d565b60208201526144e46040840161416d565b60408201526144f56060840161421a565b60608201526080830135608082015260a083013560a082015260c083013560c082015261452460e0840161432c565b60e0820152610100614537818501614484565b90820152610120614549848201614484565b9082015261014061455b84820161432c565b9082015261016061456d84820161448f565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600065ffffffffffff808416806145e7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600065ffffffffffff808316818516818304811182151516156146185761461861442a565b02949350505050565b60006020828403121561463357600080fd5b8151610b4c8161414b565b60006020828403121561465057600080fd5b610b4c8261432c565b60006020828403121561466b57600080fd5b8151610b4c8161420c565b600082198211156146895761468961442a565b500190565b600063ffffffff808316818516818304811182151516156146185761461861442a565b6000602082840312156146c357600080fd5b8151610b4c81614470565b600065ffffffffffff838116908316818110156146ed576146ed61442a565b039392505050565b60006020828403121561470757600080fd5b815160ff81168114610b4c57600080fd5b60006020828403121561472a57600080fd5b5051919050565b600065ffffffffffff8083168185168083038211156147525761475261442a565b0194935050505056fea26469706673582212201c169b5aa36785f0a3d90a804dc3dff30b93d62b94f975a7cc679d6d83865ec164736f6c634300080f0033000000000000000000000000007fe70dc9797c4198528ae43d8195fff82bdc95000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1000000000000000000000000007bd11fca0daaeadd455b51826f9a015f2f0969000000000000000000000000007a0f48a4e3d74ab4234adf9ea9eb32f87b4b14

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


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading