Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 97 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Complete Setup | 9481280 | 1538 days ago | IN | 0 ETH | 0.02248016 | ||||
Create Vault | 9481277 | 1538 days ago | IN | 0 ETH | 0.00702146 | ||||
Create Trading | 9481274 | 1538 days ago | IN | 0 ETH | 0.03506048 | ||||
Create Shares | 9481269 | 1538 days ago | IN | 0 ETH | 0.00951599 | ||||
Create Policy Ma... | 9481254 | 1538 days ago | IN | 0 ETH | 0.00524782 | ||||
Create Participa... | 9481246 | 1538 days ago | IN | 0 ETH | 0.0152328 | ||||
Create Fee Manag... | 9481236 | 1538 days ago | IN | 0 ETH | 0.01076304 | ||||
Create Accountin... | 9481233 | 1538 days ago | IN | 0 ETH | 0.01619221 | ||||
Begin Setup | 9481229 | 1538 days ago | IN | 0 ETH | 0.0198702 | ||||
Complete Setup | 9464575 | 1540 days ago | IN | 0 ETH | 0.00573329 | ||||
Create Vault | 9464572 | 1540 days ago | IN | 0 ETH | 0.00105321 | ||||
Create Trading | 9464565 | 1540 days ago | IN | 0 ETH | 0.00619366 | ||||
Create Shares | 9464559 | 1540 days ago | IN | 0 ETH | 0.00285479 | ||||
Create Policy Ma... | 9464556 | 1540 days ago | IN | 0 ETH | 0.00314869 | ||||
Create Participa... | 9464553 | 1540 days ago | IN | 0 ETH | 0.00472817 | ||||
Create Fee Manag... | 9464534 | 1540 days ago | IN | 0 ETH | 0.00161445 | ||||
Create Accountin... | 9464532 | 1540 days ago | IN | 0 ETH | 0.00242883 | ||||
Begin Setup | 9464527 | 1540 days ago | IN | 0 ETH | 0.00305821 | ||||
Complete Setup | 9431189 | 1545 days ago | IN | 0 ETH | 0.02248184 | ||||
Create Vault | 9431182 | 1545 days ago | IN | 0 ETH | 0.00702146 | ||||
Create Trading | 9431179 | 1545 days ago | IN | 0 ETH | 0.03506048 | ||||
Create Shares | 9431176 | 1545 days ago | IN | 0 ETH | 0.00951599 | ||||
Create Policy Ma... | 9431154 | 1545 days ago | IN | 0 ETH | 0.00432945 | ||||
Create Participa... | 9431131 | 1545 days ago | IN | 0 ETH | 0.03088781 | ||||
Create Fee Manag... | 9431126 | 1545 days ago | IN | 0 ETH | 0.01076304 |
Latest 21 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
9481229 | 1538 days ago | Contract Creation | 0 ETH | |||
9464527 | 1540 days ago | Contract Creation | 0 ETH | |||
9431098 | 1545 days ago | Contract Creation | 0 ETH | |||
9430149 | 1545 days ago | Contract Creation | 0 ETH | |||
9418784 | 1547 days ago | Contract Creation | 0 ETH | |||
9416503 | 1548 days ago | Contract Creation | 0 ETH | |||
9416317 | 1548 days ago | Contract Creation | 0 ETH | |||
9391881 | 1551 days ago | Contract Creation | 0 ETH | |||
9378230 | 1553 days ago | Contract Creation | 0 ETH | |||
9344199 | 1559 days ago | Contract Creation | 0 ETH | |||
9344198 | 1559 days ago | 0.6 ETH | ||||
9344196 | 1559 days ago | 0.6 ETH | ||||
9344192 | 1559 days ago | 0.6 ETH | ||||
9344189 | 1559 days ago | 0.6 ETH | ||||
9344187 | 1559 days ago | 0.6 ETH | ||||
9344185 | 1559 days ago | 0.6 ETH | ||||
9344182 | 1559 days ago | 0.6 ETH | ||||
9344180 | 1559 days ago | 0.6 ETH | ||||
9343811 | 1559 days ago | 0.03277646 ETH | ||||
9343810 | 1559 days ago | Contract Creation | 0 ETH | |||
9343730 | 1559 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
Version
Compiler Version
v0.6.1+commit.e6f7d5a4
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../factory/FundFactory.sol"; import "../fund/hub/Hub.sol"; /// @notice Controlled by governance contract Version is FundFactory, DSAuth { constructor( address _accountingFactory, address _feeManagerFactory, address _participationFactory, address _sharesFactory, address _tradingFactory, address _vaultFactory, address _policyManagerFactory, address _registry, address _postDeployOwner ) public FundFactory( _accountingFactory, _feeManagerFactory, _participationFactory, _sharesFactory, _tradingFactory, _vaultFactory, _policyManagerFactory, address(this) ) { associatedRegistry = Registry(_registry); setOwner(_postDeployOwner); } function shutDownFund(address _hub) external { require( managersToHubs[msg.sender] == _hub, "Conditions not met for fund shutdown" ); Hub(_hub).shutDownFund(); } }
/// @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); } } }
/// @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; } }
/// 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); } } } }
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; } }
pragma solidity 0.6.1; import "./PreminedToken.sol"; /// @dev Just a wrapper for premined tokens which can actually be burnt contract BurnableToken is PreminedToken { constructor(string memory _symbol, uint8 _decimals, string memory _name) public PreminedToken(_symbol, _decimals, _name) {} function burn(uint _amount) public { _burn(msg.sender, _amount); } function burnFrom(address from, uint256 value) public { _burnFrom(from, value); } }
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; }
pragma solidity 0.6.1; import "./StandardToken.sol"; contract PreminedToken is StandardToken { string public symbol; string public name; uint8 public decimals; constructor(string memory _symbol, uint8 _decimals, string memory _name) public { symbol = _symbol; decimals = _decimals; name = _name; totalSupply_ = 1000000 * 10**uint(decimals); balances[msg.sender] = totalSupply_; emit Transfer(address(0), msg.sender, totalSupply_); } }
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); } }
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" ); } }
pragma solidity 0.6.1; contract WETH { string public name = "Wrapped Ether"; string public symbol = "WETH"; uint8 public decimals = 18; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); event Deposit(address indexed dst, uint wad); event Withdrawal(address indexed src, uint wad); mapping (address => uint) public balanceOf; mapping (address => mapping (address => uint)) public allowance; receive() external payable { deposit(); } function deposit() public payable { balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); } function withdraw(uint wad) public { require(balanceOf[msg.sender] >= wad); balanceOf[msg.sender] -= wad; msg.sender.transfer(wad); emit Withdrawal(msg.sender, wad); } function totalSupply() public view returns (uint) { return address(this).balance; } function approve(address guy, uint wad) public returns (bool) { allowance[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { require(balanceOf[src] >= wad); if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { require(allowance[src][msg.sender] >= wad); allowance[src][msg.sender] -= wad; } balanceOf[src] -= wad; balanceOf[dst] += wad; emit Transfer(src, dst, wad); return true; } }
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); } }
pragma solidity 0.6.1; import "../dependencies/DSMath.sol"; import "../dependencies/token/BurnableToken.sol"; import "../prices/IPriceSource.sol"; import "../version/Registry.sol"; /// @notice Liquidity contract and token sink contract Engine is DSMath { event RegistryChange(address registry); event SetAmguPrice(uint amguPrice); event AmguPaid(uint amount); event Thaw(uint amount); event Burn(uint amount); uint public constant MLN_DECIMALS = 18; Registry public registry; uint public amguPrice; uint public frozenEther; uint public liquidEther; uint public lastThaw; uint public thawingDelay; uint public totalEtherConsumed; uint public totalAmguConsumed; uint public totalMlnBurned; constructor(uint _delay, address _registry) public { lastThaw = block.timestamp; thawingDelay = _delay; _setRegistry(_registry); } modifier onlyMGM() { require( msg.sender == registry.MGM(), "Only MGM can call this" ); _; } /// @dev Registry owner is MTC modifier onlyMTC() { require( msg.sender == registry.owner(), "Only MTC can call this" ); _; } function _setRegistry(address _registry) internal { registry = Registry(_registry); emit RegistryChange(address(registry)); } /// @dev only callable by MTC function setRegistry(address _registry) external onlyMTC { _setRegistry(_registry); } /// @dev set price of AMGU in MLN (base units) /// @dev only callable by MGM function setAmguPrice(uint _price) external onlyMGM { amguPrice = _price; emit SetAmguPrice(_price); } function getAmguPrice() public view returns (uint) { return amguPrice; } function premiumPercent() public view returns (uint) { if (liquidEther < 1 ether) { return 0; } else if (liquidEther >= 1 ether && liquidEther < 5 ether) { return 5; } else if (liquidEther >= 5 ether && liquidEther < 10 ether) { return 10; } else if (liquidEther >= 10 ether) { return 15; } } function payAmguInEther() external payable { require( registry.isFundFactory(msg.sender) || registry.isFund(msg.sender), "Sender must be a fund or the factory" ); uint mlnPerAmgu = getAmguPrice(); uint ethPerMln; (ethPerMln,) = priceSource().getPrice(address(mlnToken())); uint amguConsumed; if (mlnPerAmgu > 0 && ethPerMln > 0) { amguConsumed = (mul(msg.value, 10 ** uint(MLN_DECIMALS))) / (mul(ethPerMln, mlnPerAmgu)); } else { amguConsumed = 0; } totalEtherConsumed = add(totalEtherConsumed, msg.value); totalAmguConsumed = add(totalAmguConsumed, amguConsumed); frozenEther = add(frozenEther, msg.value); emit AmguPaid(amguConsumed); } /// @notice Move frozen ether to liquid pool after delay /// @dev Delay only restarts when this function is called function thaw() external { require( block.timestamp >= add(lastThaw, thawingDelay), "Thawing delay has not passed" ); require(frozenEther > 0, "No frozen ether to thaw"); lastThaw = block.timestamp; liquidEther = add(liquidEther, frozenEther); emit Thaw(frozenEther); frozenEther = 0; } /// @return ETH per MLN including premium function enginePrice() public view returns (uint) { uint ethPerMln; (ethPerMln, ) = priceSource().getPrice(address(mlnToken())); uint premium = (mul(ethPerMln, premiumPercent()) / 100); return add(ethPerMln, premium); } function ethPayoutForMlnAmount(uint mlnAmount) public view returns (uint) { return mul(mlnAmount, enginePrice()) / 10 ** uint(MLN_DECIMALS); } /// @notice MLN must be approved first function sellAndBurnMln(uint mlnAmount) external { require(registry.isFund(msg.sender), "Only funds can use the engine"); require( mlnToken().transferFrom(msg.sender, address(this), mlnAmount), "MLN transferFrom failed" ); uint ethToSend = ethPayoutForMlnAmount(mlnAmount); require(ethToSend > 0, "No ether to pay out"); require(liquidEther >= ethToSend, "Not enough liquid ether to send"); liquidEther = sub(liquidEther, ethToSend); totalMlnBurned = add(totalMlnBurned, mlnAmount); msg.sender.transfer(ethToSend); mlnToken().burn(mlnAmount); emit Burn(mlnAmount); } /// @dev Get MLN from the registry function mlnToken() public view returns (BurnableToken) { return BurnableToken(registry.mlnToken()); } /// @dev Get PriceSource from the registry function priceSource() public view returns (IPriceSource) { return IPriceSource(registry.priceSource()); } }
pragma solidity 0.6.1; interface IEngine { function payAmguInEther() external payable; function getAmguPrice() external view returns (uint256); }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../engine/Engine.sol"; import "../fund/hub/Hub.sol"; import "../fund/trading/Trading.sol"; import "../fund/vault/Vault.sol"; import "../dependencies/DSMath.sol"; import "../dependencies/WETH.sol"; import "../dependencies/token/IERC20.sol"; import "./ExchangeAdapter.sol"; import "../dependencies/TokenUser.sol"; /// @notice Trading adapter to Melon Engine contract EngineAdapter is DSMath, TokenUser, ExchangeAdapter { /// @notice Buys Ether from the engine, selling MLN /// @param targetExchange Address of the engine /// @param orderValues [0] Min Eth to receive from the engine /// @param orderValues [1] MLN quantity /// @param orderValues [6] Same as orderValues[1] /// @param orderAddresses [2] WETH token /// @param orderAddresses [3] MLN token function takeOrder ( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown { Hub hub = getHub(); address wethAddress = orderAddresses[2]; address mlnAddress = orderAddresses[3]; uint minEthToReceive = orderValues[0]; uint mlnQuantity = orderValues[1]; require( wethAddress == Registry(hub.registry()).nativeAsset(), "maker asset doesnt match nativeAsset on registry" ); require( orderValues[1] == orderValues[6], "fillTakerQuantity must equal takerAssetQuantity" ); withdrawAndApproveAsset(mlnAddress, targetExchange, mlnQuantity, "takerAsset"); uint ethToReceive = Engine(targetExchange).ethPayoutForMlnAmount(mlnQuantity); require( ethToReceive >= minEthToReceive, "Expected ETH to receive is less than takerQuantity (minEthToReceive)" ); Engine(targetExchange).sellAndBurnMln(mlnQuantity); WETH(payable(wethAddress)).deposit.value(ethToReceive)(); safeTransfer(wethAddress, address(Vault(hub.vault())), ethToReceive); getAccounting().addAssetToOwnedAssets(wethAddress); getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( targetExchange, bytes32(0), Trading.UpdateType.take, [payable(wethAddress), payable(mlnAddress)], [ethToReceive, mlnQuantity, mlnQuantity] ); } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/token/IERC20.sol"; import "../fund/trading/Trading.sol"; import "../fund/hub/Hub.sol"; import "../fund/vault/Vault.sol"; import "../fund/accounting/Accounting.sol"; import "../version/Registry.sol"; import "../dependencies/WETH.sol"; import "../dependencies/DSMath.sol"; import "./interfaces/IZeroExV2.sol"; import "./interfaces/IEthfinex.sol"; import "./ExchangeAdapter.sol"; /// @title EthfinexAdapter Contract /// @author Melonport AG <[email protected]> /// @notice Adapter to EthFinex exchange contract EthfinexAdapter is DSMath, ExchangeAdapter { /// @param _orderAddresses [2] Order maker asset /// @param _orderAddresses [3] Order taker asset /// @param _orderData [0] Encoded data specific to maker asset /// @param _orderData [1] Encoded data specific to taker asset modifier orderAddressesMatchOrderData( address[8] memory _orderAddresses, bytes[4] memory _orderData ) { require( getAssetAddress(_orderData[0]) == getWrapperToken(_orderAddresses[2]), "Maker asset data does not match order address in array" ); require( getAssetAddress(_orderData[1]) == _orderAddresses[3], "Taker asset data does not match order address in array" ); _; } // METHODS // PUBLIC METHODS /// @notice Make order by pre-approving signatures function makeOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override onlyManager notShutDown orderAddressesMatchOrderData(_orderAddresses, _orderData) { ensureCanMakeOrder(_orderAddresses[2]); IZeroExV2.Order memory order = constructOrderStruct(_orderAddresses, _orderValues, _orderData); bytes memory wrappedMakerAssetData = _orderData[0]; bytes memory takerAssetData = _orderData[1]; address makerAsset = _orderAddresses[2]; address takerAsset = getAssetAddress(takerAssetData); // Order parameter checks getTrading().updateAndGetQuantityBeingTraded(makerAsset); ensureNotInOpenMakeOrder(makerAsset); wrapMakerAsset(_targetExchange, makerAsset, wrappedMakerAssetData, order.makerAssetAmount, order.expirationTimeSeconds); IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(_targetExchange).getOrderInfo(order); IZeroExV2(_targetExchange).preSign(orderInfo.orderHash, address(this), _signature); require( IZeroExV2(_targetExchange).isValidSignature( orderInfo.orderHash, address(this), _signature ), "INVALID_ORDER_SIGNATURE" ); updateStateMakeOrder(_targetExchange, order); } /// @notice Cancel the 0x make order function cancelOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override orderAddressesMatchOrderData(_orderAddresses, _orderData) { IZeroExV2.Order memory order = getTrading().getZeroExV2OrderDetails(_identifier); ensureCancelPermitted(_targetExchange, getAssetAddress(order.makerAssetData)); IZeroExV2(_targetExchange).cancelOrder(order); updateStateCancelOrder(_targetExchange, order); } /// @notice Unwrap (withdraw) tokens, uses _orderAddresses for input list of tokens to be unwrapped /// @dev Call to "withdraw" fails if timestamp < `Wrapper.depositLock(tradingComponent)` function withdrawTokens( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public { Hub hub = getHub(); address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET(); for (uint i = 0; i < _orderAddresses.length; i++) { if (_orderAddresses[i] == address(0)) continue; address wrappedToken = getWrapperToken(_orderAddresses[i]); uint balance = IWrapperLock(wrappedToken).balanceOf(address(this)); require(balance > 0, "Insufficient balance"); IWrapperLock(wrappedToken).withdraw(balance, 0, bytes32(0), bytes32(0), 0); if (_orderAddresses[i] == nativeAsset) { WETH(payable(nativeAsset)).deposit.value(balance)(); } getTrading().removeOpenMakeOrder(_targetExchange, _orderAddresses[i]); getTrading().returnAssetToVault(_orderAddresses[i]); } } /// @notice Minor: Wrapped tokens directly sent to the fund are not accounted. To be called by Trading spoke function getOrder(address _targetExchange, uint256 _id, address _makerAsset) public view override returns (address, address, uint256, uint256) { uint orderId; uint orderIndex; address takerAsset; uint makerQuantity; uint takerQuantity; (orderId, , orderIndex) = Trading(msg.sender).getOpenOrderInfo(_targetExchange, _makerAsset); (, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex); // Check if order has been completely filled uint takerAssetFilledAmount = IZeroExV2(_targetExchange).filled(bytes32(orderId)); if (sub(takerQuantity, takerAssetFilledAmount) == 0) { return (_makerAsset, takerAsset, 0, 0); } // Check if tokens have been withdrawn (cancelled order may still need to be accounted if there is balance) uint balance = IWrapperLock(getWrapperTokenFromAdapterContext(_makerAsset)).balanceOf(msg.sender); if (balance == 0) { return (_makerAsset, takerAsset, 0, 0); } return (_makerAsset, takerAsset, makerQuantity, sub(takerQuantity, takerAssetFilledAmount)); } // INTERNAL METHODS /// @notice needed to avoid stack too deep error /// @dev deposit time should be greater than 1 hour function wrapMakerAsset( address _targetExchange, address _makerAsset, bytes memory _wrappedMakerAssetData, uint _makerQuantity, uint _orderExpirationTime ) internal { Hub hub = getHub(); // Deposit to rounded up value of time difference of expiration time and current time (in hours) uint depositTime = ( sub(_orderExpirationTime, block.timestamp) / 1 hours ) + 1; address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET(); address wrappedToken = getWrapperToken(_makerAsset); // Handle case for WETH vs ERC20 if (_makerAsset == nativeAsset) { Vault vault = Vault(hub.vault()); vault.withdraw(_makerAsset, _makerQuantity); WETH(payable(nativeAsset)).withdraw(_makerQuantity); IWrapperLockEth(wrappedToken).deposit.value(_makerQuantity)(_makerQuantity, depositTime); } else { withdrawAndApproveAsset( _makerAsset, wrappedToken, _makerQuantity, "makerAsset" ); IWrapperLock(wrappedToken).deposit(_makerQuantity, depositTime); } } // @dev avoids stack too deep error function updateStateCancelOrder(address _targetExchange, IZeroExV2.Order memory _order) internal { // Order is not removed from OpenMakeOrder mapping as it's needed for accounting (wrapped tokens) getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( _targetExchange, IZeroExV2(_targetExchange).getOrderInfo(_order).orderHash, Trading.UpdateType.cancel, [address(0), address(0)], [uint(0), uint(0), uint(0)] ); } // @dev avoids stack too deep error function updateStateMakeOrder(address _targetExchange, IZeroExV2.Order memory _order) internal { address wrapperRegistry = Registry(getTrading().registry()).ethfinexWrapperRegistry(); address wrappedMakerAsset = getAssetAddress(_order.makerAssetData); address makerAsset = IWrapperRegistryEFX( wrapperRegistry ).wrapper2TokenLookup(wrappedMakerAsset); address takerAsset = getAssetAddress(_order.takerAssetData); IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(_targetExchange).getOrderInfo(_order); getAccounting().addAssetToOwnedAssets(takerAsset); getTrading().orderUpdateHook( _targetExchange, orderInfo.orderHash, Trading.UpdateType.make, [payable(makerAsset), payable(takerAsset)], [_order.makerAssetAmount, _order.takerAssetAmount, uint(0)] ); getTrading().addOpenMakeOrder( _targetExchange, makerAsset, takerAsset, uint256(orderInfo.orderHash), _order.expirationTimeSeconds ); getTrading().addZeroExV2OrderData(orderInfo.orderHash, _order); } // VIEW METHODS function constructOrderStruct( address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData ) internal view returns (IZeroExV2.Order memory _order) { _order = IZeroExV2.Order({ makerAddress: _orderAddresses[0], takerAddress: _orderAddresses[1], feeRecipientAddress: _orderAddresses[4], senderAddress: _orderAddresses[5], makerAssetAmount: _orderValues[0], takerAssetAmount: _orderValues[1], makerFee: _orderValues[2], takerFee: _orderValues[3], expirationTimeSeconds: _orderValues[4], salt: _orderValues[5], makerAssetData: _orderData[0], takerAssetData: _orderData[1] }); } function getAssetProxy(address _targetExchange, bytes memory _assetData) internal view returns (address assetProxy_) { bytes4 assetProxyId; assembly { assetProxyId := and(mload( add(_assetData, 32)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 ) } assetProxy_ = IZeroExV2(_targetExchange).getAssetProxy(assetProxyId); } function getAssetAddress(bytes memory _assetData) internal view returns (address assetAddress_) { assembly { assetAddress_ := mload(add(_assetData, 36)) } } /// @dev Function to be called from Trading spoke context (Delegate call) function getWrapperToken(address _token) internal view returns (address) { address wrapperRegistry = Registry(getTrading().registry()).ethfinexWrapperRegistry(); return IWrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(_token); } /// @dev Function to be called by Trading spoke without change of context (Non delegate call) function getWrapperTokenFromAdapterContext(address _token) internal view returns (address) { address wrapperRegistry = Registry(Trading(msg.sender).registry()).ethfinexWrapperRegistry(); return IWrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(_token); } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/DSMath.sol"; import "../dependencies/token/IERC20.sol"; import "../fund/accounting/Accounting.sol"; import "../fund/hub/Hub.sol"; import "../fund/trading/Trading.sol"; import "../fund/vault/Vault.sol"; /// @title Exchange Adapter base contract /// @author Melonport AG <[email protected]> /// @notice Override the public methods to implement an adapter contract ExchangeAdapter is DSMath { modifier onlyManager() { require( getManager() == msg.sender, "Manager must be sender" ); _; } modifier notShutDown() { require( !hubShutDown(), "Hub must not be shut down" ); _; } /// @dev Either manager sends, fund shut down, or order expired function ensureCancelPermitted(address exchange, address asset) internal { require( getManager() == msg.sender || hubShutDown() || getTrading().isOrderExpired(exchange, asset), "No cancellation condition met" ); } function getTrading() internal view returns (Trading) { return Trading(payable(address(this))); } function getHub() internal view returns (Hub) { return Hub(getTrading().hub()); } function getAccounting() internal view returns (Accounting) { return Accounting(getHub().accounting()); } function hubShutDown() internal view returns (bool) { return getHub().isShutDown(); } function getManager() internal view returns (address) { return getHub().manager(); } function ensureNotInOpenMakeOrder(address _asset) internal view { require( !getTrading().isInOpenMakeOrder(_asset), "This asset is already in an open make order" ); } function ensureCanMakeOrder(address _asset) internal view { require( block.timestamp >= getTrading().makerAssetCooldown(_asset), "Cooldown for the maker asset not reached" ); } /// @notice Increment allowance of an asset for some target function withdrawAndApproveAsset( address _asset, address _target, uint256 _amount, string memory _assetType ) internal { Hub hub = getHub(); Vault vault = Vault(hub.vault()); require( IERC20(_asset).balanceOf(address(vault)) >= _amount, string(abi.encodePacked("Insufficient balance: ", _assetType)) ); vault.withdraw(_asset, _amount); uint256 allowance = IERC20(_asset).allowance(address(this), _target); require( IERC20(_asset).approve(_target, add(allowance, _amount)), string(abi.encodePacked("Approval failed: ", _assetType)) ); } /// @notice Reduce allowance of an asset for some target function revokeApproveAsset( address _asset, address _target, uint256 _amount, string memory _assetType ) internal { uint256 allowance = IERC20(_asset).allowance(address(this), _target); require( IERC20(_asset).approve(_target, sub(allowance, _amount)), string(abi.encodePacked("Revoke approval failed: ", _assetType)) ); } /// @param orderAddresses [0] Order maker /// @param orderAddresses [1] Order taker /// @param orderAddresses [2] Order maker asset /// @param orderAddresses [3] Order taker asset /// @param orderAddresses [4] feeRecipientAddress /// @param orderAddresses [5] senderAddress /// @param orderAddresses [6] maker fee asset /// @param orderAddresses [7] taker fee asset /// @param orderValues [0] makerAssetAmount /// @param orderValues [1] takerAssetAmount /// @param orderValues [2] Maker fee /// @param orderValues [3] Taker fee /// @param orderValues [4] expirationTimeSeconds /// @param orderValues [5] Salt/nonce /// @param orderValues [6] Fill amount: amount of taker token to be traded /// @param orderValues [7] Dexy signature mode /// @param orderData [0] Encoded data specific to maker asset /// @param orderData [1] Encoded data specific to taker asset /// @param orderData [2] Encoded data specific to maker asset fee /// @param orderData [3] Encoded data specific to taker asset fee /// @param identifier Order identifier /// @param signature Signature of order maker // Responsibilities of makeOrder are: // - check sender // - check fund not shut down // - check price recent // - check risk management passes // - approve funds to be traded (if necessary) // - make order on the exchange // - check order was made (if possible) // - place asset in ownedAssets if not already tracked function makeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public virtual { revert("Unimplemented"); } // Responsibilities of takeOrder are: // - check sender // - check fund not shut down // - check not buying own fund tokens // - check price exists for asset pair // - check price is recent // - check price passes risk management // - approve funds to be traded (if necessary) // - take order from the exchange // - check order was taken (if possible) // - place asset in ownedAssets if not already tracked function takeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public virtual { revert("Unimplemented"); } // responsibilities of cancelOrder are: // - check sender is owner, or that order expired, or that fund shut down // - remove order from tracking array // - cancel order on exchange function cancelOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public virtual { revert("Unimplemented"); } // PUBLIC METHODS // PUBLIC VIEW METHODS /* @return { "makerAsset": "Maker asset", "takerAsset": "Taker asset", "makerQuantity": "Amount of maker asset" "takerQuantity": "Amount of taker asset" } */ function getOrder( address onExchange, uint id, address makerAsset ) public view virtual returns ( address, address, uint, uint ) { revert("Unimplemented"); } }
pragma solidity 0.6.1; // pragma experimental ABIEncoderV2; /// @dev Minimal interface for our interactions with EthFinex WrapperLock interface IWrapperLock { function balanceOf(address) external view returns (uint256); function withdraw(uint256, uint8, bytes32, bytes32, uint256) external returns (bool); function deposit(uint256, uint256) external returns (bool); } /// @dev Minimal interface for our interactions with EthFinex WrapperLockEth interface IWrapperLockEth { function balanceOf(address) external view returns (uint256); function deposit(uint256, uint256) external payable returns (bool); } /// @dev Minimal interface for our interactions with EthFinex WrapperRegistryEFX interface IWrapperRegistryEFX { function token2WrapperLookup(address) external view returns (address); function wrapper2TokenLookup(address) external view returns (address); }
pragma solidity 0.6.1; /// @title Kyber Network interface interface IKyberNetworkProxy { function maxGasPrice() external view returns(uint256); function getUserCapInWei(address) external view returns(uint256); function getUserCapInTokenWei(address, address) external view returns(uint256); function enabled() external view returns(bool); function info(bytes32) external view returns(uint256); function swapEtherToToken(address, uint256) external payable returns(uint256); function swapTokenToEther(address, uint256, uint256) external returns(uint256); function swapTokenToToken(address, uint256, address, uint256) external returns(uint); function getExpectedRate(address, address, uint256) external view returns (uint256, uint256); function tradeWithHint( address, uint256, address, address, uint256, uint256, address, bytes calldata ) external payable returns(uint256); }
pragma solidity 0.6.1; /// @dev Minimal interface for our interactions with OasisDex MatchingMarket interface IOasisDex { function getFirstUnsortedOffer() external view returns(uint256); function getNextUnsortedOffer(uint256) external view returns(uint256); function getBestOffer(address, address) external view returns(uint256); function getOffer(uint256) external view returns (uint256, address, uint256, address); function getWorseOffer(uint256) external view returns(uint256); function isActive(uint256) external view returns (bool); function buy(uint256, uint256) external returns (bool); function cancel(uint256) external returns (bool); function offer(uint256, address, uint256, address) external returns (uint256); }
pragma solidity 0.6.1; /// @dev Minimal interface for our interactions with UniswapExchange interface IUniswapExchange { // Trade ETH to ERC20 function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought); // Trade ERC20 to ETH function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought); // Trade ERC20 to ERC20 function tokenToTokenTransferInput( uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr ) external returns (uint256 tokens_bought); /// @dev The following functions are only used in tests // Provide Liquidity function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256); // Get Prices function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought); function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought); }
pragma solidity 0.6.1; /// @dev Minimal interface for our interactions with UniswapFactory interface IUniswapFactory { function getExchange(address token) external view returns (address exchange); }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; /// @dev Minimal interface for our interactions with the ZeroEx Exchange contract interface IZeroExV2 { struct Order { address makerAddress; address takerAddress; address feeRecipientAddress; address senderAddress; uint256 makerAssetAmount; uint256 takerAssetAmount; uint256 makerFee; uint256 takerFee; uint256 expirationTimeSeconds; uint256 salt; bytes makerAssetData; bytes takerAssetData; } struct OrderInfo { uint8 orderStatus; bytes32 orderHash; uint256 orderTakerAssetFilledAmount; } struct FillResults { uint256 makerAssetFilledAmount; uint256 takerAssetFilledAmount; uint256 makerFeePaid; uint256 takerFeePaid; } function ZRX_ASSET_DATA() external view returns (bytes memory); function filled(bytes32) external view returns (uint256); function cancelled(bytes32) external view returns (bool); function getOrderInfo(Order calldata) external view returns (OrderInfo memory); function getAssetProxy(bytes4) external view returns (address); function isValidSignature(bytes32, address, bytes calldata) external view returns (bool); function preSign(bytes32, address, bytes calldata) external; function cancelOrder(Order calldata) external; function fillOrder(Order calldata, uint256, bytes calldata) external returns (FillResults memory); }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; /// @dev Minimal interface for our interactions with the ZeroEx Exchange contract interface IZeroExV3 { struct Order { address makerAddress; address takerAddress; address feeRecipientAddress; address senderAddress; uint256 makerAssetAmount; uint256 takerAssetAmount; uint256 makerFee; uint256 takerFee; uint256 expirationTimeSeconds; uint256 salt; bytes makerAssetData; bytes takerAssetData; bytes makerFeeAssetData; bytes takerFeeAssetData; } struct OrderInfo { uint8 orderStatus; bytes32 orderHash; uint256 orderTakerAssetFilledAmount; } struct FillResults { uint256 makerAssetFilledAmount; uint256 takerAssetFilledAmount; uint256 makerFeePaid; uint256 takerFeePaid; uint256 protocolFeePaid; } function cancelled(bytes32) external view returns (bool); function cancelOrder(Order calldata) external; function filled(bytes32) external view returns (uint256); function fillOrder(Order calldata, uint256, bytes calldata) external payable returns (FillResults memory); function getAssetProxy(bytes4) external view returns (address); function getOrderInfo(Order calldata) external view returns (OrderInfo memory); function isValidOrderSignature(Order calldata, bytes calldata) external view returns (bool); function preSign(bytes32) external; function protocolFeeCollector() external view returns (address); function protocolFeeMultiplier() external view returns (uint256); }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/WETH.sol"; import "../dependencies/token/IERC20.sol"; import "../fund/trading/Trading.sol"; import "../fund/hub/Hub.sol"; import "../fund/vault/Vault.sol"; import "../fund/accounting/Accounting.sol"; import "../prices/IPriceSource.sol"; import "./interfaces/IKyberNetworkProxy.sol"; import "./ExchangeAdapter.sol"; contract KyberAdapter is DSMath, ExchangeAdapter { address public constant ETH_TOKEN_ADDRESS = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); // NON-CONSTANT METHODS // Responsibilities of takeOrder (Kybers swapToken) are: // - check price recent // - check risk management passes // - approve funds to be traded (if necessary) // - perform swap order on the exchange // - place asset in ownedAssets if not already tracked /// @notice Swaps srcAmount of srcToken for destAmount of destToken /// @dev Variable naming to be close to Kyber's naming /// @dev For the purpose of PriceTolerance, fillTakerQuantity == takerAssetQuantity = Dest token amount /// @param targetExchange Address of the exchange /// @param orderAddresses [2] Maker asset (Dest token) /// @param orderAddresses [3] Taker asset (Src token) /// @param orderValues [0] Maker asset quantity (Dest token amount) /// @param orderValues [1] Taker asset quantity (Src token amount) function takeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown { Hub hub = getHub(); require( orderValues[1] == orderValues[6], "fillTakerQuantity must equal takerAssetQuantity" ); address makerAsset = orderAddresses[2]; address takerAsset = orderAddresses[3]; uint makerAssetAmount = orderValues[0]; uint takerAssetAmount = orderValues[1]; uint minRate = calcMinRate( takerAsset, makerAsset, takerAssetAmount, makerAssetAmount ); uint actualReceiveAmount = dispatchSwap( targetExchange, takerAsset, takerAssetAmount, makerAsset, minRate ); require( actualReceiveAmount >= makerAssetAmount, "Received less than expected from Kyber swap" ); getAccounting().addAssetToOwnedAssets(makerAsset); getAccounting().updateOwnedAssets(); getTrading().returnAssetToVault(makerAsset); getTrading().orderUpdateHook( targetExchange, bytes32(0), Trading.UpdateType.take, [payable(makerAsset), payable(takerAsset)], [actualReceiveAmount, takerAssetAmount, takerAssetAmount] ); } // INTERNAL FUNCTIONS /// @notice Call different functions based on type of assets supplied function dispatchSwap( address targetExchange, address srcToken, uint srcAmount, address destToken, uint minRate ) internal returns (uint actualReceiveAmount) { Hub hub = getHub(); address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET(); if (srcToken == nativeAsset) { actualReceiveAmount = swapNativeAssetToToken(targetExchange, nativeAsset, srcAmount, destToken, minRate); } else if (destToken == nativeAsset) { actualReceiveAmount = swapTokenToNativeAsset(targetExchange, srcToken, srcAmount, nativeAsset, minRate); } else { actualReceiveAmount = swapTokenToToken(targetExchange, srcToken, srcAmount, destToken, minRate); } } /// @dev If minRate is not defined, uses expected rate from the network /// @param targetExchange Address of Kyber proxy contract /// @param nativeAsset Native asset address as src token /// @param srcAmount Amount of native asset supplied /// @param destToken Address of dest token /// @param minRate Minimum rate supplied to the Kyber proxy /// @return receivedAmount Actual amount of destToken received from the exchange function swapNativeAssetToToken( address targetExchange, address nativeAsset, uint srcAmount, address destToken, uint minRate ) internal returns (uint receivedAmount) { // Convert WETH to ETH Hub hub = getHub(); Vault vault = Vault(hub.vault()); vault.withdraw(nativeAsset, srcAmount); WETH(payable(nativeAsset)).withdraw(srcAmount); receivedAmount = IKyberNetworkProxy(targetExchange).swapEtherToToken.value(srcAmount)(destToken, minRate); } /// @dev If minRate is not defined, uses expected rate from the network /// @param targetExchange Address of Kyber proxy contract /// @param srcToken Address of src token /// @param srcAmount Amount of src token supplied /// @param nativeAsset Native asset address as src token /// @param minRate Minimum rate supplied to the Kyber proxy /// @return receivedAmount Actual amount of destToken received from the exchange function swapTokenToNativeAsset( address targetExchange, address srcToken, uint srcAmount, address nativeAsset, uint minRate ) internal returns (uint receivedAmount) { withdrawAndApproveAsset(srcToken, targetExchange, srcAmount, "takerAsset"); receivedAmount = IKyberNetworkProxy(targetExchange).swapTokenToEther(srcToken, srcAmount, minRate); // Convert ETH to WETH WETH(payable(nativeAsset)).deposit.value(receivedAmount)(); } /// @dev If minRate is not defined, uses expected rate from the network /// @param targetExchange Address of Kyber proxy contract /// @param srcToken Address of src token /// @param srcAmount Amount of src token supplied /// @param destToken Address of dest token /// @param minRate Minimum rate supplied to the Kyber proxy /// @return receivedAmount Actual amount of destToken received from the exchange function swapTokenToToken( address targetExchange, address srcToken, uint srcAmount, address destToken, uint minRate ) internal returns (uint receivedAmount) { withdrawAndApproveAsset(srcToken, targetExchange, srcAmount, "takerAsset"); receivedAmount = IKyberNetworkProxy(targetExchange).swapTokenToToken(srcToken, srcAmount, destToken, minRate); } /// @param srcToken Address of src token /// @param destToken Address of dest token /// @param srcAmount Amount of src token /// @return minRate Minimum rate to be supplied to the network for some order params function calcMinRate( address srcToken, address destToken, uint srcAmount, uint destAmount ) internal view returns (uint minRate) { IPriceSource pricefeed = IPriceSource(getHub().priceSource()); minRate = pricefeed.getOrderPriceInfo( srcToken, destToken, srcAmount, destAmount ); } }
pragma solidity 0.6.1; import "./interfaces/IOasisDex.sol"; contract OasisDexAccessor { function getUnsortedOfferIds( address targetExchange, address sellAsset, address buyAsset ) public view returns (uint[] memory) { IOasisDex market = IOasisDex(targetExchange); uint[] memory ids = new uint[](1000); uint count = 0; // Iterate over all unsorted offers up to 1000 iterations. uint id = market.getFirstUnsortedOffer(); for (uint i = 0; i < 1000; i++) { if (id == 0) { break; } if (market.isActive(id)) { address sellGem; address buyGem; (, sellGem, , buyGem) = market.getOffer(id); if (sellGem == sellAsset && buyGem == buyAsset) { ids[count++] = id; } } // Get the next offer and repeat. id = market.getNextUnsortedOffer(id); } // Create a new array of offers with the correct size. uint[] memory copy = new uint[](count); for (uint i = 0; i < count; i++) { copy[i] = ids[i]; } return copy; } function getSortedOfferIds( address targetExchange, address sellAsset, address buyAsset ) public view returns(uint[] memory) { IOasisDex market = IOasisDex(targetExchange); uint[] memory ids = new uint[](1000); uint count = 0; // Iterate over all sorted offers. uint id = market.getBestOffer(sellAsset, buyAsset); for (uint i = 0; i < 1000 ; i++ ) { if (id == 0) { break; } if (market.isActive(id)) { ids[count++] = id; } // Get the next offer and repeat. id = market.getWorseOffer(id); } // Create a new array of offers with the correct size. uint[] memory copy = new uint[](count); for (uint i = 0; i < count; i++) { copy[i] = ids[i]; } return copy; } function getOrders( address targetExchange, address sellAsset, address buyAsset ) public view returns (uint[] memory, uint[] memory, uint[] memory) { IOasisDex market = IOasisDex(targetExchange); uint[] memory sIds = getSortedOfferIds(targetExchange, sellAsset, buyAsset); uint[] memory uIds = getUnsortedOfferIds(targetExchange, sellAsset, buyAsset); uint[] memory ids = new uint[](uIds.length + sIds.length); uint[] memory sellQtys = new uint[](ids.length); uint[] memory buyQtys = new uint[](ids.length); for (uint i = 0; i < sIds.length; i++) { ids[i] = sIds[i]; } for (uint i = 0; i < uIds.length; i++) { ids[i + sIds.length] = uIds[i]; } for (uint i = 0; i < ids.length; i++) { uint sellQty; uint buyQty; (sellQty, , buyQty,) = market.getOffer(ids[i]); sellQtys[i] = sellQty; buyQtys[i] = buyQty; } return (ids, sellQtys, buyQtys); } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../fund/hub/Hub.sol"; import "../fund/trading/Trading.sol"; import "../fund/vault/Vault.sol"; import "../fund/accounting/Accounting.sol"; import "../dependencies/DSMath.sol"; import "./interfaces/IOasisDex.sol"; import "./ExchangeAdapter.sol"; /// @title OasisDexAdapter Contract /// @author Melonport AG <[email protected]> /// @notice Adapter between Melon and OasisDex Matching Market contract OasisDexAdapter is DSMath, ExchangeAdapter { event OrderCreated(uint256 id); // METHODS // PUBLIC METHODS // Responsibilities of makeOrder are: // - check sender // - check fund not shut down // - check price recent // - check risk management passes // - approve funds to be traded (if necessary) // - make order on the exchange // - check order was made (if possible) // - place asset in ownedAssets if not already tracked /// @notice Makes an order on the selected exchange /// @dev These orders are not expected to settle immediately /// @param targetExchange Address of the exchange /// @param orderAddresses [2] Order maker asset /// @param orderAddresses [3] Order taker asset /// @param orderValues [0] Maker token quantity /// @param orderValues [1] Taker token quantity function makeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown { ensureCanMakeOrder(orderAddresses[2]); address makerAsset = orderAddresses[2]; address takerAsset = orderAddresses[3]; uint256 makerQuantity = orderValues[0]; uint256 takerQuantity = orderValues[1]; // Order parameter checks getTrading().updateAndGetQuantityBeingTraded(makerAsset); ensureNotInOpenMakeOrder(makerAsset); withdrawAndApproveAsset(makerAsset, targetExchange, makerQuantity, "makerAsset"); uint256 orderId = IOasisDex(targetExchange).offer(makerQuantity, makerAsset, takerQuantity, takerAsset); // defines success in MatchingMarket require(orderId != 0, "Order ID should not be zero"); getAccounting().addAssetToOwnedAssets(takerAsset); getTrading().orderUpdateHook( targetExchange, bytes32(orderId), Trading.UpdateType.make, [payable(makerAsset), payable(takerAsset)], [makerQuantity, takerQuantity, uint256(0)] ); getTrading().addOpenMakeOrder(targetExchange, makerAsset, takerAsset, orderId, orderValues[4]); emit OrderCreated(orderId); } // Responsibilities of takeOrder are: // - check sender // - check fund not shut down // - check not buying own fund tokens // - check price exists for asset pair // - check price is recent // - check price passes risk management // - approve funds to be traded (if necessary) // - take order from the exchange // - check order was taken (if possible) // - place asset in ownedAssets if not already tracked /// @notice Takes an active order on the selected exchange /// @dev These orders are expected to settle immediately /// @param targetExchange Address of the exchange /// @param orderValues [6] Fill amount : amount of taker token to fill /// @param identifier Active order id function takeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown { Hub hub = getHub(); uint256 fillTakerQuantity = orderValues[6]; uint256 maxMakerQuantity; address makerAsset; uint256 maxTakerQuantity; address takerAsset; ( maxMakerQuantity, makerAsset, maxTakerQuantity, takerAsset ) = IOasisDex(targetExchange).getOffer(uint256(identifier)); uint256 fillMakerQuantity = mul(fillTakerQuantity, maxMakerQuantity) / maxTakerQuantity; require( makerAsset == orderAddresses[2] && takerAsset == orderAddresses[3], "Maker and taker assets do not match the order addresses" ); require( makerAsset != takerAsset, "Maker and taker assets cannot be the same" ); require(fillMakerQuantity <= maxMakerQuantity, "Maker amount to fill above max"); require(fillTakerQuantity <= maxTakerQuantity, "Taker amount to fill above max"); withdrawAndApproveAsset(takerAsset, targetExchange, fillTakerQuantity, "takerAsset"); require( IOasisDex(targetExchange).buy(uint256(identifier), fillMakerQuantity), "Buy on matching market failed" ); getAccounting().addAssetToOwnedAssets(makerAsset); getAccounting().updateOwnedAssets(); getTrading().returnAssetToVault(makerAsset); getTrading().orderUpdateHook( targetExchange, bytes32(identifier), Trading.UpdateType.take, [payable(makerAsset), payable(takerAsset)], [maxMakerQuantity, maxTakerQuantity, fillTakerQuantity] ); } // responsibilities of cancelOrder are: // - check sender is owner, or that order expired, or that fund shut down // - remove order from tracking array // - cancel order on exchange /// @notice Cancels orders that were not expected to settle immediately /// @param targetExchange Address of the exchange /// @param orderAddresses [2] Order maker asset /// @param identifier Order ID on the exchange function cancelOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override { require(uint256(identifier) != 0, "ID cannot be zero"); address makerAsset; (, makerAsset, ,) = IOasisDex(targetExchange).getOffer(uint256(identifier)); ensureCancelPermitted(targetExchange, makerAsset); require( address(makerAsset) == orderAddresses[2], "Retrieved and passed assets do not match" ); getTrading().removeOpenMakeOrder(targetExchange, makerAsset); IOasisDex(targetExchange).cancel( uint256(identifier) ); getTrading().returnAssetToVault(makerAsset); getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( targetExchange, bytes32(identifier), Trading.UpdateType.cancel, [address(0), address(0)], [uint256(0), uint256(0), uint256(0)] ); } // VIEW METHODS function getOrder(address targetExchange, uint256 id, address makerAsset) public view override returns (address, address, uint256, uint256) { uint256 sellQuantity; address sellAsset; uint256 buyQuantity; address buyAsset; ( sellQuantity, sellAsset, buyQuantity, buyAsset ) = IOasisDex(targetExchange).getOffer(id); return ( sellAsset, buyAsset, sellQuantity, buyQuantity ); } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/token/IERC20.sol"; import "../dependencies/WETH.sol"; import "../fund/accounting/Accounting.sol"; import "../fund/hub/Hub.sol"; import "../fund/trading/Trading.sol"; import "../fund/vault/Vault.sol"; import "./interfaces/IUniswapFactory.sol"; import "./interfaces/IUniswapExchange.sol"; import "./ExchangeAdapter.sol"; contract UniswapAdapter is DSMath, ExchangeAdapter { /// @notice Take order that uses a user-defined src token amount to trade for a dest token amount /// @dev For the purpose of PriceTolerance, _orderValues [1] == _orderValues [6] = Dest token amount /// @param _targetExchange Address of Uniswap factory contract /// @param _orderAddresses [2] Maker asset (Dest token) /// @param _orderAddresses [3] Taker asset (Src token) /// @param _orderValues [0] Maker asset quantity (Dest token amount) /// @param _orderValues [1] Taker asset quantity (Src token amount) /// @param _orderValues [6] Taker asset fill amount function takeOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override onlyManager notShutDown { require( _orderValues[1] == _orderValues[6], "Taker asset amount must equal taker asset fill amount" ); address makerAsset = _orderAddresses[2]; address takerAsset = _orderAddresses[3]; uint makerAssetAmount = _orderValues[0]; uint takerAssetAmount = _orderValues[1]; uint actualReceiveAmount = dispatchSwap( _targetExchange, takerAsset, takerAssetAmount, makerAsset, makerAssetAmount ); require( actualReceiveAmount >= makerAssetAmount, "Received less than expected from Uniswap exchange" ); updateStateTakeOrder( _targetExchange, makerAsset, takerAsset, takerAssetAmount, actualReceiveAmount ); } // INTERNAL FUNCTIONS /// @notice Call different functions based on type of assets supplied /// @param _targetExchange Address of Uniswap factory contract /// @param _srcToken Address of src token /// @param _srcAmount Amount of src token supplied /// @param _destToken Address of dest token /// @param _minDestAmount Minimum amount of dest token to receive /// @return actualReceiveAmount_ Actual amount of _destToken received function dispatchSwap( address _targetExchange, address _srcToken, uint _srcAmount, address _destToken, uint _minDestAmount ) internal returns (uint actualReceiveAmount_) { require( _srcToken != _destToken, "Src token cannot be the same as dest token" ); Hub hub = getHub(); address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET(); if (_srcToken == nativeAsset) { actualReceiveAmount_ = swapNativeAssetToToken( _targetExchange, nativeAsset, _srcAmount, _destToken, _minDestAmount ); } else if (_destToken == nativeAsset) { actualReceiveAmount_ = swapTokenToNativeAsset( _targetExchange, _srcToken, _srcAmount, nativeAsset, _minDestAmount ); } else { actualReceiveAmount_ = swapTokenToToken( _targetExchange, _srcToken, _srcAmount, _destToken, _minDestAmount ); } } /// @param _targetExchange Address of Uniswap factory contract /// @param _nativeAsset Native asset address as src token /// @param _srcAmount Amount of native asset supplied /// @param _destToken Address of dest token /// @param _minDestAmount Minimum amount of dest token to get back /// @return actualReceiveAmount_ Actual amount of _destToken received function swapNativeAssetToToken( address _targetExchange, address _nativeAsset, uint _srcAmount, address _destToken, uint _minDestAmount ) internal returns (uint actualReceiveAmount_) { // Convert WETH to ETH Hub hub = getHub(); Vault vault = Vault(hub.vault()); vault.withdraw(_nativeAsset, _srcAmount); WETH(payable(_nativeAsset)).withdraw(_srcAmount); address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_destToken); actualReceiveAmount_ = IUniswapExchange(tokenExchange).ethToTokenTransferInput.value( _srcAmount ) ( _minDestAmount, add(block.timestamp, 1), address(vault) ); } /// @param _targetExchange Address of Uniswap factory contract /// @param _srcToken Address of src token /// @param _srcAmount Amount of src token supplied /// @param _nativeAsset Native asset address as dest token /// @param _minDestAmount Minimum amount of dest token to get back /// @return actualReceiveAmount_ Actual amount of _destToken received function swapTokenToNativeAsset( address _targetExchange, address _srcToken, uint _srcAmount, address _nativeAsset, uint _minDestAmount ) internal returns (uint actualReceiveAmount_) { address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_srcToken); withdrawAndApproveAsset(_srcToken, tokenExchange, _srcAmount, "takerAsset"); actualReceiveAmount_ = IUniswapExchange(tokenExchange).tokenToEthSwapInput( _srcAmount, _minDestAmount, add(block.timestamp, 1) ); // Convert ETH to WETH and move to Vault WETH(payable(_nativeAsset)).deposit.value(actualReceiveAmount_)(); getTrading().returnAssetToVault(_nativeAsset); } /// @param _targetExchange Address of Uniswap factory contract /// @param _srcToken Address of src token /// @param _srcAmount Amount of src token supplied /// @param _destToken Address of dest token /// @param _minDestAmount Minimum amount of dest token to get back /// @return actualReceiveAmount_ Actual amount of _destToken received function swapTokenToToken( address _targetExchange, address _srcToken, uint _srcAmount, address _destToken, uint _minDestAmount ) internal returns (uint actualReceiveAmount_) { Hub hub = getHub(); address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_srcToken); withdrawAndApproveAsset(_srcToken, tokenExchange, _srcAmount, "takerAsset"); actualReceiveAmount_ = IUniswapExchange(tokenExchange).tokenToTokenTransferInput( _srcAmount, _minDestAmount, 1, add(block.timestamp, 1), address(Vault(hub.vault())), _destToken ); } function updateStateTakeOrder( address _targetExchange, address _makerAsset, address _takerAsset, uint256 _takerAssetAmount, uint256 _actualReceiveAmount ) internal { getAccounting().addAssetToOwnedAssets(_makerAsset); getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( _targetExchange, bytes32(0), Trading.UpdateType.take, [payable(_makerAsset), payable(_takerAsset)], [_actualReceiveAmount, _takerAssetAmount, _takerAssetAmount] ); } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/token/IERC20.sol"; import "../fund/trading/Trading.sol"; import "../fund/hub/Hub.sol"; import "../fund/vault/Vault.sol"; import "../fund/accounting/Accounting.sol"; import "../dependencies/DSMath.sol"; import "./interfaces/IZeroExV2.sol"; import "./ExchangeAdapter.sol"; /// @title ZeroExV2Adapter Contract /// @author Melonport AG <[email protected]> /// @notice Adapter to 0xV2 Exchange Contract contract ZeroExV2Adapter is DSMath, ExchangeAdapter { /// @param orderAddresses [2] Order maker asset /// @param orderAddresses [3] Order taker asset /// @param orderData [0] Order maker asset data /// @param orderData [1] Order taker asset data modifier orderAddressesMatchOrderData( address[8] memory orderAddresses, bytes[4] memory orderData ) { require( getAssetAddress(orderData[0]) == orderAddresses[2], "Maker asset data does not match order address in array" ); require( getAssetAddress(orderData[1]) == orderAddresses[3], "Taker asset data does not match order address in array" ); _; } // METHODS // PUBLIC METHODS /// @notice Make order by pre-approving signatures function makeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown orderAddressesMatchOrderData(orderAddresses, orderData) { ensureCanMakeOrder(orderAddresses[2]); IZeroExV2.Order memory order = constructOrderStruct(orderAddresses, orderValues, orderData); address makerAsset = getAssetAddress(orderData[0]); address takerAsset = getAssetAddress(orderData[1]); // Order parameter checks getTrading().updateAndGetQuantityBeingTraded(makerAsset); ensureNotInOpenMakeOrder(makerAsset); approveAssetsMakeOrder(targetExchange, order); IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(targetExchange).getOrderInfo(order); IZeroExV2(targetExchange).preSign(orderInfo.orderHash, address(this), signature); require( IZeroExV2(targetExchange).isValidSignature( orderInfo.orderHash, address(this), signature ), "INVALID_ORDER_SIGNATURE" ); updateStateMakeOrder(targetExchange, order); } // Responsibilities of takeOrder are: // - check sender // - check fund not shut down // - check not buying own fund tokens // - check price exists for asset pair // - check price is recent // - check price passes risk management // - approve funds to be traded (if necessary) // - take order from the exchange // - check order was taken (if possible) // - place asset in ownedAssets if not already tracked /// @notice Takes an active order on the selected exchange /// @dev These orders are expected to settle immediately /// @param targetExchange Address of the exchange /// @param orderAddresses [0] Order maker /// @param orderAddresses [1] Order taker /// @param orderAddresses [2] Order maker asset /// @param orderAddresses [3] Order taker asset /// @param orderAddresses [4] feeRecipientAddress /// @param orderAddresses [5] senderAddress /// @param orderValues [0] makerAssetAmount /// @param orderValues [1] takerAssetAmount /// @param orderValues [2] Maker fee /// @param orderValues [3] Taker fee /// @param orderValues [4] expirationTimeSeconds /// @param orderValues [5] Salt/nonce /// @param orderValues [6] Fill amount: amount of taker token to be traded /// @param orderValues [7] Dexy signature mode /// @param orderData [0] Encoded data specific to maker asset /// @param orderData [1] Encoded data specific to taker asset /// @param orderData [2] Encoded data specific to maker asset fee /// @param orderData [3] Encoded data specific to taker asset fee /// @param identifier Order identifier /// @param signature Signature of the order. function takeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override onlyManager notShutDown orderAddressesMatchOrderData(orderAddresses, orderData) { IZeroExV2.Order memory order = constructOrderStruct(orderAddresses, orderValues, orderData); uint fillTakerQuantity = orderValues[6]; approveAssetsTakeOrder(targetExchange, order); uint takerAssetFilledAmount = executeFill(targetExchange, order, fillTakerQuantity, signature); require( takerAssetFilledAmount == fillTakerQuantity, "Filled amount does not match desired fill amount" ); updateStateTakeOrder(targetExchange, order, fillTakerQuantity); } /// @notice Cancel the 0x make order function cancelOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override orderAddressesMatchOrderData(orderAddresses, orderData) { IZeroExV2.Order memory order = getTrading().getZeroExV2OrderDetails(identifier); ensureCancelPermitted(targetExchange, getAssetAddress(order.makerAssetData)); if (order.expirationTimeSeconds > block.timestamp) { IZeroExV2(targetExchange).cancelOrder(order); } revokeApproveAssetsCancelOrder(targetExchange, order); updateStateCancelOrder(targetExchange, order); } /// @dev Get order details function getOrder(address targetExchange, uint256 id, address makerAsset) public view override returns (address, address, uint256, uint256) { uint orderId; uint orderIndex; address takerAsset; uint makerQuantity; uint takerQuantity; (orderId, , orderIndex) = Trading(msg.sender).getOpenOrderInfo(targetExchange, makerAsset); (, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex); uint takerAssetFilledAmount = IZeroExV2(targetExchange).filled(bytes32(orderId)); uint makerAssetFilledAmount = mul(takerAssetFilledAmount, makerQuantity) / takerQuantity; if (IZeroExV2(targetExchange).cancelled(bytes32(orderId)) || sub(takerQuantity, takerAssetFilledAmount) == 0) { return (makerAsset, takerAsset, 0, 0); } return ( makerAsset, takerAsset, sub(makerQuantity, makerAssetFilledAmount), sub(takerQuantity, takerAssetFilledAmount) ); } // INTERNAL METHODS /// @notice Approves makerAsset, makerFee function approveAssetsMakeOrder(address _targetExchange, IZeroExV2.Order memory _order) internal { withdrawAndApproveAsset( getAssetAddress(_order.makerAssetData), getAssetProxy(_targetExchange, _order.makerAssetData), _order.makerAssetAmount, "makerAsset" ); if (_order.makerFee > 0) { bytes memory zrxAssetData = IZeroExV2(_targetExchange).ZRX_ASSET_DATA(); withdrawAndApproveAsset( getAssetAddress(zrxAssetData), getAssetProxy(_targetExchange, zrxAssetData), _order.makerFee, "makerFeeAsset" ); } } /// @notice Approves takerAsset, takerFee function approveAssetsTakeOrder(address _targetExchange, IZeroExV2.Order memory _order) internal { withdrawAndApproveAsset( getAssetAddress(_order.takerAssetData), getAssetProxy(_targetExchange, _order.takerAssetData), _order.takerAssetAmount, "takerAsset" ); if (_order.takerFee > 0) { bytes memory zrxAssetData = IZeroExV2(_targetExchange).ZRX_ASSET_DATA(); withdrawAndApproveAsset( getAssetAddress(zrxAssetData), getAssetProxy(_targetExchange, zrxAssetData), _order.takerFee, "takerFeeAsset" ); } } /// @dev Needed to avoid stack too deep error function executeFill( address targetExchange, IZeroExV2.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (uint256) { address makerAsset = getAssetAddress(order.makerAssetData); uint preMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this)); IZeroExV2.FillResults memory fillResults = IZeroExV2(targetExchange).fillOrder( order, takerAssetFillAmount, signature ); uint256 postMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this)); // Account for case where makerAsset is ZRX (same as takerFee) uint256 makerAssetFeesTotal; if (makerAsset == getAssetAddress(IZeroExV2(targetExchange).ZRX_ASSET_DATA())) { makerAssetFeesTotal = add(makerAssetFeesTotal, order.takerFee); } require( postMakerAssetBalance == sub( add(preMakerAssetBalance, fillResults.makerAssetFilledAmount), makerAssetFeesTotal ), "Maker asset balance different than expected" ); return fillResults.takerAssetFilledAmount; } /// @notice Revoke asset approvals and return assets to vault function revokeApproveAssetsCancelOrder( address _targetExchange, IZeroExV2.Order memory _order ) internal { address makerAsset = getAssetAddress(_order.makerAssetData); bytes memory makerFeeAssetData = IZeroExV2(_targetExchange).ZRX_ASSET_DATA(); address makerFeeAsset = getAssetAddress(makerFeeAssetData); revokeApproveAsset( makerAsset, getAssetProxy(_targetExchange, _order.makerAssetData), _order.makerAssetAmount, "makerAsset" ); getTrading().returnAssetToVault(makerAsset); if (_order.makerFee > 0) { revokeApproveAsset( makerFeeAsset, getAssetProxy(_targetExchange, makerFeeAssetData), _order.makerFee, "makerFeeAsset" ); if (makerFeeAsset != makerAsset) getTrading().returnAssetToVault(makerFeeAsset); } } /// @dev Avoids stack too deep error function updateStateCancelOrder(address targetExchange, IZeroExV2.Order memory order) internal { address makerAsset = getAssetAddress(order.makerAssetData); getTrading().removeOpenMakeOrder(targetExchange, makerAsset); getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( targetExchange, IZeroExV2(targetExchange).getOrderInfo(order).orderHash, Trading.UpdateType.cancel, [address(0), address(0)], [uint(0), uint(0), uint(0)] ); } /// @dev Avoids stack too deep error function updateStateMakeOrder(address targetExchange, IZeroExV2.Order memory order) internal { address makerAsset = getAssetAddress(order.makerAssetData); address takerAsset = getAssetAddress(order.takerAssetData); IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(targetExchange).getOrderInfo(order); getAccounting().addAssetToOwnedAssets(takerAsset); getTrading().orderUpdateHook( targetExchange, orderInfo.orderHash, Trading.UpdateType.make, [payable(makerAsset), payable(takerAsset)], [order.makerAssetAmount, order.takerAssetAmount, uint(0)] ); getTrading().addOpenMakeOrder( targetExchange, makerAsset, takerAsset, uint256(orderInfo.orderHash), order.expirationTimeSeconds ); getTrading().addZeroExV2OrderData(orderInfo.orderHash, order); } /// @dev avoids stack too deep error function updateStateTakeOrder( address targetExchange, IZeroExV2.Order memory order, uint256 fillTakerQuantity ) internal { address makerAsset = getAssetAddress(order.makerAssetData); address takerAsset = getAssetAddress(order.takerAssetData); getAccounting().addAssetToOwnedAssets(makerAsset); getAccounting().updateOwnedAssets(); getTrading().returnAssetToVault(makerAsset); getTrading().orderUpdateHook( targetExchange, IZeroExV2(targetExchange).getOrderInfo(order).orderHash, Trading.UpdateType.take, [payable(makerAsset), payable(takerAsset)], [order.makerAssetAmount, order.takerAssetAmount, fillTakerQuantity] ); } // VIEW METHODS function constructOrderStruct( address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData ) internal view returns (IZeroExV2.Order memory order) { order = IZeroExV2.Order({ makerAddress: orderAddresses[0], takerAddress: orderAddresses[1], feeRecipientAddress: orderAddresses[4], senderAddress: orderAddresses[5], makerAssetAmount: orderValues[0], takerAssetAmount: orderValues[1], makerFee: orderValues[2], takerFee: orderValues[3], expirationTimeSeconds: orderValues[4], salt: orderValues[5], makerAssetData: orderData[0], takerAssetData: orderData[1] }); } function getAssetProxy(address targetExchange, bytes memory assetData) internal view returns (address assetProxy) { bytes4 assetProxyId; assembly { assetProxyId := and(mload( add(assetData, 32)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 ) } assetProxy = IZeroExV2(targetExchange).getAssetProxy(assetProxyId); } function getAssetAddress(bytes memory assetData) internal view returns (address assetAddress) { assembly { assetAddress := mload(add(assetData, 36)) } } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../dependencies/token/IERC20.sol"; import "../fund/trading/Trading.sol"; import "../fund/hub/Hub.sol"; import "../fund/vault/Vault.sol"; import "../fund/accounting/Accounting.sol"; import "../dependencies/DSMath.sol"; import "./interfaces/IZeroExV3.sol"; import "./ExchangeAdapter.sol"; /// @title ZeroExV3Adapter Contract /// @author Melonport AG <[email protected]> /// @notice Adapter to 0xV3 Exchange Contract contract ZeroExV3Adapter is DSMath, ExchangeAdapter { /// @param _orderAddresses [2] Order maker asset /// @param _orderAddresses [3] Order taker asset /// @param _orderAddresses [6] Order maker fee asset /// @param _orderAddresses [7] Order taker fee asset /// @param _orderValues [2] Order maker fee amount /// @param _orderValues [3] Order taker fee amount modifier orderAddressesMatchOrderData( address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData ) { require( getAssetAddress(_orderData[0]) == _orderAddresses[2], "Maker asset data does not match order address in array" ); require( getAssetAddress(_orderData[1]) == _orderAddresses[3], "Taker asset data does not match order address in array" ); if (_orderValues[2] > 0) { require( getAssetAddress(_orderData[2]) == _orderAddresses[6], "Maker fee asset data does not match order address in array" ); } if (_orderValues[3] > 0) { require( getAssetAddress(_orderData[3]) == _orderAddresses[7], "Taker fee asset data does not match order address in array" ); } _; } // METHODS // PUBLIC METHODS /// @notice Make order by pre-approving signatures /// @param _targetExchange Address of the exchange /// @param _orderAddresses [2] Maker asset (Dest token) /// @param _orderAddresses [3] Taker asset (Src token) /// @param _orderData [0] Encoded data specific to maker asset /// @param _orderData [1] Encoded data specific to taker asset /// @param _signature _signature of the order. function makeOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override onlyManager notShutDown orderAddressesMatchOrderData(_orderAddresses, _orderValues, _orderData) { ensureCanMakeOrder(_orderAddresses[2]); Hub hub = getHub(); IZeroExV3.Order memory order = constructOrderStruct(_orderAddresses, _orderValues, _orderData); address makerAsset = getAssetAddress(_orderData[0]); address takerAsset = getAssetAddress(_orderData[1]); // Order parameter checks getTrading().updateAndGetQuantityBeingTraded(makerAsset); ensureNotInOpenMakeOrder(makerAsset); approveAssetsMakeOrder(_targetExchange, order); IZeroExV3.OrderInfo memory orderInfo = IZeroExV3(_targetExchange).getOrderInfo(order); IZeroExV3(_targetExchange).preSign(orderInfo.orderHash); require( IZeroExV3(_targetExchange).isValidOrderSignature(order, _signature), "INVALID_ORDER_SIGNATURE" ); updateStateMakeOrder(_targetExchange, order); } /// @notice Takes an active order on the selected exchange /// @dev These orders are expected to settle immediately /// @param _targetExchange Address of the exchange /// @param _orderAddresses [2] Order maker asset /// @param _orderAddresses [3] Order taker asset /// @param _orderValues [6] Fill amount: amount of taker token to be traded /// @param _signature _signature of the order. function takeOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override onlyManager notShutDown orderAddressesMatchOrderData(_orderAddresses, _orderValues, _orderData) { IZeroExV3.Order memory order = constructOrderStruct(_orderAddresses, _orderValues, _orderData); require(IZeroExV3(_targetExchange).isValidOrderSignature(order, _signature), "Order _signature is invalid"); uint256 fillTakerQuantity = _orderValues[6]; approveAssetsTakeOrder(_targetExchange, order); uint256 takerAssetFilledAmount = executeFill(_targetExchange, order, fillTakerQuantity, _signature); require( takerAssetFilledAmount == fillTakerQuantity, "Filled amount does not match desired fill amount" ); updateStateTakeOrder(_targetExchange, order, fillTakerQuantity); } /// @notice Cancel the 0x make order /// @param _targetExchange Address of the exchange /// @param _orderAddresses [2] Order maker asset /// @param _identifier Order _identifier function cancelOrder( address _targetExchange, address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData, bytes32 _identifier, bytes memory _signature ) public override orderAddressesMatchOrderData(_orderAddresses, _orderValues, _orderData) { IZeroExV3.Order memory order = getTrading().getZeroExV3OrderDetails(_identifier); ensureCancelPermitted(_targetExchange, getAssetAddress(order.makerAssetData)); if (order.expirationTimeSeconds > block.timestamp) { IZeroExV3(_targetExchange).cancelOrder(order); } revokeApproveAssetsCancelOrder(_targetExchange, order); updateStateCancelOrder(_targetExchange, order); } /// @dev Get order details function getOrder(address _targetExchange, uint256 _id, address _makerAsset) public view override returns (address, address, uint256, uint256) { uint orderId; uint orderIndex; address takerAsset; uint makerQuantity; uint takerQuantity; (orderId, , orderIndex) = Trading(msg.sender).getOpenOrderInfo(_targetExchange, _makerAsset); (, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex); uint takerAssetFilledAmount = IZeroExV3(_targetExchange).filled(bytes32(orderId)); uint makerAssetFilledAmount = mul(takerAssetFilledAmount, makerQuantity) / takerQuantity; if (IZeroExV3(_targetExchange).cancelled(bytes32(orderId)) || sub(takerQuantity, takerAssetFilledAmount) == 0) { return (_makerAsset, takerAsset, 0, 0); } return ( _makerAsset, takerAsset, sub(makerQuantity, makerAssetFilledAmount), sub(takerQuantity, takerAssetFilledAmount) ); } // INTERNAL METHODS /// @notice Approves makerAsset, makerFeeAsset function approveAssetsMakeOrder(address _targetExchange, IZeroExV3.Order memory _order) internal { withdrawAndApproveAsset( getAssetAddress(_order.makerAssetData), getAssetProxy(_targetExchange, _order.makerAssetData), _order.makerAssetAmount, "makerAsset" ); if (_order.makerFee > 0) { withdrawAndApproveAsset( getAssetAddress(_order.makerFeeAssetData), getAssetProxy(_targetExchange, _order.makerFeeAssetData), _order.makerFee, "makerFeeAsset" ); } } /// @notice Approves takerAsset, takerFeeAsset, protocolFee function approveAssetsTakeOrder(address _targetExchange, IZeroExV3.Order memory _order) internal { approveProtocolFeeAsset(_targetExchange); withdrawAndApproveAsset( getAssetAddress(_order.takerAssetData), getAssetProxy(_targetExchange, _order.takerAssetData), _order.takerAssetAmount, "takerAsset" ); if (_order.takerFee > 0) { withdrawAndApproveAsset( getAssetAddress(_order.takerFeeAssetData), getAssetProxy(_targetExchange, _order.takerFeeAssetData), _order.takerFee, "takerFeeAsset" ); } } function approveProtocolFeeAsset(address _targetExchange) internal { address protocolFeeCollector = IZeroExV3(_targetExchange).protocolFeeCollector(); uint256 protocolFeeAmount = calcProtocolFeeAmount(_targetExchange); if (protocolFeeCollector == address(0) || protocolFeeAmount == 0) return; Hub hub = getHub(); address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET(); withdrawAndApproveAsset(nativeAsset, protocolFeeCollector, protocolFeeAmount, "protocolFee"); } /// @dev Needed to avoid stack too deep error function executeFill( address _targetExchange, IZeroExV3.Order memory _order, uint256 _takerAssetFillAmount, bytes memory _signature ) internal returns (uint256) { Hub hub = getHub(); address makerAsset = getAssetAddress(_order.makerAssetData); uint preMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this)); IZeroExV3.FillResults memory fillResults = IZeroExV3(_targetExchange).fillOrder( _order, _takerAssetFillAmount, _signature ); uint256 postMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this)); // Account for case where makerAsset, takerFee, protocolFee are the same uint256 makerAssetFeesTotal; if ( makerAsset == Accounting(hub.accounting()).NATIVE_ASSET() && IZeroExV3(_targetExchange).protocolFeeCollector() != address(0) ) { makerAssetFeesTotal = calcProtocolFeeAmount(_targetExchange); } if (makerAsset == getAssetAddress(_order.takerFeeAssetData)) { makerAssetFeesTotal = add(makerAssetFeesTotal, _order.takerFee); } require( postMakerAssetBalance == sub( add(preMakerAssetBalance, fillResults.makerAssetFilledAmount), makerAssetFeesTotal ), "Maker asset balance different than expected" ); return fillResults.takerAssetFilledAmount; } /// @notice Revoke asset approvals and return assets to vault function revokeApproveAssetsCancelOrder( address _targetExchange, IZeroExV3.Order memory _order ) internal { address makerAsset = getAssetAddress(_order.makerAssetData); address makerFeeAsset = getAssetAddress(_order.makerFeeAssetData); revokeApproveAsset( makerAsset, getAssetProxy(_targetExchange, _order.makerAssetData), _order.makerAssetAmount, "makerAsset" ); getTrading().returnAssetToVault(makerAsset); if (_order.makerFee > 0) { revokeApproveAsset( makerFeeAsset, getAssetProxy(_targetExchange, _order.makerFeeAssetData), _order.makerFee, "makerFeeAsset" ); if (makerFeeAsset != makerAsset) getTrading().returnAssetToVault(makerFeeAsset); } } function updateStateCancelOrder(address _targetExchange, IZeroExV3.Order memory _order) internal { address makerAsset = getAssetAddress(_order.makerAssetData); getTrading().removeOpenMakeOrder(_targetExchange, makerAsset); getAccounting().updateOwnedAssets(); getTrading().orderUpdateHook( _targetExchange, IZeroExV3(_targetExchange).getOrderInfo(_order).orderHash, Trading.UpdateType.cancel, [address(0), address(0)], [uint(0), uint(0), uint(0)] ); } function updateStateMakeOrder(address _targetExchange, IZeroExV3.Order memory _order) internal { address makerAsset = getAssetAddress(_order.makerAssetData); address takerAsset = getAssetAddress(_order.takerAssetData); IZeroExV3.OrderInfo memory orderInfo = IZeroExV3(_targetExchange).getOrderInfo(_order); getAccounting().addAssetToOwnedAssets(takerAsset); getTrading().orderUpdateHook( _targetExchange, orderInfo.orderHash, Trading.UpdateType.make, [payable(makerAsset), payable(takerAsset)], [_order.makerAssetAmount, _order.takerAssetAmount, uint(0)] ); getTrading().addOpenMakeOrder( _targetExchange, makerAsset, takerAsset, uint256(orderInfo.orderHash), _order.expirationTimeSeconds ); getTrading().addZeroExV3OrderData(orderInfo.orderHash, _order); } /// @dev Avoids stack too deep error function updateStateTakeOrder( address _targetExchange, IZeroExV3.Order memory _order, uint256 _fillTakerQuantity ) internal { address makerAsset = getAssetAddress(_order.makerAssetData); address takerAsset = getAssetAddress(_order.takerAssetData); getAccounting().addAssetToOwnedAssets(makerAsset); getAccounting().updateOwnedAssets(); getTrading().returnAssetToVault(makerAsset); getTrading().orderUpdateHook( _targetExchange, IZeroExV3(_targetExchange).getOrderInfo(_order).orderHash, Trading.UpdateType.take, [payable(makerAsset), payable(takerAsset)], [_order.makerAssetAmount, _order.takerAssetAmount, _fillTakerQuantity] ); } // VIEW METHODS function calcProtocolFeeAmount(address _targetExchange) internal view returns (uint256) { return mul(IZeroExV3(_targetExchange).protocolFeeMultiplier(), tx.gasprice); } function constructOrderStruct( address[8] memory _orderAddresses, uint[8] memory _orderValues, bytes[4] memory _orderData ) internal view returns (IZeroExV3.Order memory order_) { order_ = IZeroExV3.Order({ makerAddress: _orderAddresses[0], takerAddress: _orderAddresses[1], feeRecipientAddress: _orderAddresses[4], senderAddress: _orderAddresses[5], makerAssetAmount: _orderValues[0], takerAssetAmount: _orderValues[1], makerFee: _orderValues[2], takerFee: _orderValues[3], expirationTimeSeconds: _orderValues[4], salt: _orderValues[5], makerAssetData: _orderData[0], takerAssetData: _orderData[1], makerFeeAssetData: _orderData[2], takerFeeAssetData: _orderData[3] }); } function getAssetProxy(address _targetExchange, bytes memory _assetData) internal view returns (address assetProxy_) { bytes4 assetProxyId; assembly { assetProxyId := and(mload( add(_assetData, 32)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 ) } assetProxy_ = IZeroExV3(_targetExchange).getAssetProxy(assetProxyId); } function getAssetAddress(bytes memory _assetData) internal view returns (address assetAddress_) { assembly { assetAddress_ := mload(add(_assetData, 36)) } } }
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]; } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../fund/accounting/IAccounting.sol"; import "../fund/fees/IFeeManager.sol"; import "../fund/hub/Hub.sol"; import "../fund/policies/IPolicyManager.sol"; import "../fund/participation/IParticipation.sol"; import "../fund/shares/IShares.sol"; import "../fund/trading/ITrading.sol"; import "../fund/vault/IVault.sol"; import "../version/IVersion.sol"; import "../engine/AmguConsumer.sol"; import "./Factory.sol"; /// @notice Creates fund routes and links them together contract FundFactory is AmguConsumer, Factory { event NewFund( address indexed manager, address indexed hub, address[11] routes ); IVersion public version; Registry public associatedRegistry; IAccountingFactory public accountingFactory; IFeeManagerFactory public feeManagerFactory; IParticipationFactory public participationFactory; IPolicyManagerFactory public policyManagerFactory; ISharesFactory public sharesFactory; ITradingFactory public tradingFactory; IVaultFactory public vaultFactory; address[] public funds; mapping (address => address) public managersToHubs; mapping (address => Hub.Routes) public managersToRoutes; mapping (address => Settings) public managersToSettings; /// @dev Parameters stored when beginning setup struct Settings { string name; address[] exchanges; address[] adapters; address denominationAsset; address[] defaultInvestmentAssets; address[] fees; uint[] feeRates; uint[] feePeriods; } constructor( address _accountingFactory, address _feeManagerFactory, address _participationFactory, address _sharesFactory, address _tradingFactory, address _vaultFactory, address _policyManagerFactory, address _version ) public { accountingFactory = IAccountingFactory(_accountingFactory); feeManagerFactory = IFeeManagerFactory(_feeManagerFactory); participationFactory = IParticipationFactory(_participationFactory); sharesFactory = ISharesFactory(_sharesFactory); tradingFactory = ITradingFactory(_tradingFactory); vaultFactory = IVaultFactory(_vaultFactory); policyManagerFactory = IPolicyManagerFactory(_policyManagerFactory); version = IVersion(_version); } function componentExists(address _component) internal pure returns (bool) { return _component != address(0); } function ensureComponentNotSet(address _component) internal { require( !componentExists(_component), "This step has already been run" ); } function ensureComponentSet(address _component) internal { require( componentExists(_component), "Component preprequisites not met" ); } function beginSetup( string memory _name, address[] memory _fees, uint[] memory _feeRates, uint[] memory _feePeriods, address[] memory _exchanges, address[] memory _adapters, address _denominationAsset, address[] memory _defaultInvestmentAssets ) public { ensureComponentNotSet(managersToHubs[msg.sender]); associatedRegistry.reserveFundName( msg.sender, _name ); require( associatedRegistry.assetIsRegistered(_denominationAsset), "Denomination asset must be registered" ); managersToHubs[msg.sender] = address(new Hub(msg.sender, _name)); managersToSettings[msg.sender] = Settings( _name, _exchanges, _adapters, _denominationAsset, _defaultInvestmentAssets, _fees, _feeRates, _feePeriods ); managersToRoutes[msg.sender].registry = address(associatedRegistry); managersToRoutes[msg.sender].version = address(version); managersToRoutes[msg.sender].engine = engine(); managersToRoutes[msg.sender].mlnToken = mlnToken(); } function _createAccountingFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].accounting); managersToRoutes[_manager].accounting = accountingFactory.createInstance( managersToHubs[_manager], managersToSettings[_manager].denominationAsset, associatedRegistry.nativeAsset() ); } function createAccountingFor(address _manager) external amguPayable(false) payable { _createAccountingFor(_manager); } function createAccounting() external amguPayable(false) payable { _createAccountingFor(msg.sender); } function _createFeeManagerFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].feeManager); managersToRoutes[_manager].feeManager = feeManagerFactory.createInstance( managersToHubs[_manager], managersToSettings[_manager].denominationAsset, managersToSettings[_manager].fees, managersToSettings[_manager].feeRates, managersToSettings[_manager].feePeriods, managersToRoutes[_manager].registry ); } function createFeeManagerFor(address _manager) external amguPayable(false) payable { _createFeeManagerFor(_manager); } function createFeeManager() external amguPayable(false) payable { _createFeeManagerFor(msg.sender); } function _createParticipationFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].participation); managersToRoutes[_manager].participation = participationFactory.createInstance( managersToHubs[_manager], managersToSettings[_manager].defaultInvestmentAssets, managersToRoutes[_manager].registry ); } function createParticipationFor(address _manager) external amguPayable(false) payable { _createParticipationFor(_manager); } function createParticipation() external amguPayable(false) payable { _createParticipationFor(msg.sender); } function _createPolicyManagerFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].policyManager); managersToRoutes[_manager].policyManager = policyManagerFactory.createInstance( managersToHubs[_manager] ); } function createPolicyManagerFor(address _manager) external amguPayable(false) payable { _createPolicyManagerFor(_manager); } function createPolicyManager() external amguPayable(false) payable { _createPolicyManagerFor(msg.sender); } function _createSharesFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].shares); managersToRoutes[_manager].shares = sharesFactory.createInstance( managersToHubs[_manager] ); } function createSharesFor(address _manager) external amguPayable(false) payable { _createSharesFor(_manager); } function createShares() external amguPayable(false) payable { _createSharesFor(msg.sender); } function _createTradingFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].trading); managersToRoutes[_manager].trading = tradingFactory.createInstance( managersToHubs[_manager], managersToSettings[_manager].exchanges, managersToSettings[_manager].adapters, managersToRoutes[_manager].registry ); } function createTradingFor(address _manager) external amguPayable(false) payable { _createTradingFor(_manager); } function createTrading() external amguPayable(false) payable { _createTradingFor(msg.sender); } function _createVaultFor(address _manager) internal { ensureComponentSet(managersToHubs[_manager]); ensureComponentNotSet(managersToRoutes[_manager].vault); managersToRoutes[_manager].vault = vaultFactory.createInstance( managersToHubs[_manager] ); } function createVaultFor(address _manager) external amguPayable(false) payable { _createVaultFor(_manager); } function createVault() external amguPayable(false) payable { _createVaultFor(msg.sender); } function _completeSetupFor(address _manager) internal { Hub.Routes memory routes = managersToRoutes[_manager]; Hub hub = Hub(managersToHubs[_manager]); require(!childExists[address(hub)], "Setup already complete"); require( componentExists(address(hub)) && componentExists(routes.accounting) && componentExists(routes.feeManager) && componentExists(routes.participation) && componentExists(routes.policyManager) && componentExists(routes.shares) && componentExists(routes.trading) && componentExists(routes.vault), "Components must be set before completing setup" ); childExists[address(hub)] = true; hub.setSpokes([ routes.accounting, routes.feeManager, routes.participation, routes.policyManager, routes.shares, routes.trading, routes.vault, routes.registry, routes.version, routes.engine, routes.mlnToken ]); hub.setRouting(); hub.setPermissions(); funds.push(address(hub)); associatedRegistry.registerFund( address(hub), _manager, managersToSettings[_manager].name ); emit NewFund( msg.sender, address(hub), [ routes.accounting, routes.feeManager, routes.participation, routes.policyManager, routes.shares, routes.trading, routes.vault, routes.registry, routes.version, routes.engine, routes.mlnToken ] ); } function completeSetupFor(address _manager) external amguPayable(false) payable { _completeSetupFor(_manager); } function completeSetup() external amguPayable(false) payable { _completeSetupFor(msg.sender); } function getFundById(uint withId) external view returns (address) { return funds[withId]; } function getLastFundId() external view returns (uint) { return funds.length - 1; } function mlnToken() public view override returns (address) { return address(associatedRegistry.mlnToken()); } function engine() public view override returns (address) { return address(associatedRegistry.engine()); } function priceSource() public view override returns (address) { return address(associatedRegistry.priceSource()); } function registry() public view override returns (address) { return address(associatedRegistry); } function getExchangesInfo(address user) public view returns (address[] memory) { return (managersToSettings[user].exchanges); } }
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 (uint) { return ownedAssets.length; } 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 calcSharePrice() external returns (uint sharePrice) { (,,,,sharePrice,) = performCalculations(); return sharePrice; } 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; } }
pragma solidity 0.6.1; /// @notice Gives metrics about a Fund interface IAccounting { function getOwnedAssetsLength() external view returns (uint); function getFundHoldings() external returns (uint[] memory, address[] memory); function calcAssetGAV(address ofAsset) external returns (uint); function calcGav() external returns (uint gav); function calcNav(uint gav, uint unclaimedFees) external pure returns (uint); function valuePerShare(uint totalValue, uint numShares) external view returns (uint); function performCalculations() external returns ( uint gav, uint unclaimedFees, uint feesInShares, uint nav, uint sharePrice, uint gavPerShareNetManagementFee ); function calcSharePrice() external returns (uint); function calcGavPerShareNetManagementFee() external returns (uint); } interface IAccountingFactory { function createInstance(address _hub, address _denominationAsset, address _nativeAsset) external returns (address); }
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; } }
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); }
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); }
pragma solidity 0.6.1; import "./FeeManager.sol"; import "../hub/Hub.sol"; import "../shares/Shares.sol"; import "../../dependencies/DSMath.sol"; contract ManagementFee is DSMath { uint public DIVISOR = 10 ** 18; mapping (address => uint) public managementFeeRate; mapping (address => uint) public lastPayoutTime; function feeAmount() external view returns (uint feeInShares) { Hub hub = FeeManager(msg.sender).hub(); Shares shares = Shares(hub.shares()); if (shares.totalSupply() == 0 || managementFeeRate[msg.sender] == 0) { feeInShares = 0; } else { uint timePassed = sub(block.timestamp, lastPayoutTime[msg.sender]); uint preDilutionFeeShares = mul(mul(shares.totalSupply(), managementFeeRate[msg.sender]) / DIVISOR, timePassed) / 365 days; feeInShares = mul(preDilutionFeeShares, shares.totalSupply()) / sub(shares.totalSupply(), preDilutionFeeShares); } return feeInShares; } function initializeForUser(uint feeRate, uint feePeriod, address denominationAsset) external { require(lastPayoutTime[msg.sender] == 0); managementFeeRate[msg.sender] = feeRate; lastPayoutTime[msg.sender] = block.timestamp; } function updateState() external { lastPayoutTime[msg.sender] = block.timestamp; } function identifier() external pure returns (uint) { return 0; } }
pragma solidity 0.6.1; import "./FeeManager.sol"; import "../accounting/Accounting.sol"; import "../hub/Hub.sol"; import "../shares/Shares.sol"; import "../../dependencies/DSMath.sol"; contract PerformanceFee is DSMath { event HighWaterMarkUpdate(address indexed feeManager, uint indexed hwm); uint public constant DIVISOR = 10 ** 18; uint public constant REDEEM_WINDOW = 1 weeks; mapping(address => uint) public highWaterMark; mapping(address => uint) public lastPayoutTime; mapping(address => uint) public initializeTime; mapping(address => uint) public performanceFeeRate; mapping(address => uint) public performanceFeePeriod; /// @notice Sets initial state of the fee for a user function initializeForUser(uint feeRate, uint feePeriod, address denominationAsset) external { require(lastPayoutTime[msg.sender] == 0, "Already initialized"); performanceFeeRate[msg.sender] = feeRate; performanceFeePeriod[msg.sender] = feePeriod; highWaterMark[msg.sender] = 10 ** uint(ERC20WithFields(denominationAsset).decimals()); lastPayoutTime[msg.sender] = block.timestamp; initializeTime[msg.sender] = block.timestamp; } /// @notice Assumes management fee is zero function feeAmount() external returns (uint feeInShares) { Hub hub = FeeManager(msg.sender).hub(); Accounting accounting = Accounting(hub.accounting()); Shares shares = Shares(hub.shares()); uint gav = accounting.calcGav(); uint gavPerShare = shares.totalSupply() > 0 ? accounting.valuePerShare(gav, shares.totalSupply()) : accounting.DEFAULT_SHARE_PRICE(); if ( gavPerShare > highWaterMark[msg.sender] && shares.totalSupply() != 0 && gav != 0 ) { uint sharePriceGain = sub(gavPerShare, highWaterMark[msg.sender]); uint totalGain = mul(sharePriceGain, shares.totalSupply()) / DIVISOR; uint feeInAsset = mul(totalGain, performanceFeeRate[msg.sender]) / DIVISOR; uint preDilutionFee = mul(shares.totalSupply(), feeInAsset) / gav; feeInShares = mul(preDilutionFee, shares.totalSupply()) / sub(shares.totalSupply(), preDilutionFee); } else { feeInShares = 0; } return feeInShares; } function canUpdate(address _who) public view returns (bool) { uint timeSinceInit = sub( block.timestamp, initializeTime[_who] ); uint secondsSinceLastPeriod = timeSinceInit % performanceFeePeriod[_who]; uint lastPeriodEnd = sub(block.timestamp, secondsSinceLastPeriod); return ( secondsSinceLastPeriod <= REDEEM_WINDOW && lastPayoutTime[_who] < lastPeriodEnd ); } /// @notice Assumes management fee is zero function updateState() external { require(lastPayoutTime[msg.sender] != 0, "Not initialized"); require( canUpdate(msg.sender), "Not within a update window or already updated this period" ); Hub hub = FeeManager(msg.sender).hub(); Accounting accounting = Accounting(hub.accounting()); Shares shares = Shares(hub.shares()); uint gav = accounting.calcGav(); uint currentGavPerShare = accounting.valuePerShare(gav, shares.totalSupply()); require( currentGavPerShare > highWaterMark[msg.sender], "Current share price does not pass high water mark" ); lastPayoutTime[msg.sender] = block.timestamp; highWaterMark[msg.sender] = currentGavPerShare; emit HighWaterMarkUpdate(msg.sender, currentGavPerShare); } function identifier() external pure returns (uint) { return 1; } }
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 spokesSet; bool public routingSet; bool public permissionsSet; 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 setSpokes(address[11] calldata _spokes) external onlyCreator { require(!spokesSet, "Spokes already set"); 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]; spokesSet = true; } function setRouting() external onlyCreator { require(spokesSet, "Spokes must be set"); require(!routingSet, "Routing already set"); address[11] memory spokes = [ routes.accounting, routes.feeManager, routes.participation, routes.policyManager, routes.shares, routes.trading, routes.vault, routes.registry, routes.version, routes.engine, routes.mlnToken ]; 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); routingSet = true; } function setPermissions() external onlyCreator { require(spokesSet, "Spokes must be set"); require(routingSet, "Routing must be set"); require(!permissionsSet, "Permissioning already set"); 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)'))); permissionsSet = 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; } }
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; } }
pragma solidity 0.6.1; /// @notice Investor Fund interactions /// @notice Handles redemptions and requests for investment interface IParticipation { function requestInvestment( uint requestedShares, uint investmentAmount, address investmentAsset ) external payable; function hasRequest(address) external view returns (bool); function cancelRequest() external payable; function executeRequestFor(address requestOwner) external payable; function redeem() external; function redeemWithConstraints(uint shareQuantity, address[] calldata requestedAssets) external; } interface IParticipationFactory { function createInstance(address _hub, address[] calldata _defaultAssets, address _registry) external returns (address); }
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( bytes4(keccak256("requestInvestment(uint256,uint256,address)")), [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( bytes4(keccak256("requestInvestment(uint256,uint256,address)")), [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" ); require( IPriceSource(priceSource()).hasValidPrice(request.investmentAsset), "Price not valid" ); 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); if (msg.sender == hub.manager()) { return 0; } 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).getFundHoldings(); 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]; if (ofAsset == address(0)) continue; 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; } }
pragma solidity 0.6.1; import "../../dependencies/DSAuth.sol"; /// @notice Generic AddressList contract AddressList is DSAuth { event ListAddition(address[] ones); mapping(address => bool) internal list; address[] internal mirror; constructor(address[] memory _assets) public { for (uint i = 0; i < _assets.length; i++) { if (!isMember(_assets[i])) { // filter duplicates in _assets list[_assets[i]] = true; mirror.push(_assets[i]); } } emit ListAddition(_assets); } /// @return whether an asset is in the list function isMember(address _asset) public view returns (bool) { return list[_asset]; } /// @return number of assets specified in the list function getMemberCount() external view returns (uint) { return mirror.length; } /// @return array of all listed asset addresses function getMembers() external view returns (address[] memory) { return mirror; } }
pragma solidity 0.6.1; import "../../../dependencies/DSAuth.sol"; contract UserWhitelist is DSAuth { enum Applied { pre, post } event ListAddition(address indexed who); event ListRemoval(address indexed who); mapping (address => bool) public whitelisted; constructor(address[] memory _preApproved) public { batchAddToWhitelist(_preApproved); } function addToWhitelist(address _who) public auth { whitelisted[_who] = true; emit ListAddition(_who); } function removeFromWhitelist(address _who) public auth { whitelisted[_who] = false; emit ListRemoval(_who); } function batchAddToWhitelist(address[] memory _members) public auth { for (uint i = 0; i < _members.length; i++) { addToWhitelist(_members[i]); } } function batchRemoveFromWhitelist(address[] memory _members) public auth { for (uint i = 0; i < _members.length; i++) { removeFromWhitelist(_members[i]); } } function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { return whitelisted[addresses[0]]; } function position() external pure returns (Applied) { return Applied.pre; } function identifier() external pure returns (string memory) { return 'UserWhitelist'; } }
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); }
pragma solidity 0.6.1; interface IPolicyManagerFactory { function createInstance(address _hub) external returns (address); }
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; } }
pragma solidity 0.6.1; import "../AddressList.sol"; import "../TradingSignatures.sol"; /// @notice Assets can be added but not removed from blacklist contract AssetBlacklist is TradingSignatures, AddressList { enum Applied { pre, post } // bytes4 constant public MAKE_ORDER = 0x79705be7; // makeOrderSignature // bytes4 constant public TAKE_ORDER = 0xe51be6e8; // takeOrderSignature constructor(address[] memory _assets) AddressList(_assets) public {} function addToBlacklist(address _asset) external auth { require(!isMember(_asset), "Asset already in blacklist"); list[_asset] = true; mirror.push(_asset); } function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { address incomingToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3]; return !isMember(incomingToken); } function position() external pure returns (Applied) { return Applied.pre; } function identifier() external pure returns (string memory) { return 'AssetBlacklist'; } }
pragma solidity 0.6.1; import "../AddressList.sol"; import "../TradingSignatures.sol"; /// @notice Assets can be removed from but not added to whitelist contract AssetWhitelist is TradingSignatures, AddressList { enum Applied { pre, post } constructor(address[] memory _assets) public AddressList(_assets) {} function removeFromWhitelist(address _asset) external auth { require(isMember(_asset), "Asset not in whitelist"); delete list[_asset]; uint i = getAssetIndex(_asset); for (i; i < mirror.length-1; i++){ mirror[i] = mirror[i+1]; } mirror.pop(); } function getAssetIndex(address _asset) public view returns (uint) { for (uint i = 0; i < mirror.length; i++) { if (mirror[i] == _asset) { return i; } } } function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { address incomingToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3]; return isMember(incomingToken); } function position() external pure returns (Applied) { return Applied.pre; } function identifier() external pure returns (string memory) { return 'AssetWhitelist'; } }
pragma solidity 0.6.1; import "../../../dependencies/DSMath.sol"; import "../../../prices/IPriceSource.sol"; import "../../accounting/Accounting.sol"; import "../../trading/Trading.sol"; import "../TradingSignatures.sol"; import "../../../prices/IPriceSource.sol"; contract MaxConcentration is TradingSignatures, DSMath { enum Applied { pre, post } uint internal constant ONE_HUNDRED_PERCENT = 10 ** 18; // 100% uint public maxConcentration; constructor(uint _maxConcentration) public { require( _maxConcentration <= ONE_HUNDRED_PERCENT, "Max concentration cannot exceed 100%" ); maxConcentration = _maxConcentration; } function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { Accounting accounting = Accounting(Hub(Trading(msg.sender).hub()).accounting()); address denominationAsset = accounting.DENOMINATION_ASSET(); // Max concentration is only checked for non-quote assets address takerToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3]; if (denominationAsset == takerToken) { return true; } uint concentration; uint totalGav = accounting.calcGav(); if (sig == MAKE_ORDER) { IPriceSource priceSource = IPriceSource(Hub(Trading(msg.sender).hub()).priceSource()); address makerToken = addresses[2]; uint makerQuantiyBeingTraded = values[0]; uint takerQuantityBeingTraded = values[1]; uint takerTokenGavBeingTraded = priceSource.convertQuantity( takerQuantityBeingTraded, takerToken, denominationAsset ); uint makerTokenGavBeingTraded; if (makerToken == denominationAsset) { makerTokenGavBeingTraded = makerQuantiyBeingTraded; } else { makerTokenGavBeingTraded = priceSource.convertQuantity( makerQuantiyBeingTraded, makerToken, denominationAsset ); } concentration = _calcConcentration( add(accounting.calcAssetGAV(takerToken), takerTokenGavBeingTraded), add(takerTokenGavBeingTraded, sub(totalGav, makerTokenGavBeingTraded)) ); } else { concentration = _calcConcentration( accounting.calcAssetGAV(takerToken), totalGav ); } return concentration <= maxConcentration; } function position() external pure returns (Applied) { return Applied.post; } function identifier() external pure returns (string memory) { return 'MaxConcentration'; } function _calcConcentration(uint assetGav, uint totalGav) internal returns (uint) { return mul(assetGav, ONE_HUNDRED_PERCENT) / totalGav; } }
pragma solidity 0.6.1; import "../../../prices/IPriceSource.sol"; import "../../accounting/Accounting.sol"; import "../../trading/Trading.sol"; import "../TradingSignatures.sol"; contract MaxPositions is TradingSignatures { enum Applied { pre, post } uint public maxPositions; /// @dev _maxPositions = 10 means max 10 different asset tokens /// @dev _maxPositions = 0 means no asset tokens are investable constructor(uint _maxPositions) public { maxPositions = _maxPositions; } function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { Accounting accounting = Accounting(Hub(Trading(msg.sender).hub()).accounting()); address denominationAsset = accounting.DENOMINATION_ASSET(); // Always allow a trade INTO the quote asset address incomingToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3]; if (denominationAsset == incomingToken) { return true; } return accounting.getOwnedAssetsLength() <= maxPositions; } function position() external pure returns (Applied) { return Applied.post; } function identifier() external pure returns (string memory) { return 'MaxPositions'; } }
pragma solidity 0.6.1; import "../../hub/Hub.sol"; import "../../../prices/IPriceSource.sol"; import "../TradingSignatures.sol"; import "../../../dependencies/DSMath.sol"; import "../../trading/Trading.sol"; import "../../../exchanges/interfaces/IOasisDex.sol"; contract PriceTolerance is TradingSignatures, DSMath { enum Applied { pre, post } uint public tolerance; uint constant MULTIPLIER = 10 ** 16; // to give effect of a percentage uint constant DIVISOR = 10 ** 18; // _tolerance: 10 equals to 10% of tolerance constructor(uint _tolerancePercent) public { require(_tolerancePercent <= 100, "Tolerance range is 0% - 100%"); tolerance = mul(_tolerancePercent, MULTIPLIER); } /// @notice Taken from OpenZeppelin (https://git.io/fhQqo) function signedSafeSub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a)); return c; } function takeOasisDex( address ofExchange, bytes32 identifier, uint fillTakerQuantity ) public view returns (bool) { uint maxMakerQuantity; address makerAsset; uint maxTakerQuantity; address takerAsset; ( maxMakerQuantity, makerAsset, maxTakerQuantity, takerAsset ) = IOasisDex(ofExchange).getOffer(uint(identifier)); uint fillMakerQuantity = mul(fillTakerQuantity, maxMakerQuantity) / maxTakerQuantity; IPriceSource pricefeed = IPriceSource(Hub(Trading(msg.sender).hub()).priceSource()); uint referencePrice; (referencePrice,) = pricefeed.getReferencePriceInfo(takerAsset, makerAsset); uint orderPrice = pricefeed.getOrderPriceInfo( takerAsset, makerAsset, fillTakerQuantity, fillMakerQuantity ); return orderPrice >= sub( referencePrice, mul(tolerance, referencePrice) / DIVISOR ); } function takeGenericOrder( address makerAsset, address takerAsset, uint[3] memory values ) public view returns (bool) { uint fillTakerQuantity = values[2]; uint fillMakerQuantity = mul(fillTakerQuantity, values[0]) / values[1]; IPriceSource pricefeed = IPriceSource(Hub(Trading(msg.sender).hub()).priceSource()); uint referencePrice; (referencePrice, ) = pricefeed.getReferencePriceInfo(takerAsset, makerAsset); uint orderPrice = pricefeed.getOrderPriceInfo( takerAsset, makerAsset, fillTakerQuantity, fillMakerQuantity ); return orderPrice >= sub( referencePrice, mul(tolerance, referencePrice) / DIVISOR ); } function takeOrder( address[5] memory addresses, uint[3] memory values, bytes32 identifier ) public view returns (bool) { if (identifier == 0x0) { return takeGenericOrder(addresses[2], addresses[3], values); } else { return takeOasisDex(addresses[4], identifier, values[2]); } } function makeOrder( address[5] memory addresses, uint[3] memory values, bytes32 identifier ) public view returns (bool) { IPriceSource pricefeed = IPriceSource(Hub(Trading(msg.sender).hub()).priceSource()); uint ratio; (ratio,) = IPriceSource(pricefeed).getReferencePriceInfo(addresses[2], addresses[3]); uint _value = IPriceSource(pricefeed).getOrderPriceInfo(addresses[2], addresses[3], values[0], values[1]); int res = signedSafeSub(int(ratio), int(_value)); if (res < 0) { return true; } else { return wdiv(uint(res), ratio) <= tolerance; } } function rule( bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier ) external returns (bool) { if (sig == MAKE_ORDER) { return makeOrder(addresses, values, identifier); } else if (sig == TAKE_ORDER) { return takeOrder(addresses, values, identifier); } revert("Signature was neither MakeOrder nor TakeOrder"); } function position() external pure returns (Applied) { return Applied.pre; } function identifier() external pure returns (string memory) { return 'PriceTolerance'; } }
pragma solidity 0.6.1; contract TradingSignatures { bytes4 constant public MAKE_ORDER = 0x5f08e909; // makeOrderSignature bytes4 constant public TAKE_ORDER = 0x63b24ef1; // takeOrderSignature }
pragma solidity 0.6.1; /// @notice Token representing ownership of the Fund interface IShares { function createFor(address who, uint amount) external; function destroyFor(address who, uint amount) external; } interface ISharesFactory { function createInstance(address _hub) external returns (address); }
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; } }
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, 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); }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "../hub/Spoke.sol"; import "../vault/Vault.sol"; import "../policies/PolicyManager.sol"; import "../policies/TradingSignatures.sol"; import "../../factory/Factory.sol"; import "../../dependencies/DSMath.sol"; import "../../exchanges/ExchangeAdapter.sol"; import "../../exchanges/interfaces/IZeroExV2.sol"; import "../../exchanges/interfaces/IZeroExV3.sol"; import "../../version/Registry.sol"; import "../../dependencies/TokenUser.sol"; contract Trading is DSMath, TokenUser, Spoke, TradingSignatures { event ExchangeMethodCall( address indexed exchangeAddress, string indexed methodSignature, address[8] orderAddresses, uint[8] orderValues, bytes[4] orderData, bytes32 identifier, bytes signature ); struct Exchange { address exchange; address adapter; bool takesCustody; } enum UpdateType { make, take, cancel } struct Order { address exchangeAddress; bytes32 orderId; UpdateType updateType; address makerAsset; address takerAsset; uint makerQuantity; uint takerQuantity; uint timestamp; uint fillTakerQuantity; } struct OpenMakeOrder { uint id; // Order Id from exchange uint expiresAt; // Timestamp when the order expires uint orderIndex; // Index of the order in the orders array address buyAsset; // Address of the buy asset in the order } Exchange[] public exchanges; Order[] public orders; mapping (address => bool) public adapterIsAdded; mapping (address => mapping(address => OpenMakeOrder)) public exchangesToOpenMakeOrders; mapping (address => uint) public openMakeOrdersAgainstAsset; mapping (address => bool) public isInOpenMakeOrder; mapping (address => uint) public makerAssetCooldown; mapping (bytes32 => IZeroExV2.Order) internal orderIdToZeroExV2Order; mapping (bytes32 => IZeroExV3.Order) internal orderIdToZeroExV3Order; uint public constant ORDER_LIFESPAN = 1 days; uint public constant MAKE_ORDER_COOLDOWN = 30 minutes; modifier delegateInternal() { require(msg.sender == address(this), "Sender is not this contract"); _; } constructor( address _hub, address[] memory _exchanges, address[] memory _adapters, address _registry ) public Spoke(_hub) { routes.registry = _registry; require(_exchanges.length == _adapters.length, "Array lengths unequal"); for (uint i = 0; i < _exchanges.length; i++) { _addExchange(_exchanges[i], _adapters[i]); } } /// @notice Receive ether function (used to receive ETH from WETH) receive() external payable {} function addExchange(address _exchange, address _adapter) external auth { _addExchange(_exchange, _adapter); } function _addExchange( address _exchange, address _adapter ) internal { require(!adapterIsAdded[_adapter], "Adapter already added"); adapterIsAdded[_adapter] = true; Registry registry = Registry(routes.registry); require( registry.exchangeAdapterIsRegistered(_adapter), "Adapter is not registered" ); address registeredExchange; bool takesCustody; (registeredExchange, takesCustody) = registry.getExchangeInformation(_adapter); require( registeredExchange == _exchange, "Exchange and adapter do not match" ); exchanges.push(Exchange(_exchange, _adapter, takesCustody)); } /// @notice Universal method for calling exchange functions through adapters /// @notice See adapter contracts for parameters needed for each exchange /// @param exchangeIndex Index of the exchange in the "exchanges" array /// @param orderAddresses [0] Order maker /// @param orderAddresses [1] Order taker /// @param orderAddresses [2] Order maker asset /// @param orderAddresses [3] Order taker asset /// @param orderAddresses [4] feeRecipientAddress /// @param orderAddresses [5] senderAddress /// @param orderAddresses [6] maker fee asset /// @param orderAddresses [7] taker fee asset /// @param orderValues [0] makerAssetAmount /// @param orderValues [1] takerAssetAmount /// @param orderValues [2] Maker fee /// @param orderValues [3] Taker fee /// @param orderValues [4] expirationTimeSeconds /// @param orderValues [5] Salt/nonce /// @param orderValues [6] Fill amount: amount of taker token to be traded /// @param orderValues [7] Dexy signature mode /// @param orderData [0] Encoded data specific to maker asset /// @param orderData [1] Encoded data specific to taker asset /// @param orderData [2] Encoded data specific to maker asset fee /// @param orderData [3] Encoded data specific to taker asset fee /// @param identifier Order identifier /// @param signature Signature of order maker function callOnExchange( uint exchangeIndex, string memory methodSignature, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public onlyInitialized { bytes4 methodSelector = bytes4(keccak256(bytes(methodSignature))); require( Registry(routes.registry).adapterMethodIsAllowed( exchanges[exchangeIndex].adapter, methodSelector ), "Adapter method not allowed" ); PolicyManager(routes.policyManager).preValidate(methodSelector, [orderAddresses[0], orderAddresses[1], orderAddresses[2], orderAddresses[3], exchanges[exchangeIndex].exchange], [orderValues[0], orderValues[1], orderValues[6]], identifier); if ( methodSelector == MAKE_ORDER || methodSelector == TAKE_ORDER ) { require(Registry(routes.registry).assetIsRegistered( orderAddresses[2]), 'Maker asset not registered' ); require(Registry(routes.registry).assetIsRegistered( orderAddresses[3]), 'Taker asset not registered' ); if (orderAddresses[6] != address(0) && methodSelector == MAKE_ORDER) { require( Registry(routes.registry).assetIsRegistered(orderAddresses[6]), 'Maker fee asset not registered' ); } if (orderAddresses[7] != address(0) && methodSelector == TAKE_ORDER) { require( Registry(routes.registry).assetIsRegistered(orderAddresses[7]), 'Taker fee asset not registered' ); } } (bool success, bytes memory returnData) = exchanges[exchangeIndex].adapter.delegatecall( abi.encodeWithSignature( methodSignature, exchanges[exchangeIndex].exchange, orderAddresses, orderValues, orderData, identifier, signature ) ); require(success, string(returnData)); PolicyManager(routes.policyManager).postValidate(methodSelector, [orderAddresses[0], orderAddresses[1], orderAddresses[2], orderAddresses[3], exchanges[exchangeIndex].exchange], [orderValues[0], orderValues[1], orderValues[6]], identifier); emit ExchangeMethodCall( exchanges[exchangeIndex].exchange, methodSignature, orderAddresses, orderValues, orderData, identifier, signature ); } /// @dev Make sure this is called after orderUpdateHook in adapters function addOpenMakeOrder( address ofExchange, address sellAsset, address buyAsset, uint orderId, uint expirationTime ) public delegateInternal { require(!isInOpenMakeOrder[sellAsset], "Asset already in open order"); require(orders.length > 0, "No orders in array"); // If expirationTime is 0, actualExpirationTime is set to ORDER_LIFESPAN from now uint actualExpirationTime = (expirationTime == 0) ? add(block.timestamp, ORDER_LIFESPAN) : expirationTime; require( actualExpirationTime <= add(block.timestamp, ORDER_LIFESPAN) && actualExpirationTime > block.timestamp, "Expiry time greater than max order lifespan or has already passed" ); isInOpenMakeOrder[sellAsset] = true; makerAssetCooldown[sellAsset] = add(actualExpirationTime, MAKE_ORDER_COOLDOWN); openMakeOrdersAgainstAsset[buyAsset] = add(openMakeOrdersAgainstAsset[buyAsset], 1); exchangesToOpenMakeOrders[ofExchange][sellAsset].id = orderId; exchangesToOpenMakeOrders[ofExchange][sellAsset].expiresAt = actualExpirationTime; exchangesToOpenMakeOrders[ofExchange][sellAsset].orderIndex = sub(orders.length, 1); exchangesToOpenMakeOrders[ofExchange][sellAsset].buyAsset = buyAsset; } function _removeOpenMakeOrder( address exchange, address sellAsset ) internal { if (isInOpenMakeOrder[sellAsset]) { makerAssetCooldown[sellAsset] = add(block.timestamp, MAKE_ORDER_COOLDOWN); address buyAsset = exchangesToOpenMakeOrders[exchange][sellAsset].buyAsset; delete exchangesToOpenMakeOrders[exchange][sellAsset]; openMakeOrdersAgainstAsset[buyAsset] = sub(openMakeOrdersAgainstAsset[buyAsset], 1); } } function removeOpenMakeOrder( address exchange, address sellAsset ) public delegateInternal { _removeOpenMakeOrder(exchange, sellAsset); } /// @dev Bit of Redundancy for now function addZeroExV2OrderData( bytes32 orderId, IZeroExV2.Order memory zeroExOrderData ) public delegateInternal { orderIdToZeroExV2Order[orderId] = zeroExOrderData; } function addZeroExV3OrderData( bytes32 orderId, IZeroExV3.Order memory zeroExOrderData ) public delegateInternal { orderIdToZeroExV3Order[orderId] = zeroExOrderData; } function orderUpdateHook( address ofExchange, bytes32 orderId, UpdateType updateType, address payable[2] memory orderAddresses, uint[3] memory orderValues ) public delegateInternal { // only save make/take if (updateType == UpdateType.make || updateType == UpdateType.take) { orders.push(Order({ exchangeAddress: ofExchange, orderId: orderId, updateType: updateType, makerAsset: orderAddresses[0], takerAsset: orderAddresses[1], makerQuantity: orderValues[0], takerQuantity: orderValues[1], timestamp: block.timestamp, fillTakerQuantity: orderValues[2] })); } } function updateAndGetQuantityBeingTraded(address _asset) external returns (uint) { uint quantityHere = IERC20(_asset).balanceOf(address(this)); return add(updateAndGetQuantityHeldInExchange(_asset), quantityHere); } function updateAndGetQuantityHeldInExchange(address ofAsset) public returns (uint) { uint totalSellQuantity; // quantity in custody across exchanges uint totalSellQuantityInApprove; // quantity of asset in approve (allowance) but not custody of exchange for (uint i; i < exchanges.length; i++) { if (exchangesToOpenMakeOrders[exchanges[i].exchange][ofAsset].id == 0) { continue; } address sellAsset; uint remainingSellQuantity; (sellAsset, , remainingSellQuantity, ) = ExchangeAdapter(exchanges[i].adapter) .getOrder( exchanges[i].exchange, exchangesToOpenMakeOrders[exchanges[i].exchange][ofAsset].id, ofAsset ); if (remainingSellQuantity == 0) { // remove id if remaining sell quantity zero (closed) _removeOpenMakeOrder(exchanges[i].exchange, ofAsset); } totalSellQuantity = add(totalSellQuantity, remainingSellQuantity); if (!exchanges[i].takesCustody) { totalSellQuantityInApprove += remainingSellQuantity; } } if (totalSellQuantity == 0) { isInOpenMakeOrder[ofAsset] = false; } return sub(totalSellQuantity, totalSellQuantityInApprove); // Since quantity in approve is not actually in custody } function returnBatchToVault(address[] memory _tokens) public { for (uint i = 0; i < _tokens.length; i++) { returnAssetToVault(_tokens[i]); } } function returnAssetToVault(address _token) public { require( msg.sender == address(this) || msg.sender == hub.manager() || hub.isShutDown(), "Sender is not this contract or manager" ); safeTransfer(_token, routes.vault, IERC20(_token).balanceOf(address(this))); } function getExchangeInfo() public view returns (address[] memory, address[] memory, bool[] memory) { address[] memory ofExchanges = new address[](exchanges.length); address[] memory ofAdapters = new address[](exchanges.length); bool[] memory takesCustody = new bool[](exchanges.length); for (uint i = 0; i < exchanges.length; i++) { ofExchanges[i] = exchanges[i].exchange; ofAdapters[i] = exchanges[i].adapter; takesCustody[i] = exchanges[i].takesCustody; } return (ofExchanges, ofAdapters, takesCustody); } function getOpenOrderInfo(address ofExchange, address ofAsset) public view returns (uint, uint, uint) { OpenMakeOrder memory order = exchangesToOpenMakeOrders[ofExchange][ofAsset]; return (order.id, order.expiresAt, order.orderIndex); } function isOrderExpired(address exchange, address asset) public view returns(bool) { return ( exchangesToOpenMakeOrders[exchange][asset].expiresAt <= block.timestamp && exchangesToOpenMakeOrders[exchange][asset].expiresAt > 0 ); } function getOrderDetails(uint orderIndex) public view returns (address, address, uint, uint) { Order memory order = orders[orderIndex]; return (order.makerAsset, order.takerAsset, order.makerQuantity, order.takerQuantity); } function getZeroExV2OrderDetails(bytes32 orderId) public view returns (IZeroExV2.Order memory) { return orderIdToZeroExV2Order[orderId]; } function getZeroExV3OrderDetails(bytes32 orderId) public view returns (IZeroExV3.Order memory) { return orderIdToZeroExV3Order[orderId]; } function getOpenMakeOrdersAgainstAsset(address _asset) external view returns (uint256) { return openMakeOrdersAgainstAsset[_asset]; } } contract TradingFactory is Factory { event NewInstance( address indexed hub, address indexed instance, address[] exchanges, address[] adapters, address registry ); function createInstance( address _hub, address[] memory _exchanges, address[] memory _adapters, address _registry ) public returns (address) { address trading = address(new Trading(_hub, _exchanges, _adapters, _registry)); childExists[trading] = true; emit NewInstance( _hub, trading, _exchanges, _adapters, _registry ); return trading; } }
pragma solidity 0.6.1; /// @notice Custody component interface IVault { function withdraw(address token, uint amount) external; } interface IVaultFactory { function createInstance(address _hub) external returns (address); }
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; } }
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, address buyAsset, 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); }
pragma solidity 0.6.1; import "../dependencies/token/IERC20.sol"; import "../dependencies/DSMath.sol"; import "../dependencies/DSAuth.sol"; // TODO: remove? this may not be used at all import "../exchanges/interfaces/IKyberNetworkProxy.sol"; import "../version/Registry.sol"; /// @title Price Feed Template /// @author Melonport AG <[email protected]> /// @notice Routes external data to smart contracts /// @notice Where external data includes sharePrice of Melon funds /// @notice PriceFeed operator could be staked and sharePrice input validated on chain contract KyberPriceFeed is DSMath, DSAuth { event PriceUpdate(address[] token, uint[] price); address public KYBER_NETWORK_PROXY; address public QUOTE_ASSET; address public UPDATER; Registry public REGISTRY; uint public MAX_SPREAD; address public constant KYBER_ETH_TOKEN = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); uint public constant KYBER_PRECISION = 18; uint public constant VALIDITY_INTERVAL = 2 days; uint public lastUpdate; // FIELDS mapping (address => uint) public prices; // METHODS // CONSTRUCTOR /// @dev Define and register a quote asset against which all prices are measured/based against constructor( address ofRegistry, address ofKyberNetworkProxy, uint ofMaxSpread, address ofQuoteAsset, address initialUpdater ) public { KYBER_NETWORK_PROXY = ofKyberNetworkProxy; MAX_SPREAD = ofMaxSpread; QUOTE_ASSET = ofQuoteAsset; REGISTRY = Registry(ofRegistry); UPDATER = initialUpdater; } /// @dev Stores zero as a convention for invalid price function update() external { require( msg.sender == REGISTRY.owner() || msg.sender == UPDATER, "Only registry owner or updater can call" ); address[] memory assets = REGISTRY.getRegisteredAssets(); uint[] memory newPrices = new uint[](assets.length); for (uint i; i < assets.length; i++) { bool isValid; uint price; if (assets[i] == QUOTE_ASSET) { isValid = true; price = 1 ether; } else { (isValid, price) = getKyberPrice(assets[i], QUOTE_ASSET); } newPrices[i] = isValid ? price : 0; prices[assets[i]] = newPrices[i]; } lastUpdate = block.timestamp; emit PriceUpdate(assets, newPrices); } function setUpdater(address _updater) external { require(msg.sender == REGISTRY.owner(), "Only registry owner can set"); UPDATER = _updater; } /// @notice _maxSpread becomes a percentage when divided by 10^18 /// @notice (e.g. 10^17 becomes 10%) function setMaxSpread(uint _maxSpread) external { require(msg.sender == REGISTRY.owner(), "Only registry owner can set"); MAX_SPREAD = _maxSpread; } // PUBLIC VIEW METHODS // FEED INFORMATION function getQuoteAsset() public view returns (address) { return QUOTE_ASSET; } // PRICES /** @notice Gets price of an asset multiplied by ten to the power of assetDecimals @dev Asset has been registered @param _asset Asset for which price should be returned @return price Price formatting: mul(exchangePrice, 10 ** decimal), to avoid floating numbers @return timestamp When the asset's price was updated } */ function getPrice(address _asset) public view returns (uint price, uint timestamp) { (price, ) = getReferencePriceInfo(_asset, QUOTE_ASSET); timestamp = now; } function getPrices(address[] memory _assets) public view returns (uint256[] memory, uint256[] memory) { uint[] memory newPrices = new uint[](_assets.length); uint[] memory timestamps = new uint[](_assets.length); for (uint i; i < _assets.length; i++) { (newPrices[i], timestamps[i]) = getPrice(_assets[i]); } return (newPrices, timestamps); } function hasValidPrice(address _asset) public view returns (bool) { bool isRegistered = REGISTRY.assetIsRegistered(_asset); bool isFresh = block.timestamp < add(lastUpdate, VALIDITY_INTERVAL); return prices[_asset] != 0 && isRegistered && isFresh; } function hasValidPrices(address[] memory _assets) public view returns (bool) { for (uint i; i < _assets.length; i++) { if (!hasValidPrice(_assets[i])) { return false; } } return true; } /** @param _baseAsset Address of base asset @param _quoteAsset Address of quote asset @return referencePrice Quantity of quoteAsset per whole baseAsset @return decimals Decimal places for quoteAsset } */ function getReferencePriceInfo(address _baseAsset, address _quoteAsset) public view returns (uint referencePrice, uint decimals) { bool isValid; ( isValid, referencePrice, decimals ) = getRawReferencePriceInfo(_baseAsset, _quoteAsset); require(isValid, "Price is not valid"); return (referencePrice, decimals); } function getRawReferencePriceInfo(address _baseAsset, address _quoteAsset) public view returns (bool isValid, uint256 referencePrice, uint256 decimals) { isValid = hasValidPrice(_baseAsset) && hasValidPrice(_quoteAsset); uint256 quoteDecimals = ERC20WithFields(_quoteAsset).decimals(); if (prices[_quoteAsset] == 0) { return (false, 0, 0); // return early and avoid revert } referencePrice = mul( prices[_baseAsset], 10 ** uint(quoteDecimals) ) / prices[_quoteAsset]; return (isValid, referencePrice, quoteDecimals); } function getPriceInfo(address _asset) public view returns (uint256 price, uint256 assetDecimals) { return getReferencePriceInfo(_asset, QUOTE_ASSET); } /** @notice Gets inverted price of an asset @dev Asset has been initialised and its price is non-zero @param _asset Asset for which inverted price should be return @return invertedPrice Price based (instead of quoted) against QUOTE_ASSET @return assetDecimals Decimal places for this asset } */ function getInvertedPriceInfo(address _asset) public view returns (uint256 invertedPrice, uint256 assetDecimals) { return getReferencePriceInfo(QUOTE_ASSET, _asset); } /// @dev Get Kyber representation of ETH if necessary function getKyberMaskAsset(address _asset) public view returns (address) { if (_asset == REGISTRY.nativeAsset()) { return KYBER_ETH_TOKEN; } return _asset; } /// @notice Returns validity and price from Kyber function getKyberPrice(address _baseAsset, address _quoteAsset) public view returns (bool, uint) { uint bidRate; uint bidRateOfReversePair; (bidRate,) = IKyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate( getKyberMaskAsset(_baseAsset), getKyberMaskAsset(_quoteAsset), REGISTRY.getReserveMin(_baseAsset) ); (bidRateOfReversePair,) = IKyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate( getKyberMaskAsset(_quoteAsset), getKyberMaskAsset(_baseAsset), REGISTRY.getReserveMin(_quoteAsset) ); if (bidRate == 0 || bidRateOfReversePair == 0) { return (false, 0); // return early and avoid revert } uint askRate = 10 ** (KYBER_PRECISION * 2) / bidRateOfReversePair; /** Average the bid/ask prices: avgPriceFromKyber = (bidRate + askRate) / 2 kyberPrice = (avgPriceFromKyber * 10^quoteDecimals) / 10^kyberPrecision or, rearranged: kyberPrice = ((bidRate + askRate) * 10^quoteDecimals) / 2 * 10^kyberPrecision */ uint kyberPrice = mul( add(bidRate, askRate), 10 ** uint(ERC20WithFields(_quoteAsset).decimals()) // use original quote decimals (not defined on mask) ) / mul(2, 10 ** uint(KYBER_PRECISION)); // Find the "quoted spread", to inform caller whether it is below maximum uint spreadFromKyber; if (bidRate > askRate) { spreadFromKyber = 0; // crossed market condition } else { spreadFromKyber = mul( sub(askRate, bidRate), 10 ** uint(KYBER_PRECISION) ) / kyberPrice; } return ( spreadFromKyber <= MAX_SPREAD && bidRate != 0 && askRate != 0, kyberPrice ); } /// @notice Gets price of Order /// @param sellAsset Address of the asset to be sold /// @param buyAsset Address of the asset to be bought /// @param sellQuantity Quantity in base units being sold of sellAsset /// @param buyQuantity Quantity in base units being bought of buyAsset /// @return orderPrice Price as determined by an order function getOrderPriceInfo( address sellAsset, address buyAsset, uint sellQuantity, uint buyQuantity ) public view returns (uint orderPrice) { // TODO: decimals return mul(buyQuantity, 10 ** uint(ERC20WithFields(sellAsset).decimals())) / sellQuantity; } /// @notice Checks whether data exists for a given asset pair /// @dev Prices are only upated against QUOTE_ASSET /// @param sellAsset Asset for which check to be done if data exists /// @param buyAsset Asset for which check to be done if data exists function existsPriceOnAssetPair(address sellAsset, address buyAsset) public view returns (bool) { return hasValidPrice(sellAsset) && // Is tradable asset (TODO cleaner) and datafeed delivering data hasValidPrice(buyAsset); } /// @notice Get quantity of toAsset equal in value to given quantity of fromAsset function convertQuantity( uint fromAssetQuantity, address fromAsset, address toAsset ) public view returns (uint) { uint fromAssetPrice; (fromAssetPrice,) = getReferencePriceInfo(fromAsset, toAsset); uint fromAssetDecimals = ERC20WithFields(fromAsset).decimals(); return mul( fromAssetQuantity, fromAssetPrice ) / (10 ** uint(fromAssetDecimals)); } function getLastUpdate() public view returns (uint) { return lastUpdate; } }
pragma solidity 0.6.1; interface IVersion { function shutDownFund(address) external; }
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; } }
pragma solidity 0.6.1; contract BooleanPolicy { enum Applied { pre, post } bool allowed; function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) { return allowed; } function position() external pure returns (Applied) { return Applied.pre; } } contract TruePolicy is BooleanPolicy { constructor() public { allowed = true; } function identifier() external pure returns (string memory) { return "TruePolicy"; } } contract FalsePolicy is BooleanPolicy { constructor() public { allowed = false; } function identifier() external pure returns (string memory) { return "FalsePolicy"; } }
pragma solidity 0.6.1; import "main/dependencies/token/PreminedToken.sol"; contract MaliciousToken is PreminedToken { bool public isReverting = false; constructor(string memory _symbol, uint8 _decimals, string memory _name) public PreminedToken(_symbol, _decimals, _name) {} function startReverting() public { isReverting = true; } function transfer(address _to, uint256 _value) public override returns (bool) { require(!isReverting, "I'm afraid I can't do that, Dave"); super.transfer(_to, _value); } function transferFrom( address _from, address _to, uint256 _value ) public override returns (bool) { require(!isReverting, "I'm afraid I can't do that, Dave"); super.transferFrom(_from, _to, _value); } }
pragma solidity 0.6.1; import "main/fund/hub/Spoke.sol"; /// @dev Balances are fake and can be set by anyone (testing) contract MockAccounting is Spoke { uint public gav; uint public nav; uint public unclaimedFees; uint public mockValuePerShare; address[] public ownedAssets; mapping (address => bool) public isInAssetList; mapping (address => uint) public held; // mock total held across all components mapping (address => uint) public assetGav; address public DENOMINATION_ASSET; address public NATIVE_ASSET; uint public DEFAULT_SHARE_PRICE; uint public SHARES_DECIMALS; constructor(address _hub, address _denominationAsset, address _nativeAsset) public Spoke(_hub) { DENOMINATION_ASSET = _denominationAsset; NATIVE_ASSET = _nativeAsset; SHARES_DECIMALS = 18; DEFAULT_SHARE_PRICE = 10 ** uint(SHARES_DECIMALS); } function setOwnedAssets(address[] memory _assets) public { ownedAssets = _assets; } function getOwnedAssetsLength() public view returns (uint) { return ownedAssets.length; } function setGav(uint _gav) public { gav = _gav; } function setNav(uint _nav) public { nav = _nav; } function setAssetGAV(address _asset, uint _amt) public { assetGav[_asset] = _amt; } function setFundHoldings(uint[] memory _amounts, address[] memory _assets) public { for (uint i = 0; i < _assets.length; i++) { held[_assets[i]] = _amounts[i]; } } function getFundHoldings() public view 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]; // holdings formatting: mul(exchangeHoldings, 10 ** assetDecimal) uint quantityHeld = held[ofAsset]; if (quantityHeld != 0) { _assets[i] = ofAsset; _quantities[i] = quantityHeld; } } return (_quantities, _assets); } function calcGav() public view returns (uint) { return gav; } function calcNav() public view returns (uint) { return nav; } function calcAssetGAV(address _a) public view returns (uint) { return assetGav[_a]; } function valuePerShare(uint totalValue, uint numShares) public view returns (uint) { return mockValuePerShare; } function performCalculations() public view returns (uint, uint, uint, uint, uint) { return (gav, unclaimedFees, 0, nav, mockValuePerShare); } function calcSharePrice() public view returns (uint sharePrice) { (,,,,sharePrice) = performCalculations(); return sharePrice; } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "main/fund/trading/Trading.sol"; import "main/fund/accounting/Accounting.sol"; import "main/exchanges/ExchangeAdapter.sol"; contract MockAdapter is ExchangeAdapter { // METHODS // PUBLIC METHODS /// @notice Mock make order function makeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override { address makerAsset = orderAddresses[2]; address takerAsset = orderAddresses[3]; uint makerQuantity = orderValues[0]; uint takerQuantity = orderValues[1]; withdrawAndApproveAsset(makerAsset, targetExchange, makerQuantity, "makerAsset"); getTrading().orderUpdateHook( targetExchange, identifier, Trading.UpdateType.make, [payable(makerAsset), payable(takerAsset)], [makerQuantity, takerQuantity, uint(0)] ); getTrading().addOpenMakeOrder(targetExchange, makerAsset, takerAsset, uint(identifier), 0); } /// @notice Mock take order function takeOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override { address makerAsset = orderAddresses[2]; address takerAsset = orderAddresses[3]; uint makerQuantity = orderValues[0]; uint takerQuantity = orderValues[1]; uint fillTakerQuantity = orderValues[6]; withdrawAndApproveAsset(takerAsset, targetExchange, fillTakerQuantity, "takerAsset"); getTrading().orderUpdateHook( targetExchange, bytes32(identifier), Trading.UpdateType.take, [payable(makerAsset), payable(takerAsset)], [makerQuantity, takerQuantity, fillTakerQuantity] ); } /// @notice Mock cancel order function cancelOrder( address targetExchange, address[8] memory orderAddresses, uint[8] memory orderValues, bytes[4] memory orderData, bytes32 identifier, bytes memory signature ) public override { address makerAsset = orderAddresses[2]; uint makerQuantity = orderValues[0]; revokeApproveAsset(makerAsset, targetExchange, makerQuantity, "makerAsset"); getTrading().removeOpenMakeOrder(targetExchange, makerAsset); getTrading().orderUpdateHook( targetExchange, bytes32(identifier), Trading.UpdateType.cancel, [address(0), address(0)], [uint(0), uint(0), uint(0)] ); } }
pragma solidity 0.6.1; contract MockFee { uint public fee; uint public FEE_RATE; uint public FEE_PERIOD; uint public feeNumber; constructor(uint _feeNumber) public { feeNumber = _feeNumber; } function setFeeAmount(uint amount) public { fee = amount; } function feeAmount() external returns (uint feeInShares) { return fee; } function initializeForUser(uint feeRate, uint feePeriod, address denominationAsset) external { fee = 0; FEE_RATE = feeRate; FEE_PERIOD = feePeriod; } function updateState() external { fee = 0; } function identifier() external view returns (uint) { return feeNumber; } }
pragma solidity 0.6.1; pragma experimental ABIEncoderV2; import "main/fund/hub/Spoke.sol"; import "main/fund/shares/Shares.sol"; import "main/factory/Factory.sol"; import "main/dependencies/DSMath.sol"; import "main/engine/AmguConsumer.sol"; contract MockFeeManager is DSMath, Spoke, AmguConsumer { struct FeeInfo { address feeAddress; uint feeRate; uint feePeriod; } uint totalFees; uint performanceFees; constructor( address _hub, address _denominationAsset, address[] memory _fees, uint[] memory _periods, uint _rates, address registry ) Spoke(_hub) public {} function setTotalFeeAmount(uint _amt) public { totalFees = _amt; } function setPerformanceFeeAmount(uint _amt) public { performanceFees = _amt; } function rewardManagementFee() public { return; } function performanceFeeAmount() external returns (uint) { return performanceFees; } function totalFeeAmount() external returns (uint) { return totalFees; } function engine() public view override(AmguConsumer, Spoke) returns (address) { return routes.engine; } function mlnToken() public view override(AmguConsumer, Spoke) returns (address) { return routes.mlnToken; } function priceSource() public view override(AmguConsumer, Spoke) returns (address) { return hub.priceSource(); } function registry() public view override(AmguConsumer, Spoke) returns (address) { return routes.registry; } }
pragma solidity 0.6.1; import "main/dependencies/DSGuard.sol"; import "main/fund/hub/Spoke.sol"; import "main/version/Registry.sol"; /// @notice Hub used for testing contract MockHub is DSGuard { struct Routes { address accounting; address feeManager; address participation; address policyManager; address shares; address trading; address vault; address registry; address version; address engine; address mlnAddress; } Routes public routes; address public manager; string public name; bool public isShutDown; function setManager(address _manager) public { manager = _manager; } function setName(string memory _name) public { name = _name; } function shutDownFund() public { isShutDown = true; } function setShutDownState(bool _state) public { isShutDown = _state; } function setSpokes(address[11] memory _spokes) public { 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.mlnAddress = _spokes[10]; } function setRouting() public { address[11] memory spokes = [ routes.accounting, routes.feeManager, routes.participation, routes.policyManager, routes.shares, routes.trading, routes.vault, routes.registry, routes.version, routes.engine, routes.mlnAddress ]; 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); } function setPermissions() public { 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.participation, routes.accounting, bytes4(keccak256('removeFromOwnedAssets(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.feeManager, bytes4(keccak256('register(address)'))); permit(manager, routes.feeManager, bytes4(keccak256('batchRegister(address[])'))); 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(bytes32(bytes20(msg.sender)), ANY, ANY); } function permitSomething(address _from, address _to, bytes4 _sig) public { permit( bytes32(bytes20(_from)), bytes32(bytes20(_to)), _sig ); } function initializeSpoke(address _spoke) public { address[11] memory spokes = [ routes.accounting, routes.feeManager, routes.participation, routes.policyManager, routes.shares, routes.trading, routes.vault, routes.registry, routes.version, routes.engine, routes.mlnAddress ]; Spoke(_spoke).initialize(spokes); } function vault() public view returns (address) { return routes.vault; } function accounting() public view returns (address) { return routes.accounting; } function priceSource() public view returns (address) { return Registry(routes.registry).priceSource(); } function participation() public view returns (address) { return routes.participation; } function trading() public view returns (address) { return routes.trading; } function shares() public view returns (address) { return routes.shares; } function policyManager() public view returns (address) { return routes.policyManager; } function registry() public view returns (address) { return routes.registry; } }
pragma solidity 0.6.1; import "main/dependencies/DSAuth.sol"; /// @dev Simplified for testing, and by default rigged to always return true contract MockRegistry is DSAuth { bool public alwaysRegistered = true; bool public methodAllowed = true; address public priceSource; address public mlnToken; address public nativeAsset; address public engine; address public fundFactory; address[] public assets; uint public incentive; mapping (address => bool) public registered; mapping (address => bool) public fundExists; mapping (address => address) public exchangeForAdapter; mapping (address => bool) public takesCustodyForAdapter; function register(address _addr) public { registered[_addr] = true; assets.push(_addr); } function remove(address _addr) public { delete registered[_addr]; } function assetIsRegistered(address _asset) public view returns (bool) { return alwaysRegistered || registered[_asset]; } function exchangeAdapterIsRegistered(address _adapter) public view returns (bool) { return alwaysRegistered || registered[_adapter]; } function registerExchangeAdapter( address _exchange, address _adapter ) public { exchangeForAdapter[_adapter] = _exchange; takesCustodyForAdapter[_adapter] = true; } function adapterMethodIsAllowed( address _adapter, bytes4 _sig ) public view returns (bool) { return methodAllowed; } function setPriceSource(address _a) public { priceSource = _a; } function setMlnToken(address _a) public { mlnToken = _a; } function setNativeAsset(address _a) public { nativeAsset = _a; } function setEngine(address _a) public { engine = _a; } function setFundFactory(address _a) public { fundFactory = _a; } function setIsFund(address _who) public { fundExists[_who] = true; } function isFund(address _who) public view returns (bool) { return fundExists[_who]; } function isFundFactory(address _who) public view returns (bool) { return _who == fundFactory; } function getRegisteredAssets() public view returns (address[] memory) { return assets; } function getReserveMin(address _asset) public view returns (uint) { return 0; } function isFeeRegistered(address _fee) public view returns (bool) { return alwaysRegistered; } function getExchangeInformation(address _adapter) public view returns (address, bool) { return ( exchangeForAdapter[_adapter], takesCustodyForAdapter[_adapter] ); } }
pragma solidity 0.6.1; import "main/fund/hub/Spoke.sol"; import "main/dependencies/token/StandardToken.sol"; /// @dev Shares can be destroyed and created by anyone (testing) contract MockShares is Spoke, StandardToken { string public symbol; string public name; uint8 public decimals; constructor(address _hub) public Spoke(_hub) { name = hub.name(); symbol = "MOCK"; decimals = 18; } function createFor(address who, uint amount) public { _mint(who, amount); } function destroyFor(address who, uint amount) public { _burn(who, amount); } function setBalanceFor(address who, uint newBalance) public { uint currentBalance = balances[who]; if (currentBalance > newBalance) { destroyFor(who, currentBalance.sub(newBalance)); } else if (balances[who] < newBalance) { createFor(who, newBalance.sub(currentBalance)); } } }
pragma solidity 0.6.1; import "main/fund/hub/Hub.sol"; /// @notice Version contract useful for testing contract MockVersion { uint public amguPrice; bool public isShutDown; function setAmguPrice(uint _price) public { amguPrice = _price; } function securityShutDown() external { isShutDown = true; } function shutDownFund(address _hub) external { Hub(_hub).shutDownFund(); } function getShutDownStatus() external view returns (bool) {return isShutDown;} function getAmguPrice() public view returns (uint) { return amguPrice; } }
pragma solidity 0.6.1; import "main/dependencies/DSAuth.sol"; contract PermissiveAuthority is DSAuthority { function canCall(address src, address dst, bytes4 sig) public view override returns (bool) { return true; } }
pragma solidity 0.6.1; /// @dev Useful for testing force-sending of funds contract SelfDestructing { function bequeath(address payable _heir) public { selfdestruct(_heir); } receive() external payable {} }
pragma solidity 0.6.1; import "main/dependencies/token/IERC20.sol"; import "main/dependencies/DSMath.sol"; /// @notice Intended for testing purposes only /// @notice Updates and exposes price information contract TestingPriceFeed is DSMath { event PriceUpdate(address[] token, uint[] price); struct Data { uint price; uint timestamp; } address public QUOTE_ASSET; uint public updateId; uint public lastUpdate; mapping(address => Data) public assetsToPrices; mapping(address => uint) public assetsToDecimals; bool mockIsRecent = true; bool neverValid = false; constructor(address _quoteAsset, uint _quoteDecimals) public { QUOTE_ASSET = _quoteAsset; setDecimals(_quoteAsset, _quoteDecimals); } /** Input price is how much quote asset you would get for one unit of _asset (10**assetDecimals) */ function update(address[] calldata _assets, uint[] calldata _prices) external { require(_assets.length == _prices.length, "Array lengths unequal"); updateId++; for (uint i = 0; i < _assets.length; ++i) { assetsToPrices[_assets[i]] = Data({ timestamp: block.timestamp, price: _prices[i] }); } lastUpdate = block.timestamp; emit PriceUpdate(_assets, _prices); } function getPrice(address ofAsset) public view returns (uint price, uint timestamp) { Data storage data = assetsToPrices[ofAsset]; return (data.price, data.timestamp); } function getPrices(address[] memory ofAssets) public view returns (uint[] memory, uint[] memory) { uint[] memory prices = new uint[](ofAssets.length); uint[] memory timestamps = new uint[](ofAssets.length); for (uint i; i < ofAssets.length; i++) { uint price; uint timestamp; (price, timestamp) = getPrice(ofAssets[i]); prices[i] = price; timestamps[i] = timestamp; } return (prices, timestamps); } function getPriceInfo(address ofAsset) public view returns (uint price, uint assetDecimals) { (price, ) = getPrice(ofAsset); assetDecimals = assetsToDecimals[ofAsset]; } function getInvertedPriceInfo(address ofAsset) public view returns (uint invertedPrice, uint assetDecimals) { uint inputPrice; // inputPrice quoted in QUOTE_ASSET and multiplied by 10 ** assetDecimal (inputPrice, assetDecimals) = getPriceInfo(ofAsset); // outputPrice based in QUOTE_ASSET and multiplied by 10 ** quoteDecimal uint quoteDecimals = assetsToDecimals[QUOTE_ASSET]; return ( mul( 10 ** uint(quoteDecimals), 10 ** uint(assetDecimals) ) / inputPrice, quoteDecimals ); } function setNeverValid(bool _state) public { neverValid = _state; } function setIsRecent(bool _state) public { mockIsRecent = _state; } // NB: not permissioned; anyone can change this in a test function setDecimals(address _asset, uint _decimal) public { assetsToDecimals[_asset] = _decimal; } // needed just to get decimals for prices function batchSetDecimals(address[] memory _assets, uint[] memory _decimals) public { require(_assets.length == _decimals.length, "Array lengths unequal"); for (uint i = 0; i < _assets.length; i++) { setDecimals(_assets[i], _decimals[i]); } } function getReferencePriceInfo(address ofBase, address ofQuote) public view returns (uint referencePrice, uint decimal) { uint quoteDecimals = assetsToDecimals[ofQuote]; // Price of 1 unit for the pair of same asset if (ofBase == ofQuote) { return (10 ** uint(quoteDecimals), quoteDecimals); } referencePrice = mul( assetsToPrices[ofBase].price, 10 ** uint(quoteDecimals) ) / assetsToPrices[ofQuote].price; return (referencePrice, quoteDecimals); } function getOrderPriceInfo( address sellAsset, address buyAsset, uint sellQuantity, uint buyQuantity ) public view returns (uint orderPrice) { return mul(buyQuantity, 10 ** uint(assetsToDecimals[sellAsset])) / sellQuantity; } /// @notice Doesn't check validity as TestingPriceFeed has no validity variable /// @param _asset Asset in registrar /// @return isValid Price information ofAsset is recent function hasValidPrice(address _asset) public view returns (bool isValid) { uint price; (price, ) = getPrice(_asset); return !neverValid && price != 0; } function hasValidPrices(address[] memory _assets) public view returns (bool) { for (uint i; i < _assets.length; i++) { if (!hasValidPrice(_assets[i])) { return false; } } return true; } /// @notice Checks whether data exists for a given asset pair /// @dev Prices are only upated against QUOTE_ASSET /// @param sellAsset Asset for which check to be done if data exists /// @param buyAsset Asset for which check to be done if data exists function existsPriceOnAssetPair(address sellAsset, address buyAsset) public view returns (bool isExistent) { return hasValidPrice(sellAsset) && hasValidPrice(buyAsset); } function getLastUpdateId() public view returns (uint) { return updateId; } function getQuoteAsset() public view returns (address) { return QUOTE_ASSET; } /// @notice Get quantity of toAsset equal in value to given quantity of fromAsset function convertQuantity( uint fromAssetQuantity, address fromAsset, address toAsset ) public view returns (uint) { uint fromAssetPrice; (fromAssetPrice,) = getReferencePriceInfo(fromAsset, toAsset); uint fromAssetDecimals = ERC20WithFields(fromAsset).decimals(); return mul( fromAssetQuantity, fromAssetPrice ) / (10 ** uint(fromAssetDecimals)); } function getLastUpdate() public view returns (uint) { return lastUpdate; } }
{ "remappings": [ "main=./src" ], "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "istanbul", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_accountingFactory","type":"address"},{"internalType":"address","name":"_feeManagerFactory","type":"address"},{"internalType":"address","name":"_participationFactory","type":"address"},{"internalType":"address","name":"_sharesFactory","type":"address"},{"internalType":"address","name":"_tradingFactory","type":"address"},{"internalType":"address","name":"_vaultFactory","type":"address"},{"internalType":"address","name":"_policyManagerFactory","type":"address"},{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_postDeployOwner","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":"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":"manager","type":"address"},{"indexed":true,"internalType":"address","name":"hub","type":"address"},{"indexed":false,"internalType":"address[11]","name":"routes","type":"address[11]"}],"name":"NewFund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hub","type":"address"},{"indexed":true,"internalType":"address","name":"instance","type":"address"}],"name":"NewInstance","type":"event"},{"inputs":[],"name":"accountingFactory","outputs":[{"internalType":"contract IAccountingFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"associatedRegistry","outputs":[{"internalType":"contract Registry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract DSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address[]","name":"_fees","type":"address[]"},{"internalType":"uint256[]","name":"_feeRates","type":"uint256[]"},{"internalType":"uint256[]","name":"_feePeriods","type":"uint256[]"},{"internalType":"address[]","name":"_exchanges","type":"address[]"},{"internalType":"address[]","name":"_adapters","type":"address[]"},{"internalType":"address","name":"_denominationAsset","type":"address"},{"internalType":"address[]","name":"_defaultInvestmentAssets","type":"address[]"}],"name":"beginSetup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"childExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"completeSetup","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"completeSetupFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createAccounting","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createAccountingFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createFeeManager","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createFeeManagerFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createParticipation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createParticipationFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createPolicyManager","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createPolicyManagerFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createSharesFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createTrading","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createTradingFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createVault","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"createVaultFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"engine","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeManagerFactory","outputs":[{"internalType":"contract IFeeManagerFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"funds","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getExchangesInfo","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"withId","type":"uint256"}],"name":"getFundById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_child","type":"address"}],"name":"isInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"managersToHubs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"managersToRoutes","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":"address","name":"","type":"address"}],"name":"managersToSettings","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"denominationAsset","type":"address"}],"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":"participationFactory","outputs":[{"internalType":"contract IParticipationFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"policyManagerFactory","outputs":[{"internalType":"contract IPolicyManagerFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceSource","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","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":"sharesFactory","outputs":[{"internalType":"contract ISharesFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hub","type":"address"}],"name":"shutDownFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tradingFactory","outputs":[{"internalType":"contract ITradingFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"contract IVaultFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"contract IVersion","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200572b3803806200572b83398101604081905262000034916200028f565b600380546001600160a01b03199081166001600160a01b038c8116919091179092556004805482168b84161790556005805482168a8416179055600780548216898416179055600880548216888416179055600980548216878416179055600680548216928616929092179091556001805430908316179055600f8054339216821790556040516000805160206200570b83398151915290600090a2600280546001600160a01b0319166001600160a01b038416179055620000f68162000105565b505050505050505050620003df565b62000126336001600160e01b0319600035166001600160e01b036200018d16565b6200014e5760405162461bcd60e51b81526004016200014590620003a8565b60405180910390fd5b600f80546001600160a01b0319166001600160a01b0383811691909117918290556040519116906000805160206200570b83398151915290600090a250565b60006001600160a01b038316301415620001aa5750600162000271565b600f546001600160a01b0384811691161415620001ca5750600162000271565b600e546001600160a01b0316620001e45750600062000271565b600e5460405163b700961360e01b81526001600160a01b039091169063b7009613906200021a908690309087906004016200037b565b60206040518083038186803b1580156200023357600080fd5b505afa15801562000248573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200026e919081019062000352565b90505b92915050565b80516001600160a01b03811681146200027157600080fd5b60008060008060008060008060006101208a8c031215620002ae578485fd5b620002ba8b8b62000277565b9850620002cb8b60208c0162000277565b9750620002dc8b60408c0162000277565b9650620002ed8b60608c0162000277565b9550620002fe8b60808c0162000277565b94506200030f8b60a08c0162000277565b9350620003208b60c08c0162000277565b9250620003318b60e08c0162000277565b9150620003438b6101008c0162000277565b90509295985092959850929598565b60006020828403121562000364578081fd5b8151801515811462000374578182fd5b9392505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b60208082526014908201527f64732d617574682d756e617574686f72697a6564000000000000000000000000604082015260600190565b61531c80620003ef6000396000f3fe608060405260043610620002a25760003560e01c806377e3f6a81162000163578063ab5abd5f11620000c7578063d8a06f731162000085578063d8a06f7314620006db578063e865ffe814620006f3578063e8b822db146200070a578063e964c96a1462000722578063ebd0d0c71462000739578063f778c105146200074357620002a2565b8063ab5abd5f146200062c578063b6c3ddf01462000651578063bf7e214f1462000676578063c9d4623f146200068e578063d6ee80a914620006a657620002a2565b80638152a0f911620001215780638152a0f914620005ba57806386ecdc4f14620005d15780638a471df914620005db5780638aea8f7114620005f35780638da5cb5b14620005fd5780639ea32baf146200061557620002a2565b806377e3f6a8146200050d5780637a3f5c8714620005245780637a9e5e4b14620005585780637b103999146200057d5780637b8e8895146200059557620002a2565b80632bd90a59116200020b57806342e2f54c11620001c957806342e2f54c146200047257806354fd4d5014620004975780635967d7e814620004af5780635d12928b14620004c75780636b44e6be14620004d15780637295874714620004f657620002a2565b80632bd90a5914620003e357806332e143d614620003fb57806337c384df14620004395780633a1e8de314620004505780633f825ed8146200046857620002a2565b8063149e685a1162000265578063149e685a14620003465780631a966d70146200036b5780631f2d1531146200038257806320531bc9146200038c57806328e68ebe14620003a45780632b34963c14620003cb57620002a2565b806304478c3114620002a75780630a726fe514620002b35780630c1eef4a14620002f0578063116c719f14620002fa57806313af40351462000321575b600080fd5b620002b16200075b565b005b348015620002c057600080fd5b50620002d8620002d236600462002b9b565b62000b02565b604051620002e7919062003156565b60405180910390f35b620002b162000b17565b3480156200030757600080fd5b506200031262000b28565b604051620002e7919062002e3e565b3480156200032e57600080fd5b50620002b16200034036600462002b9b565b62000b37565b3480156200035357600080fd5b50620003126200036536600462002d3f565b62000bbe565b620002b16200037c36600462002b9b565b62000be9565b620002b162000f7b565b3480156200039957600080fd5b506200031262000f8c565b348015620003b157600080fd5b50620003bc62001013565b604051620002e7919062003421565b348015620003d857600080fd5b50620003126200101d565b348015620003f057600080fd5b50620003126200102c565b3480156200040857600080fd5b50620004206200041a36600462002b9b565b6200103b565b604051620002e79b9a9998979695949392919062002ea3565b620002b16200044a36600462002b9b565b620010b1565b3480156200045d57600080fd5b5062000312620010c2565b620002b1620010d1565b3480156200047f57600080fd5b50620002b16200049136600462002b9b565b620010e2565b348015620004a457600080fd5b506200031262001177565b348015620004bc57600080fd5b506200031262001186565b620002b162001195565b348015620004de57600080fd5b50620002d8620004f036600462002b9b565b620011a6565b620002b16200050736600462002b9b565b620011c4565b620002b16200051e36600462002b9b565b620011d5565b3480156200053157600080fd5b50620005496200054336600462002b9b565b620011e6565b604051620002e7919062003108565b3480156200056557600080fd5b50620002b16200057736600462002b9b565b62001261565b3480156200058a57600080fd5b5062000312620012e8565b348015620005a257600080fd5b5062000312620005b436600462002d3f565b620012f7565b620002b1620005cb36600462002b9b565b6200131f565b620002b162001330565b348015620005e857600080fd5b506200031262001341565b620002b162001387565b3480156200060a57600080fd5b506200031262001398565b620002b16200062636600462002b9b565b620013a7565b3480156200063957600080fd5b50620002b16200064b36600462002c02565b620013b8565b3480156200065e57600080fd5b50620003126200067036600462002b9b565b6200174b565b3480156200068357600080fd5b506200031262001766565b3480156200069b57600080fd5b506200031262001775565b348015620006b357600080fd5b50620006cb620006c536600462002b9b565b620017bb565b604051620002e792919062003161565b348015620006e857600080fd5b50620003126200186f565b620002b16200070436600462002b9b565b6200187e565b3480156200071757600080fd5b50620003126200188f565b620002b16200073336600462002b9b565b6200189e565b620002b1620018af565b3480156200075057600080fd5b5062000312620018c0565b6000805a90506200076c33620018cf565b60005a905060006200077d62001775565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b158015620007b657600080fd5b505afa158015620007cb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620007f1919081019062002d58565b905060006200080c8262000806868662001a0e565b62001a3a565b905060006200081a620012e8565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b1580156200085357600080fd5b505afa15801562000868573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200088e919081019062002bc1565b905060006200089c62000f8c565b6001600160a01b0316637e3bfc2f84620008b562001341565b856040518463ffffffff1660e01b8152600401620008d6939291906200342a565b60206040518083038186803b158015620008ef57600080fd5b505afa15801562000904573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200092a919081019062002d58565b905060008715620009bb576200093f620012e8565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200097857600080fd5b505afa1580156200098d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620009b3919081019062002d58565b9050620009bf565b5060005b620009cb828262001a76565b341015620009f65760405162461bcd60e51b8152600401620009ed90620033e0565b60405180910390fd5b62000a0062001775565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b15801562000a3b57600080fd5b505af115801562000a50573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc62000a7962000a72348662001a0e565b8462001a0e565b6040518115909202916000818181858888f1935050505062000aaf5760405162461bcd60e51b8152600401620009ed9062003330565b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb98362000ade8a8a62001a0e565b8460405162000af09392919062003449565b60405180910390a25050505050505050565b60006020819052908152604090205460ff1681565b6000805a90506200076c3362001a9c565b6005546001600160a01b031681565b62000b4f336000356001600160e01b03191662001bb7565b62000b6e5760405162461bcd60e51b8152600401620009ed90620031bc565b600f80546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b6000600a828154811062000bce57fe5b6000918252602090912001546001600160a01b031692915050565b6000805a905062000bfa8362001ca0565b60005a9050600062000c0b62001775565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b15801562000c4457600080fd5b505afa15801562000c59573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000c7f919081019062002d58565b9050600062000c948262000806868662001a0e565b9050600062000ca2620012e8565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b15801562000cdb57600080fd5b505afa15801562000cf0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000d16919081019062002bc1565b9050600062000d2462000f8c565b6001600160a01b0316637e3bfc2f8462000d3d62001341565b856040518463ffffffff1660e01b815260040162000d5e939291906200342a565b60206040518083038186803b15801562000d7757600080fd5b505afa15801562000d8c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000db2919081019062002d58565b90506000871562000e435762000dc7620012e8565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000e0057600080fd5b505afa15801562000e15573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000e3b919081019062002d58565b905062000e47565b5060005b62000e53828262001a76565b34101562000e755760405162461bcd60e51b8152600401620009ed90620033e0565b62000e7f62001775565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b15801562000eba57600080fd5b505af115801562000ecf573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc62000ef162000a72348662001a0e565b6040518115909202916000818181858888f1935050505062000f275760405162461bcd60e51b8152600401620009ed9062003330565b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb98362000f568a8a62001a0e565b8460405162000f689392919062003449565b60405180910390a2505050505050505050565b6000805a90506200076c3362001dbb565b600254604080516320531bc960e01b815290516000926001600160a01b0316916320531bc9916004808301926020929190829003018186803b15801562000fd257600080fd5b505afa15801562000fe7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200100d919081019062002bc1565b90505b90565b600a546000190190565b6004546001600160a01b031681565b6008546001600160a01b031681565b600c60205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a0154600a909a01546001600160a01b03998a169a988a169997881698968816979586169694861695938416949284169391821692821691168b565b6000805a905062000bfa8362001a9c565b6002546001600160a01b031681565b6000805a90506200076c3362001f5d565b336000908152600b60205260409020546001600160a01b038281169116146200111f5760405162461bcd60e51b8152600401620009ed906200339c565b806001600160a01b031663c8d705596040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200115b57600080fd5b505af115801562001170573d6000803e3d6000fd5b5050505050565b6001546001600160a01b031681565b6003546001600160a01b031681565b6000805a90506200076c3362001ca0565b6001600160a01b031660009081526020819052604090205460ff1690565b6000805a905062000bfa8362001dbb565b6000805a905062000bfa83620018cf565b6001600160a01b0381166000908152600d60209081526040918290206001018054835181840281018401909452808452606093928301828280156200125557602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001236575b50505050509050919050565b62001279336000356001600160e01b03191662001bb7565b620012985760405162461bcd60e51b8152600401620009ed90620031bc565b600e80546001600160a01b0319166001600160a01b0383811691909117918290556040519116907f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada490600090a250565b6002546001600160a01b031690565b600a81815481106200130557fe5b6000918252602090912001546001600160a01b0316905081565b6000805a905062000bfa83620020aa565b6000805a90506200076c33620020aa565b60025460408051638a471df960e01b815290516000926001600160a01b031691638a471df9916004808301926020929190829003018186803b15801562000fd257600080fd5b6000805a90506200076c33620021e3565b600f546001600160a01b031681565b6000805a905062000bfa83620021e3565b336000908152600b6020526040902054620013dc906001600160a01b0316620026e3565b600254604051636b55df8560e11b81526001600160a01b039091169063d6abbf0a90620014109033908c9060040162002e52565b600060405180830381600087803b1580156200142b57600080fd5b505af115801562001440573d6000803e3d6000fd5b5050600254604051631f8d99a960e01b81526001600160a01b039091169250631f8d99a991506200147690859060040162002e3e565b60206040518083038186803b1580156200148f57600080fd5b505afa158015620014a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620014ca919081019062002be0565b620014e95760405162461bcd60e51b8152600401620009ed9062003357565b3388604051620014f99062002864565b6200150692919062002e52565b604051809103906000f08015801562001523573d6000803e3d6000fd5b50336000818152600b6020908152604080832080546001600160a01b0319166001600160a01b039687161790558051610100810182528d81528083018a905280820189905294871660608601526080850186905260a085018c905260c085018b905260e085018a9052928252600d8152919020825180519192620015ad9284929091019062002872565b506020828101518051620015c89260018501920190620028f7565b5060408201518051620015e6916002840191602090910190620028f7565b5060608201516003820180546001600160a01b0319166001600160a01b03909216919091179055608082015180516200162a916004840191602090910190620028f7565b5060a0820151805162001648916005840191602090910190620028f7565b5060c08201518051620016669160068401916020909101906200295d565b5060e08201518051620016849160078401916020909101906200295d565b5050600254336000908152600c602052604090206007810180546001600160a01b039384166001600160a01b0319918216179091556001546008909201805492909316911617905550620016d762001775565b336000908152600c6020526040902060090180546001600160a01b0319166001600160a01b03929092169190911790556200171162001341565b336000908152600c60205260409020600a0180546001600160a01b0319166001600160a01b03929092169190911790555050505050505050565b600b602052600090815260409020546001600160a01b031681565b600e546001600160a01b031681565b6002546040805163c9d4623f60e01b815290516000926001600160a01b03169163c9d4623f916004808301926020929190829003018186803b15801562000fd257600080fd5b600d6020908152600091825260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452909291839190830182828015620018565780601f106200182a5761010080835404028352916020019162001856565b820191906000526020600020905b8154815290600101906020018083116200183857829003601f168201915b505050600390930154919250506001600160a01b031682565b6009546001600160a01b031681565b6000805a905062000bfa8362001f5d565b6007546001600160a01b031681565b6000805a905062000bfa8362002711565b6000805a90506200076c3362002711565b6006546001600160a01b031681565b6001600160a01b038082166000908152600b6020526040902054620018f591166200282c565b6001600160a01b038082166000908152600c60205260409020600501546200191e9116620026e3565b6008546001600160a01b038281166000908152600b6020908152604080832054600d8352818420600c909352928190206007015490516307aa253f60e01b8152948416946307aa253f94620019879481169360018101936002909101929116906004016200307e565b602060405180830381600087803b158015620019a257600080fd5b505af1158015620019b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620019dd919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060050180546001600160a01b03191691909216179055565b8082038281111562001a345760405162461bcd60e51b8152600401620009ed906200318d565b92915050565b600081158062001a575750508082028282828162001a5457fe5b04145b62001a345760405162461bcd60e51b8152600401620009ed90620031ea565b8082018281101562001a345760405162461bcd60e51b8152600401620009ed9062003266565b6001600160a01b038082166000908152600b602052604090205462001ac291166200282c565b6001600160a01b038082166000908152600c602052604090206003015462001aeb9116620026e3565b6006546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f7769262001b3092169060040162002e3e565b602060405180830381600087803b15801562001b4b57600080fd5b505af115801562001b60573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001b86919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060030180546001600160a01b03191691909216179055565b60006001600160a01b03831630141562001bd45750600162001a34565b600f546001600160a01b038481169116141562001bf45750600162001a34565b600e546001600160a01b031662001c0e5750600062001a34565b600e5460405163b700961360e01b81526001600160a01b039091169063b70096139062001c449086903090879060040162002f72565b60206040518083038186803b15801562001c5d57600080fd5b505afa15801562001c72573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001c98919081019062002be0565b905062001a34565b6001600160a01b038082166000908152600b602052604090205462001cc691166200282c565b6001600160a01b038082166000908152600c602052604090206006015462001cef9116620026e3565b6009546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f7769262001d3492169060040162002e3e565b602060405180830381600087803b15801562001d4f57600080fd5b505af115801562001d64573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001d8a919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060060180546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b602052604090205462001de191166200282c565b6001600160a01b038082166000908152600c602052604090205462001e079116620026e3565b600380546001600160a01b038381166000908152600b6020908152604080832054600d835292819020909501546002548651631d34cab560e21b815296519585169663b8f63ebc96948616959283169491909216926374d32ad49260048082019391829003018186803b15801562001e7e57600080fd5b505afa15801562001e93573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001eb9919081019062002bc1565b6040518463ffffffff1660e01b815260040162001ed99392919062002e80565b602060405180830381600087803b15801562001ef457600080fd5b505af115801562001f09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001f2f919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902080546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b602052604090205462001f8391166200282c565b6001600160a01b038082166000908152600c602052604090206001015462001fac9116620026e3565b600480546001600160a01b038381166000908152600b6020908152604080832054600d83528184206003810154600c909452938290206007908101549251638dc6ba2760e01b815296861697638dc6ba27976200202397938416969584169560058101956006820195949091019316910162002f06565b602060405180830381600087803b1580156200203e57600080fd5b505af115801562002053573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062002079919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060010180546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b6020526040902054620020d091166200282c565b6001600160a01b038082166000908152600c6020526040902060020154620020f99116620026e3565b6005546001600160a01b038281166000908152600b6020908152604080832054600d8352818420600c909352928190206007015490516365925b5160e01b8152948416946365925b51946200215c94811693600490810193909116910162003047565b602060405180830381600087803b1580156200217757600080fd5b505af11580156200218c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620021b2919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060020180546001600160a01b03191691909216179055565b620021ed6200299a565b506001600160a01b038082166000818152600c60209081526040808320815161016081018352815487168152600182015487168185015260028201548716818401526003820154871660608201526004820154871660808201526005820154871660a08201526006820154871660c08201526007820154871660e08201526008820154871661010082015260098201548716610120820152600a909101548616610140820152938352600b825280832054909416808352908290529290205490919060ff1615620022d25760405162461bcd60e51b8152600401620009ed9062003300565b620022dd8162002856565b8015620022f257508151620022f29062002856565b801562002309575062002309826020015162002856565b801562002320575062002320826040015162002856565b801562002337575062002337826060015162002856565b80156200234e57506200234e826080015162002856565b8015620023655750620023658260a0015162002856565b80156200237c57506200237c8260c0015162002856565b6200239b5760405162461bcd60e51b8152600401620009ed9062003218565b6001600160a01b0380821660008181526020818152604091829020805460ff19166001179055815161016081018352865185168152868201518516918101919091528582015184168183015260608087015185169082015260808087015185169082015260a08087015185169082015260c08087015185169082015260e0808701518516908201526101008681015185169082015261012080870151851690820152610140808701519094169381019390935251633377fc6560e01b81529091633377fc6591620024709190600401620030cb565b600060405180830381600087803b1580156200248b57600080fd5b505af1158015620024a0573d6000803e3d6000fd5b50505050806001600160a01b031663f1a072696040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620024e057600080fd5b505af1158015620024f5573d6000803e3d6000fd5b50505050806001600160a01b031663b73515eb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200253557600080fd5b505af11580156200254a573d6000803e3d6000fd5b5050600a8054600181019091557fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b0319166001600160a01b03858116919091179091556002548682166000908152600d60205260409081902090516303e45bbf60e01b81529190921693506303e45bbf9250620025d991859188919060040162002f9f565b600060405180830381600087803b158015620025f457600080fd5b505af115801562002609573d6000803e3d6000fd5b5050604080516101608101825285516001600160a01b0390811682526020808801518216908301528683015181168284015260608088015182169083015260808088015182169083015260a08088015182169083015260c08088015182169083015260e080880151821690830152610100808801518216908301526101208088015182169083015261014080880151821690830152915191851693503392507fa2cf3050e34f76517f20682d78f63125f3f53a3f59af052767d7df14848a6b4e91620026d69190620030cb565b60405180910390a3505050565b620026ee8162002856565b156200270e5760405162461bcd60e51b8152600401620009ed9062003294565b50565b6001600160a01b038082166000908152600b60205260409020546200273791166200282c565b6001600160a01b038082166000908152600c6020526040902060040154620027609116620026e3565b6007546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f77692620027a592169060040162002e3e565b602060405180830381600087803b158015620027c057600080fd5b505af1158015620027d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620027fb919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060040180546001600160a01b03191691909216179055565b620028378162002856565b6200270e5760405162461bcd60e51b8152600401620009ed90620032cb565b6001600160a01b0316151590565b611e2880620034bf83390190565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620028b557805160ff1916838001178555620028e5565b82800160010185558215620028e5579182015b82811115620028e5578251825591602001919060010190620028c8565b50620028f3929150620029f6565b5090565b8280548282559060005260206000209081019282156200294f579160200282015b828111156200294f57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062002918565b50620028f392915062002a13565b828054828255906000526020600020908101928215620028e55791602002820182811115620028e5578251825591602001919060010190620028c8565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6200101091905b80821115620028f35760008155600101620029fd565b6200101091905b80821115620028f35780546001600160a01b031916815560010162002a1a565b803562001a3481620034a8565b600082601f83011262002a58578081fd5b813562002a6f62002a698262003487565b6200345f565b81815291506020808301908481018184028601820187101562002a9157600080fd5b60005b8481101562002abd57813562002aaa81620034a8565b8452928201929082019060010162002a94565b505050505092915050565b600082601f83011262002ad9578081fd5b813562002aea62002a698262003487565b81815291506020808301908481018184028601820187101562002b0c57600080fd5b60005b8481101562002abd5781358452928201929082019060010162002b0f565b600082601f83011262002b3e578081fd5b813567ffffffffffffffff81111562002b55578182fd5b62002b6a601f8201601f19166020016200345f565b915080825283602082850101111562002b8257600080fd5b8060208401602084013760009082016020015292915050565b60006020828403121562002bad578081fd5b813562002bba81620034a8565b9392505050565b60006020828403121562002bd3578081fd5b815162002bba81620034a8565b60006020828403121562002bf2578081fd5b8151801515811462002bba578182fd5b600080600080600080600080610100898b03121562002c1f578384fd5b883567ffffffffffffffff8082111562002c37578586fd5b62002c458c838d0162002b2d565b995060208b013591508082111562002c5b578586fd5b62002c698c838d0162002a47565b985060408b013591508082111562002c7f578586fd5b62002c8d8c838d0162002ac8565b975060608b013591508082111562002ca3578586fd5b62002cb18c838d0162002ac8565b965060808b013591508082111562002cc7578586fd5b62002cd58c838d0162002a47565b955060a08b013591508082111562002ceb578485fd5b62002cf98c838d0162002a47565b945062002d0a8c60c08d0162002a3a565b935060e08b013591508082111562002d20578283fd5b5062002d2f8b828c0162002a47565b9150509295985092959890939650565b60006020828403121562002d51578081fd5b5035919050565b60006020828403121562002d6a578081fd5b5051919050565b6000815480845260208401935082825260208220825b8281101562002db05781546001600160a01b031686526020909501946001918201910162002d87565b5093949350505050565b6000815480845260208401935082825260208220825b8281101562002db057815486526020909501946001918201910162002dd0565b60008151808452815b8181101562002e175760208185018101518683018201520162002df9565b8181111562002e295782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b038316815260406020820181905260009062002e789083018462002df0565b949350505050565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039b8c168152998b1660208b0152978a1660408a01529589166060890152938816608088015291871660a0870152861660c0860152851660e0850152841661010084015283166101208301529091166101408201526101600190565b600060018060a01b038089168352808816602084015260c0604084015262002f3260c084018862002d71565b838103606085015262002f46818862002dba565b848103608086015262002f5a818862002dba565b9350505080841660a084015250979650505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b038481168252831660208201526060604082018190528254600091830190829060018116801562002fe0576001811462002fff576200303a565b60028204607f16845260ff198216608087015260a0860192506200303a565b6002820480855287865260208620865b8281101562003030578154898201608001526001909101906020016200300f565b8801608001945050505b5090979650505050505050565b600060018060a01b038086168352606060208401526200306b606084018662002d71565b9150808416604084015250949350505050565b600060018060a01b03808716835260806020840152620030a2608084018762002d71565b8381036040850152620030b6818762002d71565b92505080841660608401525095945050505050565b6101608101818360005b600b811015620030ff5781516001600160a01b0316835260209283019290910190600101620030d5565b50505092915050565b602080825282518282018190526000918401906040840190835b818110156200314b5783516001600160a01b031683526020938401939092019160010162003122565b509095945050505050565b901515815260200190565b60006040825262003176604083018562002df0565b905060018060a01b03831660208301529392505050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252602e908201527f436f6d706f6e656e7473206d75737420626520736574206265666f726520636f60408201526d06d706c6574696e672073657475760941b606082015260800190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601e908201527f5468697320737465702068617320616c7265616479206265656e2072756e0000604082015260600190565b6020808252818101527f436f6d706f6e656e74207072657072657175697369746573206e6f74206d6574604082015260600190565b602080825260169082015275536574757020616c726561647920636f6d706c65746560501b604082015260600190565b6020808252600d908201526c1499599d5b990819985a5b1959609a1b604082015260600190565b60208082526025908201527f44656e6f6d696e6174696f6e206173736574206d7573742062652072656769736040820152641d195c995960da1b606082015260800190565b60208082526024908201527f436f6e646974696f6e73206e6f74206d657420666f722066756e6420736875746040820152633237bbb760e11b606082015260800190565b60208082526021908201527f496e737566666963656e7420414d475520616e642f6f7220696e63656e7469766040820152606560f81b606082015260800190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff811182821017156200347f57600080fd5b604052919050565b600067ffffffffffffffff8211156200349e578081fd5b5060209081020190565b6001600160a01b03811681146200270e57600080fdfe60806040523480156200001157600080fd5b5060405162001e2838038062001e28833981810160405260408110156200003757600080fd5b8151602083018051604051929492938301929190846401000000008211156200005f57600080fd5b9083019060208201858111156200007557600080fd5b82516401000000008111828201881017156200009057600080fd5b82525081516020918201929091019080838360005b83811015620000bf578181015183820152602001620000a5565b50505050905090810190601f168015620000ed5780820380516001836020036101000a031916815260200191505b506040819052600180546001600160a01b0319163390811790915593507fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94925060009150a2600f8054336001600160a01b031991821617909155600e80549091166001600160a01b0384161790558051620001709060109060208401906200017d565b5050426012555062000222565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620001c057805160ff1916838001178555620001f0565b82800160010185558215620001f0579182015b82811115620001f0578251825591602001919060010190620001d3565b50620001fe92915062000202565b5090565b6200021f91905b80821115620001fe576000815560010162000209565b90565b611bf680620002326000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80639624e83e1161011a578063cbeea68c116100ad578063ec44acf21161007c578063ec44acf21461052b578063f0217ce514610533578063f1a072691461055c578063fbfa77cf14610564578063ff9475251461056c576101fb565b8063cbeea68c146104dd578063d1599d9214610513578063d3240bd21461051b578063d8270dce14610523576101fb565b8063b7009613116100e9578063b700961314610484578063b73515eb146104c5578063bf7e214f146104cd578063c8d70559146104d5576101fb565b80639624e83e146103e5578063a8542f66146103ed578063ab3dbf3b14610407578063b1ffd4711461040f576101fb565b806342143c2a1161019257806379d88d871161016157806379d88d87146103865780637a9e5e4b146103af5780637b103999146103d55780638da5cb5b146103dd576101fb565b806342143c2a14610366578063433f5e601461036e578063481c6a751461037657806354fd4d501461037e576101fb565b806320531bc9116101ce57806320531bc9146102d15780632bc3217d146102d95780633377fc651461030f5780633957a2251461032c576101fb565b806302d05d3f1461020057806303314efa1461022457806306fdde031461022c57806313af4035146102a9575b600080fd5b610208610574565b604080516001600160a01b039092168252519081900360200190f35b610208610583565b610234610592565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561026e578181015183820152602001610256565b50505050905090810190601f16801561029b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102cf600480360360208110156102bf57600080fd5b50356001600160a01b0316610620565b005b6102086106ce565b6102cf600480360360608110156102ef57600080fd5b506001600160a01b03813581169160208101359091169060400135610744565b6102cf600480360361016081101561032657600080fd5b5061076e565b6103526004803603602081101561034257600080fd5b50356001600160a01b0316610953565b604080519115158252519081900360200190f35b610352610968565b610352610976565b610208610986565b610208610995565b6102cf6004803603606081101561039c57600080fd5b50803590602081013590604001356109a4565b6102cf600480360360208110156103c557600080fd5b50356001600160a01b0316610a5b565b610208610b05565b610208610b14565b610208610b23565b6103f5610b32565b60408051918252519081900360200190f35b610208610b38565b610417610b47565b604080516001600160a01b039c8d1681529a8c1660208c0152988b168a8a0152968a1660608a0152948916608089015292881660a088015290871660c0870152861660e0860152851661010085015284166101208401529092166101408201529051908190036101600190f35b6103526004803603606081101561049a57600080fd5b5080356001600160a01b0390811691602081013590911690604001356001600160e01b031916610b9c565b6102cf610db1565b6102086113d1565b6102cf6113e0565b6102cf600480360360608110156104f357600080fd5b506001600160a01b0381358116916020810135909116906040013561142f565b610352611454565b610208611463565b6103f5611472565b610208611478565b6102cf6004803603606081101561054957600080fd5b5080359060208101359060400135611487565b6102cf611541565b610208611a7f565b610352611a8e565b600f546001600160a01b031681565b6007546001600160a01b031690565b6010805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106185780601f106105ed57610100808354040283529160200191610618565b820191906000526020600020905b8154815290600101906020018083116105fb57829003601f168201915b505050505081565b610636336000356001600160e01b031916611a97565b61067e576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600a54604080516320531bc960e01b815290516000926001600160a01b0316916320531bc9916004808301926020929190829003018186803b15801561071357600080fd5b505afa158015610727573d6000803e3d6000fd5b505050506040513d602081101561073d57600080fd5b5051905090565b6107698360601b6001600160601b0319168360601b6001600160601b031916836109a4565b505050565b600f546001600160a01b031633146107c8576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff161561081a576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc8185b1c9958591e481cd95d60721b604482015290519081900360640190fd5b60005b600b811015610870576001601360008484600b811061083857fe5b602090810291909101356001600160a01b03168252810191909152604001600020805460ff191691151591909117905560010161081d565b50600380546001600160a01b03199081166001600160a01b0384358116919091179092556004805482166020850135841617905560058054821660408501358416179055600680548216606085013584161790556007805482166080850135841617905560088054821660a0850135841617905560098054821660c08501358416179055600a8054821660e08501358416179055600b8054821661010080860135851691909117909155600c805483166101208601358516179055600d805490921661014090940135909216929092179091556011805461ff0019169091179055565b60136020526000908152604090205460ff1681565b601154610100900460ff1681565b6011546301000000900460ff1681565b600e546001600160a01b031681565b600b546001600160a01b031690565b6109ba336000356001600160e01b031916611a97565b610a02576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b60008381526002602090815260408083208584528252808320848452909152808220805460ff19169055518291849186917f95ba64c95d85e67ac83a0476c4a62ac2cf8ab2d0407545b8c9d79c3eefa6282991a4505050565b610a71336000356001600160e01b031916611a97565b610ab9576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b03838116919091178083556040519116917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b600a546001600160a01b031690565b6001546001600160a01b031681565b6003546001600160a01b031690565b60001981565b6006546001600160a01b031690565b600354600454600554600654600754600854600954600a54600b54600c54600d546001600160a01b039a8b169a998a16999889169897881697968716969586169594851694938416939283169291821691168b565b6bffffffffffffffffffffffff19606084811b821660008181526002602090815260408083209488901b9095168083529381528482206001600160e01b03198716835290529283205490919060ff1680610c19575060008281526002602090815260408083208484528252808320600019845290915290205460ff165b80610c5157506000828152600260209081526040808320600019845282528083206001600160e01b03198816845290915290205460ff165b80610c7c575060008281526002602090815260408083206000198452825280832090915290205460ff165b80610cc9575060008181527f38b5b2ceac7637132d27514ffcf440b705287635075af7b8bd5adcaa6a4cc5bb602090815260408083206001600160e01b03198816845290915290205460ff165b80610d0e575060008181527f38b5b2ceac7637132d27514ffcf440b705287635075af7b8bd5adcaa6a4cc5bb60209081526040808320600019845290915290205460ff165b80610d5157506001600160e01b0319841660009081527f47fa60fbc027ac3984ea309688a33182f4193c478b40ba8d294eb2cd3ddc4d97602052604090205460ff165b80610da757506000196000527f47fa60fbc027ac3984ea309688a33182f4193c478b40ba8d294eb2cd3ddc4d976020527ff423d1317b37667cd26005728bffa7c8b0499e133951fcf8e814d4fc5f4c98f65460ff165b9695505050505050565b600f546001600160a01b03163314610e0b576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff16610e5c576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc81b5d5cdd081899481cd95d60721b604482015290519081900360640190fd5b60115462010000900460ff16610eaf576040805162461bcd60e51b8152602060048201526013602482015272149bdd5d1a5b99c81b5d5cdd081899481cd95d606a1b604482015290519081900360640190fd5b6011546301000000900460ff1615610f0e576040805162461bcd60e51b815260206004820152601960248201527f5065726d697373696f6e696e6720616c72656164792073657400000000000000604482015290519081900360640190fd5b6005546009546040805178776974686472617728616464726573732c75696e743235362960381b81529051908190036019019020610f63926001600160a01b039081169216906001600160e01b03191661142f565b6008546009546040805178776974686472617728616464726573732c75696e743235362960381b81529051908190036019019020610fb8926001600160a01b039081169216906001600160e01b03191661142f565b600554600754604080517f637265617465466f7228616464726573732c75696e74323536290000000000008152905190819003601a019020611011926001600160a01b039081169216906001600160e01b03191661142f565b600554600754604080517f64657374726f79466f7228616464726573732c75696e743235362900000000008152905190819003601b01902061106a926001600160a01b039081169216906001600160e01b03191661142f565b600454600754604080517f637265617465466f7228616464726573732c75696e74323536290000000000008152905190819003601a0190206110c3926001600160a01b039081169216906001600160e01b03191661142f565b600554600354604080517f6164644173736574546f4f776e656441737365747328616464726573732900008152905190819003601e01902061111c926001600160a01b039081169216906001600160e01b03191661142f565b600854600354604080517f6164644173736574546f4f776e656441737365747328616464726573732900008152905190819003601e019020611175926001600160a01b039081169216906001600160e01b03191661142f565b600854600354604080517f72656d6f766546726f6d4f776e656441737365747328616464726573732900008152905190819003601e0190206111ce926001600160a01b039081169216906001600160e01b03191661142f565b600354600454604080516e726577617264416c6c46656573282960881b8152905190819003600f019020611219926001600160a01b039081169216906001600160e01b03191661142f565b600e54600654604080517f7265676973746572286279746573342c6164647265737329000000000000000081529051908190036018019020611272926001600160a01b039081169216906001600160e01b03191661142f565b600e546006546040516112b1926001600160a01b03908116921690806021611ba08239602101905060405180910390206001600160e01b03191661142f565b600e54600554604080517f656e61626c65496e766573746d656e7428616464726573735b5d2900000000008152905190819003601b01902061130a926001600160a01b039081169216906001600160e01b03191661142f565b600e54600554604080517f64697361626c65496e766573746d656e7428616464726573735b5d29000000008152905190819003601c019020611363926001600160a01b039081169216906001600160e01b03191661142f565b600e54600854604080517f61646445786368616e676528616464726573732c6164647265737329000000008152905190819003601c0190206113bc926001600160a01b039081169216906001600160e01b03191661142f565b6011805463ff00000019166301000000179055565b6000546001600160a01b031681565b600b546001600160a01b031633146113f757600080fd5b6011805460ff191660011790556040517f3b5df664c4e0b5a057aa8fd4cf435e4148c9ccbdd90eca96ea88c0cf0bb0fa5e90600090a1565b6107698360601b6001600160601b0319168360601b6001600160601b03191683611487565b60115462010000900460ff1681565b6005546001600160a01b031690565b60125481565b6008546001600160a01b031690565b61149d336000356001600160e01b031916611a97565b6114e5576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b60008381526002602090815260408083208584528252808320848452909152808220805460ff19166001179055518291849186917f6f50375045128971c5469d343039ba7b8e30a5b190453737b28bda6f7a30677191a4505050565b600f546001600160a01b0316331461159b576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff166115ec576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc81b5d5cdd081899481cd95d60721b604482015290519081900360640190fd5b60115462010000900460ff1615611640576040805162461bcd60e51b8152602060048201526013602482015272149bdd5d1a5b99c8185b1c9958591e481cd95d606a1b604482015290519081900360640190fd5b611648611b80565b506040805161016080820183526003546001600160a01b0390811680845260048054831660208601526005548316858701526006548316606086015260075483166080860152600854831660a0860152600954831660c0860152600a54831660e0860152600b548316610100860152600c548316610120860152600d549092166101408501529351635f630a3160e11b815292939263bec6146292859291909101908190839080838360005b8381101561170c5781810151838201526020016116f4565b50505050905001915050600060405180830381600087803b15801561173057600080fd5b505af1158015611744573d6000803e3d6000fd5b505060048054604051635f630a3160e11b81526001600160a01b03909116935063bec614629250849101808261016080838360005b83811015611791578181015183820152602001611779565b50505050905001915050600060405180830381600087803b1580156117b557600080fd5b505af11580156117c9573d6000803e3d6000fd5b5050600554604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b838110156118175781810151838201526020016117ff565b50505050905001915050600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b5050600654604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b8381101561189d578181015183820152602001611885565b50505050905001915050600060405180830381600087803b1580156118c157600080fd5b505af11580156118d5573d6000803e3d6000fd5b5050600754604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b8381101561192357818101518382015260200161190b565b50505050905001915050600060405180830381600087803b15801561194757600080fd5b505af115801561195b573d6000803e3d6000fd5b5050600854604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b838110156119a9578181015183820152602001611991565b50505050905001915050600060405180830381600087803b1580156119cd57600080fd5b505af11580156119e1573d6000803e3d6000fd5b5050600954604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b83811015611a2f578181015183820152602001611a17565b50505050905001915050600060405180830381600087803b158015611a5357600080fd5b505af1158015611a67573d6000803e3d6000fd5b50506011805462ff0000191662010000179055505050565b6009546001600160a01b031690565b60115460ff1681565b60006001600160a01b038316301415611ab257506001611b7a565b6001546001600160a01b0384811691161415611ad057506001611b7a565b6000546001600160a01b0316611ae857506000611b7a565b6000546040805163b700961360e01b81526001600160a01b0386811660048301523060248301526001600160e01b0319861660448301529151919092169163b7009613916064808301926020929190829003018186803b158015611b4b57600080fd5b505afa158015611b5f573d6000803e3d6000fd5b505050506040513d6020811015611b7557600080fd5b505190505b92915050565b604051806101600160405280600b90602082028038833950919291505056fe62617463685265676973746572286279746573345b5d2c616464726573735b5d29a26469706673582212200cf7e6e1803e51f420f17e1c5d924aca2b801332b4a6e98e2431910726c7d1db64736f6c63430006010033a264697066735822122081621c625b601375d626a758c3284cf83b64442239f35eeec83267aeb76654a864736f6c63430006010033ce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94000000000000000000000000f58035737d7df063966e360947cd26fbbec3dce70000000000000000000000000fd46e3ce7523f1d9982539a44b853ab962528eb0000000000000000000000006784703c34e4502fc120d4cd7472850b480be82500000000000000000000000004431b64303e6379b818296ff7d54481fd7fa7e4000000000000000000000000d07dca4960ce250b54cd98577ec15eb14d6d16ec00000000000000000000000091313a7bfc5f6ca957274beeaae436e26088faf200000000000000000000000058fa120e508b000c19cb6baada30c1d97a9f07ee00000000000000000000000069ccf58f882443bf0e1328e445361245fcfd3fbb0000000000000000000000000d580ae50b58fe08514deab4e38c0dfdb0d30adc
Deployed Bytecode
0x608060405260043610620002a25760003560e01c806377e3f6a81162000163578063ab5abd5f11620000c7578063d8a06f731162000085578063d8a06f7314620006db578063e865ffe814620006f3578063e8b822db146200070a578063e964c96a1462000722578063ebd0d0c71462000739578063f778c105146200074357620002a2565b8063ab5abd5f146200062c578063b6c3ddf01462000651578063bf7e214f1462000676578063c9d4623f146200068e578063d6ee80a914620006a657620002a2565b80638152a0f911620001215780638152a0f914620005ba57806386ecdc4f14620005d15780638a471df914620005db5780638aea8f7114620005f35780638da5cb5b14620005fd5780639ea32baf146200061557620002a2565b806377e3f6a8146200050d5780637a3f5c8714620005245780637a9e5e4b14620005585780637b103999146200057d5780637b8e8895146200059557620002a2565b80632bd90a59116200020b57806342e2f54c11620001c957806342e2f54c146200047257806354fd4d5014620004975780635967d7e814620004af5780635d12928b14620004c75780636b44e6be14620004d15780637295874714620004f657620002a2565b80632bd90a5914620003e357806332e143d614620003fb57806337c384df14620004395780633a1e8de314620004505780633f825ed8146200046857620002a2565b8063149e685a1162000265578063149e685a14620003465780631a966d70146200036b5780631f2d1531146200038257806320531bc9146200038c57806328e68ebe14620003a45780632b34963c14620003cb57620002a2565b806304478c3114620002a75780630a726fe514620002b35780630c1eef4a14620002f0578063116c719f14620002fa57806313af40351462000321575b600080fd5b620002b16200075b565b005b348015620002c057600080fd5b50620002d8620002d236600462002b9b565b62000b02565b604051620002e7919062003156565b60405180910390f35b620002b162000b17565b3480156200030757600080fd5b506200031262000b28565b604051620002e7919062002e3e565b3480156200032e57600080fd5b50620002b16200034036600462002b9b565b62000b37565b3480156200035357600080fd5b50620003126200036536600462002d3f565b62000bbe565b620002b16200037c36600462002b9b565b62000be9565b620002b162000f7b565b3480156200039957600080fd5b506200031262000f8c565b348015620003b157600080fd5b50620003bc62001013565b604051620002e7919062003421565b348015620003d857600080fd5b50620003126200101d565b348015620003f057600080fd5b50620003126200102c565b3480156200040857600080fd5b50620004206200041a36600462002b9b565b6200103b565b604051620002e79b9a9998979695949392919062002ea3565b620002b16200044a36600462002b9b565b620010b1565b3480156200045d57600080fd5b5062000312620010c2565b620002b1620010d1565b3480156200047f57600080fd5b50620002b16200049136600462002b9b565b620010e2565b348015620004a457600080fd5b506200031262001177565b348015620004bc57600080fd5b506200031262001186565b620002b162001195565b348015620004de57600080fd5b50620002d8620004f036600462002b9b565b620011a6565b620002b16200050736600462002b9b565b620011c4565b620002b16200051e36600462002b9b565b620011d5565b3480156200053157600080fd5b50620005496200054336600462002b9b565b620011e6565b604051620002e7919062003108565b3480156200056557600080fd5b50620002b16200057736600462002b9b565b62001261565b3480156200058a57600080fd5b5062000312620012e8565b348015620005a257600080fd5b5062000312620005b436600462002d3f565b620012f7565b620002b1620005cb36600462002b9b565b6200131f565b620002b162001330565b348015620005e857600080fd5b506200031262001341565b620002b162001387565b3480156200060a57600080fd5b506200031262001398565b620002b16200062636600462002b9b565b620013a7565b3480156200063957600080fd5b50620002b16200064b36600462002c02565b620013b8565b3480156200065e57600080fd5b50620003126200067036600462002b9b565b6200174b565b3480156200068357600080fd5b506200031262001766565b3480156200069b57600080fd5b506200031262001775565b348015620006b357600080fd5b50620006cb620006c536600462002b9b565b620017bb565b604051620002e792919062003161565b348015620006e857600080fd5b50620003126200186f565b620002b16200070436600462002b9b565b6200187e565b3480156200071757600080fd5b50620003126200188f565b620002b16200073336600462002b9b565b6200189e565b620002b1620018af565b3480156200075057600080fd5b5062000312620018c0565b6000805a90506200076c33620018cf565b60005a905060006200077d62001775565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b158015620007b657600080fd5b505afa158015620007cb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620007f1919081019062002d58565b905060006200080c8262000806868662001a0e565b62001a3a565b905060006200081a620012e8565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b1580156200085357600080fd5b505afa15801562000868573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200088e919081019062002bc1565b905060006200089c62000f8c565b6001600160a01b0316637e3bfc2f84620008b562001341565b856040518463ffffffff1660e01b8152600401620008d6939291906200342a565b60206040518083038186803b158015620008ef57600080fd5b505afa15801562000904573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200092a919081019062002d58565b905060008715620009bb576200093f620012e8565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200097857600080fd5b505afa1580156200098d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620009b3919081019062002d58565b9050620009bf565b5060005b620009cb828262001a76565b341015620009f65760405162461bcd60e51b8152600401620009ed90620033e0565b60405180910390fd5b62000a0062001775565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b15801562000a3b57600080fd5b505af115801562000a50573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc62000a7962000a72348662001a0e565b8462001a0e565b6040518115909202916000818181858888f1935050505062000aaf5760405162461bcd60e51b8152600401620009ed9062003330565b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb98362000ade8a8a62001a0e565b8460405162000af09392919062003449565b60405180910390a25050505050505050565b60006020819052908152604090205460ff1681565b6000805a90506200076c3362001a9c565b6005546001600160a01b031681565b62000b4f336000356001600160e01b03191662001bb7565b62000b6e5760405162461bcd60e51b8152600401620009ed90620031bc565b600f80546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b6000600a828154811062000bce57fe5b6000918252602090912001546001600160a01b031692915050565b6000805a905062000bfa8362001ca0565b60005a9050600062000c0b62001775565b6001600160a01b031663709bb5676040518163ffffffff1660e01b815260040160206040518083038186803b15801562000c4457600080fd5b505afa15801562000c59573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000c7f919081019062002d58565b9050600062000c948262000806868662001a0e565b9050600062000ca2620012e8565b6001600160a01b03166374d32ad46040518163ffffffff1660e01b815260040160206040518083038186803b15801562000cdb57600080fd5b505afa15801562000cf0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000d16919081019062002bc1565b9050600062000d2462000f8c565b6001600160a01b0316637e3bfc2f8462000d3d62001341565b856040518463ffffffff1660e01b815260040162000d5e939291906200342a565b60206040518083038186803b15801562000d7757600080fd5b505afa15801562000d8c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000db2919081019062002d58565b90506000871562000e435762000dc7620012e8565b6001600160a01b0316631d4632ac6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000e0057600080fd5b505afa15801562000e15573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000e3b919081019062002d58565b905062000e47565b5060005b62000e53828262001a76565b34101562000e755760405162461bcd60e51b8152600401620009ed90620033e0565b62000e7f62001775565b6001600160a01b0316635ce1fb54836040518263ffffffff1660e01b81526004016000604051808303818588803b15801562000eba57600080fd5b505af115801562000ecf573d6000803e3d6000fd5b5050505050336001600160a01b03166108fc62000ef162000a72348662001a0e565b6040518115909202916000818181858888f1935050505062000f275760405162461bcd60e51b8152600401620009ed9062003330565b337f0fa722789511f8feef9c02f613ad3ad10699034c1725894b9e7040552af4ffb98362000f568a8a62001a0e565b8460405162000f689392919062003449565b60405180910390a2505050505050505050565b6000805a90506200076c3362001dbb565b600254604080516320531bc960e01b815290516000926001600160a01b0316916320531bc9916004808301926020929190829003018186803b15801562000fd257600080fd5b505afa15801562000fe7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200100d919081019062002bc1565b90505b90565b600a546000190190565b6004546001600160a01b031681565b6008546001600160a01b031681565b600c60205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a0154600a909a01546001600160a01b03998a169a988a169997881698968816979586169694861695938416949284169391821692821691168b565b6000805a905062000bfa8362001a9c565b6002546001600160a01b031681565b6000805a90506200076c3362001f5d565b336000908152600b60205260409020546001600160a01b038281169116146200111f5760405162461bcd60e51b8152600401620009ed906200339c565b806001600160a01b031663c8d705596040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200115b57600080fd5b505af115801562001170573d6000803e3d6000fd5b5050505050565b6001546001600160a01b031681565b6003546001600160a01b031681565b6000805a90506200076c3362001ca0565b6001600160a01b031660009081526020819052604090205460ff1690565b6000805a905062000bfa8362001dbb565b6000805a905062000bfa83620018cf565b6001600160a01b0381166000908152600d60209081526040918290206001018054835181840281018401909452808452606093928301828280156200125557602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001236575b50505050509050919050565b62001279336000356001600160e01b03191662001bb7565b620012985760405162461bcd60e51b8152600401620009ed90620031bc565b600e80546001600160a01b0319166001600160a01b0383811691909117918290556040519116907f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada490600090a250565b6002546001600160a01b031690565b600a81815481106200130557fe5b6000918252602090912001546001600160a01b0316905081565b6000805a905062000bfa83620020aa565b6000805a90506200076c33620020aa565b60025460408051638a471df960e01b815290516000926001600160a01b031691638a471df9916004808301926020929190829003018186803b15801562000fd257600080fd5b6000805a90506200076c33620021e3565b600f546001600160a01b031681565b6000805a905062000bfa83620021e3565b336000908152600b6020526040902054620013dc906001600160a01b0316620026e3565b600254604051636b55df8560e11b81526001600160a01b039091169063d6abbf0a90620014109033908c9060040162002e52565b600060405180830381600087803b1580156200142b57600080fd5b505af115801562001440573d6000803e3d6000fd5b5050600254604051631f8d99a960e01b81526001600160a01b039091169250631f8d99a991506200147690859060040162002e3e565b60206040518083038186803b1580156200148f57600080fd5b505afa158015620014a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620014ca919081019062002be0565b620014e95760405162461bcd60e51b8152600401620009ed9062003357565b3388604051620014f99062002864565b6200150692919062002e52565b604051809103906000f08015801562001523573d6000803e3d6000fd5b50336000818152600b6020908152604080832080546001600160a01b0319166001600160a01b039687161790558051610100810182528d81528083018a905280820189905294871660608601526080850186905260a085018c905260c085018b905260e085018a9052928252600d8152919020825180519192620015ad9284929091019062002872565b506020828101518051620015c89260018501920190620028f7565b5060408201518051620015e6916002840191602090910190620028f7565b5060608201516003820180546001600160a01b0319166001600160a01b03909216919091179055608082015180516200162a916004840191602090910190620028f7565b5060a0820151805162001648916005840191602090910190620028f7565b5060c08201518051620016669160068401916020909101906200295d565b5060e08201518051620016849160078401916020909101906200295d565b5050600254336000908152600c602052604090206007810180546001600160a01b039384166001600160a01b0319918216179091556001546008909201805492909316911617905550620016d762001775565b336000908152600c6020526040902060090180546001600160a01b0319166001600160a01b03929092169190911790556200171162001341565b336000908152600c60205260409020600a0180546001600160a01b0319166001600160a01b03929092169190911790555050505050505050565b600b602052600090815260409020546001600160a01b031681565b600e546001600160a01b031681565b6002546040805163c9d4623f60e01b815290516000926001600160a01b03169163c9d4623f916004808301926020929190829003018186803b15801562000fd257600080fd5b600d6020908152600091825260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452909291839190830182828015620018565780601f106200182a5761010080835404028352916020019162001856565b820191906000526020600020905b8154815290600101906020018083116200183857829003601f168201915b505050600390930154919250506001600160a01b031682565b6009546001600160a01b031681565b6000805a905062000bfa8362001f5d565b6007546001600160a01b031681565b6000805a905062000bfa8362002711565b6000805a90506200076c3362002711565b6006546001600160a01b031681565b6001600160a01b038082166000908152600b6020526040902054620018f591166200282c565b6001600160a01b038082166000908152600c60205260409020600501546200191e9116620026e3565b6008546001600160a01b038281166000908152600b6020908152604080832054600d8352818420600c909352928190206007015490516307aa253f60e01b8152948416946307aa253f94620019879481169360018101936002909101929116906004016200307e565b602060405180830381600087803b158015620019a257600080fd5b505af1158015620019b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620019dd919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060050180546001600160a01b03191691909216179055565b8082038281111562001a345760405162461bcd60e51b8152600401620009ed906200318d565b92915050565b600081158062001a575750508082028282828162001a5457fe5b04145b62001a345760405162461bcd60e51b8152600401620009ed90620031ea565b8082018281101562001a345760405162461bcd60e51b8152600401620009ed9062003266565b6001600160a01b038082166000908152600b602052604090205462001ac291166200282c565b6001600160a01b038082166000908152600c602052604090206003015462001aeb9116620026e3565b6006546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f7769262001b3092169060040162002e3e565b602060405180830381600087803b15801562001b4b57600080fd5b505af115801562001b60573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001b86919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060030180546001600160a01b03191691909216179055565b60006001600160a01b03831630141562001bd45750600162001a34565b600f546001600160a01b038481169116141562001bf45750600162001a34565b600e546001600160a01b031662001c0e5750600062001a34565b600e5460405163b700961360e01b81526001600160a01b039091169063b70096139062001c449086903090879060040162002f72565b60206040518083038186803b15801562001c5d57600080fd5b505afa15801562001c72573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001c98919081019062002be0565b905062001a34565b6001600160a01b038082166000908152600b602052604090205462001cc691166200282c565b6001600160a01b038082166000908152600c602052604090206006015462001cef9116620026e3565b6009546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f7769262001d3492169060040162002e3e565b602060405180830381600087803b15801562001d4f57600080fd5b505af115801562001d64573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001d8a919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060060180546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b602052604090205462001de191166200282c565b6001600160a01b038082166000908152600c602052604090205462001e079116620026e3565b600380546001600160a01b038381166000908152600b6020908152604080832054600d835292819020909501546002548651631d34cab560e21b815296519585169663b8f63ebc96948616959283169491909216926374d32ad49260048082019391829003018186803b15801562001e7e57600080fd5b505afa15801562001e93573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001eb9919081019062002bc1565b6040518463ffffffff1660e01b815260040162001ed99392919062002e80565b602060405180830381600087803b15801562001ef457600080fd5b505af115801562001f09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062001f2f919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902080546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b602052604090205462001f8391166200282c565b6001600160a01b038082166000908152600c602052604090206001015462001fac9116620026e3565b600480546001600160a01b038381166000908152600b6020908152604080832054600d83528184206003810154600c909452938290206007908101549251638dc6ba2760e01b815296861697638dc6ba27976200202397938416969584169560058101956006820195949091019316910162002f06565b602060405180830381600087803b1580156200203e57600080fd5b505af115801562002053573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062002079919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060010180546001600160a01b03191691909216179055565b6001600160a01b038082166000908152600b6020526040902054620020d091166200282c565b6001600160a01b038082166000908152600c6020526040902060020154620020f99116620026e3565b6005546001600160a01b038281166000908152600b6020908152604080832054600d8352818420600c909352928190206007015490516365925b5160e01b8152948416946365925b51946200215c94811693600490810193909116910162003047565b602060405180830381600087803b1580156200217757600080fd5b505af11580156200218c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620021b2919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060020180546001600160a01b03191691909216179055565b620021ed6200299a565b506001600160a01b038082166000818152600c60209081526040808320815161016081018352815487168152600182015487168185015260028201548716818401526003820154871660608201526004820154871660808201526005820154871660a08201526006820154871660c08201526007820154871660e08201526008820154871661010082015260098201548716610120820152600a909101548616610140820152938352600b825280832054909416808352908290529290205490919060ff1615620022d25760405162461bcd60e51b8152600401620009ed9062003300565b620022dd8162002856565b8015620022f257508151620022f29062002856565b801562002309575062002309826020015162002856565b801562002320575062002320826040015162002856565b801562002337575062002337826060015162002856565b80156200234e57506200234e826080015162002856565b8015620023655750620023658260a0015162002856565b80156200237c57506200237c8260c0015162002856565b6200239b5760405162461bcd60e51b8152600401620009ed9062003218565b6001600160a01b0380821660008181526020818152604091829020805460ff19166001179055815161016081018352865185168152868201518516918101919091528582015184168183015260608087015185169082015260808087015185169082015260a08087015185169082015260c08087015185169082015260e0808701518516908201526101008681015185169082015261012080870151851690820152610140808701519094169381019390935251633377fc6560e01b81529091633377fc6591620024709190600401620030cb565b600060405180830381600087803b1580156200248b57600080fd5b505af1158015620024a0573d6000803e3d6000fd5b50505050806001600160a01b031663f1a072696040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620024e057600080fd5b505af1158015620024f5573d6000803e3d6000fd5b50505050806001600160a01b031663b73515eb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200253557600080fd5b505af11580156200254a573d6000803e3d6000fd5b5050600a8054600181019091557fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b0319166001600160a01b03858116919091179091556002548682166000908152600d60205260409081902090516303e45bbf60e01b81529190921693506303e45bbf9250620025d991859188919060040162002f9f565b600060405180830381600087803b158015620025f457600080fd5b505af115801562002609573d6000803e3d6000fd5b5050604080516101608101825285516001600160a01b0390811682526020808801518216908301528683015181168284015260608088015182169083015260808088015182169083015260a08088015182169083015260c08088015182169083015260e080880151821690830152610100808801518216908301526101208088015182169083015261014080880151821690830152915191851693503392507fa2cf3050e34f76517f20682d78f63125f3f53a3f59af052767d7df14848a6b4e91620026d69190620030cb565b60405180910390a3505050565b620026ee8162002856565b156200270e5760405162461bcd60e51b8152600401620009ed9062003294565b50565b6001600160a01b038082166000908152600b60205260409020546200273791166200282c565b6001600160a01b038082166000908152600c6020526040902060040154620027609116620026e3565b6007546001600160a01b038281166000908152600b602052604090819020549051633b937bbb60e11b815292821692637726f77692620027a592169060040162002e3e565b602060405180830381600087803b158015620027c057600080fd5b505af1158015620027d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620027fb919081019062002bc1565b6001600160a01b039182166000908152600c6020526040902060040180546001600160a01b03191691909216179055565b620028378162002856565b6200270e5760405162461bcd60e51b8152600401620009ed90620032cb565b6001600160a01b0316151590565b611e2880620034bf83390190565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620028b557805160ff1916838001178555620028e5565b82800160010185558215620028e5579182015b82811115620028e5578251825591602001919060010190620028c8565b50620028f3929150620029f6565b5090565b8280548282559060005260206000209081019282156200294f579160200282015b828111156200294f57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062002918565b50620028f392915062002a13565b828054828255906000526020600020908101928215620028e55791602002820182811115620028e5578251825591602001919060010190620028c8565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b6200101091905b80821115620028f35760008155600101620029fd565b6200101091905b80821115620028f35780546001600160a01b031916815560010162002a1a565b803562001a3481620034a8565b600082601f83011262002a58578081fd5b813562002a6f62002a698262003487565b6200345f565b81815291506020808301908481018184028601820187101562002a9157600080fd5b60005b8481101562002abd57813562002aaa81620034a8565b8452928201929082019060010162002a94565b505050505092915050565b600082601f83011262002ad9578081fd5b813562002aea62002a698262003487565b81815291506020808301908481018184028601820187101562002b0c57600080fd5b60005b8481101562002abd5781358452928201929082019060010162002b0f565b600082601f83011262002b3e578081fd5b813567ffffffffffffffff81111562002b55578182fd5b62002b6a601f8201601f19166020016200345f565b915080825283602082850101111562002b8257600080fd5b8060208401602084013760009082016020015292915050565b60006020828403121562002bad578081fd5b813562002bba81620034a8565b9392505050565b60006020828403121562002bd3578081fd5b815162002bba81620034a8565b60006020828403121562002bf2578081fd5b8151801515811462002bba578182fd5b600080600080600080600080610100898b03121562002c1f578384fd5b883567ffffffffffffffff8082111562002c37578586fd5b62002c458c838d0162002b2d565b995060208b013591508082111562002c5b578586fd5b62002c698c838d0162002a47565b985060408b013591508082111562002c7f578586fd5b62002c8d8c838d0162002ac8565b975060608b013591508082111562002ca3578586fd5b62002cb18c838d0162002ac8565b965060808b013591508082111562002cc7578586fd5b62002cd58c838d0162002a47565b955060a08b013591508082111562002ceb578485fd5b62002cf98c838d0162002a47565b945062002d0a8c60c08d0162002a3a565b935060e08b013591508082111562002d20578283fd5b5062002d2f8b828c0162002a47565b9150509295985092959890939650565b60006020828403121562002d51578081fd5b5035919050565b60006020828403121562002d6a578081fd5b5051919050565b6000815480845260208401935082825260208220825b8281101562002db05781546001600160a01b031686526020909501946001918201910162002d87565b5093949350505050565b6000815480845260208401935082825260208220825b8281101562002db057815486526020909501946001918201910162002dd0565b60008151808452815b8181101562002e175760208185018101518683018201520162002df9565b8181111562002e295782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b038316815260406020820181905260009062002e789083018462002df0565b949350505050565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039b8c168152998b1660208b0152978a1660408a01529589166060890152938816608088015291871660a0870152861660c0860152851660e0850152841661010084015283166101208301529091166101408201526101600190565b600060018060a01b038089168352808816602084015260c0604084015262002f3260c084018862002d71565b838103606085015262002f46818862002dba565b848103608086015262002f5a818862002dba565b9350505080841660a084015250979650505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b6001600160a01b038481168252831660208201526060604082018190528254600091830190829060018116801562002fe0576001811462002fff576200303a565b60028204607f16845260ff198216608087015260a0860192506200303a565b6002820480855287865260208620865b8281101562003030578154898201608001526001909101906020016200300f565b8801608001945050505b5090979650505050505050565b600060018060a01b038086168352606060208401526200306b606084018662002d71565b9150808416604084015250949350505050565b600060018060a01b03808716835260806020840152620030a2608084018762002d71565b8381036040850152620030b6818762002d71565b92505080841660608401525095945050505050565b6101608101818360005b600b811015620030ff5781516001600160a01b0316835260209283019290910190600101620030d5565b50505092915050565b602080825282518282018190526000918401906040840190835b818110156200314b5783516001600160a01b031683526020938401939092019160010162003122565b509095945050505050565b901515815260200190565b60006040825262003176604083018562002df0565b905060018060a01b03831660208301529392505050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252602e908201527f436f6d706f6e656e7473206d75737420626520736574206265666f726520636f60408201526d06d706c6574696e672073657475760941b606082015260800190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601e908201527f5468697320737465702068617320616c7265616479206265656e2072756e0000604082015260600190565b6020808252818101527f436f6d706f6e656e74207072657072657175697369746573206e6f74206d6574604082015260600190565b602080825260169082015275536574757020616c726561647920636f6d706c65746560501b604082015260600190565b6020808252600d908201526c1499599d5b990819985a5b1959609a1b604082015260600190565b60208082526025908201527f44656e6f6d696e6174696f6e206173736574206d7573742062652072656769736040820152641d195c995960da1b606082015260800190565b60208082526024908201527f436f6e646974696f6e73206e6f74206d657420666f722066756e6420736875746040820152633237bbb760e11b606082015260800190565b60208082526021908201527f496e737566666963656e7420414d475520616e642f6f7220696e63656e7469766040820152606560f81b606082015260800190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff811182821017156200347f57600080fd5b604052919050565b600067ffffffffffffffff8211156200349e578081fd5b5060209081020190565b6001600160a01b03811681146200270e57600080fdfe60806040523480156200001157600080fd5b5060405162001e2838038062001e28833981810160405260408110156200003757600080fd5b8151602083018051604051929492938301929190846401000000008211156200005f57600080fd5b9083019060208201858111156200007557600080fd5b82516401000000008111828201881017156200009057600080fd5b82525081516020918201929091019080838360005b83811015620000bf578181015183820152602001620000a5565b50505050905090810190601f168015620000ed5780820380516001836020036101000a031916815260200191505b506040819052600180546001600160a01b0319163390811790915593507fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94925060009150a2600f8054336001600160a01b031991821617909155600e80549091166001600160a01b0384161790558051620001709060109060208401906200017d565b5050426012555062000222565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620001c057805160ff1916838001178555620001f0565b82800160010185558215620001f0579182015b82811115620001f0578251825591602001919060010190620001d3565b50620001fe92915062000202565b5090565b6200021f91905b80821115620001fe576000815560010162000209565b90565b611bf680620002326000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80639624e83e1161011a578063cbeea68c116100ad578063ec44acf21161007c578063ec44acf21461052b578063f0217ce514610533578063f1a072691461055c578063fbfa77cf14610564578063ff9475251461056c576101fb565b8063cbeea68c146104dd578063d1599d9214610513578063d3240bd21461051b578063d8270dce14610523576101fb565b8063b7009613116100e9578063b700961314610484578063b73515eb146104c5578063bf7e214f146104cd578063c8d70559146104d5576101fb565b80639624e83e146103e5578063a8542f66146103ed578063ab3dbf3b14610407578063b1ffd4711461040f576101fb565b806342143c2a1161019257806379d88d871161016157806379d88d87146103865780637a9e5e4b146103af5780637b103999146103d55780638da5cb5b146103dd576101fb565b806342143c2a14610366578063433f5e601461036e578063481c6a751461037657806354fd4d501461037e576101fb565b806320531bc9116101ce57806320531bc9146102d15780632bc3217d146102d95780633377fc651461030f5780633957a2251461032c576101fb565b806302d05d3f1461020057806303314efa1461022457806306fdde031461022c57806313af4035146102a9575b600080fd5b610208610574565b604080516001600160a01b039092168252519081900360200190f35b610208610583565b610234610592565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561026e578181015183820152602001610256565b50505050905090810190601f16801561029b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102cf600480360360208110156102bf57600080fd5b50356001600160a01b0316610620565b005b6102086106ce565b6102cf600480360360608110156102ef57600080fd5b506001600160a01b03813581169160208101359091169060400135610744565b6102cf600480360361016081101561032657600080fd5b5061076e565b6103526004803603602081101561034257600080fd5b50356001600160a01b0316610953565b604080519115158252519081900360200190f35b610352610968565b610352610976565b610208610986565b610208610995565b6102cf6004803603606081101561039c57600080fd5b50803590602081013590604001356109a4565b6102cf600480360360208110156103c557600080fd5b50356001600160a01b0316610a5b565b610208610b05565b610208610b14565b610208610b23565b6103f5610b32565b60408051918252519081900360200190f35b610208610b38565b610417610b47565b604080516001600160a01b039c8d1681529a8c1660208c0152988b168a8a0152968a1660608a0152948916608089015292881660a088015290871660c0870152861660e0860152851661010085015284166101208401529092166101408201529051908190036101600190f35b6103526004803603606081101561049a57600080fd5b5080356001600160a01b0390811691602081013590911690604001356001600160e01b031916610b9c565b6102cf610db1565b6102086113d1565b6102cf6113e0565b6102cf600480360360608110156104f357600080fd5b506001600160a01b0381358116916020810135909116906040013561142f565b610352611454565b610208611463565b6103f5611472565b610208611478565b6102cf6004803603606081101561054957600080fd5b5080359060208101359060400135611487565b6102cf611541565b610208611a7f565b610352611a8e565b600f546001600160a01b031681565b6007546001600160a01b031690565b6010805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106185780601f106105ed57610100808354040283529160200191610618565b820191906000526020600020905b8154815290600101906020018083116105fb57829003601f168201915b505050505081565b610636336000356001600160e01b031916611a97565b61067e576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600a54604080516320531bc960e01b815290516000926001600160a01b0316916320531bc9916004808301926020929190829003018186803b15801561071357600080fd5b505afa158015610727573d6000803e3d6000fd5b505050506040513d602081101561073d57600080fd5b5051905090565b6107698360601b6001600160601b0319168360601b6001600160601b031916836109a4565b505050565b600f546001600160a01b031633146107c8576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff161561081a576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc8185b1c9958591e481cd95d60721b604482015290519081900360640190fd5b60005b600b811015610870576001601360008484600b811061083857fe5b602090810291909101356001600160a01b03168252810191909152604001600020805460ff191691151591909117905560010161081d565b50600380546001600160a01b03199081166001600160a01b0384358116919091179092556004805482166020850135841617905560058054821660408501358416179055600680548216606085013584161790556007805482166080850135841617905560088054821660a0850135841617905560098054821660c08501358416179055600a8054821660e08501358416179055600b8054821661010080860135851691909117909155600c805483166101208601358516179055600d805490921661014090940135909216929092179091556011805461ff0019169091179055565b60136020526000908152604090205460ff1681565b601154610100900460ff1681565b6011546301000000900460ff1681565b600e546001600160a01b031681565b600b546001600160a01b031690565b6109ba336000356001600160e01b031916611a97565b610a02576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b60008381526002602090815260408083208584528252808320848452909152808220805460ff19169055518291849186917f95ba64c95d85e67ac83a0476c4a62ac2cf8ab2d0407545b8c9d79c3eefa6282991a4505050565b610a71336000356001600160e01b031916611a97565b610ab9576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b03838116919091178083556040519116917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b600a546001600160a01b031690565b6001546001600160a01b031681565b6003546001600160a01b031690565b60001981565b6006546001600160a01b031690565b600354600454600554600654600754600854600954600a54600b54600c54600d546001600160a01b039a8b169a998a16999889169897881697968716969586169594851694938416939283169291821691168b565b6bffffffffffffffffffffffff19606084811b821660008181526002602090815260408083209488901b9095168083529381528482206001600160e01b03198716835290529283205490919060ff1680610c19575060008281526002602090815260408083208484528252808320600019845290915290205460ff165b80610c5157506000828152600260209081526040808320600019845282528083206001600160e01b03198816845290915290205460ff165b80610c7c575060008281526002602090815260408083206000198452825280832090915290205460ff165b80610cc9575060008181527f38b5b2ceac7637132d27514ffcf440b705287635075af7b8bd5adcaa6a4cc5bb602090815260408083206001600160e01b03198816845290915290205460ff165b80610d0e575060008181527f38b5b2ceac7637132d27514ffcf440b705287635075af7b8bd5adcaa6a4cc5bb60209081526040808320600019845290915290205460ff165b80610d5157506001600160e01b0319841660009081527f47fa60fbc027ac3984ea309688a33182f4193c478b40ba8d294eb2cd3ddc4d97602052604090205460ff165b80610da757506000196000527f47fa60fbc027ac3984ea309688a33182f4193c478b40ba8d294eb2cd3ddc4d976020527ff423d1317b37667cd26005728bffa7c8b0499e133951fcf8e814d4fc5f4c98f65460ff165b9695505050505050565b600f546001600160a01b03163314610e0b576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff16610e5c576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc81b5d5cdd081899481cd95d60721b604482015290519081900360640190fd5b60115462010000900460ff16610eaf576040805162461bcd60e51b8152602060048201526013602482015272149bdd5d1a5b99c81b5d5cdd081899481cd95d606a1b604482015290519081900360640190fd5b6011546301000000900460ff1615610f0e576040805162461bcd60e51b815260206004820152601960248201527f5065726d697373696f6e696e6720616c72656164792073657400000000000000604482015290519081900360640190fd5b6005546009546040805178776974686472617728616464726573732c75696e743235362960381b81529051908190036019019020610f63926001600160a01b039081169216906001600160e01b03191661142f565b6008546009546040805178776974686472617728616464726573732c75696e743235362960381b81529051908190036019019020610fb8926001600160a01b039081169216906001600160e01b03191661142f565b600554600754604080517f637265617465466f7228616464726573732c75696e74323536290000000000008152905190819003601a019020611011926001600160a01b039081169216906001600160e01b03191661142f565b600554600754604080517f64657374726f79466f7228616464726573732c75696e743235362900000000008152905190819003601b01902061106a926001600160a01b039081169216906001600160e01b03191661142f565b600454600754604080517f637265617465466f7228616464726573732c75696e74323536290000000000008152905190819003601a0190206110c3926001600160a01b039081169216906001600160e01b03191661142f565b600554600354604080517f6164644173736574546f4f776e656441737365747328616464726573732900008152905190819003601e01902061111c926001600160a01b039081169216906001600160e01b03191661142f565b600854600354604080517f6164644173736574546f4f776e656441737365747328616464726573732900008152905190819003601e019020611175926001600160a01b039081169216906001600160e01b03191661142f565b600854600354604080517f72656d6f766546726f6d4f776e656441737365747328616464726573732900008152905190819003601e0190206111ce926001600160a01b039081169216906001600160e01b03191661142f565b600354600454604080516e726577617264416c6c46656573282960881b8152905190819003600f019020611219926001600160a01b039081169216906001600160e01b03191661142f565b600e54600654604080517f7265676973746572286279746573342c6164647265737329000000000000000081529051908190036018019020611272926001600160a01b039081169216906001600160e01b03191661142f565b600e546006546040516112b1926001600160a01b03908116921690806021611ba08239602101905060405180910390206001600160e01b03191661142f565b600e54600554604080517f656e61626c65496e766573746d656e7428616464726573735b5d2900000000008152905190819003601b01902061130a926001600160a01b039081169216906001600160e01b03191661142f565b600e54600554604080517f64697361626c65496e766573746d656e7428616464726573735b5d29000000008152905190819003601c019020611363926001600160a01b039081169216906001600160e01b03191661142f565b600e54600854604080517f61646445786368616e676528616464726573732c6164647265737329000000008152905190819003601c0190206113bc926001600160a01b039081169216906001600160e01b03191661142f565b6011805463ff00000019166301000000179055565b6000546001600160a01b031681565b600b546001600160a01b031633146113f757600080fd5b6011805460ff191660011790556040517f3b5df664c4e0b5a057aa8fd4cf435e4148c9ccbdd90eca96ea88c0cf0bb0fa5e90600090a1565b6107698360601b6001600160601b0319168360601b6001600160601b03191683611487565b60115462010000900460ff1681565b6005546001600160a01b031690565b60125481565b6008546001600160a01b031690565b61149d336000356001600160e01b031916611a97565b6114e5576040805162461bcd60e51b8152602060048201526014602482015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604482015290519081900360640190fd5b60008381526002602090815260408083208584528252808320848452909152808220805460ff19166001179055518291849186917f6f50375045128971c5469d343039ba7b8e30a5b190453737b28bda6f7a30677191a4505050565b600f546001600160a01b0316331461159b576040805162461bcd60e51b81526020600482015260186024820152774f6e6c792063726561746f722063616e20646f207468697360401b604482015290519081900360640190fd5b601154610100900460ff166115ec576040805162461bcd60e51b815260206004820152601260248201527114dc1bdad95cc81b5d5cdd081899481cd95d60721b604482015290519081900360640190fd5b60115462010000900460ff1615611640576040805162461bcd60e51b8152602060048201526013602482015272149bdd5d1a5b99c8185b1c9958591e481cd95d606a1b604482015290519081900360640190fd5b611648611b80565b506040805161016080820183526003546001600160a01b0390811680845260048054831660208601526005548316858701526006548316606086015260075483166080860152600854831660a0860152600954831660c0860152600a54831660e0860152600b548316610100860152600c548316610120860152600d549092166101408501529351635f630a3160e11b815292939263bec6146292859291909101908190839080838360005b8381101561170c5781810151838201526020016116f4565b50505050905001915050600060405180830381600087803b15801561173057600080fd5b505af1158015611744573d6000803e3d6000fd5b505060048054604051635f630a3160e11b81526001600160a01b03909116935063bec614629250849101808261016080838360005b83811015611791578181015183820152602001611779565b50505050905001915050600060405180830381600087803b1580156117b557600080fd5b505af11580156117c9573d6000803e3d6000fd5b5050600554604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b838110156118175781810151838201526020016117ff565b50505050905001915050600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b5050600654604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b8381101561189d578181015183820152602001611885565b50505050905001915050600060405180830381600087803b1580156118c157600080fd5b505af11580156118d5573d6000803e3d6000fd5b5050600754604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b8381101561192357818101518382015260200161190b565b50505050905001915050600060405180830381600087803b15801561194757600080fd5b505af115801561195b573d6000803e3d6000fd5b5050600854604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b838110156119a9578181015183820152602001611991565b50505050905001915050600060405180830381600087803b1580156119cd57600080fd5b505af11580156119e1573d6000803e3d6000fd5b5050600954604051635f630a3160e11b81526001600160a01b03909116925063bec6146291508390600401808261016080838360005b83811015611a2f578181015183820152602001611a17565b50505050905001915050600060405180830381600087803b158015611a5357600080fd5b505af1158015611a67573d6000803e3d6000fd5b50506011805462ff0000191662010000179055505050565b6009546001600160a01b031690565b60115460ff1681565b60006001600160a01b038316301415611ab257506001611b7a565b6001546001600160a01b0384811691161415611ad057506001611b7a565b6000546001600160a01b0316611ae857506000611b7a565b6000546040805163b700961360e01b81526001600160a01b0386811660048301523060248301526001600160e01b0319861660448301529151919092169163b7009613916064808301926020929190829003018186803b158015611b4b57600080fd5b505afa158015611b5f573d6000803e3d6000fd5b505050506040513d6020811015611b7557600080fd5b505190505b92915050565b604051806101600160405280600b90602082028038833950919291505056fe62617463685265676973746572286279746573345b5d2c616464726573735b5d29a26469706673582212200cf7e6e1803e51f420f17e1c5d924aca2b801332b4a6e98e2431910726c7d1db64736f6c63430006010033a264697066735822122081621c625b601375d626a758c3284cf83b64442239f35eeec83267aeb76654a864736f6c63430006010033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f58035737d7df063966e360947cd26fbbec3dce70000000000000000000000000fd46e3ce7523f1d9982539a44b853ab962528eb0000000000000000000000006784703c34e4502fc120d4cd7472850b480be82500000000000000000000000004431b64303e6379b818296ff7d54481fd7fa7e4000000000000000000000000d07dca4960ce250b54cd98577ec15eb14d6d16ec00000000000000000000000091313a7bfc5f6ca957274beeaae436e26088faf200000000000000000000000058fa120e508b000c19cb6baada30c1d97a9f07ee00000000000000000000000069ccf58f882443bf0e1328e445361245fcfd3fbb0000000000000000000000000d580ae50b58fe08514deab4e38c0dfdb0d30adc
-----Decoded View---------------
Arg [0] : _accountingFactory (address): 0xf58035737D7dF063966e360947cD26FBBeC3DCe7
Arg [1] : _feeManagerFactory (address): 0x0fD46e3CE7523f1d9982539a44b853ab962528eb
Arg [2] : _participationFactory (address): 0x6784703C34E4502FC120D4CD7472850B480bE825
Arg [3] : _sharesFactory (address): 0x04431b64303e6379B818296Ff7D54481FD7Fa7E4
Arg [4] : _tradingFactory (address): 0xD07Dca4960CE250b54cd98577ec15Eb14d6D16ec
Arg [5] : _vaultFactory (address): 0x91313A7bfc5F6Ca957274beEaae436E26088faf2
Arg [6] : _policyManagerFactory (address): 0x58FA120e508b000C19cb6bAADA30C1d97A9F07Ee
Arg [7] : _registry (address): 0x69ccf58f882443BF0E1328E445361245fCfD3FBB
Arg [8] : _postDeployOwner (address): 0x0d580ae50B58fe08514dEAB4e38c0DFdB0D30adC
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000f58035737d7df063966e360947cd26fbbec3dce7
Arg [1] : 0000000000000000000000000fd46e3ce7523f1d9982539a44b853ab962528eb
Arg [2] : 0000000000000000000000006784703c34e4502fc120d4cd7472850b480be825
Arg [3] : 00000000000000000000000004431b64303e6379b818296ff7d54481fd7fa7e4
Arg [4] : 000000000000000000000000d07dca4960ce250b54cd98577ec15eb14d6d16ec
Arg [5] : 00000000000000000000000091313a7bfc5f6ca957274beeaae436e26088faf2
Arg [6] : 00000000000000000000000058fa120e508b000c19cb6baada30c1d97a9f07ee
Arg [7] : 00000000000000000000000069ccf58f882443bf0e1328e445361245fcfd3fbb
Arg [8] : 0000000000000000000000000d580ae50b58fe08514deab4e38c0dfdb0d30adc
Deployed Bytecode Sourcemap
163:980:63:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8112:95:30;;;:::i;:::-;;48:44:29;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;48:44:29;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;6872:107:30;;;:::i;868:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;868:49:30;;;:::i;:::-;;;;;;;;566:130:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;566:130:0;;;;;;;;:::i;10799:91:30:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;10799:91:30;;;;;;;;:::i;8529:108::-;;;;;;;;;:::i;4757:101::-;;;:::i;11231:127::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11231:127:30;;;:::i;10895:82::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10895:82:30;;;:::i;:::-;;;;;;;;819:43;;8:9:-1;5:2;;;30:1;27;20:12;5:2;819:43:30;;;:::i;1019:37::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1019:37:30;;;:::i;1186:55::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1186:55:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;6743:124;;;;;;;;;:::i;730:34::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;730:34:30;;;:::i;5583:101::-;;;:::i;928:213:63:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;928:213:63;;;;;;;;:::i;701:23:30:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;701:23:30;;;:::i;770:43::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;770:43:30;;;:::i;8642:91::-;;;:::i;192:106:29:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;192:106:29;;;;;;;;:::i;4634:118:30:-;;;;;;;;;:::i;7995:112::-;;;;;;;;;:::i;11466:139::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;11466:139:30;;;;;;;;:::i;:::-;;;;;;;;702:167:0;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;702:167:0;;;;;;;;:::i;11363:98:30:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11363:98:30;;;:::i;1102:22::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1102:22:30;;;;;;;;:::i;6153:124::-;;;;;;;;;:::i;6282:107::-;;;:::i;10983:121::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;10983:121:30;;;:::i;10698:95::-;;;:::i;433:26:0:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;433:26:0;;;:::i;10581:112:30:-;;;;;;;;;:::i;2942:1244::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2942:1244:30;;;;;;;;:::i;1130:50::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1130:50:30;;;;;;;;:::i;397:30:0:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;397:30:0;;;:::i;11109:117:30:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11109:117:30;;;:::i;1247:55::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1247:55:30;;;;;;;;:::i;:::-;;;;;;;;;1062:33;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1062:33:30;;;:::i;5460:118::-;;;;;;;;;:::i;978:35::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:35:30;;;:::i;7305:110::-;;;;;;;;;:::i;7420:93::-;;;:::i;923:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;923:49:30;;;:::i;8112:95::-;8158:5;942:11:10;956:9;942:23;;8175:29:30::1;8193:10;8175:17;:29::i;:::-;986:12:10::0;1001:9;986:24;;1021:15;1047:8;:6;:8::i;:::-;-1:-1:-1;;;;;1039:30:10;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1039:32:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1039:32:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1039:32:10;;;;;;;;;1021:50;;1081:16;1100:71;1117:10;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:10;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1203:34:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1203:34:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1203:34:10;;;;;;;;;1181:56;;1247:13;1276;:11;:13::i;:::-;-1:-1:-1;;;;;1263:43:10;;1320:11;1345:10;:8;:10::i;:::-;1369:11;1263:127;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1263:127:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1263:127:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1263:127:10;;;;;;;;;1247:143;;1400:20;1434:15;1430:146;;;1492:10;:8;:10::i;:::-;-1:-1:-1;;;;;1483:30:10;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1483:32:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1483:32:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1483:32:10;;;;;;;;;1465:50;;1430:146;;;-1:-1:-1;1564:1:10;1430:146;1619:30;1623:8;1633:15;1619:3;:30::i;:::-;1606:9;:43;;1585:123;;;;-1:-1:-1;;;1585:123:10;;;;;;;;;;;;;;;;;1726:8;:6;:8::i;:::-;-1:-1:-1;;;;;1718:32:10;;1757:8;1718:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1718:50:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1718:50:10;;;;;1800:10;-1:-1:-1;;;;;1800:15:10;:151;1833:104;1858:24;1862:9;1873:8;1858:3;:24::i;:::-;1904:15;1833:3;:104::i;:::-;1800:151;;;;;;;;;;;;;;;;;;;;;1779:211;;;;-1:-1:-1;;;1779:211:10;;;;;;;;;2014:10;2005:69;2026:8;2036:20;2040:6;2048:7;2036:3;:20::i;:::-;2058:15;2005:69;;;;;;;;;;;;;;;;;8112:95:30;;;;;;;;:::o;48:44:29:-;;;;;;;;;;;;;;;;:::o;6872:107:30:-;6924:5;942:11:10;956:9;942:23;;6941:35:30::1;6965:10;6941:23;:35::i;868:49::-:0;;;-1:-1:-1;;;;;868:49:30;;:::o;566:130:0:-;907:33;920:10;932:7;;-1:-1:-1;;;;;;932:7:0;907:12;:33::i;:::-;899:66;;;;-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;10799:91:30:-;10856:7;10874:5;10880:6;10874:13;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10874:13:30;;10799:91;-1:-1:-1;;10799:91:30:o;8529:108::-;8592:5;942:11:10;956:9;942:23;;8609:25:30::1;8625:8;8609:15;:25::i;:::-;986:12:10::0;1001:9;986:24;;1021:15;1047:8;:6;:8::i;:::-;-1:-1:-1;;;;;1039:30:10;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1039:32:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1039:32:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1039:32:10;;;;;;;;;1021:50;;1081:16;1100:71;1117:10;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:10;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1203:34:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1203:34:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1203:34:10;;;;;;;;;1181:56;;1247:13;1276;:11;:13::i;:::-;-1:-1:-1;;;;;1263:43:10;;1320:11;1345:10;:8;:10::i;:::-;1369:11;1263:127;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1263:127:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1263:127:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1263:127:10;;;;;;;;;1247:143;;1400:20;1434:15;1430:146;;;1492:10;:8;:10::i;:::-;-1:-1:-1;;;;;1483:30:10;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1483:32:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1483:32:10;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1483:32:10;;;;;;;;;1465:50;;1430:146;;;-1:-1:-1;1564:1:10;1430:146;1619:30;1623:8;1633:15;1619:3;:30::i;:::-;1606:9;:43;;1585:123;;;;-1:-1:-1;;;1585:123:10;;;;;;;;;1726:8;:6;:8::i;:::-;-1:-1:-1;;;;;1718:32:10;;1757:8;1718:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1718:50:10;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1718:50:10;;;;;1800:10;-1:-1:-1;;;;;1800:15:10;:151;1833:104;1858:24;1862:9;1873:8;1858:3;:24::i;1833:104::-;1800:151;;;;;;;;;;;;;;;;;;;;;1779:211;;;;-1:-1:-1;;;1779:211:10;;;;;;;;;2014:10;2005:69;2026:8;2036:20;2040:6;2048:7;2036:3;:20::i;:::-;2058:15;2005:69;;;;;;;;;;;;;;;;;8529:108:30;;;;;;;;;:::o;4757:101::-;4806:5;942:11:10;956:9;942:23;;4823:32:30::1;4844:10;4823:20;:32::i;11231:127::-:0;11318:18;;:32;;;-1:-1:-1;;;11318:32:30;;;;11284:7;;-1:-1:-1;;;;;11318:18:30;;:30;;:32;;;;;;;;;;;;;;:18;:32;;;5:2:-1;;;;30:1;27;20:12;5:2;11318:32:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11318:32:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;11318:32:30;;;;;;;;;11303:48;;11231:127;;:::o;10895:82::-;10958:5;:12;-1:-1:-1;;10958:16:30;10895:82;:::o;819:43::-;;;-1:-1:-1;;;;;819:43:30;;:::o;1019:37::-;;;-1:-1:-1;;;;;1019:37:30;;:::o;1186:55::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1186:55:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;6743:124::-;6814:5;942:11:10;956:9;942:23;;6831:33:30::1;6855:8;6831:23;:33::i;730:34::-:0;;;-1:-1:-1;;;;;730:34:30;;:::o;5583:101::-;5632:5;942:11:10;956:9;942:23;;5649:32:30::1;5670:10;5649:20;:32::i;928:213:63:-:0;1019:10;1004:26;;;;:14;:26;;;;;;-1:-1:-1;;;;;1004:34:63;;;:26;;:34;983:117;;;;-1:-1:-1;;;983:117:63;;;;;;;;;1114:4;-1:-1:-1;;;;;1110:22:63;;:24;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1110:24:63;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1110:24:63;;;;928:213;:::o;701:23:30:-;;;-1:-1:-1;;;;;701:23:30;;:::o;770:43::-;;;-1:-1:-1;;;;;770:43:30;;:::o;8642:91::-;8686:5;942:11:10;956:9;942:23;;8703:27:30::1;8719:10;8703:15;:27::i;192:106:29:-:0;-1:-1:-1;;;;;272:19:29;249:4;272:19;;;;;;;;;;;;;;192:106::o;4634:118:30:-;4702:5;942:11:10;956:9;942:23;;4719:30:30::1;4740:8;4719:20;:30::i;7995:112::-:0;8060:5;942:11:10;956:9;942:23;;8077:27:30::1;8095:8;8077:17;:27::i;11466:139::-:0;-1:-1:-1;;;;;11563:24:30;;;;;;:18;:24;;;;;;;;;:34;;11555:43;;;;;;;;;;;;;;;;;11527:16;;11555:43;;;11563:34;11555:43;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;11555:43:30;;;;;;;;;;;;;;;;;;;;;;;11466:139;;;:::o;702:167:0:-;907:33;920:10;932:7;;-1:-1:-1;;;;;;932:7:0;907:12;:33::i;:::-;899:66;;;;-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:-1:-1;;827:35:0::1;702:167:::0;:::o;11363:98:30:-;11439:18;;-1:-1:-1;;;;;11439:18:30;11363:98;:::o;1102:22::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1102:22:30;;-1:-1:-1;1102:22:30;:::o;6153:124::-;6224:5;942:11:10;956:9;942:23;;6241:33:30::1;6265:8;6241:23;:33::i;6282:107::-:0;6334:5;942:11:10;956:9;942:23;;6351:35:30::1;6375:10;6351:23;:35::i;10983:121::-:0;11067:18;;:29;;;-1:-1:-1;;;11067:29:30;;;;11033:7;;-1:-1:-1;;;;;11067:18:30;;:27;;:29;;;;;;;;;;;;;;:18;:29;;;5:2:-1;;;;30:1;27;20:12;10698:95:30;10744:5;942:11:10;956:9;942:23;;10761:29:30::1;10779:10;10761:17;:29::i;433:26:0:-:0;;;-1:-1:-1;;;;;433:26:0;;:::o;10581:112:30:-;10646:5;942:11:10;956:9;942:23;;10663:27:30::1;10681:8;10663:17;:27::i;2942:1244::-:0;3323:10;3308:26;;;;:14;:26;;;;;;3286:49;;-1:-1:-1;;;;;3308:26:30;3286:21;:49::i;:::-;3345:18;;:87;;-1:-1:-1;;;3345:87:30;;-1:-1:-1;;;;;3345:18:30;;;;:34;;:87;;3393:10;;3417:5;;3345:87;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3345:87:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;3463:18:30;;:56;;-1:-1:-1;;;3463:56:30;;-1:-1:-1;;;;;3463:18:30;;;;-1:-1:-1;3463:36:30;;-1:-1:-1;3463:56:30;;3500:18;;3463:56;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3463:56:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;3463:56:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;3463:56:30;;;;;;;;;3442:140;;;;-1:-1:-1;;;3442:140:30;;;;;;;;;3638:10;3650:5;3630:26;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;3608:10:30;3593:26;;;;:14;:26;;;;;;;;:64;;-1:-1:-1;;;;;;3593:64:30;-1:-1:-1;;;;;3593:64:30;;;;;;3700:221;;3593:64;3700:221;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3667:30;;;:18;:30;;;;;:254;;;;:30;;:254;;:30;;:254;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;-1:-1:-1;;;;;;3667:254:30;-1:-1:-1;;;;;3667:254:30;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3667:254:30;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;3979:18:30;;3948:10;3979:18;3931:28;;;:16;:28;;;;;:37;;;:67;;-1:-1:-1;;;;;3979:18:30;;;-1:-1:-1;;;;;;3931:67:30;;;;;;;-1:-1:-1;4055:7:30;4008:36;;;;:55;;4055:7;;;;4008:55;;;;;-1:-1:-1;4111:8:30;:6;:8::i;:::-;4090:10;4073:28;;;;:16;:28;;;;;:35;;:46;;-1:-1:-1;;;;;;4073:46:30;-1:-1:-1;;;;;4073:46:30;;;;;;;;;;4169:10;:8;:10::i;:::-;4146;4129:28;;;;:16;:28;;;;;:37;;:50;;-1:-1:-1;;;;;;4129:50:30;-1:-1:-1;;;;;4129:50:30;;;;;;;;;;-1:-1:-1;;;;;;;;2942:1244:30:o;1130:50::-;;;;;;;;;;;;-1:-1:-1;;;;;1130:50:30;;:::o;397:30:0:-;;;-1:-1:-1;;;;;397:30:0;;:::o;11109:117:30:-;11191:18;;:27;;;-1:-1:-1;;;11191:27:30;;;;11157:7;;-1:-1:-1;;;;;11191:18:30;;:25;;:27;;;;;;;;;;;;;;:18;:27;;;5:2:-1;;;;30:1;27;20:12;1247:55:30;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1247:55:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1247:55:30;;;;;;;-1:-1:-1;;;;;;;1247:55:30;;:::o;1062:33::-;;;-1:-1:-1;;;;;1062:33:30;;:::o;5460:118::-;5528:5;942:11:10;956:9;942:23;;5545:30:30::1;5566:8;5545:20;:30::i;978:35::-:0;;;-1:-1:-1;;;;;978:35:30;;:::o;7305:110::-;7369:5;942:11:10;956:9;942:23;;7386:26:30::1;7403:8;7386:16;:26::i;7420:93::-:0;7465:5;942:11:10;956:9;942:23;;7482:28:30::1;7499:10;7482:16;:28::i;923:49::-:0;;;-1:-1:-1;;;;;923:49:30;;:::o;7519:470::-;-1:-1:-1;;;;;7614:24:30;;;;;;;:14;:24;;;;;;7595:44;;7614:24;7595:18;:44::i;:::-;-1:-1:-1;;;;;7671:26:30;;;;;;;:16;:26;;;;;:34;;;7649:57;;7671:34;7649:21;:57::i;:::-;7753:14;;-1:-1:-1;;;;;7796:24:30;;;7753:14;7796:24;;;:14;:24;;;;;;;;;7834:18;:28;;;;;7937:16;:26;;;;;;;:35;;;7753:229;;-1:-1:-1;;;7753:229:30;;:14;;;;:29;;:229;;7796:24;;;7753:14;7834:38;;;7886:37;;;;;7937:35;;;7753:229;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7753:229:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7753:229:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;7753:229:30;;;;;;;;;-1:-1:-1;;;;;7716:26:30;;;;;;;:16;:26;;;;;:34;;:266;;-1:-1:-1;;;;;;7716:266:30;;;;;;;;7519:470::o;877:127:2:-;960:5;;;955:16;;;;947:50;;;;-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;;;;;;;;746:126;829:5;;;824:16;;;;816:49;;;;-1:-1:-1;;;816:49:2;;;;;;;;6395:342:30;-1:-1:-1;;;;;6496:24:30;;;;;;;:14;:24;;;;;;6477:44;;6496:24;6477:18;:44::i;:::-;-1:-1:-1;;;;;6553:26:30;;;;;;;:16;:26;;;;;:40;;;6531:63;;6553:40;6531:21;:63::i;:::-;6647:20;;-1:-1:-1;;;;;6696:24:30;;;6647:20;6696:24;;;:14;:24;;;;;;;;6647:83;;-1:-1:-1;;;6647:83:30;;:20;;;;:35;;:83;;6696:24;;6647:83;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6647:83:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;6647:83:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;6647:83:30;;;;;;;;;-1:-1:-1;;;;;6604:26:30;;;;;;;:16;:26;;;;;:40;;:126;;-1:-1:-1;;;;;;6604:126:30;;;;;;;;6395:342::o;989:370:0:-;1059:4;-1:-1:-1;;;;;1079:20:0;;1094:4;1079:20;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;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:9:0;;;;:17;;:42;;1318:3;;1331:4;;1338:3;;1300:42;;;;;;;;;;;;;;;;8:9:-1;5:2;;;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;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1300:42:0;;;;;;;;;1293:49;;;;8213:310:30;-1:-1:-1;;;;;8306:24:30;;;;;;;:14;:24;;;;;;8287:44;;8306:24;8287:18;:44::i;:::-;-1:-1:-1;;;;;8363:26:30;;;;;;;:16;:26;;;;;:32;;;8341:55;;8363:32;8341:21;:55::i;:::-;8441:12;;-1:-1:-1;;;;;8482:24:30;;;8441:12;8482:24;;;:14;:24;;;;;;;;8441:75;;-1:-1:-1;;;8441:75:30;;:12;;;;:27;;:75;;8482:24;;8441:75;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;8441:75:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;8441:75:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;8441:75:30;;;;;;;;;-1:-1:-1;;;;;8406:26:30;;;;;;;:16;:26;;;;;:32;;:110;;-1:-1:-1;;;;;;8406:110:30;;;;;;;;8213:310::o;4192:436::-;-1:-1:-1;;;;;4290:24:30;;;;;;;:14;:24;;;;;;4271:44;;4290:24;4271:18;:44::i;:::-;-1:-1:-1;;;;;4347:26:30;;;;;;;:16;:26;;;;;:37;4325:60;;4347:37;4325:21;:60::i;:::-;4435:17;;;-1:-1:-1;;;;;4481:24:30;;;4435:17;4481:24;;;:14;:24;;;;;;;;;4519:18;:28;;;;;;:46;;;;4579:18;;:32;;-1:-1:-1;;;4579:32:30;;;;4435:17;;;;:32;;4481:24;;;;4519:46;;;;4579:18;;;;;:30;;:32;;;;;;;;;;;:18;:32;;;5:2:-1;;;;30:1;27;20:12;5:2;4579:32:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4579:32:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;4579:32:30;;;;;;;;;4435:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4435:186:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;4435:186:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;4435:186:30;;;;;;;;;-1:-1:-1;;;;;4395:26:30;;;;;;;:16;:26;;;;;:226;;-1:-1:-1;;;;;;4395:226:30;;;;;;;;4192:436::o;4864:590::-;-1:-1:-1;;;;;4962:24:30;;;;;;;:14;:24;;;;;;4943:44;;4962:24;4943:18;:44::i;:::-;-1:-1:-1;;;;;5019:26:30;;;;;;;:16;:26;;;;;:37;;;4997:60;;5019:37;4997:21;:60::i;:::-;5107:17;;;-1:-1:-1;;;;;5153:24:30;;;5107:17;5153:24;;;:14;:24;;;;;;;;;5191:18;:28;;;;;:46;;;;5402:16;:26;;;;;;;5349:39;5402:35;;;;5107:340;;-1:-1:-1;;;5107:340:30;;:17;;;;:32;;:340;;5153:24;;;;5191:46;;;;5251:33;;;;5298:37;;;;5349:39;;;;;5402:35;;5107:340;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5107:340:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5107:340:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;5107:340:30;;;;;;;;;-1:-1:-1;;;;;5067:26:30;;;;;;;:16;:26;;;;;:37;;:380;;-1:-1:-1;;;;;;5067:380:30;;;;;;;;4864:590::o;5690:457::-;-1:-1:-1;;;;;5791:24:30;;;;;;;:14;:24;;;;;;5772:44;;5791:24;5772:18;:44::i;:::-;-1:-1:-1;;;;;5848:26:30;;;;;;;:16;:26;;;;;:40;;;5826:63;;5848:40;5826:21;:63::i;:::-;5942:20;;-1:-1:-1;;;;;5991:24:30;;;5942:20;5991:24;;;:14;:24;;;;;;;;;6029:18;:28;;;;;6095:16;:26;;;;;;;:35;;;5942:198;;-1:-1:-1;;;5942:198:30;;:20;;;;:35;;:198;;5991:24;;;6029:52;;;;;6095:35;;;;5942:198;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5942:198:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;5942:198:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;5942:198:30;;;;;;;;;-1:-1:-1;;;;;5899:26:30;;;;;;;:16;:26;;;;;:40;;:241;;-1:-1:-1;;;;;;5899:241:30;;;;;;;;5690:457::o;8739:1836::-;8803:24;;:::i;:::-;-1:-1:-1;;;;;;8830:26:30;;;;;;;:16;:26;;;;;;;;8803:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8880:24;;;:14;:24;;;;;;;;;8924:25;;;;;;;;;;;8803:53;;8880:24;8924:25;;8923:26;8915:61;;;;-1:-1:-1;;;8915:61:30;;;;;;;;;9007:29;9031:3;9007:15;:29::i;:::-;:79;;;;-1:-1:-1;9068:17:30;;9052:34;;:15;:34::i;:::-;9007:129;;;;;9102:34;9118:6;:17;;;9102:15;:34::i;:::-;9007:182;;;;;9152:37;9168:6;:20;;;9152:15;:37::i;:::-;9007:235;;;;;9205:37;9221:6;:20;;;9205:15;:37::i;:::-;9007:281;;;;;9258:30;9274:6;:13;;;9258:15;:30::i;:::-;9007:328;;;;;9304:31;9320:6;:14;;;9304:15;:31::i;:::-;9007:373;;;;;9351:29;9367:6;:12;;;9351:15;:29::i;:::-;8986:466;;;;-1:-1:-1;;;8986:466:30;;;;;;;;;-1:-1:-1;;;;;9462:25:30;;;:11;:25;;;;;;;;;;;;:32;;-1:-1:-1;;9462:32:30;9490:4;9462:32;;;9504:349;;;;;;;9532:17;;9504:349;;;;9563:17;;;;9504:349;;;;;;;;;9594:20;;;;9504:349;;;;;;;9628:20;;;;9504:349;;;;;;;9662:13;;;;9504:349;;;;;;;9689:14;;;;9504:349;;;;;;;9717:12;;;;9504:349;;;;;;;9743:15;;;;9504:349;;;;;;9462:32;9772:14;;;;9504:349;;;;;;;9800:13;;;;9504:349;;;;;;;9827:15;;;;9504:349;;;;;;;;;;;-1:-1:-1;;;9504:349:30;;9462:25;;9504:13;;:349;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9504:349:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9504:349:30;;;;9863:3;-1:-1:-1;;;;;9863:14:30;;:16;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9863:16:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;9863:16:30;;;;9889:3;-1:-1:-1;;;;;9889:18:30;;:20;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9889:20:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;9919:5:30;27:10:-1;;39:1;23:18;;45:23;;;9919:24:30;;;;-1:-1:-1;;;;;;9919:24:30;-1:-1:-1;;;;;9919:24:30;;;;;;;;;;9953:18;;10046:28;;;-1:-1:-1;10046:28:30;;;:18;9919:24;10046:28;;;;;;9953:136;;-1:-1:-1;;;9953:136:30;;:18;;;;;-1:-1:-1;9953:31:30;;-1:-1:-1;9953:136:30;;9919:24;;10046:28;;;9953:136;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;9953:136:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;10105:463:30;;;;;;;;10194:17;;-1:-1:-1;;;;;10105:463:30;;;;;;10229:17;;;;10105:463;;;;;;10264:20;;;;10105:463;;;;;;;10302:20;;;;10105:463;;;;;;;10340:13;;;;10105:463;;;;;;;10371:14;;;;10105:463;;;;;;;10403:12;;;;10105:463;;;;;;;10433:15;;;;10105:463;;;;;;;10466:14;;;;10105:463;;;;;;;10498:13;;;;10105:463;;;;;;;10529:15;;;;10105:463;;;;;;;;;;;;-1:-1:-1;10126:10:30;;-1:-1:-1;10105:463:30;;;;;;;;;;;;;;;8739:1836;;;:::o;2568:182::-;2660:27;2676:10;2660:15;:27::i;:::-;2659:28;2638:105;;;;-1:-1:-1;;;2638:105:30;;;;;;;;;2568:182;:::o;6985:314::-;-1:-1:-1;;;;;7079:24:30;;;;;;;:14;:24;;;;;;7060:44;;7079:24;7060:18;:44::i;:::-;-1:-1:-1;;;;;7136:26:30;;;;;;;:16;:26;;;;;:33;;;7114:56;;7136:33;7114:21;:56::i;:::-;7216:13;;-1:-1:-1;;;;;7258:24:30;;;7216:13;7258:24;;;:14;:24;;;;;;;;7216:76;;-1:-1:-1;;;7216:76:30;;:13;;;;:28;;:76;;7258:24;;7216:76;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7216:76:30;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7216:76:30;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;7216:76:30;;;;;;;;;-1:-1:-1;;;;;7180:26:30;;;;;;;:16;:26;;;;;:33;;:112;;-1:-1:-1;;;;;;7180:112:30;;;;;;;;6985:314::o;2756:180::-;2844:27;2860:10;2844:15;:27::i;:::-;2823:106;;;;-1:-1:-1;;;2823:106:30;;;;;;;;2440:122;-1:-1:-1;;;;;2531:24:30;;;;2440:122::o;163:980:63:-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;163:980:63;;;-1:-1:-1;163:980:63;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;163:980:63;-1:-1:-1;;;;;163:980:63;;;;;;;;;;;-1:-1:-1;163:980:63;;;;;;;-1:-1:-1;163:980:63;;;-1:-1:-1;163:980:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;163:980:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;163:980:63;;;;;;;5:130:-1;72:20;;97:33;72:20;97:33;;301:707;;418:3;411:4;403:6;399:17;395:27;385:2;;-1:-1;;426:12;385:2;473:6;460:20;495:80;510:64;567:6;510:64;;;495:80;;;603:21;;;486:89;-1:-1;647:4;660:14;;;;635:17;;;749;;;740:27;;;;737:36;-1:-1;734:2;;;786:1;;776:12;734:2;811:1;796:206;821:6;818:1;815:13;796:206;;;85:6;72:20;97:33;124:5;97:33;;;889:50;;953:14;;;;981;;;;843:1;836:9;796:206;;;800:14;;;;;378:630;;;;;1034:707;;1151:3;1144:4;1136:6;1132:17;1128:27;1118:2;;-1:-1;;1159:12;1118:2;1206:6;1193:20;1228:80;1243:64;1300:6;1243:64;;1228:80;1336:21;;;1219:89;-1:-1;1380:4;1393:14;;;;1368:17;;;1482;;;1473:27;;;;1470:36;-1:-1;1467:2;;;1519:1;;1509:12;1467:2;1544:1;1529:206;1554:6;1551:1;1548:13;1529:206;;;2575:20;;1622:50;;1686:14;;;;1714;;;;1576:1;1569:9;1529:206;;2058:442;;2160:3;2153:4;2145:6;2141:17;2137:27;2127:2;;-1:-1;;2168:12;2127:2;2215:6;2202:20;35233:18;35225:6;35222:30;35219:2;;;-1:-1;;35255:12;35219:2;2237:65;35328:9;35309:17;;-1:-1;;35305:33;35396:4;35386:15;2237:65;;;2228:74;;2322:6;2315:5;2308:21;2426:3;35396:4;2417:6;2350;2408:16;;2405:25;2402:2;;;2443:1;;2433:12;2402:2;42685:6;35396:4;2350:6;2346:17;35396:4;2384:5;2380:16;42662:30;42741:1;42723:16;;;35396:4;42723:16;42716:27;2384:5;2120:380;-1:-1;;2120:380;2786:241;;2890:2;2878:9;2869:7;2865:23;2861:32;2858:2;;;-1:-1;;2896:12;2858:2;85:6;72:20;97:33;124:5;97:33;;;2948:63;2852:175;-1:-1;;;2852:175;3034:263;;3149:2;3137:9;3128:7;3124:23;3120:32;3117:2;;;-1:-1;;3155:12;3117:2;226:6;220:13;238:33;265:5;238:33;;3304:257;;3416:2;3404:9;3395:7;3391:23;3387:32;3384:2;;;-1:-1;;3422:12;3384:2;1830:6;1824:13;44080:5;38562:13;38555:21;44058:5;44055:32;44045:2;;-1:-1;;44091:12;3852:2043;;;;;;;;;4235:3;4223:9;4214:7;4210:23;4206:33;4203:2;;;-1:-1;;4242:12;4203:2;4300:17;4287:31;4338:18;;4330:6;4327:30;4324:2;;;-1:-1;;4360:12;4324:2;4390:63;4445:7;4436:6;4425:9;4421:22;4390:63;;;4380:73;;4518:2;4507:9;4503:18;4490:32;4476:46;;4338:18;4534:6;4531:30;4528:2;;;-1:-1;;4564:12;4528:2;4594:78;4664:7;4655:6;4644:9;4640:22;4594:78;;;4584:88;;4737:2;4726:9;4722:18;4709:32;4695:46;;4338:18;4753:6;4750:30;4747:2;;;-1:-1;;4783:12;4747:2;4813:78;4883:7;4874:6;4863:9;4859:22;4813:78;;;4803:88;;4956:2;4945:9;4941:18;4928:32;4914:46;;4338:18;4972:6;4969:30;4966:2;;;-1:-1;;5002:12;4966:2;5032:78;5102:7;5093:6;5082:9;5078:22;5032:78;;;5022:88;;5175:3;5164:9;5160:19;5147:33;5133:47;;4338:18;5192:6;5189:30;5186:2;;;-1:-1;;5222:12;5186:2;5252:78;5322:7;5313:6;5302:9;5298:22;5252:78;;;5242:88;;5395:3;5384:9;5380:19;5367:33;5353:47;;4338:18;5412:6;5409:30;5406:2;;;-1:-1;;5442:12;5406:2;5472:78;5542:7;5533:6;5522:9;5518:22;5472:78;;;5462:88;;5606:53;5651:7;5587:3;5631:9;5627:22;5606:53;;;5596:63;;5724:3;5713:9;5709:19;5696:33;5682:47;;4338:18;5741:6;5738:30;5735:2;;;-1:-1;;5771:12;5735:2;;5801:78;5871:7;5862:6;5851:9;5847:22;5801:78;;;5791:88;;;4197:1698;;;;;;;;;;;;5902:241;;6006:2;5994:9;5985:7;5981:23;5977:32;5974:2;;;-1:-1;;6012:12;5974:2;-1:-1;2575:20;;5968:175;-1:-1;5968:175;6150:263;;6265:2;6253:9;6244:7;6240:23;6236:32;6233:2;;;-1:-1;;6271:12;6233:2;-1:-1;2723:13;;6227:186;-1:-1;6227:186;8632:709;;8819:5;36572:12;37750:6;37745:3;37738:19;37787:4;37782:3;37778:14;8831:93;;35801:3;-1:-1;35791:14;37787:4;-1:-1;35820:18;-1:-1;9031:288;9056:6;9053:1;9050:13;9031:288;;;43491:11;;-1:-1;;;;;38240:54;6994:37;;37787:4;6574:14;;;;35233:18;37331:14;;;;9071:9;9031:288;;;-1:-1;9325:10;;8753:588;-1:-1;;;;8753:588;9380:709;;9567:5;36572:12;37750:6;37745:3;37738:19;37787:4;37782:3;37778:14;9579:93;;35801:3;-1:-1;35791:14;37787:4;-1:-1;35820:18;-1:-1;9779:288;9804:6;9801:1;9798:13;9779:288;;;43636:11;;17946:37;;37787:4;6756:14;;;;9826:1;37331:14;;;;9819:9;9779:288;;12143:347;;12288:5;36425:12;37750:6;37745:3;37738:19;-1:-1;42830:101;42844:6;42841:1;42838:13;42830:101;;;37787:4;42911:11;;;;;42905:18;42892:11;;;;;42885:39;42859:10;42830:101;;;42946:6;42943:1;42940:13;42937:2;;;-1:-1;37787:4;43002:6;37782:3;42993:16;;42986:27;42937:2;-1:-1;35328:9;43728:14;-1:-1;;43724:28;12446:39;;;;37787:4;12446:39;;12235:255;-1:-1;;12235:255;18115:213;-1:-1;;;;;38240:54;;;;6994:37;;18233:2;18218:18;;18204:124;18335:428;-1:-1;;;;;38240:54;;6863:58;;18509:2;18635;18620:18;;18613:48;;;18335:428;;18675:78;;18494:18;;18739:6;18675:78;;;18667:86;18480:283;-1:-1;;;;18480:283;18770:435;-1:-1;;;;;38240:54;;;6994:37;;38240:54;;;19108:2;19093:18;;6994:37;38240:54;;;19191:2;19176:18;;6994:37;18944:2;18929:18;;18915:290;19212:1333;-1:-1;;;;;38240:54;;;6994:37;;38240:54;;;19776:2;19761:18;;6994:37;38240:54;;;19859:2;19844:18;;6994:37;38240:54;;;19942:2;19927:18;;6994:37;38240:54;;;20025:3;20010:19;;6994:37;38240:54;;;38251:42;20094:19;;6994:37;38240:54;;20193:3;20178:19;;6994:37;38240:54;;20277:3;20262:19;;6994:37;38240:54;;20361:3;20346:19;;6994:37;38240:54;;20445:3;20430:19;;6994:37;38240:54;;;20530:3;20515:19;;6994:37;19611:3;19596:19;;19582:963;20552:1197;;35233:18;;38251:42;;;;7024:5;38240:54;7001:3;6994:37;38251:42;7024:5;38240:54;21116:2;21105:9;21101:18;6994:37;20951:3;21153:2;21142:9;21138:18;21131:48;21193:105;20951:3;20940:9;20936:19;21284:6;21193:105;;;21346:9;21340:4;21336:20;21331:2;21320:9;21316:18;21309:48;21371:105;21471:4;21462:6;21371:105;;;21525:9;21519:4;21515:20;21509:3;21498:9;21494:19;21487:49;21550:105;21650:4;21641:6;21550:105;;;21542:113;;;;38251:42;7024:5;38240:54;21734:3;21723:9;21719:19;6994:37;;20922:827;;;;;;;;;;21756:431;-1:-1;;;;;38240:54;;;6994:37;;38240:54;;;;22092:2;22077:18;;6994:37;-1:-1;;;;;;38649:78;;;22173:2;22158:18;;10277:36;21928:2;21913:18;;21899:288;22194:517;-1:-1;;;;;38240:54;;;6994:37;;38240:54;;22549:2;22534:18;;6994:37;22385:2;22586;22571:18;;22564:48;;;12981:12;;22194:517;;22370:18;;;22194:517;;35233:18;13006:17;;13029:248;;;;13288:1;13283:402;;;;12999:686;;13029:248;13103:1;13088:17;;13107:4;13084:28;37738:19;;-1:-1;;13216:25;;37778:14;;;13204:38;13256:14;;;;-1:-1;13029:248;;13283:402;13352:1;13341:9;13337:17;37750:6;37745:3;37738:19;35801:3;-1:-1;35791:14;22549:2;-1:-1;35820:18;-1:-1;13523:130;13537:6;13534:1;13531:13;13523:130;;;13596:14;;13583:11;;;37778:14;13583:11;13576:35;13021:1;13630:15;;;;22549:2;13552:12;13523:130;;;13667:11;;37778:14;13667:11;;-1:-1;;;12999:686;-1:-1;22618:83;;22356:355;-1:-1;;;;;;;22356:355;22718:577;;35233:18;;38251:42;;;;38244:5;38240:54;7001:3;6994:37;22939:2;23057;23046:9;23042:18;23035:48;23097:105;22939:2;22928:9;22924:18;23188:6;23097:105;;;23089:113;;38251:42;38244:5;38240:54;23281:2;23270:9;23266:18;6994:37;;22910:385;;;;;;;23302:831;;35233:18;;38251:42;;;;38244:5;38240:54;7001:3;6994:37;23598:3;23717:2;23706:9;23702:18;23695:48;23757:105;23598:3;23587:9;23583:19;23848:6;23757:105;;;23910:9;23904:4;23900:20;23895:2;23884:9;23880:18;23873:48;23935:105;24035:4;24026:6;23935:105;;;23927:113;;;38251:42;38244:5;38240:54;24119:2;24108:9;24104:18;6994:37;;23569:564;;;;;;;;24140:310;24306:3;24291:19;;24295:9;7566:21;24140:310;7593:259;36301:4;7615:1;7612:13;7593:259;;;7679:13;;-1:-1;;;;;38240:54;6994:37;;6583:4;6574:14;;;;37104;;;;35233:18;7633:9;7593:259;;;7597:14;;;24277:173;;;;;24457:361;24625:2;24639:47;;;36425:12;;24610:18;;;37738:19;;;24457:361;;35638:14;;;37778;;;;24457:361;8311:260;8336:6;8333:1;8330:13;8311:260;;;8397:13;;-1:-1;;;;;38240:54;6994:37;;24625:2;37104:14;;;;6574;;;;35233:18;8351:9;8311:260;;;-1:-1;24692:116;;24596:222;-1:-1;;;;;24596:222;24825:201;38562:13;;38555:21;10162:34;;24937:2;24922:18;;24908:118;27721:404;;27883:2;27904:17;27897:47;27958:74;27883:2;27872:9;27868:18;28018:6;27958:74;;;27950:82;;35233:18;;38251:42;;;7024:5;38240:54;28111:2;28100:9;28096:18;6994:37;27854:271;;;;;;28132:407;28323:2;28337:47;;;13924:2;28308:18;;;37738:19;-1:-1;;;37778:14;;;13940:44;14003:12;;;28294:245;28546:407;28737:2;28751:47;;;14254:2;28722:18;;;37738:19;-1:-1;;;37778:14;;;14270:43;14332:12;;;28708:245;28960:407;29151:2;29165:47;;;14583:2;29136:18;;;37738:19;-1:-1;;;37778:14;;;14599:43;14661:12;;;29122:245;29374:407;29565:2;29579:47;;;14912:2;29550:18;;;37738:19;14948:34;37778:14;;;14928:55;-1:-1;;;15003:12;;;14996:38;15053:12;;;29536:245;29788:407;29979:2;29993:47;;;15304:2;29964:18;;;37738:19;-1:-1;;;37778:14;;;15320:43;15382:12;;;29950:245;30202:407;30393:2;30407:47;;;15633:2;30378:18;;;37738:19;15669:32;37778:14;;;15649:53;15721:12;;;30364:245;30616:407;30807:2;30821:47;;;30792:18;;;37738:19;16008:34;37778:14;;;15988:55;16062:12;;;30778:245;31030:407;31221:2;31235:47;;;16313:2;31206:18;;;37738:19;-1:-1;;;37778:14;;;16329:45;16393:12;;;31192:245;31444:407;31635:2;31649:47;;;16644:2;31620:18;;;37738:19;-1:-1;;;37778:14;;;16660:36;16715:12;;;31606:245;31858:407;32049:2;32063:47;;;16966:2;32034:18;;;37738:19;17002:34;37778:14;;;16982:55;-1:-1;;;17057:12;;;17050:29;17098:12;;;32020:245;32272:407;32463:2;32477:47;;;17349:2;32448:18;;;37738:19;17385:34;37778:14;;;17365:55;-1:-1;;;17440:12;;;17433:28;17480:12;;;32434:245;32686:407;32877:2;32891:47;;;17731:2;32862:18;;;37738:19;17767:34;37778:14;;;17747:55;-1:-1;;;17822:12;;;17815:25;17859:12;;;32848:245;33100:213;17946:37;;;33218:2;33203:18;;33189:124;33320:435;17946:37;;;-1:-1;;;;;38240:54;;;33658:2;33643:18;;6994:37;38240:54;33741:2;33726:18;;6994:37;33494:2;33479:18;;33465:290;33762:435;17946:37;;;34100:2;34085:18;;17946:37;;;;34183:2;34168:18;;17946:37;33936:2;33921:18;;33907:290;34204:256;34266:2;34260:9;34292:17;;;34367:18;34352:34;;34388:22;;;34349:62;34346:2;;;34424:1;;34414:12;34346:2;34266;34433:22;34244:216;;-1:-1;34244:216;34467:304;;34626:18;34618:6;34615:30;34612:2;;;-1:-1;;34648:12;34612:2;-1:-1;34693:4;34681:17;;;34746:15;;34549:222;43875:117;-1:-1;;;;;38240:54;;43934:35;;43924:2;;43983:1;;43973:12
Swarm Source
://81621c625b601375d626a758c3284cf83b64442239f35eeec83267aeb76654a8
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 25 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.