Contract 0x19Ca3baAEAf37b857026dfEd3A0Ba63987A1008D 1

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x2bb007afe0a41da83ad960cff23cc786d3a3dd0fc75e132ec901e5a3261fba68Split113226562021-09-29 1:01:596 mins ago0x9d52962aea8e71ee397c3cd9df5c7f5a23ea6f45 IN  Tranchess: BTCB Primary Market0 BNB0.000627965
0xb9016007590aeee5ed3780db08cf4e032b91654b8fdbe997d61a40bfdd37d190Create113224162021-09-29 0:49:1318 mins ago0x16656c8cc579454efc8283d160051cfde90b89d1 IN  Tranchess: BTCB Primary Market0 BNB0.0004740705
0x1a9c80840dd84d027c7d05caddce48314efc2da1b61593b833803e6c279603a2Split113223472021-09-29 0:45:2122 mins ago0x40d74e82d190dc3ae53747e9886a83220dbe71d6 IN  Tranchess: BTCB Primary Market0 BNB0.000627905
0xa037046e03335acf40646f82e43df2711ceabcdf8226b4e54f55fa344393947aCreate113223152021-09-29 0:43:4524 mins ago0x2d3ca83db323146fd1175b4d826bcc57c916a9ba IN  Tranchess: BTCB Primary Market0 BNB0.00041691
0x36f5348e8e35da24a730c65ecf856fc1c3f42be0347dbf56d572d39097cdcc29Create113222382021-09-29 0:39:5028 mins ago0x428c137257ce3e2ed671f931ed9ba78e8a060fef IN  Tranchess: BTCB Primary Market0 BNB0.000464775
0xdbfc358e838464cca20af7e0ae3fcd83aa7e6f241d8333021b78b1256e5a35abClaim113218952021-09-29 0:22:3945 mins ago0x99533ac624cf4d0d5c05d3b19ca2a221003956c4 IN  Tranchess: BTCB Primary Market0 BNB0.000424105
0xda5c20c3b4bf1d7a82a688d548c32199eae26fd7fd62d36f858cdb61f126856cRedeem113218822021-09-29 0:22:0046 mins ago0x0b13aca110f375644c1d8bc9690a381bec1d429f IN  Tranchess: BTCB Primary Market0 BNB0.000450385
0xe90c04662448788e6b7e7b3e60a78c4d25abcbc5bba3367fe254f50e2e2ab4deMerge113186292021-09-28 21:38:223 hrs 29 mins ago0xb5527852da7790907218c02e96504954507972f1 IN  Tranchess: BTCB Primary Market0 BNB0.00047959
0x892f694b1780b2060f6f6c7f9aa00ae74d47cd6a236ec9b4ccf450d87f2c03bfClaim113181112021-09-28 21:12:283 hrs 55 mins ago0x7b83f4aef8377f3f6a54ae6728a8a3eccb3f6b3c IN  Tranchess: BTCB Primary Market0 BNB0.000369355
0x1724b91c482253d8b5328c9b8d3f7d8e02abe55b8265e436215a86c4442d6eb0Create113165662021-09-28 19:54:165 hrs 13 mins ago0x9f6ea3d6a7aaa38e9ba351d153b427d1eeb7cff6 IN  Tranchess: BTCB Primary Market0 BNB0.0004740705
0xb0124dd87619a98b4635b5e19ab31369ef6aea4b99697c113e684bcf66ae8f00Create113165652021-09-28 19:54:135 hrs 13 mins ago0xee5d72fd8dafe7820b8c973802833c1d06c339a8 IN  Tranchess: BTCB Primary Market0 BNB0.0005505093
0x705afa718c8909b3113d5cf2ba5a138ccbed82b8a7cb19c93aed53820a02a8daRedeem113161222021-09-28 19:31:465 hrs 36 mins ago0xe5c6caed2da71e8ac8678353b9acfe9025bb9137 IN  Tranchess: BTCB Primary Market0 BNB0.000450505
0x22c64247699693eea1a03bdbde51192127e96080e43959774a1919f9d848bf8aSplit113150472021-09-28 18:37:016 hrs 31 mins ago0x8c5055b3d2cbbe75a1d8f563964812de394c05b4 IN  Tranchess: BTCB Primary Market0 BNB0.000702965
0xeafe5f9c228ab58ae8caf2cc7cb8fc02d87ce8cce83d2b42a51ae8cc25fac2d7Claim113150022021-09-28 18:34:466 hrs 33 mins ago0x8c5055b3d2cbbe75a1d8f563964812de394c05b4 IN  Tranchess: BTCB Primary Market0 BNB0.000424165
0x1b49cf31c32ef5670d42b5da43f53e19b6a63e465f5759a4a099491ee3c7d715Create113141092021-09-28 17:49:417 hrs 18 mins ago0xd87810fd7abe39564c5749daa3ba3cfd070f6e31 IN  Tranchess: BTCB Primary Market0 BNB0.00041685
0x468619b989d026890a920568bdf3d67a1bb11b850cb0919a32d9eae17c6bea65Create113135982021-09-28 17:24:057 hrs 44 mins ago0x3543f51b35bf8cadb083529f7d1c49f6340b1aa7 IN  Tranchess: BTCB Primary Market0 BNB0.000539775
0x67dd1c11118a9cf48bafd60c938a720d7582ca2388ecd612eacb6314c7390844Create113134242021-09-28 17:15:117 hrs 52 mins ago0xdf3446dd3fdecbca8a9f04e07877494a17837414 IN  Tranchess: BTCB Primary Market0 BNB0.000464775
0x46f2a844e8cba80f9b39254b8f9fcc3066bbb6b89593781aa02895c341e9936cCreate113126092021-09-28 16:33:368 hrs 34 mins ago0x6c446906ac551cbb24e8704725ea1dd3552a8feb IN  Tranchess: BTCB Primary Market0 BNB0.00041685
0x38251d3f4bdd1565a15e985f49362bf4fdef605024a11bd88014d3e4f26017fcCreate113124252021-09-28 16:24:248 hrs 43 mins ago0xa04af4516019a96db2e4a872e6168ceadbf545af IN  Tranchess: BTCB Primary Market0 BNB0.000539775
0xfb470c77ba119981c716136c9e6c79eb09a527a38778762c7c897a27e871f619Claim113124242021-09-28 16:24:218 hrs 43 mins ago0xdd610321d3cf020a6af0cc2ed352093f3343e4b8 IN  Tranchess: BTCB Primary Market0 BNB0.00037009371
0xcd1619d0161a5d66adccfae56e3e2d2d1609e60acc2e46944438f7badcdfddefCreate113121552021-09-28 16:10:548 hrs 57 mins ago0xea74f576bd67caf374e2dc24282377b8e5a7dc1c IN  Tranchess: BTCB Primary Market0 BNB0.000539775
0xee321eb31340265b2227a0b71b626fd9e542926cab253ff1d9078fe71bbe8c4eClaim113119462021-09-28 16:00:279 hrs 7 mins ago0xdda0e94955c637e30052cb28e73ce04c265f328b IN  Tranchess: BTCB Primary Market0 BNB0.000369295
0x4e230ee11888210282849f8b1a0f9b7ee5036dc7908215d59bede2c321d9cc24Claim113119342021-09-28 15:59:519 hrs 8 mins ago0x1ce9474cfd54f9b569df9906583309403d75abca IN  Tranchess: BTCB Primary Market0 BNB0.000424165
0x0ef2da37f696fcd48381d12c3b3b7993bb3811d197953959a765d3f34ac42a47Create113119022021-09-28 15:58:089 hrs 10 mins ago0x04ee6f55c8c939be068a1d4cc15d470dea5bcb3a IN  Tranchess: BTCB Primary Market0 BNB0.000464775
0xcbf9e0b329ed280edd425596364023d5ddca0eb601e17aa2f1bec382ea157aadSplit113118272021-09-28 15:53:579 hrs 14 mins ago0xca5b16eaffe81709d6256732e67e34c5df946373 IN  Tranchess: BTCB Primary Market0 BNB0.000627965
[ Download CSV Export 

OVERVIEW

Primary market of the Tranchess BTCB fund.

Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PrimaryMarket

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 14 : PrimaryMarket.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import "../utils/SafeDecimalMath.sol";

import "../interfaces/IPrimaryMarket.sol";
import "../interfaces/IFund.sol";
import "../interfaces/ITrancheIndex.sol";

contract PrimaryMarket is IPrimaryMarket, ReentrancyGuard, ITrancheIndex, Ownable {
    event Created(address indexed account, uint256 underlying);
    event Redeemed(address indexed account, uint256 shares);
    event Split(address indexed account, uint256 inM, uint256 outA, uint256 outB);
    event Merged(address indexed account, uint256 outM, uint256 inA, uint256 inB);
    event Claimed(address indexed account, uint256 createdShares, uint256 redeemedUnderlying);
    event Settled(
        uint256 indexed day,
        uint256 sharesToMint,
        uint256 sharesToBurn,
        uint256 creationUnderlying,
        uint256 redemptionUnderlying,
        uint256 fee
    );

    using SafeMath for uint256;
    using SafeDecimalMath for uint256;
    using SafeERC20 for IERC20;

    /// @dev Creation and redemption of a single account.
    /// @param day Day of the last creation or redemption request.
    /// @param creatingUnderlying Underlying that will be used for creation at the end of this day.
    /// @param redeemingShares Shares that will be redeemed at the end of this day.
    /// @param createdShares Shares already created in previous days.
    /// @param redeemedUnderlying Underlying already redeemed in previous days.
    /// @param version Rebalance version before the end of this trading day.
    struct CreationRedemption {
        uint256 day;
        uint256 creatingUnderlying;
        uint256 redeemingShares;
        uint256 createdShares;
        uint256 redeemedUnderlying;
        uint256 version;
    }

    uint256 private constant MAX_REDEMPTION_FEE_RATE = 0.01e18;
    uint256 private constant MAX_SPLIT_FEE_RATE = 0.01e18;
    uint256 private constant MAX_MERGE_FEE_RATE = 0.01e18;

    uint256 public immutable guardedLaunchStart;
    uint256 public guardedLaunchTotalCap;
    uint256 public guardedLaunchIndividualCap;
    mapping(address => uint256) public guardedLaunchCreations;

    IFund public fund;

    uint256 public redemptionFeeRate;
    uint256 public splitFeeRate;
    uint256 public mergeFeeRate;
    uint256 public minCreationUnderlying;

    mapping(address => CreationRedemption) private _creationRedemptions;

    uint256 public currentDay;
    uint256 public currentCreatingUnderlying;
    uint256 public currentRedeemingShares;
    uint256 public currentFeeInShares;

    mapping(uint256 => uint256) private _historicalCreationRate;
    mapping(uint256 => uint256) private _historicalRedemptionRate;

    constructor(
        address fund_,
        uint256 guardedLaunchStart_,
        uint256 redemptionFeeRate_,
        uint256 splitFeeRate_,
        uint256 mergeFeeRate_,
        uint256 minCreationUnderlying_
    ) public Ownable() {
        require(redemptionFeeRate_ <= MAX_REDEMPTION_FEE_RATE, "Exceed max redemption fee rate");
        require(splitFeeRate_ <= MAX_SPLIT_FEE_RATE, "Exceed max split fee rate");
        require(mergeFeeRate_ <= MAX_MERGE_FEE_RATE, "Exceed max merge fee rate");
        fund = IFund(fund_);
        guardedLaunchStart = guardedLaunchStart_;
        redemptionFeeRate = redemptionFeeRate_;
        splitFeeRate = splitFeeRate_;
        mergeFeeRate = mergeFeeRate_;
        minCreationUnderlying = minCreationUnderlying_;
        currentDay = fund.currentDay();
    }

    function creationRedemptionOf(address account)
        external
        view
        returns (CreationRedemption memory)
    {
        return _currentCreationRedemption(account);
    }

    function create(uint256 underlying) external nonReentrant onlyActive {
        require(underlying >= minCreationUnderlying, "Min amount");
        IERC20(fund.tokenUnderlying()).safeTransferFrom(msg.sender, address(this), underlying);

        CreationRedemption memory cr = _currentCreationRedemption(msg.sender);
        cr.creatingUnderlying = cr.creatingUnderlying.add(underlying);
        _updateCreationRedemption(msg.sender, cr);

        currentCreatingUnderlying = currentCreatingUnderlying.add(underlying);

        if (block.timestamp < guardedLaunchStart + 4 weeks) {
            guardedLaunchCreations[msg.sender] = guardedLaunchCreations[msg.sender].add(underlying);
            require(
                IERC20(fund.tokenUnderlying()).balanceOf(address(fund)).add(
                    currentCreatingUnderlying
                ) <= guardedLaunchTotalCap,
                "Guarded launch: exceed total cap"
            );
            require(
                guardedLaunchCreations[msg.sender] <= guardedLaunchIndividualCap,
                "Guarded launch: exceed individual cap"
            );
        }

        emit Created(msg.sender, underlying);
    }

    function redeem(uint256 shares) external onlyActive {
        require(shares != 0, "Zero shares");
        // Use burn and mint to simulate a transfer, so that we don't need a special transferFrom()
        fund.burn(TRANCHE_M, msg.sender, shares);
        fund.mint(TRANCHE_M, address(this), shares);

        CreationRedemption memory cr = _currentCreationRedemption(msg.sender);
        cr.redeemingShares = cr.redeemingShares.add(shares);
        _updateCreationRedemption(msg.sender, cr);

        currentRedeemingShares = currentRedeemingShares.add(shares);
        emit Redeemed(msg.sender, shares);
    }

    function claim(address account)
        external
        override
        nonReentrant
        returns (uint256 createdShares, uint256 redeemedUnderlying)
    {
        CreationRedemption memory cr = _currentCreationRedemption(account);
        createdShares = cr.createdShares;
        redeemedUnderlying = cr.redeemedUnderlying;

        if (createdShares > 0) {
            IERC20(fund.tokenM()).safeTransfer(account, createdShares);
            cr.createdShares = 0;
        }
        if (redeemedUnderlying > 0) {
            IERC20(fund.tokenUnderlying()).safeTransfer(account, redeemedUnderlying);
            cr.redeemedUnderlying = 0;
        }
        _updateCreationRedemption(account, cr);

        emit Claimed(account, createdShares, redeemedUnderlying);
    }

    function split(uint256 inM) external onlyActive {
        require(
            block.timestamp >= guardedLaunchStart + 2 weeks,
            "Guarded launch: split not ready yet"
        );
        (uint256 weightA, uint256 weightB) = fund.trancheWeights();
        // Charge splitting fee and round it to a multiple of (weightA + weightB)
        uint256 unit = inM.sub(inM.multiplyDecimal(splitFeeRate)) / (weightA + weightB);
        require(unit > 0, "Too little to split");
        uint256 inMAfterFee = unit * (weightA + weightB);
        uint256 outA = unit * weightA;
        uint256 outB = inMAfterFee - outA;
        uint256 feeM = inM - inMAfterFee;

        fund.burn(TRANCHE_M, msg.sender, inM);
        fund.mint(TRANCHE_A, msg.sender, outA);
        fund.mint(TRANCHE_B, msg.sender, outB);
        fund.mint(TRANCHE_M, address(this), feeM);

        currentFeeInShares = currentFeeInShares.add(feeM);
        emit Split(msg.sender, inM, outA, outB);
    }

    function merge(uint256 inA) external onlyActive {
        (uint256 weightA, uint256 weightB) = fund.trancheWeights();
        // Round to tranche weights
        uint256 unit = inA / weightA;
        require(unit > 0, "Too little to merge");
        // Keep unmergable Token A unchanged.
        inA = unit * weightA;
        uint256 inB = unit.mul(weightB);
        uint256 outMBeforeFee = inA.add(inB);
        uint256 feeM = outMBeforeFee.multiplyDecimal(mergeFeeRate);
        uint256 outM = outMBeforeFee.sub(feeM);

        fund.burn(TRANCHE_A, msg.sender, inA);
        fund.burn(TRANCHE_B, msg.sender, inB);
        fund.mint(TRANCHE_M, msg.sender, outM);
        fund.mint(TRANCHE_M, address(this), feeM);

        currentFeeInShares = currentFeeInShares.add(feeM);
        emit Merged(msg.sender, outM, inA, inB);
    }

    /// @notice Settle ongoing creations and redemptions and also split and merge fees.
    ///
    ///         Creations and redemptions are settled according to the current shares and
    ///         underlying assets in the fund. Split and merge fee charged as Token M are also
    ///         redeemed at the same rate (without redemption fee).
    ///
    ///         This function does not mint or burn shares, nor transfer underlying assets.
    ///         It returns the following changes that should be done by the fund:
    ///
    ///         1. Mint or burn net shares (creations v.s. redemptions + split/merge fee).
    ///         2. Transfer underlying to or from this contract (creations v.s. redemptions).
    ///         3. Transfer fee in underlying assets to the governance address.
    ///
    ///         This function can only be called from the Fund contract. It should be called
    ///         after protocol fee is collected and before rebalance is triggered for the same
    ///         trading day.
    /// @param day The trading day to settle
    /// @param fundTotalShares Total shares of the fund (as if all Token A and B are merged)
    /// @param fundUnderlying Underlying assets in the fund
    /// @param underlyingPrice Price of the underlying assets at the end of the trading day
    /// @param previousNav NAV of Token M of the previous trading day
    /// @return sharesToMint Amount of Token M to mint for creations
    /// @return sharesToBurn Amount of Token M to burn for redemptions and split/merge fee
    /// @return creationUnderlying Underlying assets received for creations (including creation fee)
    /// @return redemptionUnderlying Underlying assets to be redeemed (excluding redemption fee)
    /// @return fee Total fee in underlying assets for the fund to transfer to the governance address,
    ///         inlucding creation fee, redemption fee and split/merge fee
    function settle(
        uint256 day,
        uint256 fundTotalShares,
        uint256 fundUnderlying,
        uint256 underlyingPrice,
        uint256 previousNav
    )
        external
        override
        nonReentrant
        onlyFund
        returns (
            uint256 sharesToMint,
            uint256 sharesToBurn,
            uint256 creationUnderlying,
            uint256 redemptionUnderlying,
            uint256 fee
        )
    {
        require(day >= currentDay, "Already settled");

        // Creation
        creationUnderlying = currentCreatingUnderlying;
        if (creationUnderlying > 0) {
            if (fundUnderlying > 0) {
                sharesToMint = creationUnderlying.mul(fundTotalShares).div(fundUnderlying);
            } else {
                // NAV is rounded down. Computing creations using NAV results in rounded up shares,
                // which is unfair to existing share holders. We only do that when there are
                // no shares before.
                require(
                    fundTotalShares == 0,
                    "Cannot create shares for fund with shares but no underlying"
                );
                require(previousNav > 0, "Cannot create shares at zero NAV");
                sharesToMint = creationUnderlying
                    .mul(underlyingPrice)
                    .mul(fund.underlyingDecimalMultiplier())
                    .div(previousNav);
            }
            _historicalCreationRate[day] = sharesToMint.divideDecimal(creationUnderlying);
        }

        // Redemption
        sharesToBurn = currentRedeemingShares;
        if (sharesToBurn > 0) {
            uint256 underlying = sharesToBurn.mul(fundUnderlying).div(fundTotalShares);
            uint256 redemptionFee = underlying.multiplyDecimal(redemptionFeeRate);
            redemptionUnderlying = underlying.sub(redemptionFee);
            _historicalRedemptionRate[day] = redemptionUnderlying.divideDecimal(sharesToBurn);
            fee = redemptionFee;
        }

        // Redeem split and merge fee
        uint256 feeInShares = currentFeeInShares;
        if (feeInShares > 0) {
            sharesToBurn = sharesToBurn.add(feeInShares);
            fee = fee.add(feeInShares.mul(fundUnderlying).div(fundTotalShares));
        }

        // Approve the fund to take underlying if creation is more than redemption.
        // Instead of directly transfering underlying to the fund, this implementation
        // makes testing much easier.
        if (creationUnderlying > redemptionUnderlying) {
            IERC20(fund.tokenUnderlying()).safeApprove(
                address(fund),
                creationUnderlying - redemptionUnderlying
            );
        }

        // This loop should never execute, because this function is called by Fund
        // for every day. We fill the gap just in case that something goes wrong in Fund.
        for (uint256 t = currentDay; t < day; t += 1 days) {
            _historicalCreationRate[t] = _historicalCreationRate[day];
            _historicalRedemptionRate[t] = _historicalRedemptionRate[day];
        }

        currentDay = day + 1 days;
        currentCreatingUnderlying = 0;
        currentRedeemingShares = 0;
        currentFeeInShares = 0;
        emit Settled(
            day,
            sharesToMint,
            sharesToBurn,
            creationUnderlying,
            redemptionUnderlying,
            fee
        );
    }

    function updateGuardedLaunchCap(uint256 newTotalCap, uint256 newIndividualCap)
        external
        onlyOwner
    {
        guardedLaunchTotalCap = newTotalCap;
        guardedLaunchIndividualCap = newIndividualCap;
    }

    function updateRedemptionFeeRate(uint256 newRedemptionFeeRate) external onlyOwner {
        require(newRedemptionFeeRate <= MAX_REDEMPTION_FEE_RATE, "Exceed max redemption fee rate");
        redemptionFeeRate = newRedemptionFeeRate;
    }

    function updateSplitFeeRate(uint256 newSplitFeeRate) external onlyOwner {
        require(newSplitFeeRate <= MAX_SPLIT_FEE_RATE, "Exceed max split fee rate");
        splitFeeRate = newSplitFeeRate;
    }

    function updateMergeFeeRate(uint256 newMergeFeeRate) external onlyOwner {
        require(newMergeFeeRate <= MAX_MERGE_FEE_RATE, "Exceed max merge fee rate");
        mergeFeeRate = newMergeFeeRate;
    }

    function updateMinCreationUnderlying(uint256 newMinCreationUnderlying) external onlyOwner {
        minCreationUnderlying = newMinCreationUnderlying;
    }

    function _currentCreationRedemption(address account)
        private
        view
        returns (CreationRedemption memory cr)
    {
        cr = _creationRedemptions[account];
        uint256 oldDay = cr.day;
        if (oldDay < currentDay) {
            if (cr.creatingUnderlying > 0) {
                cr.createdShares = cr.createdShares.add(
                    cr.creatingUnderlying.multiplyDecimal(_historicalCreationRate[oldDay])
                );
                cr.creatingUnderlying = 0;
            }
            uint256 rebalanceSize = fund.getRebalanceSize();
            if (cr.version < rebalanceSize) {
                if (cr.createdShares > 0) {
                    (cr.createdShares, , ) = fund.batchRebalance(
                        cr.createdShares,
                        0,
                        0,
                        cr.version,
                        rebalanceSize
                    );
                }
                cr.version = rebalanceSize;
            }
            if (cr.redeemingShares > 0) {
                cr.redeemedUnderlying = cr.redeemedUnderlying.add(
                    cr.redeemingShares.multiplyDecimal(_historicalRedemptionRate[oldDay])
                );
                cr.redeemingShares = 0;
            }
            cr.day = currentDay;
        }
    }

    function _updateCreationRedemption(address account, CreationRedemption memory cr) private {
        CreationRedemption storage old = _creationRedemptions[account];
        if (old.day != cr.day) {
            old.day = cr.day;
        }
        if (old.creatingUnderlying != cr.creatingUnderlying) {
            old.creatingUnderlying = cr.creatingUnderlying;
        }
        if (old.redeemingShares != cr.redeemingShares) {
            old.redeemingShares = cr.redeemingShares;
        }
        if (old.createdShares != cr.createdShares) {
            old.createdShares = cr.createdShares;
        }
        if (old.redeemedUnderlying != cr.redeemedUnderlying) {
            old.redeemedUnderlying = cr.redeemedUnderlying;
        }
        if (old.version != cr.version) {
            old.version = cr.version;
        }
    }

    modifier onlyActive() {
        require(fund.isPrimaryMarketActive(address(this), block.timestamp), "Only when active");
        _;
    }

    modifier onlyFund() {
        require(msg.sender == address(fund), "Only fund");
        _;
    }
}

File 2 of 14 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

File 3 of 14 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 4 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 5 of 14 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 6 of 14 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 7 of 14 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 8 of 14 : SafeDecimalMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;

import "@openzeppelin/contracts/math/SafeMath.sol";

library SafeDecimalMath {
    using SafeMath for uint256;

    /* Number of decimal places in the representations. */
    uint256 private constant decimals = 18;
    uint256 private constant highPrecisionDecimals = 27;

    /* The number representing 1.0. */
    uint256 private constant UNIT = 10**uint256(decimals);

    /* The number representing 1.0 for higher fidelity numbers. */
    uint256 private constant PRECISE_UNIT = 10**uint256(highPrecisionDecimals);
    uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR =
        10**uint256(highPrecisionDecimals - decimals);

    /**
     * @return The result of multiplying x and y, interpreting the operands as fixed-point
     * decimals.
     *
     * @dev A unit factor is divided out after the product of x and y is evaluated,
     * so that product must be less than 2**256. As this is an integer division,
     * the internal division always rounds down. This helps save on gas. Rounding
     * is more expensive on gas.
     */
    function multiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        return x.mul(y).div(UNIT);
    }

    function multiplyDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        return x.mul(y).div(PRECISE_UNIT);
    }

    /**
     * @return The result of safely dividing x and y. The return value is a high
     * precision decimal.
     *
     * @dev y is divided after the product of x and the standard precision unit
     * is evaluated, so the product of x and UNIT must be less than 2**256. As
     * this is an integer division, the result is always rounded down.
     * This helps save on gas. Rounding is more expensive on gas.
     */
    function divideDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
        /* Reintroduce the UNIT factor that will be divided out by y. */
        return x.mul(UNIT).div(y);
    }

    function divideDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
        /* Reintroduce the UNIT factor that will be divided out by y. */
        return x.mul(PRECISE_UNIT).div(y);
    }

    /**
     * @dev Convert a standard decimal representation to a high precision one.
     */
    function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) {
        return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
    }

    /**
     * @dev Convert a high precision decimal to a standard decimal representation.
     */
    function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) {
        uint256 quotientTimesTen = i.mul(10).div(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);

        if (quotientTimesTen % 10 >= 5) {
            quotientTimesTen = quotientTimesTen.add(10);
        }

        return quotientTimesTen.div(10);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, and the max value of
     * uint256 on overflow.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        return c / a != b ? type(uint256).max : c;
    }

    function saturatingMultiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        return saturatingMul(x, y).div(UNIT);
    }
}

File 9 of 14 : IPrimaryMarket.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;

interface IPrimaryMarket {
    function claim(address account)
        external
        returns (uint256 createdShares, uint256 redeemedUnderlying);

    function settle(
        uint256 day,
        uint256 fundTotalShares,
        uint256 fundUnderlying,
        uint256 underlyingPrice,
        uint256 previousNav
    )
        external
        returns (
            uint256 sharesToMint,
            uint256 sharesToBurn,
            uint256 creationUnderlying,
            uint256 redemptionUnderlying,
            uint256 fee
        );
}

File 10 of 14 : IFund.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;

import "./ITwapOracle.sol";

interface IFund {
    /// @notice A linear transformation matrix that represents a rebalance.
    ///
    ///         ```
    ///             [ ratioM          0        0 ]
    ///         R = [ ratioA2M  ratioAB        0 ]
    ///             [ ratioB2M        0  ratioAB ]
    ///         ```
    ///
    ///         Amounts of the three tranches `m`, `a` and `b` can be rebalanced by multiplying the matrix:
    ///
    ///         ```
    ///         [ m', a', b' ] = [ m, a, b ] * R
    ///         ```
    struct Rebalance {
        uint256 ratioM;
        uint256 ratioA2M;
        uint256 ratioB2M;
        uint256 ratioAB;
        uint256 timestamp;
    }

    function trancheWeights() external pure returns (uint256 weightA, uint256 weightB);

    function tokenUnderlying() external view returns (address);

    function tokenM() external view returns (address);

    function tokenA() external view returns (address);

    function tokenB() external view returns (address);

    function underlyingDecimalMultiplier() external view returns (uint256);

    function twapOracle() external view returns (ITwapOracle);

    function feeCollector() external view returns (address);

    function endOfDay(uint256 timestamp) external pure returns (uint256);

    function shareTotalSupply(uint256 tranche) external view returns (uint256);

    function shareBalanceOf(uint256 tranche, address account) external view returns (uint256);

    function allShareBalanceOf(address account)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    function shareBalanceVersion(address account) external view returns (uint256);

    function shareAllowance(
        uint256 tranche,
        address owner,
        address spender
    ) external view returns (uint256);

    function shareAllowanceVersion(address owner, address spender) external view returns (uint256);

    function getRebalanceSize() external view returns (uint256);

    function getRebalance(uint256 index) external view returns (Rebalance memory);

    function getRebalanceTimestamp(uint256 index) external view returns (uint256);

    function currentDay() external view returns (uint256);

    function fundActivityStartTime() external view returns (uint256);

    function exchangeActivityStartTime() external view returns (uint256);

    function isFundActive(uint256 timestamp) external view returns (bool);

    function isPrimaryMarketActive(address primaryMarket, uint256 timestamp)
        external
        view
        returns (bool);

    function isExchangeActive(uint256 timestamp) external view returns (bool);

    function getTotalShares() external view returns (uint256);

    function extrapolateNav(uint256 timestamp, uint256 price)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    function calculateNavB(uint256 navM, uint256 navA) external pure returns (uint256);

    function doRebalance(
        uint256 amountM,
        uint256 amountA,
        uint256 amountB,
        uint256 index
    )
        external
        view
        returns (
            uint256 newAmountM,
            uint256 newAmountA,
            uint256 newAmountB
        );

    function batchRebalance(
        uint256 amountM,
        uint256 amountA,
        uint256 amountB,
        uint256 fromIndex,
        uint256 toIndex
    )
        external
        view
        returns (
            uint256 newAmountM,
            uint256 newAmountA,
            uint256 newAmountB
        );

    function refreshBalance(address account, uint256 targetVersion) external;

    function refreshAllowance(
        address owner,
        address spender,
        uint256 targetVersion
    ) external;

    function mint(
        uint256 tranche,
        address account,
        uint256 amount
    ) external;

    function burn(
        uint256 tranche,
        address account,
        uint256 amount
    ) external;

    function transfer(
        uint256 tranche,
        address sender,
        address recipient,
        uint256 amount
    ) external;

    function transferFrom(
        uint256 tranche,
        address spender,
        address sender,
        address recipient,
        uint256 amount
    ) external returns (uint256 newAllowance);

    function increaseAllowance(
        uint256 tranche,
        address sender,
        address spender,
        uint256 addedValue
    ) external returns (uint256 newAllowance);

    function decreaseAllowance(
        uint256 tranche,
        address sender,
        address spender,
        uint256 subtractedValue
    ) external returns (uint256 newAllowance);

    function approve(
        uint256 tranche,
        address owner,
        address spender,
        uint256 amount
    ) external;

    event RebalanceTriggered(
        uint256 indexed index,
        uint256 indexed day,
        uint256 ratioM,
        uint256 ratioA2M,
        uint256 ratioB2M,
        uint256 ratioAB
    );
    event Settled(uint256 indexed day, uint256 navM, uint256 navA, uint256 navB);
    event InterestRateUpdated(uint256 baseInterestRate, uint256 floatingInterestRate);
}

File 11 of 14 : ITrancheIndex.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;

/// @notice Amounts of Token M, A and B are sometimes stored in a `uint256[3]` array. This contract
///         defines index of each tranche in this array.
///
///         Solidity does not allow constants to be defined in interfaces. So this contract follows
///         the naming convention of interfaces but is implemented as an `abstract contract`.
abstract contract ITrancheIndex {
    uint256 internal constant TRANCHE_M = 0;
    uint256 internal constant TRANCHE_A = 1;
    uint256 internal constant TRANCHE_B = 2;

    uint256 internal constant TRANCHE_COUNT = 3;
}

File 12 of 14 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 13 of 14 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 14 of 14 : ITwapOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.10 <0.8.0;

interface ITwapOracle {
    function getTwap(uint256 timestamp) external view returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"fund_","type":"address"},{"internalType":"uint256","name":"guardedLaunchStart_","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeRate_","type":"uint256"},{"internalType":"uint256","name":"splitFeeRate_","type":"uint256"},{"internalType":"uint256","name":"mergeFeeRate_","type":"uint256"},{"internalType":"uint256","name":"minCreationUnderlying_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"createdShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemedUnderlying","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlying","type":"uint256"}],"name":"Created","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"outM","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inB","type":"uint256"}],"name":"Merged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToMint","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creationUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redemptionUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Settled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"inM","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outB","type":"uint256"}],"name":"Split","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256","name":"createdShares","type":"uint256"},{"internalType":"uint256","name":"redeemedUnderlying","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlying","type":"uint256"}],"name":"create","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"creationRedemptionOf","outputs":[{"components":[{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"creatingUnderlying","type":"uint256"},{"internalType":"uint256","name":"redeemingShares","type":"uint256"},{"internalType":"uint256","name":"createdShares","type":"uint256"},{"internalType":"uint256","name":"redeemedUnderlying","type":"uint256"},{"internalType":"uint256","name":"version","type":"uint256"}],"internalType":"struct PrimaryMarket.CreationRedemption","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCreatingUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentFeeInShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRedeemingShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fund","outputs":[{"internalType":"contract IFund","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"guardedLaunchCreations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardedLaunchIndividualCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardedLaunchStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardedLaunchTotalCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inA","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mergeFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCreationUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"fundTotalShares","type":"uint256"},{"internalType":"uint256","name":"fundUnderlying","type":"uint256"},{"internalType":"uint256","name":"underlyingPrice","type":"uint256"},{"internalType":"uint256","name":"previousNav","type":"uint256"}],"name":"settle","outputs":[{"internalType":"uint256","name":"sharesToMint","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"internalType":"uint256","name":"creationUnderlying","type":"uint256"},{"internalType":"uint256","name":"redemptionUnderlying","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"inM","type":"uint256"}],"name":"split","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"splitFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newTotalCap","type":"uint256"},{"internalType":"uint256","name":"newIndividualCap","type":"uint256"}],"name":"updateGuardedLaunchCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMergeFeeRate","type":"uint256"}],"name":"updateMergeFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinCreationUnderlying","type":"uint256"}],"name":"updateMinCreationUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRedemptionFeeRate","type":"uint256"}],"name":"updateRedemptionFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newSplitFeeRate","type":"uint256"}],"name":"updateSplitFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162002c6138038062002c618339810160408190526200003491620001df565b6001600090815562000045620001db565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350662386f26fc10000841115620000c65760405162461bcd60e51b8152600401620000bd90620002c5565b60405180910390fd5b662386f26fc10000831115620000f05760405162461bcd60e51b8152600401620000bd9062000257565b662386f26fc100008211156200011a5760405162461bcd60e51b8152600401620000bd906200028e565b600580546001600160a01b0319166001600160a01b0388811691909117918290556080879052600686905560078590556008849055600983905560408051635c9302c960e01b815290519290911691635c9302c991600480820192602092909190829003018186803b1580156200019057600080fd5b505afa158015620001a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001cb91906200023e565b600b5550620002fc945050505050565b3390565b60008060008060008060c08789031215620001f8578182fd5b86516001600160a01b03811681146200020f578283fd5b6020880151604089015160608a015160808b015160a0909b0151939c929b509099909850965090945092505050565b60006020828403121562000250578081fd5b5051919050565b60208082526019908201527f457863656564206d61782073706c697420666565207261746500000000000000604082015260600190565b60208082526019908201527f457863656564206d6178206d6572676520666565207261746500000000000000604082015260600190565b6020808252601e908201527f457863656564206d617820726564656d7074696f6e2066656520726174650000604082015260600190565b60805161294062000321600039806103965280610f0b52806114e052506129406000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80638da5cb5b116100f9578063db006a7511610097578063ed5614b611610071578063ed5614b614610353578063f2fde38b1461035b578063fa1f93971461036e578063fdf7c9b514610381576101c4565b8063db006a7514610325578063dbceb00514610338578063e211618b1461034b576101c4565b8063b60d4288116100d3578063b60d4288146102ef578063d4149395146102f7578063d4a70f961461030a578063d89f22b914610312576101c4565b80638da5cb5b146102bf5780639a6e977b146102d4578063a439cb37146102dc576101c4565b80635235bf90116101665780635c9302c9116101405780635c9302c914610294578063715018a61461029c578063780900dc146102a457806389dc22cf146102b7576101c4565b80635235bf901461024857806354e5bffe1461026c578063570e9c401461028c576101c4565b806324a47aeb116101a257806324a47aeb146102105780633a42877a146102255780633c7707371461022d57806348d9d3e014610235576101c4565b80630120f27a146101c95780631bc6b05e146101e75780631e83409a146101ef575b600080fd5b6101d1610394565b6040516101de9190612857565b60405180910390f35b6101d16103b8565b6102026101fd3660046120d2565b6103be565b6040516101de9291906128a2565b61022361021e36600461212a565b610578565b005b6101d1610901565b6101d1610907565b6101d16102433660046120d2565b61090d565b61025b6102563660046121cb565b61091f565b6040516101de95949392919061287f565b61027f61027a3660046120d2565b610c9c565b6040516101de9190612813565b6101d1610cb3565b6101d1610cb9565b610223610cbf565b6102236102b236600461212a565b610d3e565b6101d1611105565b6102c761110b565b6040516101de9190612221565b6101d161111a565b6102236102ea36600461215a565b611120565b6102c7611160565b61022361030536600461212a565b61116f565b6101d16111d0565b61022361032036600461212a565b6111d6565b61022361033336600461212a565b611237565b61022361034636600461212a565b611440565b6101d16117e7565b6101d16117ed565b6102236103693660046120d2565b6117f3565b61022361037c36600461212a565b6118aa565b61022361038f36600461212a565b6118e4565b7f000000000000000000000000000000000000000000000000000000000000000081565b60095481565b600080600260005414156103ed5760405162461bcd60e51b81526004016103e49061271c565b60405180910390fd5b60026000556103fa61209c565b61040384611945565b606081015160808201519094509250905082156104bd576104b58484600560009054906101000a90046001600160a01b03166001600160a01b03166393af74e16040518163ffffffff1660e01b815260040160206040518083038186803b15801561046d57600080fd5b505afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a591906120ee565b6001600160a01b03169190611b84565b600060608201525b811561051e576105168483600560009054906101000a90046001600160a01b03166001600160a01b031663db77e2b26040518163ffffffff1660e01b815260040160206040518083038186803b15801561046d57600080fd5b600060808201525b6105288482611bdf565b836001600160a01b03167f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a84846040516105639291906128a2565b60405180910390a25060016000559092909150565b60055460405163059cfa4560e21b81526001600160a01b0390911690631673e914906105aa9030904290600401612273565b60206040518083038186803b1580156105c257600080fd5b505afa1580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa919061210a565b6106165760405162461bcd60e51b81526004016103e490612432565b600554604080516303fa4f5960e41b8152815160009384936001600160a01b0390911692633fa4f5909260048083019392829003018186803b15801561065b57600080fd5b505afa15801561066f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610693919061217b565b9150915060008284816106a257fe5b049050600081116106c55760405162461bcd60e51b81526004016103e49061260e565b808302935060006106d68284611c8b565b905060006106e48683611ccc565b905060006106fd60085483611cf190919063ffffffff16565b9050600061070b8383611d09565b600554604051634f752fb360e11b81529192506001600160a01b031690639eea5f66906107419060019033908d90600401612860565b600060405180830381600087803b15801561075b57600080fd5b505af115801561076f573d6000803e3d6000fd5b5050600554604051634f752fb360e11b81526001600160a01b039091169250639eea5f6691506107a89060029033908990600401612860565b600060405180830381600087803b1580156107c257600080fd5b505af11580156107d6573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a1040915061080f9060009033908690600401612860565b600060405180830381600087803b15801561082957600080fd5b505af115801561083d573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a104091506108769060009030908790600401612860565b600060405180830381600087803b15801561089057600080fd5b505af11580156108a4573d6000803e3d6000fd5b5050600e546108b69250905083611ccc565b600e5560405133907fce7f10f82d9561d266b30c12cdda31505b73abff9eb0d6c1f45938a21c41bbbb906108ef9084908c9089906128b0565b60405180910390a25050505050505050565b60075481565b600d5481565b60046020526000908152604090205481565b60008060008060006002600054141561094a5760405162461bcd60e51b81526004016103e49061271c565b60026000556005546001600160a01b031633146109795760405162461bcd60e51b81526004016103e490612573565b600b548a101561099b5760405162461bcd60e51b81526004016103e49061263b565b600c5492508215610abf5787156109c7576109c0886109ba858c611c8b565b90611d4b565b9450610aa5565b88156109e55760405162461bcd60e51b81526004016103e49061239e565b60008611610a055760405162461bcd60e51b81526004016103e4906122bf565b610aa2866109ba600560009054906101000a90046001600160a01b03166001600160a01b031663094fc9216040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5a57600080fd5b505afa158015610a6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a929190612142565b610a9c878c611c8b565b90611c8b565b94505b610aaf8584611d8d565b60008b8152600f60205260409020555b600d5493508315610b1e576000610ada8a6109ba878c611c8b565b90506000610af360065483611cf190919063ffffffff16565b9050610aff8282611d09565b9350610b0b8487611d8d565b60008d8152601060205260409020559150505b600e548015610b4e57610b318582611ccc565b9450610b4b610b448b6109ba848d611c8b565b8390611ccc565b91505b82841115610bea5760055460408051636dbbf15960e11b81529051610bea926001600160a01b03169186880391839163db77e2b2916004808301926020929190829003018186803b158015610ba257600080fd5b505afa158015610bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda91906120ee565b6001600160a01b03169190611da5565b600b545b8b811015610c2b5760008c8152600f6020908152604080832054848452818420558e83526010909152808220548383529120556201518001610bee565b50620151808b01600b556000600c819055600d819055600e556040518b907fd6bc57af9bdeff672c39eb7ac8725e83883c78f01ea44f6ce017a99e3ef5bb3c90610c7e908990899089908990899061287f565b60405180910390a25060016000819055509550955095509550959050565b610ca461209c565b610cad82611945565b92915050565b600e5481565b600b5481565b610cc7611e68565b6001546001600160a01b03908116911614610cf45760405162461bcd60e51b81526004016103e49061253e565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60026000541415610d615760405162461bcd60e51b81526004016103e49061271c565b600260005560055460405163059cfa4560e21b81526001600160a01b0390911690631673e91490610d989030904290600401612273565b60206040518083038186803b158015610db057600080fd5b505afa158015610dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de8919061210a565b610e045760405162461bcd60e51b81526004016103e490612432565b600954811015610e265760405162461bcd60e51b81526004016103e490612493565b610ec3333083600560009054906101000a90046001600160a01b03166001600160a01b031663db77e2b26040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7a57600080fd5b505afa158015610e8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb291906120ee565b6001600160a01b0316929190611e6c565b610ecb61209c565b610ed433611945565b6020810151909150610ee69083611ccc565b6020820152610ef53382611bdf565b600c54610f029083611ccc565b600c556224ea007f0000000000000000000000000000000000000000000000000000000000000000014210156110bb5733600090815260046020526040902054610f4c9083611ccc565b3360009081526004602081815260409283902093909355600254600c546005548451636dbbf15960e11b81529451929561106c9592946001600160a01b039092169363db77e2b2938084019390829003018186803b158015610fad57600080fd5b505afa158015610fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe591906120ee565b6005546040516370a0823160e01b81526001600160a01b03928316926370a082319261101692911690600401612221565b60206040518083038186803b15801561102e57600080fd5b505afa158015611042573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110669190612142565b90611ccc565b111561108a5760405162461bcd60e51b81526004016103e490612596565b6003543360009081526004602052604090205411156110bb5760405162461bcd60e51b81526004016103e4906127a9565b336001600160a01b03167f0ce3610e89a4bb9ec9359763f99110ed52a4abaea0b62028a1637e242ca2768b836040516110f49190612857565b60405180910390a250506001600055565b60085481565b6001546001600160a01b031690565b60025481565b611128611e68565b6001546001600160a01b039081169116146111555760405162461bcd60e51b81526004016103e49061253e565b600291909155600355565b6005546001600160a01b031681565b611177611e68565b6001546001600160a01b039081169116146111a45760405162461bcd60e51b81526004016103e49061253e565b662386f26fc100008111156111cb5760405162461bcd60e51b81526004016103e49061245c565b600855565b600c5481565b6111de611e68565b6001546001600160a01b0390811691161461120b5760405162461bcd60e51b81526004016103e49061253e565b662386f26fc100008111156112325760405162461bcd60e51b81526004016103e4906123fb565b600755565b60055460405163059cfa4560e21b81526001600160a01b0390911690631673e914906112699030904290600401612273565b60206040518083038186803b15801561128157600080fd5b505afa158015611295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b9919061210a565b6112d55760405162461bcd60e51b81526004016103e490612432565b806112f25760405162461bcd60e51b81526004016103e4906127ee565b600554604051634f752fb360e11b81526001600160a01b0390911690639eea5f66906113279060009033908690600401612860565b600060405180830381600087803b15801561134157600080fd5b505af1158015611355573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a1040915061138e9060009030908690600401612860565b600060405180830381600087803b1580156113a857600080fd5b505af11580156113bc573d6000803e3d6000fd5b505050506113c861209c565b6113d133611945565b60408101519091506113e39083611ccc565b60408201526113f23382611bdf565b600d546113ff9083611ccc565b600d5560405133907f4896181ff8f4543cc00db9fe9b6fb7e6f032b7eb772c72ab1ec1b4d2e03b936990611434908590612857565b60405180910390a25050565b60055460405163059cfa4560e21b81526001600160a01b0390911690631673e914906114729030904290600401612273565b60206040518083038186803b15801561148a57600080fd5b505afa15801561149e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c2919061210a565b6114de5760405162461bcd60e51b81526004016103e490612432565b7f000000000000000000000000000000000000000000000000000000000000000062127500014210156115235760405162461bcd60e51b81526004016103e4906125cb565b600554604080516303fa4f5960e41b8152815160009384936001600160a01b0390911692633fa4f5909260048083019392829003018186803b15801561156857600080fd5b505afa15801561157c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a0919061217b565b9150915060008183016115c86115c160075487611cf190919063ffffffff16565b8690611d09565b816115cf57fe5b049050600081116115f25760405162461bcd60e51b81526004016103e49061233a565b600554604051634f752fb360e11b81528484018302918386029182840391848903916001600160a01b0390911690639eea5f66906116399060009033908d90600401612860565b600060405180830381600087803b15801561165357600080fd5b505af1158015611667573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a104091506116a09060019033908890600401612860565b600060405180830381600087803b1580156116ba57600080fd5b505af11580156116ce573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a104091506117079060029033908790600401612860565b600060405180830381600087803b15801561172157600080fd5b505af1158015611735573d6000803e3d6000fd5b505060055460405163020da84160e61b81526001600160a01b03909116925063836a1040915061176e9060009030908690600401612860565b600060405180830381600087803b15801561178857600080fd5b505af115801561179c573d6000803e3d6000fd5b5050600e546117ae9250905082611ccc565b600e5560405133907ff66885c33d648fcd0d97e0f2a18e30102169c22763473af0fb716f11b4a17dd6906108ef908b90879087906128b0565b60035481565b60065481565b6117fb611e68565b6001546001600160a01b039081169116146118285760405162461bcd60e51b81526004016103e49061253e565b6001600160a01b03811661184e5760405162461bcd60e51b81526004016103e4906122f4565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6118b2611e68565b6001546001600160a01b039081169116146118df5760405162461bcd60e51b81526004016103e49061253e565b600955565b6118ec611e68565b6001546001600160a01b039081169116146119195760405162461bcd60e51b81526004016103e49061253e565b662386f26fc100008111156119405760405162461bcd60e51b81526004016103e49061269b565b600655565b61194d61209c565b506001600160a01b0381166000908152600a6020908152604091829020825160c081018452815480825260018301549382019390935260028201549381019390935260038101546060840152600481015460808401526005015460a0830152600b54811015611b7e576020820151156119fc576000818152600f6020908152604090912054908301516119ef916119e49190611cf1565b606084015190611ccc565b6060830152600060208301525b60055460408051635264e68160e01b815290516000926001600160a01b031691635264e681916004808301926020929190829003018186803b158015611a4157600080fd5b505afa158015611a55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a799190612142565b9050808360a001511015611b3257606083015115611b2a57600554606084015160a085015160405163ed056e2160e01b81526001600160a01b039093169263ed056e2192611ad29290916000918291889060040161287f565b60606040518083038186803b158015611aea57600080fd5b505afa158015611afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b22919061219e565b505060608401525b60a083018190525b604083015115611b7757600082815260106020526040908190205490840151611b6a91611b5f9190611cf1565b608085015190611ccc565b6080840152600060408401525b50600b5482525b50919050565b611bda8363a9059cbb60e01b8484604051602401611ba3929190612273565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611e93565b505050565b6001600160a01b0382166000908152600a602052604090208151815414611c0557815181555b8160200151816001015414611c1f57602082015160018201555b8160400151816002015414611c3957604082015160028201555b8160600151816003015414611c5357606082015160038201555b8160800151816004015414611c6d57608082015160048201555b8160a00151816005015414611bda5760a08201516005820155505050565b600082611c9a57506000610cad565b82820282848281611ca757fe5b0414611cc55760405162461bcd60e51b81526004016103e4906124fd565b9392505050565b600082820183811015611cc55760405162461bcd60e51b81526004016103e490612367565b6000611cc5670de0b6b3a76400006109ba8585611c8b565b6000611cc583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611f22565b6000611cc583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611f4e565b6000611cc5826109ba85670de0b6b3a7640000611c8b565b801580611e2d5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611ddb9030908690600401612235565b60206040518083038186803b158015611df357600080fd5b505afa158015611e07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2b9190612142565b155b611e495760405162461bcd60e51b81526004016103e490612753565b611bda8363095ea7b360e01b8484604051602401611ba3929190612273565b3390565b611e8d846323b872dd60e01b858585604051602401611ba39392919061224f565b50505050565b6060611ee8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611f859092919063ffffffff16565b805190915015611bda5780806020019051810190611f06919061210a565b611bda5760405162461bcd60e51b81526004016103e4906126d2565b60008184841115611f465760405162461bcd60e51b81526004016103e4919061228c565b505050900390565b60008183611f6f5760405162461bcd60e51b81526004016103e4919061228c565b506000838581611f7b57fe5b0495945050505050565b6060611f948484600085611f9c565b949350505050565b606082471015611fbe5760405162461bcd60e51b81526004016103e4906124b7565b611fc78561205d565b611fe35760405162461bcd60e51b81526004016103e490612664565b60006060866001600160a01b031685876040516120009190612205565b60006040518083038185875af1925050503d806000811461203d576040519150601f19603f3d011682016040523d82523d6000602084013e612042565b606091505b5091509150612052828286612063565b979650505050505050565b3b151590565b60608315612072575081611cc5565b8251156120825782518084602001fd5b8160405162461bcd60e51b81526004016103e4919061228c565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000602082840312156120e3578081fd5b8135611cc5816128f2565b6000602082840312156120ff578081fd5b8151611cc5816128f2565b60006020828403121561211b578081fd5b81518015158114611cc5578182fd5b60006020828403121561213b578081fd5b5035919050565b600060208284031215612153578081fd5b5051919050565b6000806040838503121561216c578081fd5b50508035926020909101359150565b6000806040838503121561218d578182fd5b505080516020909101519092909150565b6000806000606084860312156121b2578081fd5b8351925060208401519150604084015190509250925092565b600080600080600060a086880312156121e2578081fd5b505083359560208501359550604085013594606081013594506080013592509050565b600082516122178184602087016128c6565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b60006020825282518060208401526122ab8160408501602087016128c6565b601f01601f19169190910160400192915050565b6020808252818101527f43616e6e6f742063726561746520736861726573206174207a65726f204e4156604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b602080825260139082015272151bdbc81b1a5d1d1b19481d1bc81cdc1b1a5d606a1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252603b908201527f43616e6e6f74206372656174652073686172657320666f722066756e6420776960408201527f74682073686172657320627574206e6f20756e6465726c79696e670000000000606082015260800190565b60208082526019908201527f457863656564206d61782073706c697420666565207261746500000000000000604082015260600190565b60208082526010908201526f4f6e6c79207768656e2061637469766560801b604082015260600190565b60208082526019908201527f457863656564206d6178206d6572676520666565207261746500000000000000604082015260600190565b6020808252600a9082015269135a5b88185b5bdd5b9d60b21b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526009908201526813db9b1e48199d5b9960ba1b604082015260600190565b6020808252818101527f47756172646564206c61756e63683a2065786365656420746f74616c20636170604082015260600190565b60208082526023908201527f47756172646564206c61756e63683a2073706c6974206e6f74207265616479206040820152621e595d60ea1b606082015260800190565b602080825260139082015272546f6f206c6974746c6520746f206d6572676560681b604082015260600190565b6020808252600f908201526e105b1c9958591e481cd95d1d1b1959608a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601e908201527f457863656564206d617820726564656d7074696f6e2066656520726174650000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b60208082526025908201527f47756172646564206c61756e63683a2065786365656420696e6469766964756160408201526406c206361760dc1b606082015260800190565b6020808252600b908201526a5a65726f2073686172657360a81b604082015260600190565b600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b90815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b918252602082015260400190565b9283526020830191909152604082015260600190565b60005b838110156128e15781810151838201526020016128c9565b83811115611e8d5750506000910152565b6001600160a01b038116811461290757600080fd5b5056fea2646970667358221220ea255da2b13ac8496cc97d5c3f5641d8a0d1ea12debd56fbe7a8bd48f31ea50564736f6c634300060c0033000000000000000000000000d6b3b86209ebb3c608f3f42bf52818169944e4020000000000000000000000000000000000000000000000000000000060d48fe000000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000000001c6bf526340000000000000000000000000000000000000000000000000000001c6bf52634000000000000000000000000000000000000000000000000000002386f26fc10000

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000d6b3b86209ebb3c608f3f42bf52818169944e4020000000000000000000000000000000000000000000000000000000060d48fe000000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000000001c6bf526340000000000000000000000000000000000000000000000000000001c6bf52634000000000000000000000000000000000000000000000000000002386f26fc10000

-----Decoded View---------------
Arg [0] : fund_ (address): 0xd6b3b86209ebb3c608f3f42bf52818169944e402
Arg [1] : guardedLaunchStart_ (uint256): 1624543200
Arg [2] : redemptionFeeRate_ (uint256): 1000000000000000
Arg [3] : splitFeeRate_ (uint256): 500000000000000
Arg [4] : mergeFeeRate_ (uint256): 500000000000000
Arg [5] : minCreationUnderlying_ (uint256): 10000000000000000

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000d6b3b86209ebb3c608f3f42bf52818169944e402
Arg [1] : 0000000000000000000000000000000000000000000000000000000060d48fe0
Arg [2] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [3] : 0000000000000000000000000000000000000000000000000001c6bf52634000
Arg [4] : 0000000000000000000000000000000000000000000000000001c6bf52634000
Arg [5] : 000000000000000000000000000000000000000000000000002386f26fc10000


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.