creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/BondController.sol": {
        "content": "pragma solidity 0.8.3;\n\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@uniswap/lib/contracts/libraries/TransferHelper.sol\";\nimport \"./interfaces/IBondController.sol\";\nimport \"./interfaces/ITrancheFactory.sol\";\nimport \"./interfaces/ITranche.sol\";\nimport \"./interfaces/IRebasingERC20.sol\";\n\n/**\n * @dev Controller for a ButtonTranche bond\n *\n * Invariants:\n *  - `totalDebt` should always equal the sum of all tranche tokens' `totalSupply()`\n */\ncontract BondController is IBondController, OwnableUpgradeable {\n    uint256 private constant TRANCHE_RATIO_GRANULARITY = 1000;\n    // One tranche for A-Z\n    uint256 private constant MAX_TRANCHE_COUNT = 26;\n    // Denominator for basis points. Used to calculate fees\n    uint256 private constant BPS = 10_000;\n    // Maximum fee in terms of basis points\n    uint256 private constant MAX_FEE_BPS = 50;\n\n    // to avoid precision loss and other weird math from a small total debt\n    // we require the debt to be at least MINIMUM_VALID_DEBT if any\n    uint256 private constant MINIMUM_VALID_DEBT = 10e9;\n\n    address public override collateralToken;\n    TrancheData[] public override tranches;\n    uint256 public override trancheCount;\n    mapping(address => bool) public trancheTokenAddresses;\n    uint256 public override creationDate;\n    uint256 public override maturityDate;\n    bool public override isMature;\n    uint256 public override totalDebt;\n    uint256 public lastScaledCollateralBalance;\n\n    // Maximum amount of collateral that can be deposited into this bond\n    // Used as a guardrail for initial launch.\n    // If set to 0, no deposit limit will be enforced\n    uint256 public depositLimit;\n    // Fee taken on deposit in basis points. Can be set by the contract owner\n    uint256 public override feeBps;\n\n    /**\n     * @dev Constructor for Tranche ERC20 token\n     * @param _trancheFactory The address of the tranche factory\n     * @param _collateralToken The address of the ERC20 collateral token\n     * @param _admin The address of the initial admin for this contract\n     * @param trancheRatios The tranche ratios for this bond\n     * @param _maturityDate The date timestamp in seconds at which this bond matures\n     * @param _depositLimit The maximum amount of collateral that can be deposited. 0 if no limit\n     */\n    function init(\n        address _trancheFactory,\n        address _collateralToken,\n        address _admin,\n        uint256[] memory trancheRatios,\n        uint256 _maturityDate,\n        uint256 _depositLimit\n    ) external initializer {\n        require(_trancheFactory != address(0), \"BondController: invalid trancheFactory address\");\n        require(_collateralToken != address(0), \"BondController: invalid collateralToken address\");\n        require(_admin != address(0), \"BondController: invalid admin address\");\n        require(trancheRatios.length <= MAX_TRANCHE_COUNT, \"BondController: invalid tranche count\");\n        __Ownable_init();\n        transferOwnership(_admin);\n\n        trancheCount = trancheRatios.length;\n        collateralToken = _collateralToken;\n        string memory collateralSymbol = IERC20Metadata(collateralToken).symbol();\n\n        uint256 totalRatio;\n        for (uint256 i = 0; i < trancheRatios.length; i++) {\n            uint256 ratio = trancheRatios[i];\n            require(ratio <= TRANCHE_RATIO_GRANULARITY, \"BondController: Invalid tranche ratio\");\n            totalRatio += ratio;\n\n            address trancheTokenAddress = ITrancheFactory(_trancheFactory).createTranche(\n                getTrancheName(collateralSymbol, i, trancheRatios.length),\n                getTrancheSymbol(collateralSymbol, i, trancheRatios.length),\n                _collateralToken\n            );\n            tranches.push(TrancheData(ITranche(trancheTokenAddress), ratio));\n            trancheTokenAddresses[trancheTokenAddress] = true;\n        }\n\n        require(totalRatio == TRANCHE_RATIO_GRANULARITY, \"BondController: Invalid tranche ratios\");\n        require(_maturityDate > block.timestamp, \"BondController: Invalid maturity date\");\n        creationDate = block.timestamp;\n        maturityDate = _maturityDate;\n        depositLimit = _depositLimit;\n    }\n\n    /**\n     * @dev Skims extraneous collateral that was incorrectly sent to the contract\n     */\n    modifier onSkim() {\n        uint256 scaledCollateralBalance = IRebasingERC20(collateralToken).scaledBalanceOf(address(this));\n        // If there is extraneous collateral, transfer to the owner\n        if (scaledCollateralBalance > lastScaledCollateralBalance) {\n            uint256 _collateralBalance = IERC20(collateralToken).balanceOf(address(this));\n            uint256 virtualCollateralBalance = Math.mulDiv(\n                lastScaledCollateralBalance,\n                _collateralBalance,\n                scaledCollateralBalance\n            );\n            TransferHelper.safeTransfer(collateralToken, owner(), _collateralBalance - virtualCollateralBalance);\n        }\n        _;\n        // Update the lastScaledCollateralBalance after the function call\n        lastScaledCollateralBalance = IRebasingERC20(collateralToken).scaledBalanceOf(address(this));\n    }\n\n    /**\n     * @inheritdoc IBondController\n     */\n    function deposit(uint256 amount) external override onSkim {\n        require(amount > 0, \"BondController: invalid amount\");\n\n        require(!isMature, \"BondController: Already mature\");\n\n        uint256 _collateralBalance = IERC20(collateralToken).balanceOf(address(this));\n        require(depositLimit == 0 || _collateralBalance + amount <= depositLimit, \"BondController: Deposit limit\");\n\n        TrancheData[] memory _tranches = tranches;\n\n        uint256 newDebt;\n        uint256[] memory trancheValues = new uint256[](trancheCount);\n        for (uint256 i = 0; i < _tranches.length; i++) {\n            // NOTE: solidity 0.8 checks for over/underflow natively so no need for SafeMath\n            uint256 trancheValue = (amount * _tranches[i].ratio) / TRANCHE_RATIO_GRANULARITY;\n\n            // if there is any collateral, we should scale by the debt:collateral ratio\n            // note: if totalDebt == 0 then we're minting for the first time\n            // so shouldn't scale even if there is some collateral mistakenly sent in\n            if (_collateralBalance > 0 && totalDebt > 0) {\n                trancheValue = Math.mulDiv(trancheValue, totalDebt, _collateralBalance);\n            }\n            newDebt += trancheValue;\n            trancheValues[i] = trancheValue;\n        }\n        totalDebt += newDebt;\n\n        TransferHelper.safeTransferFrom(collateralToken, _msgSender(), address(this), amount);\n        // saving feeBps in memory to minimize sloads\n        uint256 _feeBps = feeBps;\n        for (uint256 i = 0; i < trancheValues.length; i++) {\n            uint256 trancheValue = trancheValues[i];\n            // fee tranche tokens are minted and held by the contract\n            // upon maturity, they are redeemed and underlying collateral are sent to the owner\n            uint256 fee = (trancheValue * _feeBps) / BPS;\n            if (fee > 0) {\n                _tranches[i].token.mint(address(this), fee);\n            }\n\n            _tranches[i].token.mint(_msgSender(), trancheValue - fee);\n        }\n        emit Deposit(_msgSender(), amount, _feeBps);\n\n        _enforceTotalDebt();\n    }\n\n    /**\n     * @inheritdoc IBondController\n     */\n    function mature() external override onSkim {\n        require(!isMature, \"BondController: Already mature\");\n        require(owner() == _msgSender() || maturityDate < block.timestamp, \"BondController: Invalid call to mature\");\n        isMature = true;\n\n        TrancheData[] memory _tranches = tranches;\n        uint256 _collateralBalance = IERC20(collateralToken).balanceOf(address(this));\n        // Go through all tranches A-Y (not Z) delivering collateral if possible\n        for (uint256 i = 0; i < _tranches.length - 1 && _collateralBalance > 0; i++) {\n            ITranche _tranche = _tranches[i].token;\n            // pay out the entire tranche token's owed collateral (equal to the supply of tranche tokens)\n            // if there is not enough collateral to pay it out, pay as much as we have\n            uint256 amount = Math.min(_tranche.totalSupply(), _collateralBalance);\n            _collateralBalance -= amount;\n\n            TransferHelper.safeTransfer(collateralToken, address(_tranche), amount);\n\n            // redeem fees, sending output tokens to owner\n            _tranche.redeem(address(this), owner(), IERC20(_tranche).balanceOf(address(this)));\n        }\n\n        // Transfer any remaining collaeral to the Z tranche\n        if (_collateralBalance > 0) {\n            ITranche _tranche = _tranches[_tranches.length - 1].token;\n            TransferHelper.safeTransfer(collateralToken, address(_tranche), _collateralBalance);\n            _tranche.redeem(address(this), owner(), IERC20(_tranche).balanceOf(address(this)));\n        }\n\n        emit Mature(_msgSender());\n    }\n\n    /**\n     * @inheritdoc IBondController\n     */\n    function redeemMature(address tranche, uint256 amount) external override {\n        require(isMature, \"BondController: Bond is not mature\");\n        require(trancheTokenAddresses[tranche], \"BondController: Invalid tranche address\");\n\n        ITranche(tranche).redeem(_msgSender(), _msgSender(), amount);\n        totalDebt -= amount;\n        emit RedeemMature(_msgSender(), tranche, amount);\n    }\n\n    /**\n     * @inheritdoc IBondController\n     */\n    function redeem(uint256[] memory amounts) external override onSkim {\n        require(!isMature, \"BondController: Bond is already mature\");\n\n        TrancheData[] memory _tranches = tranches;\n        require(amounts.length == _tranches.length, \"BondController: Invalid redeem amounts\");\n        uint256 total;\n\n        for (uint256 i = 0; i < amounts.length; i++) {\n            total += amounts[i];\n        }\n\n        for (uint256 i = 0; i < amounts.length; i++) {\n            require(\n                (amounts[i] * TRANCHE_RATIO_GRANULARITY) / total == _tranches[i].ratio,\n                \"BondController: Invalid redemption ratio\"\n            );\n            _tranches[i].token.burn(_msgSender(), amounts[i]);\n        }\n\n        uint256 _collateralBalance = IERC20(collateralToken).balanceOf(address(this));\n        // return as a proportion of the total debt redeemed\n        uint256 returnAmount = Math.mulDiv(total, _collateralBalance, totalDebt);\n\n        totalDebt -= total;\n        TransferHelper.safeTransfer(collateralToken, _msgSender(), returnAmount);\n        emit Redeem(_msgSender(), amounts);\n\n        _enforceTotalDebt();\n    }\n\n    /**\n     * @inheritdoc IBondController\n     */\n    function setFee(uint256 newFeeBps) external override onlyOwner {\n        require(!isMature, \"BondController: Invalid call to setFee\");\n        require(newFeeBps <= MAX_FEE_BPS, \"BondController: New fee too high\");\n        feeBps = newFeeBps;\n\n        emit FeeUpdate(newFeeBps);\n    }\n\n    /**\n     * @dev Get the string name for a tranche\n     * @param collateralSymbol the symbol of the collateral token\n     * @param index the tranche index\n     * @param _trancheCount the total number of tranches\n     * @return the string name of the tranche\n     */\n    function getTrancheName(\n        string memory collateralSymbol,\n        uint256 index,\n        uint256 _trancheCount\n    ) internal pure returns (string memory) {\n        return\n            string(abi.encodePacked(\"ButtonTranche \", collateralSymbol, \" \", getTrancheLetter(index, _trancheCount)));\n    }\n\n    /**\n     * @dev Get the string symbol for a tranche\n     * @param collateralSymbol the symbol of the collateral token\n     * @param index the tranche index\n     * @param _trancheCount the total number of tranches\n     * @return the string symbol of the tranche\n     */\n    function getTrancheSymbol(\n        string memory collateralSymbol,\n        uint256 index,\n        uint256 _trancheCount\n    ) internal pure returns (string memory) {\n        return string(abi.encodePacked(\"TRANCHE-\", collateralSymbol, \"-\", getTrancheLetter(index, _trancheCount)));\n    }\n\n    /**\n     * @dev Get the string letter for a tranche index\n     * @param index the tranche index\n     * @param _trancheCount the total number of tranches\n     * @return the string letter of the tranche index\n     */\n    function getTrancheLetter(uint256 index, uint256 _trancheCount) internal pure returns (string memory) {\n        bytes memory trancheLetters = bytes(\"ABCDEFGHIJKLMNOPQRSTUVWXY\");\n        bytes memory target = new bytes(1);\n        if (index == _trancheCount - 1) {\n            target[0] = \"Z\";\n        } else {\n            target[0] = trancheLetters[index];\n        }\n        return string(target);\n    }\n\n    // @dev Ensuring total debt isn't too small\n    function _enforceTotalDebt() internal {\n        require(totalDebt >= MINIMUM_VALID_DEBT, \"BondController: Expected minimum valid debt\");\n    }\n\n    /**\n     * @dev Get the virtual collateral balance of the bond\n     * @return the virtual collateral balance\n     */\n    function collateralBalance() external view returns (uint256) {\n        uint256 scaledCollateralBalance = IRebasingERC20(collateralToken).scaledBalanceOf(address(this));\n        uint256 _collateralBalance = IERC20(collateralToken).balanceOf(address(this));\n\n        return\n            (scaledCollateralBalance > lastScaledCollateralBalance)\n                ? Math.mulDiv(lastScaledCollateralBalance, _collateralBalance, scaledCollateralBalance)\n                : _collateralBalance;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10**64) {\n                value /= 10**64;\n                result += 64;\n            }\n            if (value >= 10**32) {\n                value /= 10**32;\n                result += 32;\n            }\n            if (value >= 10**16) {\n                value /= 10**16;\n                result += 16;\n            }\n            if (value >= 10**8) {\n                value /= 10**8;\n                result += 8;\n            }\n            if (value >= 10**4) {\n                value /= 10**4;\n                result += 4;\n            }\n            if (value >= 10**2) {\n                value /= 10**2;\n                result += 2;\n            }\n            if (value >= 10**1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal initializer {\n        __Context_init_unchained();\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal initializer {\n        _setOwner(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _setOwner(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _setOwner(newOwner);\n    }\n\n    function _setOwner(address newOwner) private {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n    uint256[49] private __gap;\n}\n"
      },
      "@uniswap/lib/contracts/libraries/TransferHelper.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary TransferHelper {\n    function safeApprove(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('approve(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::safeApprove: approve failed'\n        );\n    }\n\n    function safeTransfer(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transfer(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::safeTransfer: transfer failed'\n        );\n    }\n\n    function safeTransferFrom(\n        address token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::transferFrom: transferFrom failed'\n        );\n    }\n\n    function safeTransferETH(address to, uint256 value) internal {\n        (bool success, ) = to.call{value: value}(new bytes(0));\n        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');\n    }\n}\n"
      },
      "contracts/interfaces/IBondController.sol": {
        "content": "pragma solidity ^0.8.3;\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@uniswap/lib/contracts/libraries/TransferHelper.sol\";\nimport \"./ITranche.sol\";\n\nstruct TrancheData {\n    ITranche token;\n    uint256 ratio;\n}\n\n/**\n * @dev Controller for a ButtonTranche bond system\n */\ninterface IBondController {\n    event Deposit(address from, uint256 amount, uint256 feeBps);\n    event Mature(address caller);\n    event RedeemMature(address user, address tranche, uint256 amount);\n    event Redeem(address user, uint256[] amounts);\n    event FeeUpdate(uint256 newFee);\n\n    function collateralToken() external view returns (address);\n\n    function tranches(uint256 i) external view returns (ITranche token, uint256 ratio);\n\n    function trancheCount() external view returns (uint256 count);\n\n    function feeBps() external view returns (uint256 fee);\n\n    function maturityDate() external view returns (uint256 maturityDate);\n\n    function isMature() external view returns (bool isMature);\n\n    function creationDate() external view returns (uint256 creationDate);\n\n    function totalDebt() external view returns (uint256 totalDebt);\n\n    /**\n     * @dev Deposit `amount` tokens from `msg.sender`, get tranche tokens in return\n     * Requirements:\n     *  - `msg.sender` must have `approved` `amount` collateral tokens to this contract\n     */\n    function deposit(uint256 amount) external;\n\n    /**\n     * @dev Matures the bond. Disables deposits,\n     * fixes the redemption ratio, and distributes collateral to redemption pools\n     * Redeems any fees collected from deposits, sending redeemed funds to the contract owner\n     * Requirements:\n     *  - The bond is not already mature\n     *  - One of:\n     *      - `msg.sender` is owner\n     *      - `maturityDate` has passed\n     */\n    function mature() external;\n\n    /**\n     * @dev Redeems some tranche tokens\n     * Requirements:\n     *  - The bond is mature\n     *  - `msg.sender` owns at least `amount` tranche tokens from address `tranche`\n     *  - `tranche` must be a valid tranche token on this bond\n     */\n    function redeemMature(address tranche, uint256 amount) external;\n\n    /**\n     * @dev Redeems a slice of tranche tokens from all tranches.\n     *  Returns collateral to the user proportionally to the amount of debt they are removing\n     * Requirements\n     *  - The bond is not mature\n     *  - The number of `amounts` is the same as the number of tranches\n     *  - The `amounts` are in equivalent ratio to the tranche order\n     */\n    function redeem(uint256[] memory amounts) external;\n\n    /**\n     * @dev Updates the fee taken on deposit to the given new fee\n     *\n     * Requirements\n     * - `msg.sender` has admin role\n     * - `newFeeBps` is in range [0, 50]\n     */\n    function setFee(uint256 newFeeBps) external;\n}\n"
      },
      "contracts/interfaces/ITrancheFactory.sol": {
        "content": "pragma solidity ^0.8.3;\n\n/**\n * @dev Factory for Tranche minimal proxy contracts\n */\ninterface ITrancheFactory {\n    event TrancheCreated(address newTrancheAddress);\n\n    /**\n     * @dev Deploys a minimal proxy instance for a new tranche ERC20 token with the given parameters.\n     */\n    function createTranche(\n        string memory name,\n        string memory symbol,\n        address _collateralToken\n    ) external returns (address);\n}\n"
      },
      "contracts/interfaces/ITranche.sol": {
        "content": "pragma solidity ^0.8.3;\n\nimport \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@uniswap/lib/contracts/libraries/TransferHelper.sol\";\n\n/**\n * @dev ERC20 token to represent a single tranche for a ButtonTranche bond\n *\n */\ninterface ITranche is IERC20 {\n    /**\n     * @dev returns the BondController address which owns this Tranche contract\n     *  It should have admin permissions to call mint, burn, and redeem functions\n     */\n    function bond() external view returns (address);\n\n    /**\n     * @dev Mint `amount` tokens to `to`\n     *  Only callable by the owner (bond controller). Used to\n     *  manage bonds, specifically creating tokens upon deposit\n     * @param to the address to mint tokens to\n     * @param amount The amount of tokens to mint\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * @dev Burn `amount` tokens from `from`'s balance\n     *  Only callable by the owner (bond controller). Used to\n     *  manage bonds, specifically burning tokens upon redemption\n     * @param from The address to burn tokens from\n     * @param amount The amount of tokens to burn\n     */\n    function burn(address from, uint256 amount) external;\n\n    /**\n     * @dev Burn `amount` tokens from `from` and return the proportional\n     * value of the collateral token to `to`\n     * @param from The address to burn tokens from\n     * @param to The address to send collateral back to\n     * @param amount The amount of tokens to burn\n     */\n    function redeem(\n        address from,\n        address to,\n        uint256 amount\n    ) external;\n}\n"
      },
      "contracts/interfaces/IRebasingERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// Interface definition for Rebasing ERC20 tokens which have a \"elastic\" external\n// balance and \"fixed\" internal balance. Each user's external balance is\n// represented as a product of a \"scalar\" and the user's internal balance.\n//\n// From time to time the \"Rebase\" event updates scaler,\n// which increases/decreases all user balances proportionally.\n//\n// The standard ERC-20 methods are denominated in the elastic balance\n//\ninterface IRebasingERC20 is IERC20, IERC20Metadata {\n    /// @notice Returns the fixed balance of the specified address.\n    /// @param who The address to query.\n    function scaledBalanceOf(address who) external view returns (uint256);\n\n    /// @notice Returns the total fixed supply.\n    function scaledTotalSupply() external view returns (uint256);\n\n    /// @notice Transfer all of the sender's balance to a specified address.\n    /// @param to The address to transfer to.\n    /// @return True on success, false otherwise.\n    function transferAll(address to) external returns (bool);\n\n    /// @notice Transfer all balance tokens from one address to another.\n    /// @param from The address to send tokens from.\n    /// @param to The address to transfer to.\n    function transferAllFrom(address from, address to) external returns (bool);\n\n    /// @notice Triggers the next rebase, if applicable.\n    function rebase() external;\n\n    /// @notice Event emitted when the balance scalar is updated.\n    /// @param epoch The number of rebases since inception.\n    /// @param newScalar The new scalar.\n    event Rebase(uint256 indexed epoch, uint256 newScalar);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal initializer {\n        __Context_init_unchained();\n    }\n\n    function __Context_init_unchained() internal initializer {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n    uint256[50] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     */\n    bool private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Modifier to protect an initializer function from being invoked twice.\n     */\n    modifier initializer() {\n        require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n        bool isTopLevelCall = !_initializing;\n        if (isTopLevelCall) {\n            _initializing = true;\n            _initialized = true;\n        }\n\n        _;\n\n        if (isTopLevelCall) {\n            _initializing = false;\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "metadata": {
        "bytecodeHash": "none"
      },
      "optimizer": {
        "enabled": true,
        "runs": 999999
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}