ETH Price: $2,990.53 (+3.64%)
Gas: 6 Gwei

Contract

0xC87B0E99Cc0706097266410B6ce5F3Bd41275C53
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Redeem117720532021-02-01 18:50:441198 days ago1612205444IN
0xC87B0E99...d41275C53
0 ETH0.22094799159
Redeem117296522021-01-26 6:16:221205 days ago1611641782IN
0xC87B0E99...d41275C53
0 ETH0.0766589454
Redeem117010182021-01-21 20:38:231209 days ago1611261503IN
0xC87B0E99...d41275C53
0 ETH0.0786581656
Redeem116978072021-01-21 8:54:171210 days ago1611219257IN
0xC87B0E99...d41275C53
0 ETH0.0971528670
Redeem116917292021-01-20 10:27:371211 days ago1611138457IN
0xC87B0E99...d41275C53
0 ETH0.09733056109
Cancel Request F...116845442021-01-19 8:06:121212 days ago1611043572IN
0xC87B0E99...d41275C53
0.00082443 ETH0.0129058484
Request Investme...116747142021-01-17 19:50:571213 days ago1610913057IN
0xC87B0E99...d41275C53
0.01100371 ETH0.0152476856
Cancel Request F...116585362021-01-15 8:14:361216 days ago1610698476IN
0xC87B0E99...d41275C53
0.00075339 ETH0.0084502555
Request Investme...116498132021-01-13 23:44:001217 days ago1610581440IN
0xC87B0E99...d41275C53
0.01115389 ETH0.0097766438
Execute Request ...116304712021-01-11 0:52:571220 days ago1610326377IN
0xC87B0E99...d41275C53
0.00404442 ETH0.0822183766
Execute Request ...116263282021-01-10 9:42:021221 days ago1610271722IN
0xC87B0E99...d41275C53
0.0041461 ETH0.061051149
Request Investme...116247212021-01-10 3:49:591221 days ago1610250599IN
0xC87B0E99...d41275C53
0.01090459 ETH0.0204791275
Request Investme...116217022021-01-09 16:41:451222 days ago1610210505IN
0xC87B0E99...d41275C53
0.01089006 ETH0.0228715284
Cancel Request F...115937312021-01-05 9:31:531226 days ago1609839113IN
0xC87B0E99...d41275C53
0.00076263 ETH0.0142886193
Request Investme...115228472020-12-25 12:40:151237 days ago1608900015IN
0xC87B0E99...d41275C53
0.01153475 ETH0.0162086463
Cancel Request F...115105012020-12-23 15:01:101239 days ago1608735670IN
0xC87B0E99...d41275C53
0.00132613 ETH0.01751507114
Request Investme...114974362020-12-21 14:56:321241 days ago1608562592IN
0xC87B0E99...d41275C53
0.01168715 ETH0.021868885
Cancel Request F...114404842020-12-12 21:13:031249 days ago1607807583IN
0xC87B0E99...d41275C53
0.00138431 ETH0.004148327
Cancel Request F...114361882020-12-12 5:29:561250 days ago1607750996IN
0xC87B0E99...d41275C53
0.00129357 ETH0.0032264621
Request Investme...114176442020-12-09 8:41:271253 days ago1607503287IN
0xC87B0E99...d41275C53
0.01165942 ETH0.0250497692
Request Investme...113968492020-12-06 3:59:231256 days ago1607227163IN
0xC87B0E99...d41275C53
0.0115044 ETH0.0038849215.1
Execute Request ...112443792020-11-12 18:21:211279 days ago1605205281IN
0xC87B0E99...d41275C53
0.00666821 ETH0.0201169817
Request Investme...112435402020-11-12 15:17:561280 days ago1605194276IN
0xC87B0E99...d41275C53
0.01154359 ETH0.0135015947
Execute Request ...111439372020-10-28 8:04:431295 days ago1603872283IN
0xC87B0E99...d41275C53
0.00895351 ETH0.0453938736
Request Investme...111387762020-10-27 13:02:101296 days ago1603803730IN
0xC87B0E99...d41275C53
0.01190116 ETH0.009002735
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
116845442021-01-19 8:06:121212 days ago1611043572
0xC87B0E99...d41275C53
0.00052833 ETH
116845442021-01-19 8:06:121212 days ago1611043572
0xC87B0E99...d41275C53
0.00029609 ETH
116845442021-01-19 8:06:121212 days ago1611043572
0xC87B0E99...d41275C53
0.01 ETH
116747142021-01-17 19:50:571213 days ago1610913057
0xC87B0E99...d41275C53
0.00055497 ETH
116747142021-01-17 19:50:571213 days ago1610913057
0xC87B0E99...d41275C53
0.00044873 ETH
116585362021-01-15 8:14:361216 days ago1610698476
0xC87B0E99...d41275C53
0.0004828 ETH
116585362021-01-15 8:14:361216 days ago1610698476
0xC87B0E99...d41275C53
0.00027058 ETH
116585362021-01-15 8:14:361216 days ago1610698476
0xC87B0E99...d41275C53
0.01 ETH
116498132021-01-13 23:44:001217 days ago1610581440
0xC87B0E99...d41275C53
0.00063801 ETH
116498132021-01-13 23:44:001217 days ago1610581440
0xC87B0E99...d41275C53
0.00051587 ETH
116304712021-01-11 0:52:571220 days ago1610326377
0xC87B0E99...d41275C53
0.00076285 ETH
116304712021-01-11 0:52:571220 days ago1610326377
0xC87B0E99...d41275C53
0.00328156 ETH
116304712021-01-11 0:52:571220 days ago1610326377
0xC87B0E99...d41275C53
0.01 ETH
116263282021-01-10 9:42:021221 days ago1610271722
0xC87B0E99...d41275C53
0.00078197 ETH
116263282021-01-10 9:42:021221 days ago1610271722
0xC87B0E99...d41275C53
0.00336413 ETH
116263282021-01-10 9:42:021221 days ago1610271722
0xC87B0E99...d41275C53
0.01 ETH
116247212021-01-10 3:49:591221 days ago1610250599
0xC87B0E99...d41275C53
0.00049908 ETH
116247212021-01-10 3:49:591221 days ago1610250599
0xC87B0E99...d41275C53
0.0004055 ETH
116217022021-01-09 16:41:451222 days ago1610210505
0xC87B0E99...d41275C53
0.00049213 ETH
116217022021-01-09 16:41:451222 days ago1610210505
0xC87B0E99...d41275C53
0.00039792 ETH
115937312021-01-05 9:31:531226 days ago1609839113
0xC87B0E99...d41275C53
0.00048872 ETH
115937312021-01-05 9:31:531226 days ago1609839113
0xC87B0E99...d41275C53
0.0002739 ETH
115937312021-01-05 9:31:531226 days ago1609839113
0xC87B0E99...d41275C53
0.01 ETH
115228472020-12-25 12:40:151237 days ago1608900015
0xC87B0E99...d41275C53
0.0008486 ETH
115228472020-12-25 12:40:151237 days ago1608900015
0xC87B0E99...d41275C53
0.00068614 ETH
View All Internal Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x0F74ce61...A84f00286
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Participation

Compiler Version
v0.6.1+commit.e6f7d5a4

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion, None license
File 1 of 25 : Participation.sol
pragma solidity 0.6.1;

import "../vault/Vault.sol";
import "../shares/Shares.sol";
import "../policies/PolicyManager.sol";
import "../hub/Spoke.sol";
import "../accounting/Accounting.sol";
import "../../prices/IPriceSource.sol";
import "../../factory/Factory.sol";
import "../../engine/AmguConsumer.sol";
import "../../dependencies/token/IERC20.sol";
import "../../dependencies/DSMath.sol";
import "../../dependencies/TokenUser.sol";

/// @notice Entry and exit point for investors
contract Participation is TokenUser, AmguConsumer, Spoke {
    event EnableInvestment (address[] asset);
    event DisableInvestment (address[] assets);

    event InvestmentRequest (
        address indexed requestOwner,
        address indexed investmentAsset,
        uint requestedShares,
        uint investmentAmount
    );

    event RequestExecution (
        address indexed requestOwner,
        address indexed executor,
        address indexed investmentAsset,
        uint investmentAmount,
        uint requestedShares
    );

    event CancelRequest (
        address indexed requestOwner
    );

    event Redemption (
        address indexed redeemer,
        address[] assets,
        uint[] assetQuantities,
        uint redeemedShares
    );

    struct Request {
        address investmentAsset;
        uint investmentAmount;
        uint requestedShares;
        uint timestamp;
    }

    uint constant public SHARES_DECIMALS = 18;
    uint constant public REQUEST_LIFESPAN = 1 days;

    mapping (address => Request) public requests;
    mapping (address => bool) public investAllowed;
    mapping (address => bool) public hasInvested; // for information purposes only (read)

    address[] public historicalInvestors; // for information purposes only (read)

    constructor(address _hub, address[] memory _defaultAssets, address _registry)
        public
        Spoke(_hub)
    {
        routes.registry = _registry;
        _enableInvestment(_defaultAssets);
    }

    receive() external payable {}

    function _enableInvestment(address[] memory _assets) internal {
        for (uint i = 0; i < _assets.length; i++) {
            require(
                Registry(routes.registry).assetIsRegistered(_assets[i]),
                "Asset not registered"
            );
            investAllowed[_assets[i]] = true;
        }
        emit EnableInvestment(_assets);
    }

    function enableInvestment(address[] calldata _assets) external auth {
        _enableInvestment(_assets);
    }

    function disableInvestment(address[] calldata _assets) external auth {
        for (uint i = 0; i < _assets.length; i++) {
            investAllowed[_assets[i]] = false;
        }
        emit DisableInvestment(_assets);
    }

    function hasRequest(address _who) public view returns (bool) {
        return requests[_who].timestamp > 0;
    }

    function hasExpiredRequest(address _who) public view returns (bool) {
        return block.timestamp > add(requests[_who].timestamp, REQUEST_LIFESPAN);
    }

    /// @notice Whether request is OK and invest delay is being respected
    /// @dev Request valid if price update happened since request and not expired
    /// @dev If no shares exist and not expired, request can be executed immediately
    function hasValidRequest(address _who) public view returns (bool) {
        IPriceSource priceSource = IPriceSource(priceSource());
        bool delayRespectedOrNoShares = requests[_who].timestamp < priceSource.getLastUpdate() ||
            Shares(routes.shares).totalSupply() == 0;

        return hasRequest(_who) &&
            delayRespectedOrNoShares &&
            !hasExpiredRequest(_who) &&
            requests[_who].investmentAmount > 0 &&
            requests[_who].requestedShares > 0;
    }

    function requestInvestment(
        uint requestedShares,
        uint investmentAmount,
        address investmentAsset
    )
        external
        notShutDown
        payable
        amguPayable(true)
        onlyInitialized
    {
        PolicyManager(routes.policyManager).preValidate(
            msg.sig,
            [msg.sender, address(0), address(0), investmentAsset, address(0)],
            [uint(0), uint(0), uint(0)],
            bytes32(0)
        );
        require(
            investAllowed[investmentAsset],
            "Investment not allowed in this asset"
        );
        safeTransferFrom(
            investmentAsset, msg.sender, address(this), investmentAmount
        );
        require(
            requests[msg.sender].timestamp == 0,
            "Only one request can exist at a time"
        );
        requests[msg.sender] = Request({
            investmentAsset: investmentAsset,
            investmentAmount: investmentAmount,
            requestedShares: requestedShares,
            timestamp: block.timestamp
        });
        PolicyManager(routes.policyManager).postValidate(
            msg.sig,
            [msg.sender, address(0), address(0), investmentAsset, address(0)],
            [uint(0), uint(0), uint(0)],
            bytes32(0)
        );

        emit InvestmentRequest(
            msg.sender,
            investmentAsset,
            requestedShares,
            investmentAmount
        );
    }

    function _cancelRequestFor(address requestOwner) internal {
        require(hasRequest(requestOwner), "No request to cancel");
        IPriceSource priceSource = IPriceSource(priceSource());
        Request memory request = requests[requestOwner];
        require(
            !priceSource.hasValidPrice(request.investmentAsset) ||
            hasExpiredRequest(requestOwner) ||
            hub.isShutDown(),
            "No cancellation condition was met"
        );
        IERC20 investmentAsset = IERC20(request.investmentAsset);
        uint investmentAmount = request.investmentAmount;
        delete requests[requestOwner];
        msg.sender.transfer(Registry(routes.registry).incentive());
        safeTransfer(address(investmentAsset), requestOwner, investmentAmount);

        emit CancelRequest(requestOwner);
    }

    /// @notice Can only cancel when no price, request expired or fund shut down
    /// @dev Only request owner can cancel their request
    function cancelRequest() external payable amguPayable(false) {
        _cancelRequestFor(msg.sender);
    }

    function cancelRequestFor(address requestOwner)
        external
        payable
        amguPayable(false)
    {
        _cancelRequestFor(requestOwner);
    }

    function executeRequestFor(address requestOwner)
        external
        notShutDown
        amguPayable(false)
        payable
    {
        Request memory request = requests[requestOwner];
        require(
            hasValidRequest(requestOwner),
            "No valid request for this address"
        );

        FeeManager(routes.feeManager).rewardManagementFee();

        uint totalShareCostInInvestmentAsset = Accounting(routes.accounting)
            .getShareCostInAsset(
                request.requestedShares,
                request.investmentAsset
            );

        require(
            totalShareCostInInvestmentAsset <= request.investmentAmount,
            "Invested amount too low"
        );
        // send necessary amount of investmentAsset to vault
        safeTransfer(
            request.investmentAsset,
            routes.vault,
            totalShareCostInInvestmentAsset
        );

        uint investmentAssetChange = sub(
            request.investmentAmount,
            totalShareCostInInvestmentAsset
        );

        // return investmentAsset change to request owner
        if (investmentAssetChange > 0) {
            safeTransfer(
                request.investmentAsset,
                requestOwner,
                investmentAssetChange
            );
        }

        msg.sender.transfer(Registry(routes.registry).incentive());

        Shares(routes.shares).createFor(requestOwner, request.requestedShares);
        Accounting(routes.accounting).addAssetToOwnedAssets(request.investmentAsset);

        if (!hasInvested[requestOwner]) {
            hasInvested[requestOwner] = true;
            historicalInvestors.push(requestOwner);
        }

        emit RequestExecution(
            requestOwner,
            msg.sender,
            request.investmentAsset,
            request.investmentAmount,
            request.requestedShares
        );
        delete requests[requestOwner];
    }

    function getOwedPerformanceFees(uint shareQuantity)
        public
        returns (uint remainingShareQuantity)
    {
        Shares shares = Shares(routes.shares);

        uint totalPerformanceFee = FeeManager(routes.feeManager).performanceFeeAmount();
        // The denominator is augmented because performanceFeeAmount() accounts for inflation
        // Since shares are directly transferred, we don't need to account for inflation in this case
        uint performanceFeePortion = mul(
            totalPerformanceFee,
            shareQuantity
        ) / add(shares.totalSupply(), totalPerformanceFee);
        return performanceFeePortion;
    }

    /// @dev "Happy path" (no asset throws & quantity available)
    /// @notice Redeem all shares and across all assets
    function redeem() external {
        uint ownedShares = Shares(routes.shares).balanceOf(msg.sender);
        redeemQuantity(ownedShares);
    }

    /// @notice Redeem shareQuantity across all assets
    function redeemQuantity(uint shareQuantity) public {
        address[] memory assetList;
        assetList = Accounting(routes.accounting).getOwnedAssets();
        redeemWithConstraints(shareQuantity, assetList);
    }

    // TODO: reconsider the scenario where the user has enough funds to force shutdown on a large trade (any way around this?)
    /// @dev Redeem only selected assets (used only when an asset throws)
    function redeemWithConstraints(uint shareQuantity, address[] memory requestedAssets) public {
        Shares shares = Shares(routes.shares);
        require(
            shares.balanceOf(msg.sender) >= shareQuantity &&
            shares.balanceOf(msg.sender) > 0,
            "Sender does not have enough shares to fulfill request"
        );

        uint owedPerformanceFees = 0;
        if (
            IPriceSource(priceSource()).hasValidPrices(requestedAssets) &&
            msg.sender != hub.manager()
        ) {
            FeeManager(routes.feeManager).rewardManagementFee();
            owedPerformanceFees = getOwedPerformanceFees(shareQuantity);
            shares.destroyFor(msg.sender, owedPerformanceFees);
            shares.createFor(hub.manager(), owedPerformanceFees);
        }
        uint remainingShareQuantity = sub(shareQuantity, owedPerformanceFees);

        address ofAsset;
        uint[] memory ownershipQuantities = new uint[](requestedAssets.length);
        address[] memory redeemedAssets = new address[](requestedAssets.length);
        // Check whether enough assets held by fund
        Accounting accounting = Accounting(routes.accounting);
        for (uint i = 0; i < requestedAssets.length; ++i) {
            ofAsset = requestedAssets[i];
            require(
                accounting.isInAssetList(ofAsset),
                "Requested asset not in asset list"
            );
            for (uint j = 0; j < redeemedAssets.length; j++) {
                require(
                    ofAsset != redeemedAssets[j],
                    "Asset can only be redeemed once"
                );
            }
            redeemedAssets[i] = ofAsset;
            uint quantityHeld = accounting.assetHoldings(ofAsset);
            if (quantityHeld == 0) continue;

            // participant's ownership percentage of asset holdings
            ownershipQuantities[i] = mul(quantityHeld, remainingShareQuantity) / shares.totalSupply();
        }

        shares.destroyFor(msg.sender, remainingShareQuantity);

        // Transfer owned assets
        for (uint k = 0; k < requestedAssets.length; ++k) {
            ofAsset = requestedAssets[k];
            if (ownershipQuantities[k] == 0) {
                continue;
            } else {
                Vault(routes.vault).withdraw(ofAsset, ownershipQuantities[k]);
                safeTransfer(ofAsset, msg.sender, ownershipQuantities[k]);
            }
        }
        emit Redemption(
            msg.sender,
            requestedAssets,
            ownershipQuantities,
            remainingShareQuantity
        );
    }

    function getHistoricalInvestors() external view returns (address[] memory) {
        return historicalInvestors;
    }

    function engine() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.engine(); }
    function mlnToken() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.mlnToken(); }
    function priceSource() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.priceSource(); }
    function registry() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.registry(); }
}

contract ParticipationFactory is Factory {
    event NewInstance(
        address indexed hub,
        address indexed instance,
        address[] defaultAssets,
        address registry
    );

    function createInstance(address _hub, address[] calldata _defaultAssets, address _registry)
        external
        returns (address)
    {
        address participation = address(
            new Participation(_hub, _defaultAssets, _registry)
        );
        childExists[participation] = true;
        emit NewInstance(_hub, participation, _defaultAssets, _registry);
        return participation;
    }
}

File 3 of 25 : Vault.sol
pragma solidity 0.6.1;

import "../hub/Spoke.sol";
import "../../factory/Factory.sol";
import "../../dependencies/TokenUser.sol";

/// @notice Dumb custody component
contract Vault is TokenUser, Spoke {

    constructor(address _hub) public Spoke(_hub) {}

    function withdraw(address token, uint amount) external auth {
        safeTransfer(token, msg.sender, amount);
    }
}

contract VaultFactory is Factory {
    function createInstance(address _hub) external returns (address) {
        address vault = address(new Vault(_hub));
        childExists[vault] = true;
        emit NewInstance(_hub, vault);
        return vault;
    }
}

File 4 of 25 : Shares.sol
pragma solidity 0.6.1;

import "../hub/Spoke.sol";
import "../../dependencies/token/StandardToken.sol";
import "../../factory/Factory.sol";

contract Shares is Spoke, StandardToken {
    string public symbol;
    string public name;
    uint8 public decimals;

    constructor(address _hub) public Spoke(_hub) {
        name = hub.name();
        symbol = "MLNF";
        decimals = 18;
    }

    function createFor(address who, uint amount) public auth {
        _mint(who, amount);
    }

    function destroyFor(address who, uint amount) public auth {
        _burn(who, amount);
    }

    function transfer(address to, uint amount) public override returns (bool) {
        revert("Unimplemented");
    }

    function transferFrom(
        address from,
        address to,
        uint amount
    )
        public
        override
        returns (bool)
    {
        revert("Unimplemented");
    }

    function approve(address spender, uint amount) public override returns (bool) {
        revert("Unimplemented");
    }

    function increaseApproval(
        address spender,
        uint amount
    )
        public
        override
        returns (bool)
    {
        revert("Unimplemented");
    }

    function decreaseApproval(
        address spender,
        uint amount
    )
        public
        override
        returns (bool)
    {
        revert("Unimplemented");
    }
}

contract SharesFactory is Factory {
    function createInstance(address _hub) external returns (address) {
        address shares = address(new Shares(_hub));
        childExists[shares] = true;
        emit NewInstance(_hub, shares);
        return shares;
    }
}

File 5 of 25 : PolicyManager.sol
pragma solidity 0.6.1;

import "../../factory/Factory.sol";
import "../hub/Spoke.sol";
import "./IPolicy.sol";

contract PolicyManager is Spoke {

    event Registration(
        bytes4 indexed sig,
        IPolicy.Applied position,
        address indexed policy
    );

    struct Entry {
        IPolicy[] pre;
        IPolicy[] post;
    }

    mapping(bytes4 => Entry) policies;

    constructor (address _hub) public Spoke(_hub) {}

    function register(bytes4 sig, address _policy) public auth {
        IPolicy.Applied position = IPolicy(_policy).position();
        if (position == IPolicy.Applied.pre) {
            policies[sig].pre.push(IPolicy(_policy));
        } else if (position == IPolicy.Applied.post) {
            policies[sig].post.push(IPolicy(_policy));
        } else {
            revert("Only pre and post allowed");
        }
        emit Registration(sig, position, _policy);
    }

    function batchRegister(bytes4[] memory sig, address[] memory _policies) public auth {
        require(sig.length == _policies.length, "Arrays lengths unequal");
        for (uint i = 0; i < sig.length; i++) {
            register(sig[i], _policies[i]);
        }
    }

    function PoliciesToAddresses(IPolicy[] storage _policies) internal view returns (address[] memory) {
        address[] memory res = new address[](_policies.length);
        for(uint i = 0; i < _policies.length; i++) {
            res[i] = address(_policies[i]);
        }
        return res;
    }

    function getPoliciesBySig(bytes4 sig) public view returns (address[] memory, address[] memory) {
        return (PoliciesToAddresses(policies[sig].pre), PoliciesToAddresses(policies[sig].post));
    }

    modifier isValidPolicyBySig(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) {
        preValidate(sig, addresses, values, identifier);
        _;
        postValidate(sig, addresses, values, identifier);
    }

    modifier isValidPolicy(address[5] memory addresses, uint[3] memory values, bytes32 identifier) {
        preValidate(msg.sig, addresses, values, identifier);
        _;
        postValidate(msg.sig, addresses, values, identifier);
    }

    function preValidate(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) public {
        validate(policies[sig].pre, sig, addresses, values, identifier);
    }

    function postValidate(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) public {
        validate(policies[sig].post, sig, addresses, values, identifier);
    }

    function validate(IPolicy[] storage aux, bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) internal {
        for(uint i = 0; i < aux.length; i++) {
            require(
                aux[i].rule(sig, addresses, values, identifier),
                string(abi.encodePacked("Rule evaluated to false: ", aux[i].identifier()))
            );
        }
    }
}

contract PolicyManagerFactory is Factory {
    function createInstance(address _hub) external returns (address) {
        address policyManager = address(new PolicyManager(_hub));
        childExists[policyManager] = true;
        emit NewInstance(_hub, policyManager);
        return policyManager;
    }
}

File 6 of 25 : Spoke.sol
pragma solidity 0.6.1;

import "./Hub.sol";
import "../../dependencies/DSAuth.sol";

/// @notice Has one Hub
contract Spoke is DSAuth {
    Hub public hub;
    Hub.Routes public routes;
    bool public initialized;

    modifier onlyInitialized() {
        require(initialized, "Component not yet initialized");
        _;
    }

    modifier notShutDown() {
        require(!hub.isShutDown(), "Hub is shut down");
        _;
    }

    constructor(address _hub) public {
        hub = Hub(_hub);
        setAuthority(hub);
        setOwner(address(hub)); // temporary, to allow initialization
    }

    function initialize(address[11] calldata _spokes) external auth {
        require(msg.sender == address(hub));
        require(!initialized, "Already initialized");
        routes = Hub.Routes(
            _spokes[0],
            _spokes[1],
            _spokes[2],
            _spokes[3],
            _spokes[4],
            _spokes[5],
            _spokes[6],
            _spokes[7],
            _spokes[8],
            _spokes[9],
            _spokes[10]
        );
        initialized = true;
        setOwner(address(0));
    }

    function engine() public view virtual returns (address) { return routes.engine; }
    function mlnToken() public view virtual returns (address) { return routes.mlnToken; }
    function priceSource() public view virtual returns (address) { return hub.priceSource(); }
    function version() public view virtual returns (address) { return routes.version; }
    function registry() public view virtual returns (address) { return routes.registry; }
}

File 7 of 25 : Accounting.sol
pragma solidity 0.6.1;

import "../../dependencies/token/StandardToken.sol";
import "../../factory/Factory.sol";
import "../../prices/IPriceSource.sol";
import "../fees/FeeManager.sol";
import "../hub/Spoke.sol";
import "../shares/Shares.sol";
import "../trading/ITrading.sol";
import "../vault/Vault.sol";
import "../../engine/AmguConsumer.sol";

contract Accounting is AmguConsumer, Spoke {

    event AssetAddition(address indexed asset);
    event AssetRemoval(address indexed asset);

    struct Calculations {
        uint gav;
        uint nav;
        uint allocatedFees;
        uint totalSupply;
        uint timestamp;
    }

    uint constant public MAX_OWNED_ASSETS = 20;
    address[] public ownedAssets;
    mapping (address => bool) public isInAssetList;
    uint public constant SHARES_DECIMALS = 18;
    address public NATIVE_ASSET;
    address public DENOMINATION_ASSET;
    uint public DENOMINATION_ASSET_DECIMALS;
    uint public DEFAULT_SHARE_PRICE;
    Calculations public atLastAllocation;

    constructor(address _hub, address _denominationAsset, address _nativeAsset)
        public
        Spoke(_hub)
    {
        DENOMINATION_ASSET = _denominationAsset;
        NATIVE_ASSET = _nativeAsset;
        DENOMINATION_ASSET_DECIMALS = ERC20WithFields(DENOMINATION_ASSET).decimals();
        DEFAULT_SHARE_PRICE = 10 ** uint(DENOMINATION_ASSET_DECIMALS);
    }

    function getOwnedAssetsLength() external view returns (uint256) {
        return ownedAssets.length;
    }

    function getOwnedAssets() external view returns (address[] memory) {
        return ownedAssets;
    }

    function assetHoldings(address _asset) public returns (uint256) {
        return add(
            uint256(ERC20WithFields(_asset).balanceOf(routes.vault)),
            ITrading(routes.trading).updateAndGetQuantityBeingTraded(_asset)
        );
    }

    /// @dev Returns sparse array
    function getFundHoldings() external returns (uint[] memory, address[] memory) {
        uint[] memory _quantities = new uint[](ownedAssets.length);
        address[] memory _assets = new address[](ownedAssets.length);
        for (uint i = 0; i < ownedAssets.length; i++) {
            address ofAsset = ownedAssets[i];
            // assetHoldings formatting: mul(exchangeHoldings, 10 ** assetDecimal)
            uint quantityHeld = assetHoldings(ofAsset);
            _assets[i] = ofAsset;
            _quantities[i] = quantityHeld;
        }
        return (_quantities, _assets);
    }

    function calcAssetGAV(address _queryAsset) external returns (uint) {
        uint queryAssetQuantityHeld = assetHoldings(_queryAsset);
        return IPriceSource(priceSource()).convertQuantity(
            queryAssetQuantityHeld, _queryAsset, DENOMINATION_ASSET
        );
    }

    // prices are quoted in DENOMINATION_ASSET so they use denominationDecimals
    function calcGav() public returns (uint gav) {
        for (uint i = 0; i < ownedAssets.length; ++i) {
            address asset = ownedAssets[i];
            // assetHoldings formatting: mul(exchangeHoldings, 10 ** assetDecimals)
            uint quantityHeld = assetHoldings(asset);
            // Dont bother with the calculations if the balance of the asset is 0
            if (quantityHeld == 0) {
                continue;
            }
            // gav as sum of mul(assetHoldings, assetPrice) with formatting: mul(mul(exchangeHoldings, exchangePrice), 10 ** shareDecimals)
            gav = add(
                gav,
                IPriceSource(priceSource()).convertQuantity(
                    quantityHeld, asset, DENOMINATION_ASSET
                )
            );
        }
        return gav;
    }

    function calcNav(uint gav, uint unclaimedFeesInDenominationAsset) public pure returns (uint) {
        return sub(gav, unclaimedFeesInDenominationAsset);
    }

    function valuePerShare(uint totalValue, uint numShares) public pure returns (uint) {
        require(numShares > 0, "No shares to calculate value for");
        return (totalValue * 10 ** uint(SHARES_DECIMALS)) / numShares;
    }

    function performCalculations()
        public
        returns (
            uint gav,
            uint feesInDenominationAsset,  // unclaimed amount
            uint feesInShares,             // unclaimed amount
            uint nav,
            uint sharePrice,
            uint gavPerShareNetManagementFee
        )
    {
        gav = calcGav();
        uint totalSupply = Shares(routes.shares).totalSupply();
        feesInShares = FeeManager(routes.feeManager).totalFeeAmount();
        feesInDenominationAsset = (totalSupply == 0) ?
            0 :
            mul(feesInShares, gav) / add(totalSupply, feesInShares);
        nav = calcNav(gav, feesInDenominationAsset);

        // The total share supply including the value of feesInDenominationAsset, measured in shares of this fund
        uint totalSupplyAccountingForFees = add(totalSupply, feesInShares);
        sharePrice = (totalSupply > 0) ?
            valuePerShare(gav, totalSupplyAccountingForFees) :
            DEFAULT_SHARE_PRICE;
        gavPerShareNetManagementFee = (totalSupply > 0) ?
            valuePerShare(gav, add(totalSupply, FeeManager(routes.feeManager).managementFeeAmount())) :
            DEFAULT_SHARE_PRICE;
        return (gav, feesInDenominationAsset, feesInShares, nav, sharePrice, gavPerShareNetManagementFee);
    }

    function calcGavPerShareNetManagementFee()
        public
        returns (uint gavPerShareNetManagementFee)
    {
        (,,,,,gavPerShareNetManagementFee) = performCalculations();
        return gavPerShareNetManagementFee;
    }

    function getShareCostInAsset(uint _numShares, address _altAsset)
        external
        returns (uint)
    {
        uint denominationAssetQuantity = mul(
            _numShares,
            calcGavPerShareNetManagementFee()
        ) / 10 ** uint(SHARES_DECIMALS);
        return IPriceSource(priceSource()).convertQuantity(
            denominationAssetQuantity, DENOMINATION_ASSET, _altAsset
        );
    }

    /// @notice Reward all fees and perform some updates
    /// @dev Anyone can call this
    function triggerRewardAllFees()
        external
        amguPayable(false)
        payable
    {
        updateOwnedAssets();
        uint256 gav;
        uint256 feesInDenomination;
        uint256 feesInShares;
        uint256 nav;
        (gav, feesInDenomination, feesInShares, nav,,) = performCalculations();
        uint256 totalSupply = Shares(routes.shares).totalSupply();
        FeeManager(routes.feeManager).rewardAllFees();
        atLastAllocation = Calculations({
            gav: gav,
            nav: nav,
            allocatedFees: feesInDenomination,
            totalSupply: totalSupply,
            timestamp: block.timestamp
        });
    }

    /// @dev Check holdings for all assets, and adjust list
    function updateOwnedAssets() public {
        for (uint i = 0; i < ownedAssets.length; i++) {
            address asset = ownedAssets[i];
            if (
                assetHoldings(asset) == 0 &&
                !(asset == address(DENOMINATION_ASSET)) &&
                ITrading(routes.trading).getOpenMakeOrdersAgainstAsset(asset) == 0
            ) {
                _removeFromOwnedAssets(asset);
            }
        }
    }

    function addAssetToOwnedAssets(address _asset) external auth {
        _addAssetToOwnedAssets(_asset);
    }

    function removeFromOwnedAssets(address _asset) external auth {
        _removeFromOwnedAssets(_asset);
    }

    /// @dev Just pass if asset already in list
    function _addAssetToOwnedAssets(address _asset) internal {
        if (isInAssetList[_asset]) { return; }

        require(
            ownedAssets.length < MAX_OWNED_ASSETS,
            "Max owned asset limit reached"
        );
        isInAssetList[_asset] = true;
        ownedAssets.push(_asset);
        emit AssetAddition(_asset);
    }

    /// @dev Just pass if asset not in list
    function _removeFromOwnedAssets(address _asset) internal {
        if (!isInAssetList[_asset]) { return; }

        isInAssetList[_asset] = false;
        for (uint i; i < ownedAssets.length; i++) {
            if (ownedAssets[i] == _asset) {
                ownedAssets[i] = ownedAssets[ownedAssets.length - 1];
                ownedAssets.pop();
                break;
            }
        }
        emit AssetRemoval(_asset);
    }

    function engine() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.engine(); }
    function mlnToken() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.mlnToken(); }
    function priceSource() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.priceSource(); }
    function registry() public view override(AmguConsumer, Spoke) returns (address) { return Spoke.registry(); }
}

contract AccountingFactory is Factory {
    event NewInstance(
        address indexed hub,
        address indexed instance,
        address denominationAsset,
        address nativeAsset
    );

    function createInstance(address _hub, address _denominationAsset, address _nativeAsset) external returns (address) {
        address accounting = address(new Accounting(_hub, _denominationAsset, _nativeAsset));
        childExists[accounting] = true;
        emit NewInstance(_hub, accounting, _denominationAsset, _nativeAsset);
        return accounting;
    }
}

File 8 of 25 : IPriceSource.sol
pragma solidity 0.6.1;

/// @notice Must return a value for an asset
interface IPriceSource {
    function getQuoteAsset() external view returns (address);
    function getLastUpdate() external view returns (uint);

    /// @notice Returns false if asset not applicable, or price not recent
    function hasValidPrice(address) external view returns (bool);
    function hasValidPrices(address[] calldata) external view returns (bool);

    /// @notice Return the last known price, and when it was issued
    function getPrice(address _asset) external view returns (uint price, uint timestamp);
    function getPrices(address[] calldata _assets) external view returns (uint[] memory prices, uint[] memory timestamps);

    /// @notice Get price info, and revert if not valid
    function getPriceInfo(address _asset) external view returns (uint price, uint decimals);
    function getInvertedPriceInfo(address ofAsset) external view returns (uint price, uint decimals);

    function getReferencePriceInfo(address _base, address _quote) external view returns (uint referencePrice, uint decimal);
    function getOrderPriceInfo(address sellAsset, uint sellQuantity, uint buyQuantity) external view returns (uint orderPrice);
    function existsPriceOnAssetPair(address sellAsset, address buyAsset) external view returns (bool isExistent);
    function convertQuantity(
        uint fromAssetQuantity,
        address fromAsset,
        address toAsset
    ) external view returns (uint);
}

File 9 of 25 : Factory.sol
pragma solidity 0.6.1;


contract Factory {
    mapping (address => bool) public childExists;

    event NewInstance(
        address indexed hub,
        address indexed instance
    );

    function isInstance(address _child) public view returns (bool) {
        return childExists[_child];
    }
}

File 10 of 25 : AmguConsumer.sol
pragma solidity 0.6.1;

import "../dependencies/DSMath.sol";
import "../dependencies/token/IERC20.sol";
import "../prices/IPriceSource.sol";
import "../version/IVersion.sol";
import "./IEngine.sol";
import "../version/Registry.sol";

/// @notice Abstract contracts
/// @notice inherit this to pay AMGU on a function call
abstract contract AmguConsumer is DSMath {

    /// @dev each of these must be implemented by the inheriting contract
    function engine() public view virtual returns (address);
    function mlnToken() public view virtual returns (address);
    function priceSource() public view virtual returns (address);
    function registry() public view virtual returns (address);
    event AmguPaid(address indexed payer, uint256 totalAmguPaidInEth, uint256 amguChargableGas, uint256 incentivePaid);

    /// bool deductIncentive is used when sending extra eth beyond amgu
    modifier amguPayable(bool deductIncentive) {
        uint preGas = gasleft();
        _;
        uint postGas = gasleft();

        uint mlnPerAmgu = IEngine(engine()).getAmguPrice();
        uint mlnQuantity = mul(
            mlnPerAmgu,
            sub(preGas, postGas)
        );
        address nativeAsset = Registry(registry()).nativeAsset();
        uint ethToPay = IPriceSource(priceSource()).convertQuantity(
            mlnQuantity,
            mlnToken(),
            nativeAsset
        );
        uint incentiveAmount;
        if (deductIncentive) {
            incentiveAmount = Registry(registry()).incentive();
        } else {
            incentiveAmount = 0;
        }
        require(
            msg.value >= add(ethToPay, incentiveAmount),
            "Insufficent AMGU and/or incentive"
        );
        IEngine(engine()).payAmguInEther.value(ethToPay)();

        require(
            msg.sender.send(
                sub(
                    sub(msg.value, ethToPay),
                    incentiveAmount
                )
            ),
            "Refund failed"
        );
        emit AmguPaid(msg.sender, ethToPay, sub(preGas, postGas), incentiveAmount);
    }
}

File 11 of 25 : IERC20.sol
pragma solidity 0.6.1;

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 * Altered from https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a466e76d26c394b1faa6e2797aefe34668566392/contracts/token/ERC20/ERC20.sol
 */
interface IERC20 {
  function totalSupply() external view returns (uint256);

  function balanceOf(address _who) external view returns (uint256);

  function allowance(address _owner, address _spender)
    external view returns (uint256);

  function transfer(address _to, uint256 _value) external returns (bool);

  function approve(address _spender, uint256 _value) external returns (bool);

  function transferFrom(address _from, address _to, uint256 _value) external returns (bool);

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 value
  );

  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

/// @dev Just adds extra functions that we use elsewhere
abstract contract ERC20WithFields is IERC20 {
    string public symbol;
    string public name;
    uint8 public decimals;
}

File 12 of 25 : DSMath.sol
/// DSMath.sol -- mixin for inline numerical wizardry

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >0.4.13;

contract DSMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, "ds-math-sub-underflow");
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }
    function max(uint x, uint y) internal pure returns (uint z) {
        return x >= y ? x : y;
    }
    function imin(int x, int y) internal pure returns (int z) {
        return x <= y ? x : y;
    }
    function imax(int x, int y) internal pure returns (int z) {
        return x >= y ? x : y;
    }

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    function wmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }
    function rmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }
    function wdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint x, uint n) internal pure returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}

File 13 of 25 : TokenUser.sol
pragma solidity 0.6.1;

import "./token/IERC20.sol";
import "./DSMath.sol";

/// @notice Wrapper to ensure tokens are received
contract TokenUser is DSMath {
    function safeTransfer(
        address _token,
        address _to,
        uint _value
    ) internal {
        uint receiverPreBalance = IERC20(_token).balanceOf(_to);
        IERC20(_token).transfer(_to, _value);
        uint receiverPostBalance = IERC20(_token).balanceOf(_to);
        require(
            add(receiverPreBalance, _value) == receiverPostBalance,
            "Receiver did not receive tokens in transfer"
        );
    }

    function safeTransferFrom(
        address _token,
        address _from,
        address _to,
        uint _value
    ) internal {
        uint receiverPreBalance = IERC20(_token).balanceOf(_to);
        IERC20(_token).transferFrom(_from, _to, _value);
        uint receiverPostBalance = IERC20(_token).balanceOf(_to);
        require(
            add(receiverPreBalance, _value) == receiverPostBalance,
            "Receiver did not receive tokens in transferFrom"
        );
    }
}

File 14 of 25 : StandardToken.sol
pragma solidity 0.6.1;

import "./IERC20.sol";
import "../SafeMath.sol";

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 * Modified from https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a466e76d26c394b1faa6e2797aefe34668566392/contracts/token/ERC20/StandardToken.sol
 */
contract StandardToken is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) balances;

    mapping (address => mapping (address => uint256)) allowed;

    uint256 totalSupply_;

    /**
     * @dev Total number of tokens in existence
     */
    function totalSupply() public view override returns (uint256) {
        return totalSupply_;
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param _owner The address to query the the balance of.
     * @return An uint256 representing the amount owned by the passed address.
     */
    function balanceOf(address _owner) public view override returns (uint256) {
        return balances[_owner];
    }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param _owner address The address which owns the funds.
     * @param _spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(
        address _owner,
        address _spender
    )
        public
        view
        override
        returns (uint256)
    {
        return allowed[_owner][_spender];
    }

    /**
    * @dev Transfer token for a specified address
    * @param _to The address to transfer to.
    * @param _value The amount to be transferred.
    */
    function transfer(address _to, uint256 _value) public virtual override returns (bool) {
        require(_value <= balances[msg.sender]);
        require(_to != address(0));

        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    /**
    * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
    * 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
    * @param _spender The address which will spend the funds.
        * @param _value The amount of tokens to be spent.
        */
    function approve(address _spender, uint256 _value) public virtual override returns (bool) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
    * @dev Transfer tokens from one address to another
    * @param _from address The address which you want to send tokens from
    * @param _to address The address which you want to transfer to
    * @param _value uint256 the amount of tokens to be transferred
    */
    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    )
        public
        virtual
        override
        returns (bool)
    {
        require(_value <= balances[_from]);
        require(_value <= allowed[_from][msg.sender]);
        require(_to != address(0));

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        emit Approval(_from, msg.sender, allowed[_from][msg.sender]);
        emit Transfer(_from, _to, _value);
        return true;
    }

    /**
    * @dev Increase the amount of tokens that an owner allowed to a spender.
    * approve should be called when allowed[_spender] == 0. To increment
    * allowed value is better to use this function to avoid 2 calls (and wait until
    * the first transaction is mined)
    * From MonolithDAO Token.sol
    * @param _spender The address which will spend the funds.
    * @param _addedValue The amount of tokens to increase the allowance by.
    */
    function increaseApproval(
        address _spender,
        uint256 _addedValue
    )
        public
        virtual
        returns (bool)
    {
        allowed[msg.sender][_spender] = (allowed[msg.sender][_spender].add(_addedValue));
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * @param _spender The address which will spend the funds.
     * @param _subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseApproval(
        address _spender,
        uint256 _subtractedValue
    )
        public
        virtual
        returns (bool)
    {
        uint256 oldValue = allowed[msg.sender][_spender];
        if (_subtractedValue >= oldValue) {
            allowed[msg.sender][_spender] = 0;
        } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
        }
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /**
    * @dev Internal function that mints an amount of the token and assigns it to
    * an account. This encapsulates the modification of balances such that the
    * proper events are emitted.
    * @param _account The account that will receive the created tokens.
    * @param _amount The amount that will be created.
     */
    function _mint(address _account, uint256 _amount) internal {
        require(_account != address(0));
        totalSupply_ = totalSupply_.add(_amount);
        balances[_account] = balances[_account].add(_amount);
        emit Transfer(address(0), _account, _amount);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account.
     * @param _account The account whose tokens will be burnt.
     * @param _amount The amount that will be burnt.
     */
    function _burn(address _account, uint256 _amount) internal {
        require(_account != address(0));
        require(_amount <= balances[_account]);

        totalSupply_ = totalSupply_.sub(_amount);
        balances[_account] = balances[_account].sub(_amount);
        emit Transfer(_account, address(0), _amount);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account, deducting from the sender's allowance for said account. Uses the
     * internal _burn function.
     * @param _account The account whose tokens will be burnt.
     * @param _amount The amount that will be burnt.
     */
    function _burnFrom(address _account, uint256 _amount) internal {
        require(_amount <= allowed[_account][msg.sender]);
        allowed[_account][msg.sender] = allowed[_account][msg.sender].sub(_amount);
        emit Approval(_account, msg.sender, allowed[_account][msg.sender]);
        _burn(_account, _amount);
    }
}

File 15 of 25 : IPolicy.sol
pragma solidity 0.6.1;

interface IPolicy {
    enum Applied { pre, post }

    // In Trading context:
    // addresses: Order maker, Order taker, Order maker asset, Order taker asset, Exchange address
    // values: Maker token quantity, Taker token quantity, Fill Taker Quantity

    // In Participation context:
    // address[0]: Investor address, address[3]: Investment asset
    function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool);

    function position() external view returns (Applied);
    function identifier() external view returns (string memory);
}

File 16 of 25 : Hub.sol
pragma solidity 0.6.1;

import "../../dependencies/DSGuard.sol";
import "./Spoke.sol";
import "../../version/Registry.sol";

/// @notice Router for communication between components
/// @notice Has one or more Spokes
contract Hub is DSGuard {

    event FundShutDown();

    struct Routes {
        address accounting;
        address feeManager;
        address participation;
        address policyManager;
        address shares;
        address trading;
        address vault;
        address registry;
        address version;
        address engine;
        address mlnToken;
    }

    Routes public routes;
    address public manager;
    address public creator;
    string public name;
    bool public isShutDown;
    bool public fundInitialized;
    uint public creationTime;
    mapping (address => bool) public isSpoke;

    constructor(address _manager, string memory _name) public {
        creator = msg.sender;
        manager = _manager;
        name = _name;
        creationTime = block.timestamp;
    }

    modifier onlyCreator() {
        require(msg.sender == creator, "Only creator can do this");
        _;
    }

    function shutDownFund() external {
        require(msg.sender == routes.version);
        isShutDown = true;
        emit FundShutDown();
    }

    function initializeAndSetPermissions(address[11] calldata _spokes) external onlyCreator {
        require(!fundInitialized, "Fund is already initialized");
        for (uint i = 0; i < _spokes.length; i++) {
            isSpoke[_spokes[i]] = true;
        }
        routes.accounting = _spokes[0];
        routes.feeManager = _spokes[1];
        routes.participation = _spokes[2];
        routes.policyManager = _spokes[3];
        routes.shares = _spokes[4];
        routes.trading = _spokes[5];
        routes.vault = _spokes[6];
        routes.registry = _spokes[7];
        routes.version = _spokes[8];
        routes.engine = _spokes[9];
        routes.mlnToken = _spokes[10];

        Spoke(routes.accounting).initialize(_spokes);
        Spoke(routes.feeManager).initialize(_spokes);
        Spoke(routes.participation).initialize(_spokes);
        Spoke(routes.policyManager).initialize(_spokes);
        Spoke(routes.shares).initialize(_spokes);
        Spoke(routes.trading).initialize(_spokes);
        Spoke(routes.vault).initialize(_spokes);

        permit(routes.participation, routes.vault, bytes4(keccak256('withdraw(address,uint256)')));
        permit(routes.trading, routes.vault, bytes4(keccak256('withdraw(address,uint256)')));
        permit(routes.participation, routes.shares, bytes4(keccak256('createFor(address,uint256)')));
        permit(routes.participation, routes.shares, bytes4(keccak256('destroyFor(address,uint256)')));
        permit(routes.feeManager, routes.shares, bytes4(keccak256('createFor(address,uint256)')));
        permit(routes.participation, routes.accounting, bytes4(keccak256('addAssetToOwnedAssets(address)')));
        permit(routes.trading, routes.accounting, bytes4(keccak256('addAssetToOwnedAssets(address)')));
        permit(routes.trading, routes.accounting, bytes4(keccak256('removeFromOwnedAssets(address)')));
        permit(routes.accounting, routes.feeManager, bytes4(keccak256('rewardAllFees()')));
        permit(manager, routes.policyManager, bytes4(keccak256('register(bytes4,address)')));
        permit(manager, routes.policyManager, bytes4(keccak256('batchRegister(bytes4[],address[])')));
        permit(manager, routes.participation, bytes4(keccak256('enableInvestment(address[])')));
        permit(manager, routes.participation, bytes4(keccak256('disableInvestment(address[])')));
        permit(manager, routes.trading, bytes4(keccak256('addExchange(address,address)')));
        fundInitialized = true;
    }

    function vault() external view returns (address) { return routes.vault; }
    function accounting() external view returns (address) { return routes.accounting; }
    function priceSource() external view returns (address) { return Registry(routes.registry).priceSource(); }
    function participation() external view returns (address) { return routes.participation; }
    function trading() external view returns (address) { return routes.trading; }
    function shares() external view returns (address) { return routes.shares; }
    function registry() external view returns (address) { return routes.registry; }
    function version() external view returns (address) { return routes.version; }
    function policyManager() external view returns (address) { return routes.policyManager; }
}

File 17 of 25 : DSAuth.sol
/// @notice Modified from DappHub (https://git.io/fpwrq)

pragma solidity 0.6.1;

abstract contract DSAuthority {
    function canCall(
        address src, address dst, bytes4 sig
    ) public view virtual returns (bool);
}

contract DSAuthEvents {
    event LogSetAuthority (address indexed authority);
    event LogSetOwner     (address indexed owner);
}

contract DSAuth is DSAuthEvents {
    DSAuthority  public  authority;
    address      public  owner;

    constructor() public {
        owner = msg.sender;
        emit LogSetOwner(msg.sender);
    }

    function setOwner(address owner_)
        public
        auth
    {
        owner = owner_;
        emit LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_)
        public
        auth
    {
        authority = authority_;
        emit LogSetAuthority(address(authority));
    }

    modifier auth {
        require(isAuthorized(msg.sender, msg.sig), "ds-auth-unauthorized");
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(0)) {
            return false;
        } else {
            return authority.canCall(src, address(this), sig);
        }
    }
}

File 18 of 25 : FeeManager.sol
pragma solidity 0.6.1;
pragma experimental ABIEncoderV2;

import "./IFee.sol";
import "../hub/Spoke.sol";
import "../shares/Shares.sol";
import "../../factory/Factory.sol";
import "../../version/Registry.sol";
import "../../dependencies/DSMath.sol";
import "./IFeeManager.sol";

/// @notice Manages and allocates fees for a particular fund
contract FeeManager is DSMath, Spoke {

    event FeeReward(uint shareQuantity);
    event FeeRegistration(address fee);

    struct FeeInfo {
        address feeAddress;
        uint feeRate;
        uint feePeriod;
    }

    IFee[] public fees;
    mapping (address => bool) public feeIsRegistered;

    constructor(address _hub, address _denominationAsset, address[] memory _fees, uint[] memory _rates, uint[] memory _periods, address _registry) Spoke(_hub) public {
        for (uint i = 0; i < _fees.length; i++) {
            require(
                Registry(_registry).isFeeRegistered(_fees[i]),
                "Fee must be known to Registry"
            );
            register(_fees[i], _rates[i], _periods[i], _denominationAsset);
        }
        if (fees.length > 0) {
            require(
                fees[0].identifier() == 0,
                "Management fee must be at 0 index"
            );
        }
        if (fees.length > 1) {
            require(
                fees[1].identifier() == 1,
                "Performance fee must be at 1 index"
            );
        }
    }

    function register(address feeAddress, uint feeRate, uint feePeriod, address denominationAsset) internal {
        require(!feeIsRegistered[feeAddress], "Fee already registered");
        feeIsRegistered[feeAddress] = true;
        fees.push(IFee(feeAddress));
        IFee(feeAddress).initializeForUser(feeRate, feePeriod, denominationAsset);  // initialize state
        emit FeeRegistration(feeAddress);
    }

    function totalFeeAmount() external returns (uint total) {
        for (uint i = 0; i < fees.length; i++) {
            total = add(total, fees[i].feeAmount());
        }
        return total;
    }

    /// @dev Shares to be inflated after update state
    function _rewardFee(IFee fee) internal {
        require(feeIsRegistered[address(fee)], "Fee is not registered");
        uint rewardShares = fee.feeAmount();
        fee.updateState();
        Shares(routes.shares).createFor(hub.manager(), rewardShares);
        emit FeeReward(rewardShares);
    }

    function _rewardAllFees() internal {
        for (uint i = 0; i < fees.length; i++) {
            _rewardFee(fees[i]);
        }
    }

    /// @dev Used when calling from other components
    function rewardAllFees() public auth { _rewardAllFees(); }

    /// @dev Convenience function; anyone can reward management fee any time
    /// @dev Convention that management fee is 0
    function rewardManagementFee() public {
        if (fees.length >= 1) _rewardFee(fees[0]);
    }

    /// @dev Convenience function
    /// @dev Convention that management fee is 0
    function managementFeeAmount() external returns (uint) {
        if (fees.length < 1) return 0;
        return fees[0].feeAmount();
    }

    /// @dev Convenience function
    /// @dev Convention that performace fee is 1
    function performanceFeeAmount() external returns (uint) {
        if (fees.length < 2) return 0;
        return fees[1].feeAmount();
    }
}

contract FeeManagerFactory is Factory {
    function createInstance(
        address _hub,
        address _denominationAsset,
        address[] memory _fees,
        uint[] memory _feeRates,
        uint[] memory _feePeriods,
        address _registry
    ) public returns (address) {
        address feeManager = address(
            new FeeManager(_hub, _denominationAsset, _fees, _feeRates, _feePeriods, _registry)
        );
        childExists[feeManager] = true;
        emit NewInstance(_hub, feeManager);
        return feeManager;
    }
}

File 19 of 25 : ITrading.sol
pragma solidity 0.6.1;

pragma experimental ABIEncoderV2;

// TODO: Restore indexed params

/// @notice Mediation between a Fund and exchanges
interface ITrading {
    function callOnExchange(
        uint exchangeIndex,
        string calldata methodSignature,
        address[8] calldata orderAddresses,
        uint[8] calldata orderValues,
        bytes[4] calldata orderData,
        bytes32 identifier,
        bytes calldata signature
    ) external;

    function addOpenMakeOrder(
        address ofExchange,
        address ofSellAsset,
        address ofBuyAsset,
        address ofFeeAsset,
        uint orderId,
        uint expiryTime
    ) external;

    function removeOpenMakeOrder(
        address ofExchange,
        address ofSellAsset
    ) external;

    function updateAndGetQuantityBeingTraded(address _asset) external returns (uint256);
    function getOpenMakeOrdersAgainstAsset(address _asset) external view returns (uint256);
}

interface ITradingFactory {
     function createInstance(
        address _hub,
        address[] calldata _exchanges,
        address[] calldata _adapters,
        address _registry
    ) external returns (address);
}

File 20 of 25 : IVersion.sol
pragma solidity 0.6.1;

interface IVersion {
    function shutDownFund(address) external;
}

File 21 of 25 : IEngine.sol
pragma solidity 0.6.1;


interface IEngine {
    function payAmguInEther() external payable;
    function getAmguPrice() external view returns (uint256);
}

File 22 of 25 : Registry.sol
pragma solidity 0.6.1;

import "../dependencies/DSAuth.sol";
import "../fund/hub/Hub.sol";
import "../dependencies/token/IERC20.sol";

contract Registry is DSAuth {

    // EVENTS
    event AssetUpsert (
        address indexed asset,
        string name,
        string symbol,
        uint decimals,
        string url,
        uint reserveMin,
        uint[] standards,
        bytes4[] sigs
    );

    event ExchangeAdapterUpsert (
        address indexed exchange,
        address indexed adapter,
        bool takesCustody,
        bytes4[] sigs
    );

    event AssetRemoval (address indexed asset);
    event EfxWrapperRegistryChange(address indexed registry);
    event EngineChange(address indexed engine);
    event ExchangeAdapterRemoval (address indexed exchange);
    event IncentiveChange(uint incentiveAmount);
    event MGMChange(address indexed MGM);
    event MlnTokenChange(address indexed mlnToken);
    event NativeAssetChange(address indexed nativeAsset);
    event PriceSourceChange(address indexed priceSource);
    event VersionRegistration(address indexed version);

    // TYPES
    struct Asset {
        bool exists;
        string name;
        string symbol;
        uint decimals;
        string url;
        uint reserveMin;
        uint[] standards;
        bytes4[] sigs;
    }

    struct Exchange {
        bool exists;
        address exchangeAddress;
        bool takesCustody;
        bytes4[] sigs;
    }

    struct Version {
        bool exists;
        bytes32 name;
    }

    // CONSTANTS
    uint public constant MAX_REGISTERED_ENTITIES = 20;
    uint public constant MAX_FUND_NAME_BYTES = 66;

    // FIELDS
    mapping (address => Asset) public assetInformation;
    address[] public registeredAssets;

    // Mapping from adapter address to exchange Information (Adapters are unique)
    mapping (address => Exchange) public exchangeInformation;
    address[] public registeredExchangeAdapters;

    mapping (address => Version) public versionInformation;
    address[] public registeredVersions;

    mapping (address => bool) public isFeeRegistered;

    mapping (address => address) public fundsToVersions;
    mapping (bytes32 => bool) public versionNameExists;
    mapping (bytes32 => address) public fundNameHashToOwner;


    uint public incentive = 10 finney;
    address public priceSource;
    address public mlnToken;
    address public nativeAsset;
    address public engine;
    address public ethfinexWrapperRegistry;
    address public MGM;

    modifier onlyVersion() {
        require(
            versionInformation[msg.sender].exists,
            "Only a Version can do this"
        );
        _;
    }

    // METHODS

    constructor(address _postDeployOwner) public {
        setOwner(_postDeployOwner);
    }

    // PUBLIC METHODS

    /// @notice Whether _name has only valid characters
    function isValidFundName(string memory _name) public pure returns (bool) {
        bytes memory b = bytes(_name);
        if (b.length > MAX_FUND_NAME_BYTES) return false;
        for (uint i; i < b.length; i++){
            bytes1 char = b[i];
            if(
                !(char >= 0x30 && char <= 0x39) && // 9-0
                !(char >= 0x41 && char <= 0x5A) && // A-Z
                !(char >= 0x61 && char <= 0x7A) && // a-z
                !(char == 0x20 || char == 0x2D) && // space, dash
                !(char == 0x2E || char == 0x5F) && // period, underscore
                !(char == 0x2A) // *
            ) {
                return false;
            }
        }
        return true;
    }

    /// @notice Whether _user can use _name for their fund
    function canUseFundName(address _user, string memory _name) public view returns (bool) {
        bytes32 nameHash = keccak256(bytes(_name));
        return (
            isValidFundName(_name) &&
            (
                fundNameHashToOwner[nameHash] == address(0) ||
                fundNameHashToOwner[nameHash] == _user
            )
        );
    }

    function reserveFundName(address _owner, string calldata _name)
        external
        onlyVersion
    {
        require(canUseFundName(_owner, _name), "Fund name cannot be used");
        fundNameHashToOwner[keccak256(bytes(_name))] = _owner;
    }

    function registerFund(address _fund, address _owner, string calldata _name)
        external
        onlyVersion
    {
        require(canUseFundName(_owner, _name), "Fund name cannot be used");
        fundsToVersions[_fund] = msg.sender;
    }

    /// @notice Registers an Asset information entry
    /// @dev Pre: Only registrar owner should be able to register
    /// @dev Post: Address _asset is registered
    /// @param _asset Address of asset to be registered
    /// @param _name Human-readable name of the Asset
    /// @param _symbol Human-readable symbol of the Asset
    /// @param _url Url for extended information of the asset
    /// @param _standards Integers of EIP standards this asset adheres to
    /// @param _sigs Function signatures for whitelisted asset functions
    function registerAsset(
        address _asset,
        string calldata _name,
        string calldata _symbol,
        string calldata _url,
        uint _reserveMin,
        uint[] calldata _standards,
        bytes4[] calldata _sigs
    ) external auth {
        require(registeredAssets.length < MAX_REGISTERED_ENTITIES);
        require(!assetInformation[_asset].exists);
        assetInformation[_asset].exists = true;
        registeredAssets.push(_asset);
        updateAsset(
            _asset,
            _name,
            _symbol,
            _url,
            _reserveMin,
            _standards,
            _sigs
        );
    }

    /// @notice Register an exchange information entry (A mapping from exchange adapter -> Exchange information)
    /// @dev Adapters are unique so are used as the mapping key. There may be different adapters for same exchange (0x / Ethfinex)
    /// @dev Pre: Only registrar owner should be able to register
    /// @dev Post: Address _exchange is registered
    /// @param _exchange Address of the exchange for the adapter
    /// @param _adapter Address of exchange adapter
    /// @param _takesCustody Whether this exchange takes custody of tokens before trading
    /// @param _sigs Function signatures for whitelisted exchange functions
    function registerExchangeAdapter(
        address _exchange,
        address _adapter,
        bool _takesCustody,
        bytes4[] calldata _sigs
    ) external auth {
        require(!exchangeInformation[_adapter].exists, "Adapter already exists");
        exchangeInformation[_adapter].exists = true;
        require(registeredExchangeAdapters.length < MAX_REGISTERED_ENTITIES, "Exchange limit reached");
        registeredExchangeAdapters.push(_adapter);
        updateExchangeAdapter(
            _exchange,
            _adapter,
            _takesCustody,
            _sigs
        );
    }

    /// @notice Versions cannot be removed from registry
    /// @param _version Address of the version contract
    /// @param _name Name of the version
    function registerVersion(
        address _version,
        bytes32 _name
    ) external auth {
        require(!versionInformation[_version].exists, "Version already exists");
        require(!versionNameExists[_name], "Version name already exists");
        versionInformation[_version].exists = true;
        versionNameExists[_name] = true;
        versionInformation[_version].name = _name;
        registeredVersions.push(_version);
        emit VersionRegistration(_version);
    }

    function setIncentive(uint _weiAmount) external auth {
        incentive = _weiAmount;
        emit IncentiveChange(_weiAmount);
    }

    function setPriceSource(address _priceSource) external auth {
        priceSource = _priceSource;
        emit PriceSourceChange(_priceSource);
    }

    function setMlnToken(address _mlnToken) external auth {
        mlnToken = _mlnToken;
        emit MlnTokenChange(_mlnToken);
    }

    function setNativeAsset(address _nativeAsset) external auth {
        nativeAsset = _nativeAsset;
        emit NativeAssetChange(_nativeAsset);
    }

    function setEngine(address _engine) external auth {
        engine = _engine;
        emit EngineChange(_engine);
    }

    function setMGM(address _MGM) external auth {
        MGM = _MGM;
        emit MGMChange(_MGM);
    }

    function setEthfinexWrapperRegistry(address _registry) external auth {
        ethfinexWrapperRegistry = _registry;
        emit EfxWrapperRegistryChange(_registry);
    }

    /// @notice Updates description information of a registered Asset
    /// @dev Pre: Owner can change an existing entry
    /// @dev Post: Changed Name, Symbol, URL and/or IPFSHash
    /// @param _asset Address of the asset to be updated
    /// @param _name Human-readable name of the Asset
    /// @param _symbol Human-readable symbol of the Asset
    /// @param _url Url for extended information of the asset
    function updateAsset(
        address _asset,
        string memory _name,
        string memory _symbol,
        string memory _url,
        uint _reserveMin,
        uint[] memory _standards,
        bytes4[] memory _sigs
    ) public auth {
        require(assetInformation[_asset].exists);
        Asset storage asset = assetInformation[_asset];
        asset.name = _name;
        asset.symbol = _symbol;
        asset.decimals = ERC20WithFields(_asset).decimals();
        asset.url = _url;
        asset.reserveMin = _reserveMin;
        asset.standards = _standards;
        asset.sigs = _sigs;
        emit AssetUpsert(
            _asset,
            _name,
            _symbol,
            asset.decimals,
            _url,
            _reserveMin,
            _standards,
            _sigs
        );
    }

    function updateExchangeAdapter(
        address _exchange,
        address _adapter,
        bool _takesCustody,
        bytes4[] memory _sigs
    ) public auth {
        require(exchangeInformation[_adapter].exists, "Exchange with adapter doesn't exist");
        Exchange storage exchange = exchangeInformation[_adapter];
        exchange.exchangeAddress = _exchange;
        exchange.takesCustody = _takesCustody;
        exchange.sigs = _sigs;
        emit ExchangeAdapterUpsert(
            _exchange,
            _adapter,
            _takesCustody,
            _sigs
        );
    }

    /// @notice Deletes an existing entry
    /// @dev Owner can delete an existing entry
    /// @param _asset address for which specific information is requested
    function removeAsset(
        address _asset,
        uint _assetIndex
    ) external auth {
        require(assetInformation[_asset].exists);
        require(registeredAssets[_assetIndex] == _asset);
        delete assetInformation[_asset];
        delete registeredAssets[_assetIndex];
        for (uint i = _assetIndex; i < registeredAssets.length-1; i++) {
            registeredAssets[i] = registeredAssets[i+1];
        }
        registeredAssets.pop();
        emit AssetRemoval(_asset);
    }

    /// @notice Deletes an existing entry
    /// @dev Owner can delete an existing entry
    /// @param _adapter address of the adapter of the exchange that is to be removed
    /// @param _adapterIndex index of the exchange in array
    function removeExchangeAdapter(
        address _adapter,
        uint _adapterIndex
    ) external auth {
        require(exchangeInformation[_adapter].exists, "Exchange with adapter doesn't exist");
        require(registeredExchangeAdapters[_adapterIndex] == _adapter, "Incorrect adapter index");
        delete exchangeInformation[_adapter];
        delete registeredExchangeAdapters[_adapterIndex];
        for (uint i = _adapterIndex; i < registeredExchangeAdapters.length-1; i++) {
            registeredExchangeAdapters[i] = registeredExchangeAdapters[i+1];
        }
        registeredExchangeAdapters.pop();
        emit ExchangeAdapterRemoval(_adapter);
    }

    function registerFees(address[] calldata _fees) external auth {
        for (uint i; i < _fees.length; i++) {
            isFeeRegistered[_fees[i]] = true;
        }
    }

    function deregisterFees(address[] calldata _fees) external auth {
        for (uint i; i < _fees.length; i++) {
            delete isFeeRegistered[_fees[i]];
        }
    }

    // PUBLIC VIEW METHODS

    // get asset specific information
    function getName(address _asset) external view returns (string memory) {
        return assetInformation[_asset].name;
    }
    function getSymbol(address _asset) external view returns (string memory) {
        return assetInformation[_asset].symbol;
    }
    function getDecimals(address _asset) external view returns (uint) {
        return assetInformation[_asset].decimals;
    }
    function getReserveMin(address _asset) external view returns (uint) {
        return assetInformation[_asset].reserveMin;
    }
    function assetIsRegistered(address _asset) external view returns (bool) {
        return assetInformation[_asset].exists;
    }
    function getRegisteredAssets() external view returns (address[] memory) {
        return registeredAssets;
    }
    function assetMethodIsAllowed(address _asset, bytes4 _sig)
        external
        view
        returns (bool)
    {
        bytes4[] memory signatures = assetInformation[_asset].sigs;
        for (uint i = 0; i < signatures.length; i++) {
            if (signatures[i] == _sig) {
                return true;
            }
        }
        return false;
    }

    // get exchange-specific information
    function exchangeAdapterIsRegistered(address _adapter) external view returns (bool) {
        return exchangeInformation[_adapter].exists;
    }
    function getRegisteredExchangeAdapters() external view returns (address[] memory) {
        return registeredExchangeAdapters;
    }
    function getExchangeInformation(address _adapter)
        public
        view
        returns (address, bool)
    {
        Exchange memory exchange = exchangeInformation[_adapter];
        return (
            exchange.exchangeAddress,
            exchange.takesCustody
        );
    }
    function exchangeForAdapter(address _adapter) external view returns (address) {
        Exchange memory exchange = exchangeInformation[_adapter];
        return exchange.exchangeAddress;
    }
    function getAdapterFunctionSignatures(address _adapter)
        public
        view
        returns (bytes4[] memory)
    {
        return exchangeInformation[_adapter].sigs;
    }
    function adapterMethodIsAllowed(
        address _adapter, bytes4 _sig
    )
        external
        view
        returns (bool)
    {
        bytes4[] memory signatures = exchangeInformation[_adapter].sigs;
        for (uint i = 0; i < signatures.length; i++) {
            if (signatures[i] == _sig) {
                return true;
            }
        }
        return false;
    }

    // get version and fund information
    function getRegisteredVersions() external view returns (address[] memory) {
        return registeredVersions;
    }

    function isFund(address _who) external view returns (bool) {
        if (fundsToVersions[_who] != address(0)) {
            return true; // directly from a hub
        } else {
            Hub hub = Hub(Spoke(_who).hub());
            require(
                hub.isSpoke(_who),
                "Call from either a spoke or hub"
            );
            return fundsToVersions[address(hub)] != address(0);
        }
    }

    function isFundFactory(address _who) external view returns (bool) {
        return versionInformation[_who].exists;
    }
}

File 23 of 25 : SafeMath.sol
pragma solidity 0.6.1;


/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, reverts on 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-solidity/pull/522
    if (_a == 0) {
      return 0;
    }

    uint256 c = _a * _b;
    require(c / _a == _b);

    return c;
  }

  /**
  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  */
  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b > 0); // Solidity only automatically asserts when dividing by 0
    uint256 c = _a / _b;
    // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold

    return c;
  }

  /**
  * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b <= _a);
    uint256 c = _a - _b;

    return c;
  }

  /**
  * @dev Adds two numbers, reverts on overflow.
  */
  function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
    uint256 c = _a + _b;
    require(c >= _a);

    return c;
  }

  /**
  * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
  * reverts when dividing by zero.
  */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0);
    return a % b;
  }
}

File 24 of 25 : DSGuard.sol
/// @notice Retrieved from DappHub (https://git.io/fpwMi)

pragma solidity 0.6.1;

import "./DSAuth.sol";

contract DSGuardEvents {
    event LogPermit(
        bytes32 indexed src,
        bytes32 indexed dst,
        bytes32 indexed sig
    );

    event LogForbid(
        bytes32 indexed src,
        bytes32 indexed dst,
        bytes32 indexed sig
    );
}

contract DSGuard is DSAuth, DSAuthority, DSGuardEvents {
    bytes32 constant public ANY = bytes32(uint(-1));

    mapping (bytes32 => mapping (bytes32 => mapping (bytes32 => bool))) acl;

    function canCall(
        address src_, address dst_, bytes4 sig
    ) public view override returns (bool) {
        bytes32 src = bytes32(bytes20(src_));
        bytes32 dst = bytes32(bytes20(dst_));

        return acl[src][dst][sig]
            || acl[src][dst][ANY]
            || acl[src][ANY][sig]
            || acl[src][ANY][ANY]
            || acl[ANY][dst][sig]
            || acl[ANY][dst][ANY]
            || acl[ANY][ANY][sig]
            || acl[ANY][ANY][ANY];
    }

    function permit(bytes32 src, bytes32 dst, bytes32 sig) public auth {
        acl[src][dst][sig] = true;
        emit LogPermit(src, dst, sig);
    }

    function forbid(bytes32 src, bytes32 dst, bytes32 sig) public auth {
        acl[src][dst][sig] = false;
        emit LogForbid(src, dst, sig);
    }

    function permit(address src, address dst, bytes32 sig) public {
        permit(bytes32(bytes20(src)), bytes32(bytes20(dst)), sig);
    }
    function forbid(address src, address dst, bytes32 sig) public {
        forbid(bytes32(bytes20(src)), bytes32(bytes20(dst)), sig);
    }

}

contract DSGuardFactory {
    mapping (address => bool)  public  isGuard;

    function newGuard() public returns (DSGuard guard) {
        guard = new DSGuard();
        guard.setOwner(msg.sender);
        isGuard[address(guard)] = true;
    }
}

File 25 of 25 : IFee.sol
pragma solidity 0.6.1;

/// @dev Exposes "feeAmount", which maps fund state and fee state to uint
/// @dev Notice that "feeAmount" *may* change contract state
/// @dev Also exposes "updateState", which changes fee's internal state
interface IFee {
    function initializeForUser(uint feeRate, uint feePeriod, address denominationAsset) external;
    function feeAmount() external returns (uint);
    function updateState() external;

    /// @notice Used to enforce a convention
    function identifier() external view returns (uint);
}

File 26 of 25 : IFeeManager.sol
pragma solidity 0.6.1;

interface IFeeManagerFactory {
    function createInstance(
        address _hub,
        address _denominationAsset,
        address[] calldata _fees,
        uint[] calldata _feeRates,
        uint[] calldata _feePeriods,
        address _registry
    ) external returns (address);
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "istanbul",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_hub","type":"address"},{"internalType":"address[]","name":"_defaultAssets","type":"address[]"},{"internalType":"address","name":"_registry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalAmguPaidInEth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amguChargableGas","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"incentivePaid","type":"uint256"}],"name":"AmguPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestOwner","type":"address"}],"name":"CancelRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"assets","type":"address[]"}],"name":"DisableInvestment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"asset","type":"address[]"}],"name":"EnableInvestment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestOwner","type":"address"},{"indexed":true,"internalType":"address","name":"investmentAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestedShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"investmentAmount","type":"uint256"}],"name":"InvestmentRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"address[]","name":"assets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"assetQuantities","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"redeemedShares","type":"uint256"}],"name":"Redemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestOwner","type":"address"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"investmentAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"investmentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedShares","type":"uint256"}],"name":"RequestExecution","type":"event"},{"inputs":[],"name":"REQUEST_LIFESPAN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARES_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract DSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"requestOwner","type":"address"}],"name":"cancelRequestFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"disableInvestment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"enableInvestment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"engine","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requestOwner","type":"address"}],"name":"executeRequestFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getHistoricalInvestors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareQuantity","type":"uint256"}],"name":"getOwedPerformanceFees","outputs":[{"internalType":"uint256","name":"remainingShareQuantity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"}],"name":"hasExpiredRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasInvested","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"}],"name":"hasRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_who","type":"address"}],"name":"hasValidRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"historicalInvestors","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract Hub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[11]","name":"_spokes","type":"address[11]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"investAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mlnToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceSource","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareQuantity","type":"uint256"}],"name":"redeemQuantity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareQuantity","type":"uint256"},{"internalType":"address[]","name":"requestedAssets","type":"address[]"}],"name":"redeemWithConstraints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestedShares","type":"uint256"},{"internalType":"uint256","name":"investmentAmount","type":"uint256"},{"internalType":"address","name":"investmentAsset","type":"address"}],"name":"requestInvestment","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"requests","outputs":[{"internalType":"address","name":"investmentAsset","type":"address"},{"internalType":"uint256","name":"investmentAmount","type":"uint256"},{"internalType":"uint256","name":"requestedShares","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"routes","outputs":[{"internalType":"address","name":"accounting","type":"address"},{"internalType":"address","name":"feeManager","type":"address"},{"internalType":"address","name":"participation","type":"address"},{"internalType":"address","name":"policyManager","type":"address"},{"internalType":"address","name":"shares","type":"address"},{"internalType":"address","name":"trading","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"registry","type":"address"},{"internalType":"address","name":"version","type":"address"},{"internalType":"address","name":"engine","type":"address"},{"internalType":"address","name":"mlnToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract DSAuthority","name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106101f25760003560e01c8063643466af1161010d578063b1ffd471116100a0578063c9d4623f1161006f578063c9d4623f146107a6578063e216ea2b146107bb578063ec622892146107ee578063edb9a5c014610869578063f16ab6dc1461089c576101f9565b8063b1ffd471146106d0578063be040fb014610752578063bec6146214610767578063bf7e214f14610791576101f9565b80637baf5929116100dc5780637baf592914610678578063851b16f51461069e5780638a471df9146106a65780638da5cb5b146106bb576101f9565b8063643466af1461056857806374adad1d146105cd5780637a9e5e4b146106305780637b10399914610663576101f9565b806344ed98dd1161018557806354c3b8c51161015457806354c3b8c51461043957806354fd4d501461046c5780635810a54c146104815780635d58287014610536576101f9565b806344ed98dd146103a0578063474e19f2146103dc57806349837b5e146103f15780634a248e2714610406576101f9565b806320531bc9116101c157806320531bc9146102ac578063212f6066146102dd578063365a86fc14610358578063429f41a71461036d576101f9565b80630b797141146101fe5780630d2485b11461022a57806313af403514610250578063158ef93e14610283576101f9565b366101f957005b600080fd5b34801561020a57600080fd5b506102286004803603602081101561022157600080fd5b50356108c6565b005b6102286004803603602081101561024057600080fd5b50356001600160a01b03166109e2565b34801561025c57600080fd5b506102286004803603602081101561027357600080fd5b50356001600160a01b0316610d94565b34801561028f57600080fd5b50610298610e42565b604080519115158252519081900360200190f35b3480156102b857600080fd5b506102c1610e4b565b604080516001600160a01b039092168252519081900360200190f35b3480156102e957600080fd5b506102286004803603602081101561030057600080fd5b810190602081018135600160201b81111561031a57600080fd5b82018360208201111561032c57600080fd5b803590602001918460208302840111600160201b8311171561034d57600080fd5b509092509050610e5a565b34801561036457600080fd5b506102c1610ef4565b34801561037957600080fd5b506102986004803603602081101561039057600080fd5b50356001600160a01b0316610f03565b3480156103ac57600080fd5b506103ca600480360360208110156103c357600080fd5b5035611087565b60408051918252519081900360200190f35b3480156103e857600080fd5b506103ca611199565b3480156103fd57600080fd5b506103ca61119e565b34801561041257600080fd5b506102986004803603602081101561042957600080fd5b50356001600160a01b03166111a5565b34801561044557600080fd5b506102986004803603602081101561045c57600080fd5b50356001600160a01b03166111d6565b34801561047857600080fd5b506102c16111eb565b34801561048d57600080fd5b50610228600480360360408110156104a457600080fd5b81359190810190604081016020820135600160201b8111156104c557600080fd5b8201836020820111156104d757600080fd5b803590602001918460208302840111600160201b831117156104f857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506111fa945050505050565b6102286004803603606081101561054c57600080fd5b50803590602081013590604001356001600160a01b0316611b9a565b34801561057457600080fd5b5061057d6123d1565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105b95781810151838201526020016105a1565b505050509050019250505060405180910390f35b3480156105d957600080fd5b50610600600480360360208110156105f057600080fd5b50356001600160a01b0316612433565b604080516001600160a01b0390951685526020850193909352838301919091526060830152519081900360800190f35b34801561063c57600080fd5b506102286004803603602081101561065357600080fd5b50356001600160a01b0316612464565b34801561066f57600080fd5b506102c161250e565b6102286004803603602081101561068e57600080fd5b50356001600160a01b0316612518565b610228612aaa565b3480156106b257600080fd5b506102c1612e50565b3480156106c757600080fd5b506102c1612e5a565b3480156106dc57600080fd5b506106e5612e69565b604080516001600160a01b039c8d1681529a8c1660208c0152988b168a8a0152968a1660608a0152948916608089015292881660a088015290871660c0870152861660e0860152851661010085015284166101208401529092166101408201529051908190036101600190f35b34801561075e57600080fd5b50610228612ebe565b34801561077357600080fd5b50610228600480360361016081101561078b57600080fd5b50612f43565b34801561079d57600080fd5b506102c161326f565b3480156107b257600080fd5b506102c161327e565b3480156107c757600080fd5b50610298600480360360208110156107de57600080fd5b50356001600160a01b0316613288565b3480156107fa57600080fd5b506102286004803603602081101561081157600080fd5b810190602081018135600160201b81111561082b57600080fd5b82018360208201111561083d57600080fd5b803590602001918460208302840111600160201b8311171561085e57600080fd5b5090925090506132a8565b34801561087557600080fd5b506102986004803603602081101561088c57600080fd5b50356001600160a01b03166133c4565b3480156108a857600080fd5b506102c1600480360360208110156108bf57600080fd5b50356133d9565b60035460408051630a616f2560e21b815290516060926001600160a01b031691632985bc94916004808301926000929190829003018186803b15801561090b57600080fd5b505afa15801561091f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561094857600080fd5b8101908080516040519392919084600160201b82111561096757600080fd5b90830190602082018581111561097c57600080fd5b82518660208202830111600160201b8211171561099857600080fd5b82525081516020918201928201910280838360005b838110156109c55781810151838201526020016109ad565b5050505090500160405250505090506109de82826111fa565b5050565b6000805a90506109f183613400565b60005a90506000610a0061327e565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3857600080fd5b505afa158015610a4c573d6000803e3d6000fd5b505050506040513d6020811015610a6257600080fd5b505190506000610a7b82610a768686613703565b613759565b90506000610a8761250e565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b158015610abf57600080fd5b505afa158015610ad3573d6000803e3d6000fd5b505050506040513d6020811015610ae957600080fd5b505190506000610af7610e4b565b6001600160a01b0316637e3bfc2f84610b0e612e50565b856040518463ffffffff1660e01b815260040180848152602001836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b03168152602001935050505060206040518083038186803b158015610b7557600080fd5b505afa158015610b89573d6000803e3d6000fd5b505050506040513d6020811015610b9f57600080fd5b5051905060008715610c1e57610bb361250e565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b158015610beb57600080fd5b505afa158015610bff573d6000803e3d6000fd5b505050506040513d6020811015610c1557600080fd5b50519050610c22565b5060005b610c2c82826137bc565b341015610c6a5760405162461bcd60e51b81526004018080602001828103825260218152602001806140366021913960400191505060405180910390fd5b610c7261327e565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610cac57600080fd5b505af1158015610cc0573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc610ce5610cdf3486613703565b84613703565b6040518115909202916000818181858888f19350505050610d3d576040805162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b604482015290519081900360640190fd5b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb983610d6a8a8a613703565b604080519283526020830191909152818101859052519081900360600190a2505050505050505050565b610daa336000356001600160e01b03191661380b565b610df2576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600e5460ff1681565b6000610e556138f2565b905090565b610e70336000356001600160e01b03191661380b565b610eb8576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b6109de82828080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061396892505050565b6002546001600160a01b031681565b600080610f0e610e4b565b90506000816001600160a01b0316634c89867f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f4b57600080fd5b505afa158015610f5f573d6000803e3d6000fd5b505050506040513d6020811015610f7557600080fd5b50516001600160a01b0385166000908152600f6020526040902060030154108061100d5750600754604080516318160ddd60e01b815290516001600160a01b03909216916318160ddd91600481810192602092909190829003018186803b158015610fdf57600080fd5b505afa158015610ff3573d6000803e3d6000fd5b505050506040513d602081101561100957600080fd5b5051155b905061101884613288565b80156110215750805b80156110335750611031846111a5565b155b801561105957506001600160a01b0384166000908152600f602052604090206001015415155b801561107f57506001600160a01b0384166000908152600f602052604090206002015415155b949350505050565b60075460048054604080516335ff1bb760e01b815290516000946001600160a01b03908116948694909116926335ff1bb7928183019260209282900301818787803b1580156110d557600080fd5b505af11580156110e9573d6000803e3d6000fd5b505050506040513d60208110156110ff57600080fd5b5051604080516318160ddd60e01b8152905191925060009161117e916001600160a01b038616916318160ddd91600480820192602092909190829003018186803b15801561114c57600080fd5b505afa158015611160573d6000803e3d6000fd5b505050506040513d602081101561117657600080fd5b5051836137bc565b6111888387613759565b8161118f57fe5b0495945050505050565b601281565b6201518081565b6001600160a01b0381166000908152600f60205260408120600301546111ce90620151806137bc565b421192915050565b60106020526000908152604090205460ff1681565b600b546001600160a01b031690565b600754604080516370a0823160e01b815233600482015290516001600160a01b0390921691849183916370a0823191602480820192602092909190829003018186803b15801561124957600080fd5b505afa15801561125d573d6000803e3d6000fd5b505050506040513d602081101561127357600080fd5b5051108015906112f65750604080516370a0823160e01b815233600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156112c857600080fd5b505afa1580156112dc573d6000803e3d6000fd5b505050506040513d60208110156112f257600080fd5b5051115b6113315760405162461bcd60e51b8152600401808060200182810382526035815260200180613fb16035913960400191505060405180910390fd5b600061133b610e4b565b6001600160a01b03166380971a36846040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b83811015611399578181015183820152602001611381565b505050509050019250505060206040518083038186803b1580156113bc57600080fd5b505afa1580156113d0573d6000803e3d6000fd5b505050506040513d60208110156113e657600080fd5b505180156114765750600260009054906101000a90046001600160a01b03166001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b15801561143d57600080fd5b505afa158015611451573d6000803e3d6000fd5b505050506040513d602081101561146757600080fd5b50516001600160a01b03163314155b15611638576004805460408051631bb7381160e31b815290516001600160a01b039092169263ddb9c08892828201926000929082900301818387803b1580156114be57600080fd5b505af11580156114d2573d6000803e3d6000fd5b505050506114df84611087565b604080516366bde28b60e11b81523360048201526024810183905290519192506001600160a01b0384169163cd7bc5169160448082019260009290919082900301818387803b15801561153157600080fd5b505af1158015611545573d6000803e3d6000fd5b50505050816001600160a01b0316631d48946c600260009054906101000a90046001600160a01b03166001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b1580156115a657600080fd5b505afa1580156115ba573d6000803e3d6000fd5b505050506040513d60208110156115d057600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820185905251604480830192600092919082900301818387803b15801561161f57600080fd5b505af1158015611633573d6000803e3d6000fd5b505050505b60006116448583613703565b9050600060608551604051908082528060200260200182016040528015611675578160200160208202803883390190505b509050606086516040519080825280602002602001820160405280156116a5578160200160208202803883390190505b506003549091506001600160a01b031660005b885181101561195c578881815181106116cd57fe5b60200260200101519450816001600160a01b0316630e7a2d4e866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561172d57600080fd5b505afa158015611741573d6000803e3d6000fd5b505050506040513d602081101561175757600080fd5b50516117945760405162461bcd60e51b8152600401808060200182810382526021815260200180613f6f6021913960400191505060405180910390fd5b60005b8351811015611822578381815181106117ac57fe5b60200260200101516001600160a01b0316866001600160a01b0316141561181a576040805162461bcd60e51b815260206004820152601f60248201527f41737365742063616e206f6e6c792062652072656465656d6564206f6e636500604482015290519081900360640190fd5b600101611797565b508483828151811061183057fe5b6001600160a01b039283166020918202929092018101919091526040805163ca334fe560e01b81528884166004820152905160009386169263ca334fe5926024808201939182900301818787803b15801561188a57600080fd5b505af115801561189e573d6000803e3d6000fd5b505050506040513d60208110156118b457600080fd5b50519050806118c35750611954565b886001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118fc57600080fd5b505afa158015611910573d6000803e3d6000fd5b505050506040513d602081101561192657600080fd5b50516119328289613759565b8161193957fe5b0485838151811061194657fe5b602002602001018181525050505b6001016116b8565b50604080516366bde28b60e11b81523360048201526024810187905290516001600160a01b0389169163cd7bc51691604480830192600092919082900301818387803b1580156119ab57600080fd5b505af11580156119bf573d6000803e3d6000fd5b506000925050505b8851811015611ac1578881815181106119dc57fe5b602002602001015194508381815181106119f257fe5b602002602001015160001415611a0757611ab9565b60095484516001600160a01b039091169063f3fef3a3908790879085908110611a2c57fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611a8357600080fd5b505af1158015611a97573d6000803e3d6000fd5b50505050611ab98533868481518110611aac57fe5b6020026020010151613b1e565b6001016119c7565b50336001600160a01b03167f976b5f495b9d6400bbe35e173a78de5e77ffd728e55e900f45a495dec4143e17898588604051808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b83811015611b3a578181015183820152602001611b22565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015611b79578181015183820152602001611b61565b505050509050019550505050505060405180910390a2505050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b031663ff9475256040518163ffffffff1660e01b815260040160206040518083038186803b158015611be857600080fd5b505afa158015611bfc573d6000803e3d6000fd5b505050506040513d6020811015611c1257600080fd5b505115611c59576040805162461bcd60e51b815260206004820152601060248201526f243ab11034b99039b43aba103237bbb760811b604482015290519081900360640190fd5b600160005a600e5490915060ff16611cb8576040805162461bcd60e51b815260206004820152601d60248201527f436f6d706f6e656e74206e6f742079657420696e697469616c697a6564000000604482015290519081900360640190fd5b6006546040805160a08082018352338252600060208084018290528385018290526001600160a01b038981166060808701919091526080860184905286519081018752838152918201839052818601839052945163da6670d360e01b81526001600160e01b031983351660048201818152969097169663da6670d3969095949293929091602401908590808383875b83811015611d5f578181015183820152602001611d47565b5050505090500183600360200280838360005b83811015611d8a578181015183820152602001611d72565b50505050905001828152602001945050505050600060405180830381600087803b158015611db757600080fd5b505af1158015611dcb573d6000803e3d6000fd5b505050506001600160a01b03831660009081526010602052604090205460ff16611e265760405162461bcd60e51b81526004018080602001828103825260248152602001806140576024913960400191505060405180910390fd5b611e3283333087613ceb565b336000908152600f602052604090206003015415611e815760405162461bcd60e51b8152600401808060200182810382526024815260200180613f4b6024913960400191505060405180910390fd5b60408051608080820183526001600160a01b0386811680845260208085018a81528587018c8152426060808901918252336000818152600f87528b81209a518b546001600160a01b031916908a16178b55945160018b0155925160028a01559051600390980197909755600654885160a08082018b52928152808501849052808a018490528089019590955295840182905287519687018852818752918601819052858701819052955163185f31cf60e31b815286356001600160e01b03191660048201818152959094169663c2f98e7896949593949390929091602401908590808383875b83811015611f7f578181015183820152602001611f67565b5050505090500183600360200280838360005b83811015611faa578181015183820152602001611f92565b50505050905001828152602001945050505050600060405180830381600087803b158015611fd757600080fd5b505af1158015611feb573d6000803e3d6000fd5b5050604080518881526020810188905281516001600160a01b03881694503393507f7ac4e9fa94c85b700a3c05a368f0cbc8503fba59158d3e01cc96f608c82bb202929181900390910190a360005a9050600061204661327e565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561207e57600080fd5b505afa158015612092573d6000803e3d6000fd5b505050506040513d60208110156120a857600080fd5b5051905060006120bc82610a768686613703565b905060006120c861250e565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b15801561210057600080fd5b505afa158015612114573d6000803e3d6000fd5b505050506040513d602081101561212a57600080fd5b505190506000612138610e4b565b6001600160a01b0316637e3bfc2f8461214f612e50565b856040518463ffffffff1660e01b815260040180848152602001836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b03168152602001935050505060206040518083038186803b1580156121b657600080fd5b505afa1580156121ca573d6000803e3d6000fd5b505050506040513d60208110156121e057600080fd5b505190506000871561225f576121f461250e565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b15801561222c57600080fd5b505afa158015612240573d6000803e3d6000fd5b505050506040513d602081101561225657600080fd5b50519050612263565b5060005b61226d82826137bc565b3410156122ab5760405162461bcd60e51b81526004018080602001828103825260218152602001806140366021913960400191505060405180910390fd5b6122b361327e565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122ed57600080fd5b505af1158015612301573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc612320610cdf3486613703565b6040518115909202916000818181858888f19350505050612378576040805162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b604482015290519081900360640190fd5b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb9836123a58a8a613703565b604080519283526020830191909152818101859052519081900360600190a25050505050505050505050565b6060601280548060200260200160405190810160405280929190818152602001828054801561242957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161240b575b5050505050905090565b600f6020526000908152604090208054600182015460028301546003909301546001600160a01b0390921692909184565b61247a336000356001600160e01b03191661380b565b6124c2576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b03838116919091178083556040519116917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b6000610e55613ec1565b600260009054906101000a90046001600160a01b03166001600160a01b031663ff9475256040518163ffffffff1660e01b815260040160206040518083038186803b15801561256657600080fd5b505afa15801561257a573d6000803e3d6000fd5b505050506040513d602081101561259057600080fd5b5051156125d7576040805162461bcd60e51b815260206004820152601060248201526f243ab11034b99039b43aba103237bbb760811b604482015290519081900360640190fd5b6000805a90506125e5613eee565b506001600160a01b038084166000908152600f602090815260409182902082516080810184528154909416845260018101549184019190915260028101549183019190915260030154606082015261263c84610f03565b6126775760405162461bcd60e51b81526004018080602001828103825260218152602001806140156021913960400191505060405180910390fd5b6004805460408051631bb7381160e31b815290516001600160a01b039092169263ddb9c08892828201926000929082900301818387803b1580156126ba57600080fd5b505af11580156126ce573d6000803e3d6000fd5b50506003546040808501518551825163896aad5360e01b815260048101929092526001600160a01b03908116602483015291516000955091909216925063896aad539160448082019260209290919082900301818787803b15801561273257600080fd5b505af1158015612746573d6000803e3d6000fd5b505050506040513d602081101561275c57600080fd5b505160208301519091508111156127ba576040805162461bcd60e51b815260206004820152601760248201527f496e76657374656420616d6f756e7420746f6f206c6f77000000000000000000604482015290519081900360640190fd5b81516009546127d391906001600160a01b031683613b1e565b60006127e3836020015183613703565b905080156127f85782516127f8908783613b1e565b600a54604080516307518cab60e21b8152905133926108fc926001600160a01b0390911691631d4632ac91600480820192602092909190829003018186803b15801561284357600080fd5b505afa158015612857573d6000803e3d6000fd5b505050506040513d602081101561286d57600080fd5b50516040518115909202916000818181858888f19350505050158015612897573d6000803e3d6000fd5b506007546040808501518151630752251b60e21b81526001600160a01b038a8116600483015260248201929092529151921691631d48946c9160448082019260009290919082900301818387803b1580156128f157600080fd5b505af1158015612905573d6000803e3d6000fd5b50506003548551604080516301ebef9d60e21b81526001600160a01b03928316600482015290519190921693506307afbe749250602480830192600092919082900301818387803b15801561295957600080fd5b505af115801561296d573d6000803e3d6000fd5b505050506001600160a01b03861660009081526011602052604090205460ff166129f7576001600160a01b0386166000818152601160205260408120805460ff191660019081179091556012805491820181559091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b03191690911790555b82600001516001600160a01b0316336001600160a01b0316876001600160a01b03167fd826cdb072fceaa49209a7f9dc6283914ae87fb72f26cc328c67f8b54599957b86602001518760400151604051808381526020018281526020019250505060405180910390a45050506001600160a01b0383166000908152600f6020526040812080546001600160a01b031916815560018101829055600281018290556003018190555a90506000610a0061327e565b6000805a9050612ab933613400565b60005a90506000612ac861327e565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0057600080fd5b505afa158015612b14573d6000803e3d6000fd5b505050506040513d6020811015612b2a57600080fd5b505190506000612b3e82610a768686613703565b90506000612b4a61250e565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b158015612b8257600080fd5b505afa158015612b96573d6000803e3d6000fd5b505050506040513d6020811015612bac57600080fd5b505190506000612bba610e4b565b6001600160a01b0316637e3bfc2f84612bd1612e50565b856040518463ffffffff1660e01b815260040180848152602001836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b03168152602001935050505060206040518083038186803b158015612c3857600080fd5b505afa158015612c4c573d6000803e3d6000fd5b505050506040513d6020811015612c6257600080fd5b5051905060008715612ce157612c7661250e565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cae57600080fd5b505afa158015612cc2573d6000803e3d6000fd5b505050506040513d6020811015612cd857600080fd5b50519050612ce5565b5060005b612cef82826137bc565b341015612d2d5760405162461bcd60e51b81526004018080602001828103825260218152602001806140366021913960400191505060405180910390fd5b612d3561327e565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b158015612d6f57600080fd5b505af1158015612d83573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc612da2610cdf3486613703565b6040518115909202916000818181858888f19350505050612dfa576040805162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b604482015290519081900360640190fd5b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb983612e278a8a613703565b604080519283526020830191909152818101859052519081900360600190a25050505050505050565b6000610e55613ed0565b6001546001600160a01b031681565b600354600454600554600654600754600854600954600a54600b54600c54600d546001600160a01b039a8b169a998a16999889169897881697968716969586169594851694938416939283169291821691168b565b600754604080516370a0823160e01b815233600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015612f0957600080fd5b505afa158015612f1d573d6000803e3d6000fd5b505050506040513d6020811015612f3357600080fd5b50519050612f40816108c6565b50565b612f59336000356001600160e01b03191661380b565b612fa1576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b6002546001600160a01b03163314612fb857600080fd5b600e5460ff1615613006576040805162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604482015290519081900360640190fd5b60408051610160810182526001600160a01b038335811682526020808501358216908301528383013516918101919091526060810182600360200201356001600160a01b03166001600160a01b03168152602001826004600b811061306757fe5b60200201356001600160a01b03166001600160a01b03168152602001826005600b811061309057fe5b60200201356001600160a01b03166001600160a01b03168152602001826006600b81106130b957fe5b60200201356001600160a01b03166001600160a01b03168152602001826007600b81106130e257fe5b60200201356001600160a01b03166001600160a01b03168152602001826008600b811061310b57fe5b60200201356001600160a01b03166001600160a01b03168152602001826009600b811061313457fe5b60200201356001600160a01b03166001600160a01b0316815260200182600a600b811061315d57fe5b602090810291909101356001600160a01b039081169092528251600380546001600160a01b03199081169285169290921790559083015160048054831691841691909117905560408301516005805483169184169190911790556060830151600680548316918416919091179055608083015160078054831691841691909117905560a083015160088054831691841691909117905560c083015160098054831691841691909117905560e0830151600a80548316918416919091179055610100830151600b80548316918416919091179055610120830151600c8054831691841691909117905561014090920151600d80549093169116179055600e805460ff19166001179055612f406000610d94565b6000546001600160a01b031681565b6000610e55613edf565b6001600160a01b03166000908152600f6020526040902060030154151590565b6132be336000356001600160e01b03191661380b565b613306576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b60005b8181101561335c5760006010600085858581811061332357fe5b602090810292909201356001600160a01b0316835250810191909152604001600020805460ff1916911515919091179055600101613309565b507f3dc6367c991e43485e267da6f765655c7afd64b44b9414b04ff80de370cf5121828260405180806020018281038252848482818152602001925060200280828437600083820152604051601f909101601f19169092018290039550909350505050a15050565b60116020526000908152604090205460ff1681565b601281815481106133e657fe5b6000918252602090912001546001600160a01b0316905081565b61340981613288565b613451576040805162461bcd60e51b8152602060048201526014602482015273139bc81c995c5d595cdd081d1bc818d85b98d95b60621b604482015290519081900360640190fd5b600061345b610e4b565b9050613465613eee565b506001600160a01b038083166000908152600f6020908152604091829020825160808101845281548516808252600183015482850152600283015482860152600390920154606082015283516313533b5560e01b81526004810192909252925192938516926313533b5592602480840193919291829003018186803b1580156134ed57600080fd5b505afa158015613501573d6000803e3d6000fd5b505050506040513d602081101561351757600080fd5b505115806135295750613529836111a5565b806135aa5750600260009054906101000a90046001600160a01b03166001600160a01b031663ff9475256040518163ffffffff1660e01b815260040160206040518083038186803b15801561357d57600080fd5b505afa158015613591573d6000803e3d6000fd5b505050506040513d60208110156135a757600080fd5b50515b6135e55760405162461bcd60e51b8152600401808060200182810382526021815260200180613f906021913960400191505060405180910390fd5b80516020808301516001600160a01b038087166000908152600f8452604080822080546001600160a01b0319168155600181018390556002810183905560030191909155600a5481516307518cab60e21b81529151939433946108fc949290921692631d4632ac9260048083019392829003018186803b15801561366857600080fd5b505afa15801561367c573d6000803e3d6000fd5b505050506040513d602081101561369257600080fd5b50516040518115909202916000818181858888f193505050501580156136bc573d6000803e3d6000fd5b506136c8828683613b1e565b6040516001600160a01b038616907f8a46aebe3d6766257a923c4a998b5fd32d693bd7877df2e25ea7b7099310da2b90600090a25050505050565b80820382811115613753576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b92915050565b60008115806137745750508082028282828161377157fe5b04145b613753576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820182811015613753576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b60006001600160a01b03831630141561382657506001613753565b6001546001600160a01b038481169116141561384457506001613753565b6000546001600160a01b031661385c57506000613753565b6000546040805163b700961360e01b81526001600160a01b0386811660048301523060248301526001600160e01b0319861660448301529151919092169163b7009613916064808301926020929190829003018186803b1580156138bf57600080fd5b505afa1580156138d3573d6000803e3d6000fd5b505050506040513d60208110156138e957600080fd5b50519050613753565b600254604080516320531bc960e01b815290516000926001600160a01b0316916320531bc9916004808301926020929190829003018186803b15801561393757600080fd5b505afa15801561394b573d6000803e3d6000fd5b505050506040513d602081101561396157600080fd5b5051905090565b60005b8151811015613aa557600a5482516001600160a01b0390911690631f8d99a99084908490811061399757fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156139e557600080fd5b505afa1580156139f9573d6000803e3d6000fd5b505050506040513d6020811015613a0f57600080fd5b5051613a59576040805162461bcd60e51b8152602060048201526014602482015273105cdcd95d081b9bdd081c9959da5cdd195c995960621b604482015290519081900360640190fd5b600160106000848481518110613a6b57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905560010161396b565b507f144a61ed164a4708d46e9929ca93ac8226b76226e0ceb5182c6eaa4d9cdc3429816040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015613b08578181015183820152602001613af0565b505050509050019250505060405180910390a150565b6000836001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015613b7657600080fd5b505afa158015613b8a573d6000803e3d6000fd5b505050506040513d6020811015613ba057600080fd5b50516040805163a9059cbb60e01b81526001600160a01b0386811660048301526024820186905291519293509086169163a9059cbb916044808201926020929091908290030181600087803b158015613bf857600080fd5b505af1158015613c0c573d6000803e3d6000fd5b505050506040513d6020811015613c2257600080fd5b5050604080516370a0823160e01b81526001600160a01b03858116600483015291516000928716916370a08231916024808301926020929190829003018186803b158015613c6f57600080fd5b505afa158015613c83573d6000803e3d6000fd5b505050506040513d6020811015613c9957600080fd5b5051905080613ca883856137bc565b14613ce45760405162461bcd60e51b815260040180806020018281038252602b815260200180613f20602b913960400191505060405180910390fd5b5050505050565b6000846001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015613d4357600080fd5b505afa158015613d57573d6000803e3d6000fd5b505050506040513d6020811015613d6d57600080fd5b5051604080516323b872dd60e01b81526001600160a01b0387811660048301528681166024830152604482018690529151929350908716916323b872dd916064808201926020929091908290030181600087803b158015613dcd57600080fd5b505af1158015613de1573d6000803e3d6000fd5b505050506040513d6020811015613df757600080fd5b5050604080516370a0823160e01b81526001600160a01b03858116600483015291516000928816916370a08231916024808301926020929190829003018186803b158015613e4457600080fd5b505afa158015613e58573d6000803e3d6000fd5b505050506040513d6020811015613e6e57600080fd5b5051905080613e7d83856137bc565b14613eb95760405162461bcd60e51b815260040180806020018281038252602f815260200180613fe6602f913960400191505060405180910390fd5b505050505050565b600a546001600160a01b031690565b600d546001600160a01b031690565b600c546001600160a01b031690565b604051806080016040528060006001600160a01b03168152602001600081526020016000815260200160008152509056fe526563656976657220646964206e6f74207265636569766520746f6b656e7320696e207472616e736665724f6e6c79206f6e6520726571756573742063616e20657869737420617420612074696d65526571756573746564206173736574206e6f7420696e206173736574206c6973744e6f2063616e63656c6c6174696f6e20636f6e646974696f6e20776173206d657453656e64657220646f6573206e6f74206861766520656e6f7567682073686172657320746f2066756c66696c6c2072657175657374526563656976657220646964206e6f74207265636569766520746f6b656e7320696e207472616e7366657246726f6d4e6f2076616c6964207265717565737420666f7220746869732061646472657373496e737566666963656e7420414d475520616e642f6f7220696e63656e74697665496e766573746d656e74206e6f7420616c6c6f77656420696e2074686973206173736574a2646970667358221220c8c881c31bf73e6260fa333441b2a86f898fe182daeacbdee21155d2d6683c2d64736f6c63430006010033

Deployed Bytecode Sourcemap

483:12567:16:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9426:219;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9426:219:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9426:219:16;;:::i;:::-;;6314:160;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6314:160:16;-1:-1:-1;;;;;6314:160:16;;:::i;566:130:0:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;566:130:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;566:130:0;-1:-1:-1;;;;;566:130:0;;:::i;190:23:15:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190:23:15;;;:::i;:::-;;;;;;;;;;;;;;;;;;12821:114:16;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12821:114:16;;;:::i;:::-;;;;-1:-1:-1;;;;;12821:114:16;;;;;;;;;;;;;;2388:111;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2388:111:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2388:111:16;;;;;;;;-1:-1:-1;5:28;;2:2;;;46:1;43;36:12;2:2;2388:111:16;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;2388:111:16;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;2388:111:16;;-1:-1:-1;2388:111:16;-1:-1:-1;2388:111:16;:::i;140:14:15:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;140:14:15;;;:::i;3260:504:16:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3260:504:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3260:504:16;-1:-1:-1;;;;;3260:504:16;;:::i;8439:656::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8439:656:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8439:656:16;;:::i;:::-;;;;;;;;;;;;;;;;1396:41;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1396:41:16;;;:::i;1443:46::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1443:46:16;;;:::i;2856:157::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2856:157:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2856:157:16;-1:-1:-1;;;;;2856:157:16;;:::i;1546:46::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1546:46:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1546:46:16;-1:-1:-1;;;;;1546:46:16;;:::i;1414:83:15:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1414:83:15;;;:::i;9852:2617:16:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9852:2617:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;9852:2617:16;;;;;;;;;;;;;;-1:-1:-1;5:28;;2:2;;;46:1;43;36:12;2:2;9852:2617:16;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;9852:2617:16;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;9852:2617:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;9852:2617:16;;-1:-1:-1;9852:2617:16;;-1:-1:-1;;;;;9852:2617:16:i;3770:1454::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3770:1454:16;;;;;;;;;;;-1:-1:-1;;;;;3770:1454:16;;:::i;12475:118::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12475:118:16;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;12475:118:16;;;;;;;;;;;;;;;;;1496:44;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1496:44:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1496:44:16;-1:-1:-1;;;;;1496:44:16;;:::i;:::-;;;;-1:-1:-1;;;;;1496:44:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;702:167:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;702:167:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;702:167:0;-1:-1:-1;;;;;702:167:0;;:::i;12940:108:16:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12940:108:16;;;:::i;6480:1953::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;6480:1953:16;-1:-1:-1;;;;;6480:1953:16;;:::i;6201:107::-;;;:::i;12708:108::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12708:108:16;;;:::i;433:26:0:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;433:26:0;;;:::i;160:24:15:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;160:24:15;;;:::i;:::-;;;;-1:-1:-1;;;;;160:24:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;160:24:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9222:143:16;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9222:143:16;;;:::i;605:532:15:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;605:532:15;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;605:532:15;:::i;397:30:0:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;397:30:0;;;:::i;12599:104:16:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12599:104:16;;;:::i;2737:113::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2737:113:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2737:113:16;-1:-1:-1;;;;;2737:113:16;;:::i;2505:226::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2505:226:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2505:226:16;;;;;;;;-1:-1:-1;5:28;;2:2;;;46:1;43;36:12;2:2;2505:226:16;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;2505:226:16;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;2505:226:16;;-1:-1:-1;2505:226:16;-1:-1:-1;2505:226:16;:::i;1598:44::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1598:44:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1598:44:16;-1:-1:-1;;;;;1598:44:16;;:::i;1689:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1689:36:16;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1689:36:16;;:::i;9426:219::-;9546:6;:17;9535:46;;;-1:-1:-1;;;9535:46:16;;;;9487:26;;-1:-1:-1;;;;;9546:17:16;;9535:44;;:46;;;;;9546:17;;9535:46;;;;;;;9546:17;9535:46;;;5:2:-1;;;;30:1;27;20:12;5:2;9535:46:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9535:46:16;;;;;;39:16:-1;36:1;17:17;2:54;101:4;9535:46:16;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;9535:46:16;;;;;;;;;;;;;-1:-1:-1;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;244:29;;325:2;307:21;;285:44;;282:59;-1:-1;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;9535:46:16;;421:4:-1;412:14;;;;9535:46:16;;;;;412:14:-1;9535:46:16;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;9535:46:16;;;;;;;;;;;9523:58;;9591:47;9613:13;9628:9;9591:21;:47::i;:::-;9426:219;;:::o;6314:160::-;6415:5;942:11:7;956:9;942:23;;6436:31:16::1;6454:12;6436:17;:31::i;:::-;986:12:7::0;1001:9;986:24;;1021:15;1047:8;:6;:8::i;:::-;-1:-1:-1;;;;;1039:30:7;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1039:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1039:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1039:32:7;;-1:-1:-1;1081:16:7;1100:71;1039:32;1141:20;1145:6;1153:7;1141:3;:20::i;:::-;1100:3;:71::i;:::-;1081:90;;1181:19;1212:10;:8;:10::i;:::-;-1:-1:-1;;;;;1203:32:7;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1203:34:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1203:34:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1203:34:7;;-1:-1:-1;1247:13:7;1276;:11;:13::i;:::-;-1:-1:-1;;;;;1263:43:7;;1320:11;1345:10;:8;:10::i;:::-;1263:127;;;-1:-1:-1;;;;;;1263:127:7;;;;;;;;;;;;;;-1:-1:-1;;;;;1263:127:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;1263:127:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1263:127:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1263:127:7;;-1:-1:-1;1400:20:7;1430:146;;;;1492:10;:8;:10::i;:::-;-1:-1:-1;;;;;1483:30:7;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1483:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1483:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1483:32:7;;-1:-1:-1;1430:146:7;;;-1:-1:-1;1564:1:7;1430:146;1619:30;1623:8;1633:15;1619:3;:30::i;:::-;1606:9;:43;;1585:123;;;;-1:-1:-1;;;1585:123:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1726:8;:6;:8::i;:::-;-1:-1:-1;;;;;1718:32:7;;1757:8;1718:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1718:50:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;1800:10:7;;-1:-1:-1;1800:151:7;;-1:-1:-1;1833:104:7;;-1:-1:-1;1858:24:7;;-1:-1:-1;1862:9:7;1873:8;1858:3;:24::i;:::-;1904:15;1833:3;:104::i;:::-;1800:151;;;;;;;;;;;;;;;;;;;;;1779:211;;;;;-1:-1:-1;;;1779:211:7;;;;;;;;;;;;-1:-1:-1;;;1779:211:7;;;;;;;;;;;;;;;2014:10;2005:69;2026:8;2036:20;2040:6;2048:7;2036:3;:20::i;:::-;2005:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;6314:160:16;;;;;;;;;:::o;566:130:0:-;907:33;920:10;-1:-1:-1;;;;;;932:7:0;;;907:12;:33::i;:::-;899:66;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;;;;642:5:::1;:14:::0;;-1:-1:-1;;;;;;642:14:0::1;-1:-1:-1::0;;;;;642:14:0;;::::1;::::0;;;::::1;::::0;;;;671:18:::1;::::0;683:5;::::1;::::0;671:18:::1;::::0;-1:-1:-1;;671:18:0::1;566:130:::0;:::o;190:23:15:-;;;;;;:::o;12821:114:16:-;12895:7;12913:19;:17;:19::i;:::-;12906:26;;12821:114;:::o;2388:111::-;907:33:0;920:10;-1:-1:-1;;;;;;932:7:0;;;907:12;:33::i;:::-;899:66;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;;;;2466:26:16::1;2484:7;;2466:26;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;2466:17:16::1;::::0;-1:-1:-1;;;2466:26:16:i:1;140:14:15:-:0;;;-1:-1:-1;;;;;140:14:15;;:::o;3260:504:16:-;3320:4;3336:24;3376:13;:11;:13::i;:::-;3336:54;;3400:29;3459:11;-1:-1:-1;;;;;3459:25:16;;:27;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3459:27:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3459:27:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3459:27:16;-1:-1:-1;;;;;3432:14:16;;;;;;:8;3459:27;3432:14;;;;:24;;;:54;;:110;;-1:-1:-1;3509:13:16;;3502:35;;;-1:-1:-1;;;3502:35:16;;;;-1:-1:-1;;;;;3509:13:16;;;;-1:-1:-1;;3509:13:16;3502:35;;;;;;;;;;;;;;3509:13;3502:35;;;5:2:-1;;;;30:1;27;20:12;5:2;3502:35:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3502:35:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;3502:35:16;:40;3432:110;3400:142;;3560:16;3571:4;3560:10;:16::i;:::-;:56;;;;;3592:24;3560:56;:96;;;;;3633:23;3651:4;3633:17;:23::i;:::-;3632:24;3560:96;:147;;;;-1:-1:-1;;;;;;3672:14:16;;3706:1;3672:14;;;:8;:14;;;;;-1:-1:-1;3672:31:16;;:35;;3560:147;:197;;;;-1:-1:-1;;;;;;3723:14:16;;3756:1;3723:14;;;:8;:14;;;;;:30;;;:34;;3560:197;3553:204;3260:504;-1:-1:-1;;;;3260:504:16:o;8439:656::-;8589:13;;;8652:17;;8641:52;;;-1:-1:-1;;;8641:52:16;;;;8523:27;;-1:-1:-1;;;;;8589:13:16;;;;8523:27;;8652:17;;;;;-1:-1:-1;;8641:52:16;;;;;;;;;;;8523:27;8652:17;8641:52;;;5:2:-1;;;;30:1;27;20:12;5:2;8641:52:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;8641:52:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;8641:52:16;9008:20;;;-1:-1:-1;;;9008:20:16;;;;8641:52;;-1:-1:-1;8899:26:16;;9004:46;;-1:-1:-1;;;;;9008:18:16;;;-1:-1:-1;;9008:20:16;;;;;8641:52;;9008:20;;;;;;;;:18;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;9008:20:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9008:20:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9008:20:16;9030:19;9004:3;:46::i;:::-;8928:73;8945:19;8978:13;8928:3;:73::i;:::-;:122;;;;;;;8439:656;-1:-1:-1;;;;;8439:656:16:o;1396:41::-;1435:2;1396:41;:::o;1443:46::-;1483:6;1443:46;:::o;2856:157::-;-1:-1:-1;;;;;2963:14:16;;2918:4;2963:14;;;:8;:14;;;;;:24;;;2959:47;;1483:6;2959:3;:47::i;:::-;2941:15;:65;;2856:157;-1:-1:-1;;2856:157:16:o;1546:46::-;;;;;;;;;;;;;;;:::o;1414:83:15:-;1480:14;;-1:-1:-1;;;;;1480:14:15;;1414:83::o;9852:2617:16:-;9977:13;;10022:28;;;-1:-1:-1;;;10022:28:16;;10039:10;9977:13;10022:28;;;;;-1:-1:-1;;;;;9977:13:16;;;;10054;;9977;;-1:-1:-1;;10022:28:16;;;;;;;;;;;;;;;9977:13;10022:28;;;5:2:-1;;;;30:1;27;20:12;5:2;10022:28:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10022:28:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10022:28:16;:45;;;;:93;;-1:-1:-1;10083:28:16;;;-1:-1:-1;;;10083:28:16;;10100:10;10083:28;;;;;;-1:-1:-1;;;;;;;10083:16:16;;;-1:-1:-1;;10083:28:16;;;;;;;;;;;;;;;:16;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;10083:28:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10083:28:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10083:28:16;:32;10022:93;10001:193;;;;-1:-1:-1;;;10001:193:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10205:24;10273:13;:11;:13::i;:::-;10260:59;;-1:-1:-1;;;10260:59:16;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10260:42:16;;;;;;;10303:15;;10260:59;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;10260:59:16;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10260:59:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10260:59:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10260:59:16;:102;;;;-1:-1:-1;10349:3:16;;:13;;;-1:-1:-1;;;10349:13:16;;;;-1:-1:-1;;;;;10349:3:16;;;;:11;;:13;;;;;;;;;;;;;;;:3;:13;;;5:2:-1;;;;30:1;27;20:12;5:2;10349:13:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10349:13:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10349:13:16;-1:-1:-1;;;;;10335:27:16;:10;:27;;10260:102;10243:409;;;10398:17;;;10387:51;;;-1:-1:-1;;;10387:51:16;;;;-1:-1:-1;;;;;10398:17:16;;;;10387:49;;:51;;;;10398:17;;10387:51;;;;;;10398:17;;10387:51;;;5:2:-1;;;;30:1;27;20:12;5:2;10387:51:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10387:51:16;;;;10474:37;10497:13;10474:22;:37::i;:::-;10525:50;;;-1:-1:-1;;;10525:50:16;;10543:10;10525:50;;;;;;;;;;;;;;-1:-1:-1;;;;;;10525:17:16;;;;;:50;;;;;-1:-1:-1;;10525:50:16;;;;;;;;-1:-1:-1;10525:17:16;:50;;;5:2:-1;;;;30:1;27;20:12;5:2;10525:50:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;10606:3:16;;:13;;;-1:-1:-1;;;10606:13:16;;;;-1:-1:-1;;;;;10589:16:16;;;;-1:-1:-1;10589:16:16;;-1:-1:-1;10606:3:16;;;;:11;;:13;;;;;;;;;;;;;;;:3;:13;;;5:2:-1;;;;30:1;27;20:12;5:2;10606:13:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10606:13:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;10606:13:16;10589:52;;;-1:-1:-1;10589:52:16;;;-1:-1:-1;;;;;;10589:52:16;;;-1:-1:-1;;;;;10589:52:16;;;;;;;;;;;;;;;;;;;-1:-1:-1;;10589:52:16;;;;;;;-1:-1:-1;10589:52:16;;;;5:2:-1;;;;30:1;27;20:12;5:2;10589:52:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10589:52:16;;;;10243:409;10661:27;10691:39;10695:13;10710:19;10691:3;:39::i;:::-;10661:69;;10741:15;10766:33;10813:15;:22;10802:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;10802:34:16;;10766:70;;10846:31;10894:15;:22;10880:37;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;10880:37:16;-1:-1:-1;11014:6:16;:17;10846:71;;-1:-1:-1;;;;;;11014:17:16;10979:21;11042:792;11063:15;:22;11059:1;:26;11042:792;;;11116:15;11132:1;11116:18;;;;;;;;;;;;;;;;;;;11173:33;;;-1:-1:-1;;;11173:33:16;;-1:-1:-1;;;;;11173:33:16;;;;;;;;;11116:18;;-1:-1:-1;11173:24:16;;;;;;:33;;;;;;;;;;:24;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;11173:33:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11173:33:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11173:33:16;11148:125;;;;-1:-1:-1;;;11148:125:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11292:6;11287:212;11308:14;:21;11304:1;:25;11287:212;;;11394:14;11409:1;11394:17;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;11383:28:16;;;;;;;11354:130;;;;;-1:-1:-1;;;11354:130:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;11331:3;;11287:212;;;;11532:7;11512:14;11527:1;11512:17;;;;;;;;-1:-1:-1;;;;;11512:27:16;;;:17;;;;;;;;;;:27;;;;11573:33;;;-1:-1:-1;;;11573:33:16;;;;;;;;;;;-1:-1:-1;;11573:24:16;;;-1:-1:-1;;11573:33:16;;;;;;;;;;;-1:-1:-1;11573:24:16;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;11573:33:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11573:33:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11573:33:16;;-1:-1:-1;11624:17:16;11620:31;;11643:8;;;11620:31;11803:6;-1:-1:-1;;;;;11803:18:16;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11803:20:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11803:20:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11803:20:16;11759:41;11763:12;11777:22;11759:3;:41::i;:::-;:64;;;;;;11734:19;11754:1;11734:22;;;;;;;;;;;;;:89;;;;;11042:792;;11087:3;;11042:792;;;-1:-1:-1;11844:53:16;;;-1:-1:-1;;;11844:53:16;;11862:10;11844:53;;;;;;;;;;;;-1:-1:-1;;;;;11844:17:16;;;;;:53;;;;;-1:-1:-1;;11844:53:16;;;;;;;-1:-1:-1;11844:17:16;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;11844:53:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;11946:6:16;;-1:-1:-1;;;11941:365:16;11962:15;:22;11958:1;:26;11941:365;;;12015:15;12031:1;12015:18;;;;;;;;;;;;;;12005:28;;12051:19;12071:1;12051:22;;;;;;;;;;;;;;12077:1;12051:27;12047:249;;;12098:8;;12047:249;12151:12;;12183:22;;-1:-1:-1;;;;;12151:12:16;;;;12145:28;;12174:7;;12183:22;;12203:1;;12183:22;;;;;;;;;;;;12145:61;;;;;;;;;;;;;-1:-1:-1;;;;;12145:61:16;-1:-1:-1;;;;;12145:61:16;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12145:61:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;12145:61:16;;;;12224:57;12237:7;12246:10;12258:19;12278:1;12258:22;;;;;;;;;;;;;;12224:12;:57::i;:::-;11986:3;;11941:365;;;;12344:10;-1:-1:-1;;;;;12320:142:16;;12368:15;12397:19;12430:22;12320:142;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;12320:142:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;12320:142:16;;;;;;;;;;;;;;;;;;;;9852:2617;;;;;;;;;:::o;3770:1454::-;376:3:15;;:16;;;-1:-1:-1;;;;;;376:16:15;;;;-1:-1:-1;;;;;376:3:15;;;;:14;;:16;;;;;;;;;;;;;;;:3;:16;;;5:2:-1;;;;30:1;27;20:12;5:2;376:16:15;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;376:16:15;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;376:16:15;375:17;367:46;;;;;-1:-1:-1;;;367:46:15;;;;;;;;;;;;-1:-1:-1;;;367:46:15;;;;;;;;;;;;;;;3970:4:16::1;942:11:7;956:9;265:11:15::2;::::0;942:23:7;;-1:-1:-1;265:11:15::2;;257:53;;;::::0;;-1:-1:-1;;;257:53:15;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;4028:20:16::0;;4014:222:::3;::::0;;::::3;::::0;;::::3;::::0;;4097:10:::3;4014:222:::0;;-1:-1:-1;4014:222:16::3;::::0;;::::3;::::0;;;;;;;;;-1:-1:-1;;;;;4014:222:16;;::::3;::::0;;;;;;;;;;;;;;;;;;::::3;::::0;;;;;;;::::3;::::0;;;;;;;;;;;-1:-1:-1;;;4014:222:16;;4075:7;::::3;-1:-1:-1::0;;;;;;4075:7:16::3;4014:222;::::0;::::3;::::0;;;4028:20;;;::::3;::::0;-1:-1:-1;;4075:7:16;;4014:222;;;-1:-1:-1;4014:222:16;;;;;;;;;;-1:-1:-1;8:100:::3;33:3;30:1;27:10;8:100;;;90:11:::0;;::::3;84:18:::0;71:11;;::::3;64:39:::0;52:2:::3;45:10;8:100;;;12:14;4014:222:16;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11:::0;;::::3;84:18:::0;71:11;;::::3;64:39:::0;52:2:::3;45:10;8:100;;;12:14;4014:222:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::3;5:2;4014:222:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::3;77:16;74:1;67:27;5:2;-1:-1:::0;;;;;;;;;4267:30:16;::::3;;::::0;;;:13:::3;:30;::::0;;;;;::::3;;4246:113;;;;-1:-1:-1::0;;;4246:113:16::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4369:100;4399:15;4416:10;4436:4;4443:16;4369;:100::i;:::-;4509:10;4500:20;::::0;;;:8:::3;:20;::::0;;;;:30:::3;;::::0;:35;4479:118:::3;;;;-1:-1:-1::0;;;4479:118:16::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4630:199;::::0;;::::3;::::0;;::::3;::::0;;-1:-1:-1;;;;;4630:199:16;;::::3;::::0;;;::::3;::::0;;::::3;::::0;;;;;;;;;4803:15:::3;4630:199:::0;;;;;;;4616:10:::3;-1:-1:-1::0;4607:20:16;;;:8:::3;:20:::0;;;;;:222;;;;-1:-1:-1;;;;;;4607:222:16::3;::::0;;::::3;;::::0;;;;-1:-1:-1;4607:222:16;::::3;::::0;;;::::3;::::0;::::3;::::0;;;::::3;::::0;;::::3;::::0;;;;4853:20;;4839:223;;-1:-1:-1;4839:223:16;;::::3;::::0;;;;;;;::::3;::::0;;;;;;;;;;;;;;;;;;;;;;;;;;::::3;::::0;;;;;;;::::3;::::0;;;;;;;;;;;-1:-1:-1;;;4839:223:16;;4901:7;::::3;-1:-1:-1::0;;;;;;4901:7:16::3;4839:223;::::0;::::3;::::0;;;4853:20;;;::::3;::::0;4839:48:::3;::::0;4901:7;;4839:223;;;-1:-1:-1;;4839:223:16;;;;;;;-1:-1:-1;4839:223:16;;-1:-1:-1;8:100:::3;33:3;30:1;27:10;8:100;;;90:11:::0;;::::3;84:18:::0;71:11;;::::3;64:39:::0;52:2:::3;45:10;8:100;;;12:14;4839:223:16;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11:::0;;::::3;84:18:::0;71:11;;::::3;64:39:::0;52:2:::3;45:10;8:100;;;12:14;4839:223:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::3;5:2;4839:223:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::3;77:16;74:1;67:27;5:2;-1:-1:::0;;5078:139:16::3;::::0;;;;;::::3;::::0;::::3;::::0;;;;;-1:-1:-1;;;;;5078:139:16;::::3;::::0;-1:-1:-1;5109:10:16::3;::::0;-1:-1:-1;5078:139:16::3;::::0;;;;;;;;;::::3;986:12:7::1;1001:9;986:24;;1021:15;1047:8;:6;:8::i;:::-;-1:-1:-1::0;;;;;1039:30:7::1;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::1;5:2;1039:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;1039:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::1;2:2;-1:-1:::0;1039:32:7;;-1:-1:-1;1081:16:7::1;1100:71;1039:32:::0;1141:20:::1;1145:6:::0;1153:7;1141:3:::1;:20::i;1100:71::-;1081:90;;1181:19;1212:10;:8;:10::i;:::-;-1:-1:-1::0;;;;;1203:32:7::1;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::1;5:2;1203:34:7;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;1203:34:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::1;2:2;-1:-1:::0;1203:34:7;;-1:-1:-1;1247:13:7::1;1276;:11;:13::i;:::-;-1:-1:-1::0;;;;;1263:43:7::1;;1320:11:::0;1345:10:::1;:8;:10::i;:::-;1263:127;::::0;;-1:-1:-1;;;;;;1263:127:7::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;1263:127:7;;::::1;::::0;;;;;;::::1;::::0;;;;;;;;;;::::1;::::0;;;;;;;;;;::::1;;5:2:-1::0;::::1;;;30:1;27::::0;20:12:::1;5:2;1263:127:7;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;1263:127:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::1;2:2;-1:-1:::0;1263:127:7;;-1:-1:-1;1400:20:7::1;1430:146:::0;::::1;;;1492:10;:8;:10::i;:::-;-1:-1:-1::0;;;;;1483:30:7::1;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::1;5:2;1483:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;1483:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::1;2:2;-1:-1:::0;1483:32:7;;-1:-1:-1;1430:146:7::1;;;-1:-1:-1::0;1564:1:7::1;1430:146;1619:30;1623:8;1633:15;1619:3;:30::i;:::-;1606:9;:43;;1585:123;;;;-1:-1:-1::0;;;1585:123:7::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1726:8;:6;:8::i;:::-;-1:-1:-1::0;;;;;1718:32:7::1;;1757:8;1718:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::1;5:2;1718:50:7;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;-1:-1:::0;1800:10:7::1;::::0;-1:-1:-1;1800:151:7::1;::::0;-1:-1:-1;1833:104:7::1;::::0;-1:-1:-1;1858:24:7::1;::::0;-1:-1:-1;1862:9:7::1;1873:8:::0;1858:3:::1;:24::i;1833:104::-;1800:151;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;::::1;;;;;;1779:211;;;::::0;;-1:-1:-1;;;1779:211:7;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;1779:211:7;;;;;;;;;;;;;::::1;;2014:10;2005:69;2026:8:::0;2036:20:::1;2040:6:::0;2048:7;2036:3:::1;:20::i;:::-;2005:69;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;;;;;;::::1;423:1:15;;;;;;;;3770:1454:16::0;;;:::o;12475:118::-;12532:16;12567:19;12560:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;12560:26:16;;;-1:-1:-1;12560:26:16;;;;;;;;;;;;;;;;;;;12475:118;:::o;1496:44::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1496:44:16;;;;;;;:::o;702:167:0:-;907:33;920:10;-1:-1:-1;;;;;;932:7:0;;;907:12;:33::i;:::-;899:66;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;;;;790:9:::1;:22:::0;;-1:-1:-1;;;;;;790:22:0::1;-1:-1:-1::0;;;;;790:22:0;;::::1;::::0;;;::::1;::::0;;;827:35:::1;::::0;851:9;::::1;::::0;827:35:::1;::::0;::::1;702:167:::0;:::o;12940:108:16:-;13011:7;13029:16;:14;:16::i;6480:1953::-;376:3:15;;:16;;;-1:-1:-1;;;;;;376:16:15;;;;-1:-1:-1;;;;;376:3:15;;;;:14;;:16;;;;;;;;;;;;;;;:3;:16;;;5:2:-1;;;;30:1;27;20:12;5:2;376:16:15;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;376:16:15;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;376:16:15;375:17;367:46;;;;;-1:-1:-1;;;367:46:15;;;;;;;;;;;;-1:-1:-1;;;367:46:15;;;;;;;;;;;;;;;6586:5:16::1;942:11:7::0;956:9:::1;942:23;;6623:22:16::2;;:::i;:::-;-1:-1:-1::0;;;;;;6648:22:16;;::::2;;::::0;;;:8:::2;:22;::::0;;;;;;;;6623:47;;::::2;::::0;::::2;::::0;;;;;;::::2;::::0;;-1:-1:-1;6623:47:16;::::2;::::0;;;::::2;::::0;;;;::::2;::::0;::::2;::::0;;;;;;;;::::2;;::::0;;;;;6701:29:::2;6648:22:::0;6701:15:::2;:29::i;:::-;6680:109;;;;-1:-1:-1::0;;;6680:109:16::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6811:17:::0;;;6800:51:::2;::::0;;-1:-1:-1;;;6800:51:16;;;;-1:-1:-1;;;;;6811:17:16;;::::2;::::0;6800:49:::2;::::0;:51;;::::2;::::0;6811:17:::2;::::0;6800:51;;;;;;6811:17;;6800:51;::::2;;5:2:-1::0;::::2;;;30:1;27::::0;20:12:::2;5:2;6800:51:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;;6912:6:16::2;:17:::0;6981:23:::2;::::0;;::::2;::::0;7022;;6901:158;;-1:-1:-1;;;6901:158:16;;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;;;6901:158:16;;::::2;::::0;;;;;;-1:-1:-1;;;6912:17:16;;;::::2;::::0;-1:-1:-1;;;6901:158:16;;;;;::::2;::::0;;;;;;;;;-1:-1:-1;6912:17:16;6901:158;::::2;;5:2:-1::0;::::2;;;30:1;27::::0;20:12:::2;5:2;6901:158:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;6901:158:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::2;2:2;-1:-1:::0;6901:158:16;::::2;7126:24:::0;::::2;::::0;6901:158;;-1:-1:-1;7091:59:16;::::2;;7070:129;;;::::0;;-1:-1:-1;;;7070:129:16;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;7296:23:::0;;7333:12;;7270:130:::2;::::0;7296:23;-1:-1:-1;;;;;7333:12:16::2;7359:31:::0;7270:12:::2;:130::i;:::-;7411:26;7440:96;7457:7;:24;;;7495:31;7440:3;:96::i;:::-;7411:125:::0;-1:-1:-1;7609:25:16;;7605:192:::2;;7680:23:::0;;7650:136:::2;::::0;7721:12;7751:21;7650:12:::2;:136::i;:::-;7836:15:::0;;7827:37:::2;::::0;;-1:-1:-1;;;7827:37:16;;;;7807:10:::2;::::0;:58:::2;::::0;-1:-1:-1;;;;;7836:15:16;;::::2;::::0;7827:35:::2;::::0;:37:::2;::::0;;::::2;::::0;::::2;::::0;;;;;;;;;7836:15;7827:37;::::2;;5:2:-1::0;::::2;;;30:1;27::::0;20:12:::2;5:2;7827:37:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;7827:37:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26::::0;19:12:::2;2:2;-1:-1:::0;7827:37:16;7807:58:::2;::::0;;::::2;::::0;;::::2;::::0;::::2;::::0;;;7827:37;7807:58;;::::2;;;;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;7883:13:16;;7922:23:::2;::::0;;::::2;::::0;7876:70;;-1:-1:-1;;;7876:70:16;;-1:-1:-1;;;;;7876:70:16;;::::2;7883:13;7876:70:::0;::::2;::::0;;;;;;;;;;7883:13;::::2;::::0;7876:31:::2;::::0;:70;;;;;-1:-1:-1;;7876:70:16;;;;;;;;-1:-1:-1;7883:13:16;7876:70;::::2;;5:2:-1::0;::::2;;;30:1;27::::0;20:12:::2;5:2;7876:70:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;;7967:6:16::2;:17:::0;8008:23;;7956:76:::2;::::0;;-1:-1:-1;;;7956:76:16;;-1:-1:-1;;;;;7956:76:16;;::::2;;::::0;::::2;::::0;;;7967:17;;;::::2;::::0;-1:-1:-1;7956:51:16::2;::::0;-1:-1:-1;7956:76:16;;;;;-1:-1:-1;;7956:76:16;;;;;;;-1:-1:-1;7967:17:16;7956:76;::::2;;5:2:-1::0;::::2;;;30:1;27::::0;20:12:::2;5:2;7956:76:16;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;;;;;;;;;8048:25:16;::::2;;::::0;;;:11:::2;:25;::::0;;;;;::::2;;8043:141;;-1:-1:-1::0;;;;;8089:25:16;::::2;;::::0;;;:11:::2;:25;::::0;;;;:32;;-1:-1:-1;;8089:32:16::2;-1:-1:-1::0;8089:32:16;;::::2;::::0;;;8135:19:::2;27:10:-1::0;;23:18;;::::2;45:23:::0;;8135:38:16;;;;::::2;::::0;;-1:-1:-1;;;;;;8135:38:16::2;::::0;;::::2;::::0;;8043:141:::2;8279:23:::0;;8316:24:::2;::::0;;::::2;::::0;8354:23:::2;::::0;;::::2;::::0;8199:188;;;;;;;::::2;::::0;;;;;;-1:-1:-1;;;;;8199:188:16;;::::2;::::0;8255:10:::2;::::0;8199:188;;::::2;::::0;::::2;::::0;;;;;;;;;::::2;-1:-1:-1::0;;;;;;;;8404:22:16;::::2;;::::0;;;:8:::2;:22;::::0;;;;8397:29;;-1:-1:-1;;;;;;8397:29:16::2;::::0;;-1:-1:-1;8397:29:16;::::2;::::0;;;::::2;::::0;::::2;::::0;;;::::2;;::::0;;;1001:9:7::1;986:24;;1021:15;1047:8;:6;:8::i;6201:107:16:-:0;6255:5;942:11:7;956:9;942:23;;6272:29:16::1;6290:10;6272:17;:29::i;:::-;986:12:7::0;1001:9;986:24;;1021:15;1047:8;:6;:8::i;:::-;-1:-1:-1;;;;;1039:30:7;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1039:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1039:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1039:32:7;;-1:-1:-1;1081:16:7;1100:71;1039:32;1141:20;1145:6;1153:7;1141:3;:20::i;1100:71::-;1081:90;;1181:19;1212:10;:8;:10::i;:::-;-1:-1:-1;;;;;1203:32:7;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1203:34:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1203:34:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1203:34:7;;-1:-1:-1;1247:13:7;1276;:11;:13::i;:::-;-1:-1:-1;;;;;1263:43:7;;1320:11;1345:10;:8;:10::i;:::-;1263:127;;;-1:-1:-1;;;;;;1263:127:7;;;;;;;;;;;;;;-1:-1:-1;;;;;1263:127:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;1263:127:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1263:127:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1263:127:7;;-1:-1:-1;1400:20:7;1430:146;;;;1492:10;:8;:10::i;:::-;-1:-1:-1;;;;;1483:30:7;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1483:32:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1483:32:7;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1483:32:7;;-1:-1:-1;1430:146:7;;;-1:-1:-1;1564:1:7;1430:146;1619:30;1623:8;1633:15;1619:3;:30::i;:::-;1606:9;:43;;1585:123;;;;-1:-1:-1;;;1585:123:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1726:8;:6;:8::i;:::-;-1:-1:-1;;;;;1718:32:7;;1757:8;1718:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1718:50:7;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;1800:10:7;;-1:-1:-1;1800:151:7;;-1:-1:-1;1833:104:7;;-1:-1:-1;1858:24:7;;-1:-1:-1;1862:9:7;1873:8;1858:3;:24::i;1833:104::-;1800:151;;;;;;;;;;;;;;;;;;;;;1779:211;;;;;-1:-1:-1;;;1779:211:7;;;;;;;;;;;;-1:-1:-1;;;1779:211:7;;;;;;;;;;;;;;;2014:10;2005:69;2026:8;2036:20;2040:6;2048:7;2036:3;:20::i;:::-;2005:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;6201:107:16;;;;;;;;:::o;12708:108::-;12779:7;12797:16;:14;:16::i;433:26:0:-;;;-1:-1:-1;;;;;433:26:0;;:::o;160:24:15:-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;160:24:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;9222:143:16:-;9285:13;;9278:43;;;-1:-1:-1;;;9278:43:16;;9310:10;9285:13;9278:43;;;;;-1:-1:-1;;;;;;;9285:13:16;;-1:-1:-1;;9278:43:16;;;;;;;;;;;;;;9285:13;9278:43;;;5:2:-1;;;;30:1;27;20:12;5:2;9278:43:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9278:43:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;9278:43:16;;-1:-1:-1;9331:27:16;9278:43;9331:14;:27::i;:::-;9222:143;:::o;605:532:15:-;907:33:0;920:10;-1:-1:-1;;;;;;932:7:0;;;907:12;:33::i;:::-;899:66;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;;;;709:3:15::1;::::0;-1:-1:-1;;;;;709:3:15::1;687:10;:26;679:35;;;::::0;::::1;;733:11;::::0;::::1;;732:12;724:44;;;::::0;;-1:-1:-1;;;724:44:15;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;724:44:15;;;;;;;;;;;;;::::1;;787:285;::::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;;;;;811:10:15;::::1;::::0;::::1;787:285:::0;;;811:10:::1;835::::0;;::::1;;::::0;::::1;787:285:::0;;::::1;::::0;;;859:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;883:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;907:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;931:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;955:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;979:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;1003:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;1027:10;;::::1;;::::0;::::1;787:285:::0;;;;;;;1051:11;;::::1;;::::0;;::::1;787:285:::0;;;;;;;778:6:::1;:294:::0;;-1:-1:-1;;;;;;778:294:15;;::::1;::::0;;::::1;::::0;;915:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;;939:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;;963:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;;987:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;;1011:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;1035:1:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;1059:2:::1;778:294:::0;;;::::1;::::0;;::::1;::::0;;;;;;;::::1;::::0;;::::1;::::0;;;;;;;::::1;::::0;;::::1;::::0;;;;;;;;::::1;;::::0;;1082:11:::1;:18:::0;;-1:-1:-1;;1082:18:15::1;-1:-1:-1::0;1082:18:15::1;::::0;;1110:20:::1;-1:-1:-1::0;1110:8:15::1;:20::i;397:30:0:-:0;;;-1:-1:-1;;;;;397:30:0;;:::o;12599:104:16:-;12668:7;12686:14;:12;:14::i;2737:113::-;-1:-1:-1;;;;;2815:14:16;2792:4;2815:14;;;:8;:14;;;;;:24;;;:28;;;2737:113::o;2505:226::-;907:33:0;920:10;-1:-1:-1;;;;;;932:7:0;;;907:12;:33::i;:::-;899:66;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;-1:-1:-1;;;899:66:0;;;;;;;;;;;;;;;2589:6:16::1;2584:100;2601:18:::0;;::::1;2584:100;;;2668:5;2640:13;:25;2654:7;;2662:1;2654:10;;;;;;;;::::0;;::::1;::::0;;;::::1;;-1:-1:-1::0;;;;;2654:10:16::1;2640:25:::0;;-1:-1:-1;2640:25:16;::::1;::::0;;;;;;-1:-1:-1;2640:25:16;:33;;-1:-1:-1;;2640:33:16::1;::::0;::::1;;::::0;;;::::1;::::0;;-1:-1:-1;2621:3:16::1;2584:100;;;;2698:26;2716:7;;2698:26;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;;::::1;74:27:::0;2698:26:16::1;::::0;137:4:-1::1;117:14:::0;;::::1;-1:-1:::0;;113:30:::1;157:16:::0;;::::1;2698:26:16::0;;::::1;::::0;-1:-1:-1;2698:26:16;;-1:-1:-1;;;;2698:26:16::1;2505:226:::0;;:::o;1598:44::-;;;;;;;;;;;;;;;:::o;1689:36::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1689:36:16;;-1:-1:-1;1689:36:16;:::o;5230:827::-;5306:24;5317:12;5306:10;:24::i;:::-;5298:57;;;;;-1:-1:-1;;;5298:57:16;;;;;;;;;;;;-1:-1:-1;;;5298:57:16;;;;;;;;;;;;;;;5365:24;5405:13;:11;:13::i;:::-;5365:54;;5429:22;;:::i;:::-;-1:-1:-1;;;;;;5454:22:16;;;;;;;:8;:22;;;;;;;;;5429:47;;;;;;;;;;;;;;-1:-1:-1;5429:47:16;;;;;;;;;;;;;;;;;;;;;;;;5508:50;;-1:-1:-1;;;5508:50:16;;;;;;;;;;;5429:47;;5508:25;;;-1:-1:-1;;5508:50:16;;;;;5454:22;;5508:50;;;;;;:25;:50;;;5:2:-1;;;;30:1;27;20:12;5:2;5508:50:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5508:50:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5508:50:16;5507:51;;:98;;;5574:31;5592:12;5574:17;:31::i;:::-;5507:130;;;-1:-1:-1;5621:3:16;;:16;;;-1:-1:-1;;;;;;5621:16:16;;;;-1:-1:-1;;;;;5621:3:16;;;;:14;;:16;;;;;;;;;;;;;;;:3;:16;;;5:2:-1;;;;30:1;27;20:12;5:2;5621:16:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5621:16:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5621:16:16;5507:130;5486:210;;;;-1:-1:-1;;;5486:210:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5738:23;;5796:24;;;;;-1:-1:-1;;;;;5837:22:16;;;5706;5837;;;:8;:22;;;;;;5830:29;;-1:-1:-1;;;;;;5830:29:16;;;-1:-1:-1;5830:29:16;;;;;;;;;;;;;;;;;5898:15;;5889:37;;-1:-1:-1;;;5889:37:16;;;;5796:24;;5869:10;;:58;;5898:15;;;;;5889:35;;:37;;;;;5796:24;5889:37;;;;;5898:15;5889:37;;;5:2:-1;;;;30:1;27;20:12;5:2;5889:37:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5889:37:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;5889:37:16;5869:58;;;;;;;;;;;;5889:37;5869:58;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5869:58:16;5937:70;5958:15;5976:12;5990:16;5937:12;:70::i;:::-;6023:27;;-1:-1:-1;;;;;6023:27:16;;;;;;;;5230:827;;;;;:::o;877:127:2:-;960:5;;;955:16;;;;947:50;;;;;-1:-1:-1;;;947:50:2;;;;;;;;;;;;-1:-1:-1;;;947:50:2;;;;;;;;;;;;;;;877:127;;;;:::o;1009:140::-;1061:6;1087;;;:30;;-1:-1:-1;;1102:5:2;;;1116:1;1111;1102:5;1111:1;1097:15;;;;;:20;1087:30;1079:63;;;;;-1:-1:-1;;;1079:63:2;;;;;;;;;;;;-1:-1:-1;;;1079:63:2;;;;;;;;;;;;;;746:126;829:5;;;824:16;;;;816:49;;;;;-1:-1:-1;;;816:49:2;;;;;;;;;;;;-1:-1:-1;;;816:49:2;;;;;;;;;;;;;;989:370:0;1059:4;1094;-1:-1:-1;;;;;1079:20:0;;;1075:278;;;-1:-1:-1;1122:4:0;1115:11;;1075:278;1154:5;;-1:-1:-1;;;;;1147:12:0;;;1154:5;;1147:12;1143:210;;;-1:-1:-1;1182:4:0;1175:11;;1143:210;1232:1;1207:9;-1:-1:-1;;;;;1207:9:0;1203:150;;-1:-1:-1;1257:5:0;1250:12;;1203:150;1300:9;;:42;;;-1:-1:-1;;;1300:42:0;;-1:-1:-1;;;;;1300:42:0;;;;;;;1331:4;1300:42;;;;-1:-1:-1;;;;;;1300:42:0;;;;;;;;:9;;;;;-1:-1:-1;;1300:42:0;;;;;;;;;;;;;;:9;:42;;;5:2:-1;;;;30:1;27;20:12;5:2;1300:42:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1300:42:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1300:42:0;;-1:-1:-1;1293:49:0;;1319:90:15;1389:3;;:17;;;-1:-1:-1;;;1389:17:15;;;;1371:7;;-1:-1:-1;;;;;1389:3:15;;-1:-1:-1;;1389:17:15;;;;;;;;;;;;;;:3;:17;;;5:2:-1;;;;30:1;27;20:12;5:2;1389:17:15;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1389:17:15;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1389:17:15;;-1:-1:-1;1319:90:15;:::o;2017:365:16:-;2094:6;2089:247;2110:7;:14;2106:1;:18;2089:247;;;2179:15;;2214:10;;-1:-1:-1;;;;;2179:15:16;;;;2170:43;;2214:10;;2222:1;;2214:10;;;;;;;;;;;;;;;;;2170:55;;;-1:-1:-1;;;;;;2170:55:16;;;;;;;-1:-1:-1;;;;;2170:55:16;;;;;;;;;;;;;2214:10;2170:55;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;2170:55:16;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2170:55:16;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;2170:55:16;2145:134;;;;;-1:-1:-1;;;2145:134:16;;;;;;;;;;;;-1:-1:-1;;;2145:134:16;;;;;;;;;;;;;;;2321:4;2293:13;:25;2307:7;2315:1;2307:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2293:25:16;;;;;;;;;;;-1:-1:-1;2293:25:16;:32;;-1:-1:-1;;2293:32:16;;;;;;;;;;-1:-1:-1;2126:3:16;2089:247;;;;2350:25;2367:7;2350:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;2350:25:16;;;;;;;;;;;;;;;;;2017:365;:::o;162:441:4:-;301:29;;;-1:-1:-1;;;301:29:4;;-1:-1:-1;;;;;301:29:4;;;;;;;;;275:23;;301:24;;;;;:29;;;;;;;;;;;;;;:24;:29;;;5:2:-1;;;;30:1;27;20:12;5:2;301:29:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;301:29:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;301:29:4;340:36;;;-1:-1:-1;;;340:36:4;;-1:-1:-1;;;;;340:36:4;;;;;;;;;;;;;;;301:29;;-1:-1:-1;340:23:4;;;;-1:-1:-1;;340:36:4;;;;;301:29;;340:36;;;;;;;;-1:-1:-1;340:23:4;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;340:36:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;340:36:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;413:29:4;;;-1:-1:-1;;;413:29:4;;-1:-1:-1;;;;;413:29:4;;;;;;;;;-1:-1:-1;;413:24:4;;;-1:-1:-1;;413:29:4;;;;;340:36;;413:29;;;;;;;:24;:29;;;5:2:-1;;;;30:1;27;20:12;5:2;413:29:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;413:29:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;413:29:4;;-1:-1:-1;413:29:4;473:31;477:18;497:6;473:3;:31::i;:::-;:54;452:144;;;;-1:-1:-1;;;452:144:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;162:441;;;;;:::o;609:483::-;775:29;;;-1:-1:-1;;;775:29:4;;-1:-1:-1;;;;;775:29:4;;;;;;;;;749:23;;775:24;;;;;:29;;;;;;;;;;;;;;:24;:29;;;5:2:-1;;;;30:1;27;20:12;5:2;775:29:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;775:29:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;775:29:4;814:47;;;-1:-1:-1;;;814:47:4;;-1:-1:-1;;;;;814:47:4;;;;;;;;;;;;;;;;;;;;;;775:29;;-1:-1:-1;814:27:4;;;;-1:-1:-1;;814:47:4;;;;;775:29;;814:47;;;;;;;;-1:-1:-1;814:27:4;:47;;;5:2:-1;;;;30:1;27;20:12;5:2;814:47:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;814:47:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;898:29:4;;;-1:-1:-1;;;898:29:4;;-1:-1:-1;;;;;898:29:4;;;;;;;;;-1:-1:-1;;898:24:4;;;-1:-1:-1;;898:29:4;;;;;814:47;;898:29;;;;;;;:24;:29;;;5:2:-1;;;;30:1;27;20:12;5:2;898:29:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;898:29:4;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;898:29:4;;-1:-1:-1;898:29:4;958:31;962:18;982:6;958:3;:31::i;:::-;:54;937:148;;;;-1:-1:-1;;;937:148:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;609:483;;;;;;:::o;1502:85:15:-;1569:15;;-1:-1:-1;;;;;1569:15:15;;1502:85::o;1229:::-;1296:15;;-1:-1:-1;;;;;1296:15:15;;1229:85::o;1143:81::-;1208:13;;-1:-1:-1;;;;;1208:13:15;;1143:81::o;483:12567:16:-;;;;;;;;;-1:-1:-1;483:12567:16;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://c8c881c31bf73e6260fa333441b2a86f898fe182daeacbdee21155d2d6683c2d

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.