Feature Tip: Add private address tag to any address under My Name Tag !
Token migration announcement. Metronome token contract has migrated to a new address.
ERC-20
Overview
Max Total Supply
16,500,098.263286902246912986 MET
Holders
3,665 (0.00%)
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
12.332211861962895319 METValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
METToken
Compiler Version
v0.4.21+commit.dfe3193c
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2018-05-24 */ /* The MIT License (MIT) Copyright 2017 - 2018, Alchemy Limited, LLC and Smart Contract Solutions. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.21; /** * Reference: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol * * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws 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 Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } /* end SafeMath library */ /// @title Math operation when both numbers has decimal places. /// @notice Use this contract when both numbers has 18 decimal places. contract FixedMath { using SafeMath for uint; uint constant internal METDECIMALS = 18; uint constant internal METDECMULT = 10 ** METDECIMALS; uint constant internal DECIMALS = 18; uint constant internal DECMULT = 10 ** DECIMALS; /// @notice Multiplication. function fMul(uint x, uint y) internal pure returns (uint) { return (x.mul(y)).div(DECMULT); } /// @notice Division. function fDiv(uint numerator, uint divisor) internal pure returns (uint) { return (numerator.mul(DECMULT)).div(divisor); } /// @notice Square root. /// @dev Reference: https://stackoverflow.com/questions/3766020/binary-search-to-compute-square-root-java function fSqrt(uint n) internal pure returns (uint) { if (n == 0) { return 0; } uint z = n * n; require(z / n == n); uint high = fAdd(n, DECMULT); uint low = 0; while (fSub(high, low) > 1) { uint mid = fAdd(low, high) / 2; if (fSqr(mid) <= n) { low = mid; } else { high = mid; } } return low; } /// @notice Square. function fSqr(uint n) internal pure returns (uint) { return fMul(n, n); } /// @notice Add. function fAdd(uint x, uint y) internal pure returns (uint) { return x.add(y); } /// @notice Sub. function fSub(uint x, uint y) internal pure returns (uint) { return x.sub(y); } } /// @title A formula contract for converter contract Formula is FixedMath { /// @notice Trade in reserve(ETH/MET) and mint new smart tokens /// @param smartTokenSupply Total supply of smart token /// @param reserveTokensSent Amount of token sent by caller /// @param reserveTokenBalance Balance of reserve token in the contract /// @return Smart token minted function returnForMint(uint smartTokenSupply, uint reserveTokensSent, uint reserveTokenBalance) internal pure returns (uint) { uint s = smartTokenSupply; uint e = reserveTokensSent; uint r = reserveTokenBalance; /// smartToken for mint(T) = S * (sqrt(1 + E/R) - 1) /// DECMULT is same as 1 for values with 18 decimal places return ((fMul(s, (fSub(fSqrt(fAdd(DECMULT, fDiv(e, r))), DECMULT)))).mul(METDECMULT)).div(DECMULT); } /// @notice Redeem smart tokens, get back reserve(ETH/MET) token /// @param smartTokenSupply Total supply of smart token /// @param smartTokensSent Smart token sent /// @param reserveTokenBalance Balance of reserve token in the contract /// @return Reserve token redeemed function returnForRedemption(uint smartTokenSupply, uint smartTokensSent, uint reserveTokenBalance) internal pure returns (uint) { uint s = smartTokenSupply; uint t = smartTokensSent; uint r = reserveTokenBalance; /// reserveToken (E) = R * (1 - (1 - T/S)**2) /// DECMULT is same as 1 for values with 18 decimal places return ((fMul(r, (fSub(DECMULT, fSqr(fSub(DECMULT, fDiv(t, s))))))).mul(METDECMULT)).div(DECMULT); } } /// @title Pricer contract to calculate descending price during auction. contract Pricer { using SafeMath for uint; uint constant internal METDECIMALS = 18; uint constant internal METDECMULT = 10 ** METDECIMALS; uint public minimumPrice = 33*10**11; uint public minimumPriceInDailyAuction = 1; uint public tentimes; uint public hundredtimes; uint public thousandtimes; uint constant public MULTIPLIER = 1984320568*10**5; /// @notice Pricer constructor, calculate 10, 100 and 1000 times of 0.99. function initPricer() public { uint x = METDECMULT; uint i; /// Calculate 10 times of 0.99 for (i = 0; i < 10; i++) { x = x.mul(99).div(100); } tentimes = x; x = METDECMULT; /// Calculate 100 times of 0.99 using tentimes calculated above. /// tentimes has 18 decimal places and due to this METDECMLT is /// used as divisor. for (i = 0; i < 10; i++) { x = x.mul(tentimes).div(METDECMULT); } hundredtimes = x; x = METDECMULT; /// Calculate 1000 times of 0.99 using hundredtimes calculated above. /// hundredtimes has 18 decimal places and due to this METDECMULT is /// used as divisor. for (i = 0; i < 10; i++) { x = x.mul(hundredtimes).div(METDECMULT); } thousandtimes = x; } /// @notice Price of MET at nth minute out during operational auction /// @param initialPrice The starting price ie last purchase price /// @param _n The number of minutes passed since last purchase /// @return The resulting price function priceAt(uint initialPrice, uint _n) public view returns (uint price) { uint mult = METDECMULT; uint i; uint n = _n; /// If quotient of n/1000 is greater than 0 then calculate multiplier by /// multiplying thousandtimes and mult in a loop which runs quotient times. /// Also assign new value to n which is remainder of n/1000. if (n / 1000 > 0) { for (i = 0; i < n / 1000; i++) { mult = mult.mul(thousandtimes).div(METDECMULT); } n = n % 1000; } /// If quotient of n/100 is greater than 0 then calculate multiplier by /// multiplying hundredtimes and mult in a loop which runs quotient times. /// Also assign new value to n which is remainder of n/100. if (n / 100 > 0) { for (i = 0; i < n / 100; i++) { mult = mult.mul(hundredtimes).div(METDECMULT); } n = n % 100; } /// If quotient of n/10 is greater than 0 then calculate multiplier by /// multiplying tentimes and mult in a loop which runs quotient times. /// Also assign new value to n which is remainder of n/10. if (n / 10 > 0) { for (i = 0; i < n / 10; i++) { mult = mult.mul(tentimes).div(METDECMULT); } n = n % 10; } /// Calculate multiplier by multiplying 0.99 and mult, repeat it n times. for (i = 0; i < n; i++) { mult = mult.mul(99).div(100); } /// price is calculated as initialPrice multiplied by 0.99 and that too _n times. /// Here mult is METDECMULT multiplied by 0.99 and that too _n times. price = initialPrice.mul(mult).div(METDECMULT); if (price < minimumPriceInDailyAuction) { price = minimumPriceInDailyAuction; } } /// @notice Price of MET at nth minute during initial auction. /// @param lastPurchasePrice The price of MET in last transaction /// @param numTicks The number of minutes passed since last purchase /// @return The resulting price function priceAtInitialAuction(uint lastPurchasePrice, uint numTicks) public view returns (uint price) { /// Price will decrease linearly every minute by the factor of MULTIPLIER. /// If lastPurchasePrice is greater than decrease in price then calculated the price. /// Return minimumPrice, if calculated price is less than minimumPrice. /// If decrease in price is more than lastPurchasePrice then simply return the minimumPrice. if (lastPurchasePrice > MULTIPLIER.mul(numTicks)) { price = lastPurchasePrice.sub(MULTIPLIER.mul(numTicks)); } if (price < minimumPrice) { price = minimumPrice; } } } /// @dev Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md /// @notice ERC20 standard interface interface ERC20 { function totalSupply() public constant returns (uint256); function balanceOf(address _owner) public constant returns (uint256); function allowance(address _owner, address _spender) public constant returns (uint256); event Transfer(address indexed _from, address indexed _to, uint256 _value); function transfer(address _to, uint256 _value) public returns (bool); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); event Approval(address indexed _owner, address indexed _spender, uint256 _value); function approve(address _spender, uint256 _value) public returns (bool); } /// @title Ownable contract Ownable { address public owner; event OwnershipChanged(address indexed prevOwner, address indexed newOwner); function Ownable() public { owner = msg.sender; } /// @dev Throws if called by any account other than the owner. modifier onlyOwner() { require(msg.sender == owner); _; } /// @notice Allows the current owner to transfer control of the contract to a newOwner. /// @param _newOwner /// @return true/false function changeOwnership(address _newOwner) public onlyOwner returns (bool) { require(_newOwner != address(0)); require(_newOwner != owner); emit OwnershipChanged(owner, _newOwner); owner = _newOwner; return true; } } /// @title Owned contract Owned is Ownable { address public newOwner; /// @notice Allows the current owner to transfer control of the contract to a newOwner. /// @param _newOwner /// @return true/false function changeOwnership(address _newOwner) public onlyOwner returns (bool) { require(_newOwner != owner); newOwner = _newOwner; return true; } /// @notice Allows the new owner to accept ownership of the contract. /// @return true/false function acceptOwnership() public returns (bool) { require(msg.sender == newOwner); emit OwnershipChanged(owner, newOwner); owner = newOwner; return true; } } /// @title Mintable contract to allow minting and destroy. contract Mintable is Owned { using SafeMath for uint256; event Mint(address indexed _to, uint _value); event Destroy(address indexed _from, uint _value); event Transfer(address indexed _from, address indexed _to, uint256 _value); uint256 internal _totalSupply; mapping(address => uint256) internal _balanceOf; address public autonomousConverter; address public minter; ITokenPorter public tokenPorter; /// @notice init reference of other contract and initial supply /// @param _autonomousConverter /// @param _minter /// @param _initialSupply /// @param _decmult Decimal places function initMintable(address _autonomousConverter, address _minter, uint _initialSupply, uint _decmult) public onlyOwner { require(autonomousConverter == 0x0 && _autonomousConverter != 0x0); require(minter == 0x0 && _minter != 0x0); autonomousConverter = _autonomousConverter; minter = _minter; _totalSupply = _initialSupply.mul(_decmult); _balanceOf[_autonomousConverter] = _totalSupply; } function totalSupply() public constant returns (uint256) { return _totalSupply; } function balanceOf(address _owner) public constant returns (uint256) { return _balanceOf[_owner]; } /// @notice set address of token porter /// @param _tokenPorter address of token porter function setTokenPorter(address _tokenPorter) public onlyOwner returns (bool) { require(_tokenPorter != 0x0); tokenPorter = ITokenPorter(_tokenPorter); return true; } /// @notice allow minter and tokenPorter to mint token and assign to address /// @param _to /// @param _value Amount to be minted function mint(address _to, uint _value) public returns (bool) { require(msg.sender == minter || msg.sender == address(tokenPorter)); _balanceOf[_to] = _balanceOf[_to].add(_value); _totalSupply = _totalSupply.add(_value); emit Mint(_to, _value); emit Transfer(0x0, _to, _value); return true; } /// @notice allow autonomousConverter and tokenPorter to mint token and assign to address /// @param _from /// @param _value Amount to be destroyed function destroy(address _from, uint _value) public returns (bool) { require(msg.sender == autonomousConverter || msg.sender == address(tokenPorter)); _balanceOf[_from] = _balanceOf[_from].sub(_value); _totalSupply = _totalSupply.sub(_value); emit Destroy(_from, _value); emit Transfer(_from, 0x0, _value); return true; } } /// @title Token contract contract Token is ERC20, Mintable { mapping(address => mapping(address => uint256)) internal _allowance; function initToken(address _autonomousConverter, address _minter, uint _initialSupply, uint _decmult) public onlyOwner { initMintable(_autonomousConverter, _minter, _initialSupply, _decmult); } /// @notice Provide allowance information function allowance(address _owner, address _spender) public constant returns (uint256) { return _allowance[_owner][_spender]; } /// @notice Transfer tokens from sender to the provided address. /// @param _to Receiver of the tokens /// @param _value Amount of token /// @return true/false function transfer(address _to, uint256 _value) public returns (bool) { require(_to != address(0)); require(_to != minter); require(_to != address(this)); require(_to != autonomousConverter); Proceeds proceeds = Auctions(minter).proceeds(); require((_to != address(proceeds))); _balanceOf[msg.sender] = _balanceOf[msg.sender].sub(_value); _balanceOf[_to] = _balanceOf[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } /// @notice Transfer tokens based on allowance. /// msg.sender must have allowance for spending the tokens from owner ie _from /// @param _from Owner of the tokens /// @param _to Receiver of the tokens /// @param _value Amount of tokens to transfer /// @return true/false function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(_to != address(0)); require(_to != minter && _from != minter); require(_to != address(this) && _from != address(this)); Proceeds proceeds = Auctions(minter).proceeds(); require(_to != address(proceeds) && _from != address(proceeds)); //AC can accept MET via this function, needed for MetToEth conversion require(_from != autonomousConverter); require(_allowance[_from][msg.sender] >= _value); _balanceOf[_from] = _balanceOf[_from].sub(_value); _balanceOf[_to] = _balanceOf[_to].add(_value); _allowance[_from][msg.sender] = _allowance[_from][msg.sender].sub(_value); emit Transfer(_from, _to, _value); return true; } /// @notice Approve spender to spend the tokens ie approve allowance /// @param _spender Spender of the tokens /// @param _value Amount of tokens that can be spent by spender /// @return true/false function approve(address _spender, uint256 _value) public returns (bool) { require(_spender != address(this)); _allowance[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /// @notice Transfer the tokens from sender to all the address provided in the array. /// @dev Left 160 bits are the recipient address and the right 96 bits are the token amount. /// @param bits array of uint /// @return true/false function multiTransfer(uint[] bits) public returns (bool) { for (uint i = 0; i < bits.length; i++) { address a = address(bits[i] >> 96); uint amount = bits[i] & ((1 << 96) - 1); if (!transfer(a, amount)) revert(); } return true; } /// @notice Increase allowance of spender /// @param _spender Spender of the tokens /// @param _value Amount of tokens that can be spent by spender /// @return true/false function approveMore(address _spender, uint256 _value) public returns (bool) { uint previous = _allowance[msg.sender][_spender]; uint newAllowance = previous.add(_value); _allowance[msg.sender][_spender] = newAllowance; emit Approval(msg.sender, _spender, newAllowance); return true; } /// @notice Decrease allowance of spender /// @param _spender Spender of the tokens /// @param _value Amount of tokens that can be spent by spender /// @return true/false function approveLess(address _spender, uint256 _value) public returns (bool) { uint previous = _allowance[msg.sender][_spender]; uint newAllowance = previous.sub(_value); _allowance[msg.sender][_spender] = newAllowance; emit Approval(msg.sender, _spender, newAllowance); return true; } } /// @title Smart tokens are an intermediate token generated during conversion of MET-ETH contract SmartToken is Mintable { uint constant internal METDECIMALS = 18; uint constant internal METDECMULT = 10 ** METDECIMALS; function initSmartToken(address _autonomousConverter, address _minter, uint _initialSupply) public onlyOwner { initMintable(_autonomousConverter, _minter, _initialSupply, METDECMULT); } } /// @title ERC20 token. Metronome token contract METToken is Token { string public constant name = "Metronome"; string public constant symbol = "MET"; uint8 public constant decimals = 18; bool public transferAllowed; function initMETToken(address _autonomousConverter, address _minter, uint _initialSupply, uint _decmult) public onlyOwner { initToken(_autonomousConverter, _minter, _initialSupply, _decmult); } /// @notice Transferable modifier to allow transfer only after initial auction ended. modifier transferable() { require(transferAllowed); _; } function enableMETTransfers() public returns (bool) { require(!transferAllowed && Auctions(minter).isInitialAuctionEnded()); transferAllowed = true; return true; } /// @notice Transfer tokens from caller to another address /// @param _to address The address which you want to transfer to /// @param _value uint256 the amout of tokens to be transfered function transfer(address _to, uint256 _value) public transferable returns (bool) { return super.transfer(_to, _value); } /// @notice Transfer tokens from one address to another /// @param _from address The address from which you want to transfer /// @param _to address The address which you want to transfer to /// @param _value uint256 the amout of tokens to be transfered function transferFrom(address _from, address _to, uint256 _value) public transferable returns (bool) { return super.transferFrom(_from, _to, _value); } /// @notice Transfer the token from sender to all the addresses provided in array. /// @dev Left 160 bits are the recipient address and the right 96 bits are the token amount. /// @param bits array of uint /// @return true/false function multiTransfer(uint[] bits) public transferable returns (bool) { return super.multiTransfer(bits); } mapping (address => bytes32) public roots; function setRoot(bytes32 data) public { roots[msg.sender] = data; } function getRoot(address addr) public view returns (bytes32) { return roots[addr]; } function rootsMatch(address a, address b) public view returns (bool) { return roots[a] == roots[b]; } /// @notice import MET tokens from another chain to this chain. /// @param _destinationChain destination chain name /// @param _addresses _addresses[0] is destMetronomeAddr and _addresses[1] is recipientAddr /// @param _extraData extra information for import /// @param _burnHashes _burnHashes[0] is previous burnHash, _burnHashes[1] is current burnHash /// @param _supplyOnAllChains MET supply on all supported chains /// @param _importData _importData[0] is _blockTimestamp, _importData[1] is _amount, _importData[2] is _fee /// _importData[3] is _burnedAtTick, _importData[4] is _genesisTime, _importData[5] is _dailyMintable /// _importData[6] is _burnSequence, _importData[7] is _dailyAuctionStartTime /// @param _proof proof /// @return true/false function importMET(bytes8 _originChain, bytes8 _destinationChain, address[] _addresses, bytes _extraData, bytes32[] _burnHashes, uint[] _supplyOnAllChains, uint[] _importData, bytes _proof) public returns (bool) { require(address(tokenPorter) != 0x0); return tokenPorter.importMET(_originChain, _destinationChain, _addresses, _extraData, _burnHashes, _supplyOnAllChains, _importData, _proof); } /// @notice export MET tokens from this chain to another chain. /// @param _destChain destination chain address /// @param _destMetronomeAddr address of Metronome contract on the destination chain /// where this MET will be imported. /// @param _destRecipAddr address of account on destination chain /// @param _amount amount /// @param _extraData extra information for future expansion /// @return true/false function export(bytes8 _destChain, address _destMetronomeAddr, address _destRecipAddr, uint _amount, uint _fee, bytes _extraData) public returns (bool) { require(address(tokenPorter) != 0x0); return tokenPorter.export(msg.sender, _destChain, _destMetronomeAddr, _destRecipAddr, _amount, _fee, _extraData); } struct Sub { uint startTime; uint payPerWeek; uint lastWithdrawTime; } event LogSubscription(address indexed subscriber, address indexed subscribesTo); event LogCancelSubscription(address indexed subscriber, address indexed subscribesTo); mapping (address => mapping (address => Sub)) public subs; /// @notice subscribe for a weekly recurring payment /// @param _startTime Subscription start time. /// @param _payPerWeek weekly payment /// @param _recipient address of beneficiary /// @return true/false function subscribe(uint _startTime, uint _payPerWeek, address _recipient) public returns (bool) { require(_startTime >= block.timestamp); require(_payPerWeek != 0); require(_recipient != 0); subs[msg.sender][_recipient] = Sub(_startTime, _payPerWeek, _startTime); emit LogSubscription(msg.sender, _recipient); return true; } /// @notice cancel a subcription. /// @param _recipient address of beneficiary /// @return true/false function cancelSubscription(address _recipient) public returns (bool) { require(subs[msg.sender][_recipient].startTime != 0); require(subs[msg.sender][_recipient].payPerWeek != 0); subs[msg.sender][_recipient].startTime = 0; subs[msg.sender][_recipient].payPerWeek = 0; subs[msg.sender][_recipient].lastWithdrawTime = 0; emit LogCancelSubscription(msg.sender, _recipient); return true; } /// @notice get subcription details /// @param _owner /// @param _recipient /// @return startTime, payPerWeek, lastWithdrawTime function getSubscription(address _owner, address _recipient) public constant returns (uint startTime, uint payPerWeek, uint lastWithdrawTime) { Sub storage sub = subs[_owner][_recipient]; return ( sub.startTime, sub.payPerWeek, sub.lastWithdrawTime ); } /// @notice caller can withdraw the token from subscribers. /// @param _owner subcriber /// @return true/false function subWithdraw(address _owner) public transferable returns (bool) { require(subWithdrawFor(_owner, msg.sender)); return true; } /// @notice Allow callers to withdraw token in one go from all of its subscribers /// @param _owners array of address of subscribers /// @return number of successful transfer done function multiSubWithdraw(address[] _owners) public returns (uint) { uint n = 0; for (uint i=0; i < _owners.length; i++) { if (subWithdrawFor(_owners[i], msg.sender)) { n++; } } return n; } /// @notice Trigger MET token transfers for all pairs of subscribers and beneficiaries /// @dev address at i index in owners and recipients array is subcriber-beneficiary pair. /// @param _owners /// @param _recipients /// @return number of successful transfer done function multiSubWithdrawFor(address[] _owners, address[] _recipients) public returns (uint) { // owners and recipients need 1-to-1 mapping, must be same length require(_owners.length == _recipients.length); uint n = 0; for (uint i = 0; i < _owners.length; i++) { if (subWithdrawFor(_owners[i], _recipients[i])) { n++; } } return n; } function subWithdrawFor(address _from, address _to) internal returns (bool) { Sub storage sub = subs[_from][_to]; if (sub.startTime > 0 && sub.startTime < block.timestamp && sub.payPerWeek > 0) { uint weekElapsed = (now.sub(sub.lastWithdrawTime)).div(7 days); uint amount = weekElapsed.mul(sub.payPerWeek); if (weekElapsed > 0 && _balanceOf[_from] >= amount) { subs[_from][_to].lastWithdrawTime = block.timestamp; _balanceOf[_from] = _balanceOf[_from].sub(amount); _balanceOf[_to] = _balanceOf[_to].add(amount); emit Transfer(_from, _to, amount); return true; } } return false; } } /// @title Autonomous Converter contract for MET <=> ETH exchange contract AutonomousConverter is Formula, Owned { SmartToken public smartToken; METToken public reserveToken; Auctions public auctions; enum WhichToken { Eth, Met } bool internal initialized = false; event LogFundsIn(address indexed from, uint value); event ConvertEthToMet(address indexed from, uint eth, uint met); event ConvertMetToEth(address indexed from, uint eth, uint met); function init(address _reserveToken, address _smartToken, address _auctions) public onlyOwner payable { require(!initialized); auctions = Auctions(_auctions); reserveToken = METToken(_reserveToken); smartToken = SmartToken(_smartToken); initialized = true; } function handleFund() public payable { require(msg.sender == address(auctions.proceeds())); emit LogFundsIn(msg.sender, msg.value); } function getMetBalance() public view returns (uint) { return balanceOf(WhichToken.Met); } function getEthBalance() public view returns (uint) { return balanceOf(WhichToken.Eth); } /// @notice return the expected MET for ETH /// @param _depositAmount ETH. /// @return expected MET value for ETH function getMetForEthResult(uint _depositAmount) public view returns (uint256) { return convertingReturn(WhichToken.Eth, _depositAmount); } /// @notice return the expected ETH for MET /// @param _depositAmount MET. /// @return expected ETH value for MET function getEthForMetResult(uint _depositAmount) public view returns (uint256) { return convertingReturn(WhichToken.Met, _depositAmount); } /// @notice send ETH and get MET /// @param _mintReturn execute conversion only if return is equal or more than _mintReturn /// @return returnedMet MET retured after conversion function convertEthToMet(uint _mintReturn) public payable returns (uint returnedMet) { returnedMet = convert(WhichToken.Eth, _mintReturn, msg.value); emit ConvertEthToMet(msg.sender, msg.value, returnedMet); } /// @notice send MET and get ETH /// @dev Caller will be required to approve the AutonomousConverter to initiate the transfer /// @param _amount MET amount /// @param _mintReturn execute conversion only if return is equal or more than _mintReturn /// @return returnedEth ETh returned after conversion function convertMetToEth(uint _amount, uint _mintReturn) public returns (uint returnedEth) { returnedEth = convert(WhichToken.Met, _mintReturn, _amount); emit ConvertMetToEth(msg.sender, returnedEth, _amount); } function balanceOf(WhichToken which) internal view returns (uint) { if (which == WhichToken.Eth) return address(this).balance; if (which == WhichToken.Met) return reserveToken.balanceOf(this); revert(); } function convertingReturn(WhichToken whichFrom, uint _depositAmount) internal view returns (uint256) { WhichToken to = WhichToken.Met; if (whichFrom == WhichToken.Met) { to = WhichToken.Eth; } uint reserveTokenBalanceFrom = balanceOf(whichFrom).add(_depositAmount); uint mintRet = returnForMint(smartToken.totalSupply(), _depositAmount, reserveTokenBalanceFrom); uint newSmartTokenSupply = smartToken.totalSupply().add(mintRet); uint reserveTokenBalanceTo = balanceOf(to); return returnForRedemption( newSmartTokenSupply, mintRet, reserveTokenBalanceTo); } function convert(WhichToken whichFrom, uint _minReturn, uint amnt) internal returns (uint) { WhichToken to = WhichToken.Met; if (whichFrom == WhichToken.Met) { to = WhichToken.Eth; require(reserveToken.transferFrom(msg.sender, this, amnt)); } uint mintRet = mint(whichFrom, amnt, 1); return redeem(to, mintRet, _minReturn); } function mint(WhichToken which, uint _depositAmount, uint _minReturn) internal returns (uint256 amount) { require(_minReturn > 0); amount = mintingReturn(which, _depositAmount); require(amount >= _minReturn); require(smartToken.mint(msg.sender, amount)); } function mintingReturn(WhichToken which, uint _depositAmount) internal view returns (uint256) { uint256 smartTokenSupply = smartToken.totalSupply(); uint256 reserveBalance = balanceOf(which); return returnForMint(smartTokenSupply, _depositAmount, reserveBalance); } function redeem(WhichToken which, uint _amount, uint _minReturn) internal returns (uint redeemable) { require(_amount <= smartToken.balanceOf(msg.sender)); require(_minReturn > 0); redeemable = redemptionReturn(which, _amount); require(redeemable >= _minReturn); uint256 reserveBalance = balanceOf(which); require(reserveBalance >= redeemable); uint256 tokenSupply = smartToken.totalSupply(); require(_amount < tokenSupply); smartToken.destroy(msg.sender, _amount); if (which == WhichToken.Eth) { msg.sender.transfer(redeemable); } else { require(reserveToken.transfer(msg.sender, redeemable)); } } function redemptionReturn(WhichToken which, uint smartTokensSent) internal view returns (uint256) { uint smartTokenSupply = smartToken.totalSupply(); uint reserveTokenBalance = balanceOf(which); return returnForRedemption( smartTokenSupply, smartTokensSent, reserveTokenBalance); } } /// @title Proceeds contract contract Proceeds is Owned { using SafeMath for uint256; AutonomousConverter public autonomousConverter; Auctions public auctions; event LogProceedsIn(address indexed from, uint value); event LogClosedAuction(address indexed from, uint value); uint latestAuctionClosed; function initProceeds(address _autonomousConverter, address _auctions) public onlyOwner { require(address(auctions) == 0x0 && _auctions != 0x0); require(address(autonomousConverter) == 0x0 && _autonomousConverter != 0x0); autonomousConverter = AutonomousConverter(_autonomousConverter); auctions = Auctions(_auctions); } function handleFund() public payable { require(msg.sender == address(auctions)); emit LogProceedsIn(msg.sender, msg.value); } /// @notice Forward 0.25% of total ETH balance of proceeds to AutonomousConverter contract function closeAuction() public { uint lastPurchaseTick = auctions.lastPurchaseTick(); uint currentAuction = auctions.currentAuction(); uint val = ((address(this).balance).mul(25)).div(10000); if (val > 0 && (currentAuction > auctions.whichAuction(lastPurchaseTick)) && (latestAuctionClosed < currentAuction)) { latestAuctionClosed = currentAuction; autonomousConverter.handleFund.value(val)(); emit LogClosedAuction(msg.sender, val); } } } /// @title Auction contract. Send ETH to the contract address and buy MET. contract Auctions is Pricer, Owned { using SafeMath for uint256; METToken public token; Proceeds public proceeds; address[] public founders; mapping(address => TokenLocker) public tokenLockers; uint internal constant DAY_IN_SECONDS = 86400; uint internal constant DAY_IN_MINUTES = 1440; uint public genesisTime; uint public lastPurchaseTick; uint public lastPurchasePrice; uint public constant INITIAL_GLOBAL_DAILY_SUPPLY = 2880 * METDECMULT; uint public INITIAL_FOUNDER_SUPPLY = 1999999 * METDECMULT; uint public INITIAL_AC_SUPPLY = 1 * METDECMULT; uint public totalMigratedOut = 0; uint public totalMigratedIn = 0; uint public timeScale = 1; uint public constant INITIAL_SUPPLY = 10000000 * METDECMULT; uint public mintable = INITIAL_SUPPLY; uint public initialAuctionDuration = 7 days; uint public initialAuctionEndTime; uint public dailyAuctionStartTime; uint public constant DAILY_PURCHASE_LIMIT = 1000 ether; mapping (address => uint) internal purchaseInTheAuction; mapping (address => uint) internal lastPurchaseAuction; bool public minted; bool public initialized; uint public globalSupplyAfterPercentageLogic = 52598080 * METDECMULT; uint public constant AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS = 14791; bytes8 public chain = "ETH"; event LogAuctionFundsIn(address indexed sender, uint amount, uint tokens, uint purchasePrice, uint refund); function Auctions() public { mintable = INITIAL_SUPPLY - 2000000 * METDECMULT; } /// @notice Payable function to buy MET in descending price auction function () public payable running { require(msg.value > 0); uint amountForPurchase = msg.value; uint excessAmount; if (currentAuction() > whichAuction(lastPurchaseTick)) { proceeds.closeAuction(); restartAuction(); } if (isInitialAuctionEnded()) { require(now >= dailyAuctionStartTime); if (lastPurchaseAuction[msg.sender] < currentAuction()) { if (amountForPurchase > DAILY_PURCHASE_LIMIT) { excessAmount = amountForPurchase.sub(DAILY_PURCHASE_LIMIT); amountForPurchase = DAILY_PURCHASE_LIMIT; } purchaseInTheAuction[msg.sender] = msg.value; lastPurchaseAuction[msg.sender] = currentAuction(); } else { require(purchaseInTheAuction[msg.sender] < DAILY_PURCHASE_LIMIT); if (purchaseInTheAuction[msg.sender].add(amountForPurchase) > DAILY_PURCHASE_LIMIT) { excessAmount = (purchaseInTheAuction[msg.sender].add(amountForPurchase)).sub(DAILY_PURCHASE_LIMIT); amountForPurchase = amountForPurchase.sub(excessAmount); } purchaseInTheAuction[msg.sender] = purchaseInTheAuction[msg.sender].add(msg.value); } } uint _currentTick = currentTick(); uint weiPerToken; uint tokens; uint refund; (weiPerToken, tokens, refund) = calcPurchase(amountForPurchase, _currentTick); require(tokens > 0); if (now < initialAuctionEndTime && (token.totalSupply()).add(tokens) >= INITIAL_SUPPLY) { initialAuctionEndTime = now; dailyAuctionStartTime = ((initialAuctionEndTime / 1 days) + 1) * 1 days; } lastPurchaseTick = _currentTick; lastPurchasePrice = weiPerToken; assert(tokens <= mintable); mintable = mintable.sub(tokens); assert(refund <= amountForPurchase); uint ethForProceeds = amountForPurchase.sub(refund); proceeds.handleFund.value(ethForProceeds)(); require(token.mint(msg.sender, tokens)); refund = refund.add(excessAmount); if (refund > 0) { if (purchaseInTheAuction[msg.sender] > 0) { purchaseInTheAuction[msg.sender] = purchaseInTheAuction[msg.sender].sub(refund); } msg.sender.transfer(refund); } emit LogAuctionFundsIn(msg.sender, ethForProceeds, tokens, lastPurchasePrice, refund); } modifier running() { require(isRunning()); _; } function isRunning() public constant returns (bool) { return (block.timestamp >= genesisTime && genesisTime > 0); } /// @notice current tick(minute) of the metronome clock /// @return tick count function currentTick() public view returns(uint) { return whichTick(block.timestamp); } /// @notice current auction /// @return auction count function currentAuction() public view returns(uint) { return whichAuction(currentTick()); } /// @notice tick count at the timestamp t. /// @param t timestamp /// @return tick count function whichTick(uint t) public view returns(uint) { if (genesisTime > t) { revert(); } return (t - genesisTime) * timeScale / 1 minutes; } /// @notice Auction count at given the timestamp t /// @param t timestamp /// @return Auction count function whichAuction(uint t) public view returns(uint) { if (whichTick(dailyAuctionStartTime) > t) { return 0; } else { return ((t - whichTick(dailyAuctionStartTime)) / DAY_IN_MINUTES) + 1; } } /// @notice one single function telling everything about Metronome Auction function heartbeat() public view returns ( bytes8 _chain, address auctionAddr, address convertAddr, address tokenAddr, uint minting, uint totalMET, uint proceedsBal, uint currTick, uint currAuction, uint nextAuctionGMT, uint genesisGMT, uint currentAuctionPrice, uint _dailyMintable, uint _lastPurchasePrice) { _chain = chain; convertAddr = proceeds.autonomousConverter(); tokenAddr = token; auctionAddr = this; totalMET = token.totalSupply(); proceedsBal = address(proceeds).balance; currTick = currentTick(); currAuction = currentAuction(); if (currAuction == 0) { nextAuctionGMT = dailyAuctionStartTime; } else { nextAuctionGMT = (currAuction * DAY_IN_SECONDS) / timeScale + dailyAuctionStartTime; } genesisGMT = genesisTime; currentAuctionPrice = currentPrice(); _dailyMintable = dailyMintable(); minting = currentMintable(); _lastPurchasePrice = lastPurchasePrice; } /// @notice Skip Initialization and minting if we're not the OG Metronome /// @param _token MET token contract address /// @param _proceeds Address of Proceeds contract /// @param _genesisTime The block.timestamp when first auction started on OG chain /// @param _minimumPrice Nobody can buy tokens for less than this price /// @param _startingPrice Start price of MET when first auction starts /// @param _timeScale time scale factor for auction. will be always 1 in live environment /// @param _chain chain where this contract is being deployed /// @param _initialAuctionEndTime Initial Auction end time in ETH chain. function skipInitBecauseIAmNotOg(address _token, address _proceeds, uint _genesisTime, uint _minimumPrice, uint _startingPrice, uint _timeScale, bytes8 _chain, uint _initialAuctionEndTime) public onlyOwner returns (bool) { require(!minted); require(!initialized); require(_timeScale != 0); require(address(token) == 0x0 && _token != 0x0); require(address(proceeds) == 0x0 && _proceeds != 0x0); initPricer(); // minting substitute section token = METToken(_token); proceeds = Proceeds(_proceeds); INITIAL_FOUNDER_SUPPLY = 0; INITIAL_AC_SUPPLY = 0; mintable = 0; // // initial auction substitute section genesisTime = _genesisTime; initialAuctionEndTime = _initialAuctionEndTime; // if initialAuctionEndTime is midnight, then daily auction will start immediately // after initial auction. if (initialAuctionEndTime == (initialAuctionEndTime / 1 days) * 1 days) { dailyAuctionStartTime = initialAuctionEndTime; } else { dailyAuctionStartTime = ((initialAuctionEndTime / 1 days) + 1) * 1 days; } lastPurchaseTick = 0; if (_minimumPrice > 0) { minimumPrice = _minimumPrice; } timeScale = _timeScale; if (_startingPrice > 0) { lastPurchasePrice = _startingPrice * 1 ether; } else { lastPurchasePrice = 2 ether; } chain = _chain; minted = true; initialized = true; return true; } /// @notice Initialize Auctions parameters /// @param _startTime The block.timestamp when first auction starts /// @param _minimumPrice Nobody can buy tokens for less than this price /// @param _startingPrice Start price of MET when first auction starts /// @param _timeScale time scale factor for auction. will be always 1 in live environment function initAuctions(uint _startTime, uint _minimumPrice, uint _startingPrice, uint _timeScale) public onlyOwner returns (bool) { require(minted); require(!initialized); require(_timeScale != 0); initPricer(); if (_startTime > 0) { genesisTime = (_startTime / (1 minutes)) * (1 minutes) + 60; } else { genesisTime = block.timestamp + 60 - (block.timestamp % 60); } initialAuctionEndTime = genesisTime + initialAuctionDuration; // if initialAuctionEndTime is midnight, then daily auction will start immediately // after initial auction. if (initialAuctionEndTime == (initialAuctionEndTime / 1 days) * 1 days) { dailyAuctionStartTime = initialAuctionEndTime; } else { dailyAuctionStartTime = ((initialAuctionEndTime / 1 days) + 1) * 1 days; } lastPurchaseTick = 0; if (_minimumPrice > 0) { minimumPrice = _minimumPrice; } timeScale = _timeScale; if (_startingPrice > 0) { lastPurchasePrice = _startingPrice * 1 ether; } else { lastPurchasePrice = 2 ether; } for (uint i = 0; i < founders.length; i++) { TokenLocker tokenLocker = tokenLockers[founders[i]]; tokenLocker.lockTokenLocker(); } initialized = true; return true; } function createTokenLocker(address _founder, address _token) public onlyOwner { require(_token != 0x0); require(_founder != 0x0); founders.push(_founder); TokenLocker tokenLocker = new TokenLocker(address(this), _token); tokenLockers[_founder] = tokenLocker; tokenLocker.changeOwnership(_founder); } /// @notice Mint initial supply for founder and move to token locker /// @param _founders Left 160 bits are the founder address and the right 96 bits are the token amount. /// @param _token MET token contract address /// @param _proceeds Address of Proceeds contract function mintInitialSupply(uint[] _founders, address _token, address _proceeds, address _autonomousConverter) public onlyOwner returns (bool) { require(!minted); require(_founders.length != 0); require(address(token) == 0x0 && _token != 0x0); require(address(proceeds) == 0x0 && _proceeds != 0x0); require(_autonomousConverter != 0x0); token = METToken(_token); proceeds = Proceeds(_proceeds); // _founders will be minted into individual token lockers uint foundersTotal; for (uint i = 0; i < _founders.length; i++) { address addr = address(_founders[i] >> 96); require(addr != 0x0); uint amount = _founders[i] & ((1 << 96) - 1); require(amount > 0); TokenLocker tokenLocker = tokenLockers[addr]; require(token.mint(address(tokenLocker), amount)); tokenLocker.deposit(addr, amount); foundersTotal = foundersTotal.add(amount); } // reconcile minted total for founders require(foundersTotal == INITIAL_FOUNDER_SUPPLY); // mint a small amount to the AC require(token.mint(_autonomousConverter, INITIAL_AC_SUPPLY)); minted = true; return true; } /// @notice Suspend auction if not started yet function stopEverything() public onlyOwner { if (genesisTime < block.timestamp) { revert(); } genesisTime = genesisTime + 1000 years; initialAuctionEndTime = genesisTime; dailyAuctionStartTime = genesisTime; } /// @notice Return information about initial auction status. function isInitialAuctionEnded() public view returns (bool) { return (initialAuctionEndTime != 0 && (now >= initialAuctionEndTime || token.totalSupply() >= INITIAL_SUPPLY)); } /// @notice Global MET supply function globalMetSupply() public view returns (uint) { uint currAuc = currentAuction(); if (currAuc > AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS) { return globalSupplyAfterPercentageLogic; } else { return INITIAL_SUPPLY.add(INITIAL_GLOBAL_DAILY_SUPPLY.mul(currAuc)); } } /// @notice Global MET daily supply. Daily supply is greater of 1) 2880 2)2% of then outstanding supply per year. /// @dev 2% logic will kicks in at 14792th auction. function globalDailySupply() public view returns (uint) { uint dailySupply = INITIAL_GLOBAL_DAILY_SUPPLY; uint thisAuction = currentAuction(); if (thisAuction > AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS) { uint lastAuctionPurchase = whichAuction(lastPurchaseTick); uint recentAuction = AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS + 1; if (lastAuctionPurchase > recentAuction) { recentAuction = lastAuctionPurchase; } uint totalAuctions = thisAuction - recentAuction; if (totalAuctions > 1) { // derived formula to find close to accurate daily supply when some auction missed. uint factor = 36525 + ((totalAuctions - 1) * 2); dailySupply = (globalSupplyAfterPercentageLogic.mul(2).mul(factor)).div(36525 ** 2); } else { dailySupply = globalSupplyAfterPercentageLogic.mul(2).div(36525); } if (dailySupply < INITIAL_GLOBAL_DAILY_SUPPLY) { dailySupply = INITIAL_GLOBAL_DAILY_SUPPLY; } } return dailySupply; } /// @notice Current price of MET in current auction /// @return weiPerToken function currentPrice() public constant returns (uint weiPerToken) { weiPerToken = calcPriceAt(currentTick()); } /// @notice Daily mintable MET in current auction function dailyMintable() public constant returns (uint) { return nextAuctionSupply(0); } /// @notice Total tokens on this chain function tokensOnThisChain() public view returns (uint) { uint totalSupply = token.totalSupply(); uint currMintable = currentMintable(); return totalSupply.add(currMintable); } /// @notice Current mintable MET in auction function currentMintable() public view returns (uint) { uint currMintable = mintable; uint currAuction = currentAuction(); uint totalAuctions = currAuction.sub(whichAuction(lastPurchaseTick)); if (totalAuctions > 0) { currMintable = mintable.add(nextAuctionSupply(totalAuctions)); } return currMintable; } /// @notice prepare auction when first import is done on a non ETH chain function prepareAuctionForNonOGChain() public { require(msg.sender == address(token.tokenPorter()) || msg.sender == address(token)); require(token.totalSupply() == 0); require(chain != "ETH"); lastPurchaseTick = currentTick(); } /// @notice Find out what the results would be of a prospective purchase /// @param _wei Amount of wei the purchaser will pay /// @param _timestamp Prospective purchase timestamp /// @return weiPerToken expected MET token rate /// @return tokens Expected token for a prospective purchase /// @return refund Wei refund the purchaser will get if amount is excess and MET supply is less function whatWouldPurchaseDo(uint _wei, uint _timestamp) public constant returns (uint weiPerToken, uint tokens, uint refund) { weiPerToken = calcPriceAt(whichTick(_timestamp)); uint calctokens = METDECMULT.mul(_wei).div(weiPerToken); tokens = calctokens; if (calctokens > mintable) { tokens = mintable; uint weiPaying = mintable.mul(weiPerToken).div(METDECMULT); refund = _wei.sub(weiPaying); } } /// @notice Return the information about the next auction /// @return _startTime Start time of next auction /// @return _startPrice Start price of MET in next auction /// @return _auctionTokens MET supply in next auction function nextAuction() internal constant returns(uint _startTime, uint _startPrice, uint _auctionTokens) { if (block.timestamp < genesisTime) { _startTime = genesisTime; _startPrice = lastPurchasePrice; _auctionTokens = mintable; return; } uint recentAuction = whichAuction(lastPurchaseTick); uint currAuc = currentAuction(); uint totalAuctions = currAuc - recentAuction; _startTime = dailyAuctionStartTime; if (currAuc > 1) { _startTime = auctionStartTime(currentTick()); } _auctionTokens = nextAuctionSupply(totalAuctions); if (totalAuctions > 1) { _startPrice = lastPurchasePrice / 100 + 1; } else { if (mintable == 0 || totalAuctions == 0) { // Sold out scenario or someone querying projected start price of next auction _startPrice = (lastPurchasePrice * 2) + 1; } else { // Timed out and all tokens not sold. if (currAuc == 1) { // If initial auction timed out then price before start of new auction will touch floor price _startPrice = minimumPrice * 2; } else { // Descending price till end of auction and then multiply by 2 uint tickWhenAuctionEnded = whichTick(_startTime); uint numTick = 0; if (tickWhenAuctionEnded > lastPurchaseTick) { numTick = tickWhenAuctionEnded - lastPurchaseTick; } _startPrice = priceAt(lastPurchasePrice, numTick) * 2; } } } } /// @notice Calculate results of a purchase /// @param _wei Amount of wei the purchaser will pay /// @param _t Prospective purchase tick /// @return weiPerToken expected MET token rate /// @return tokens Expected token for a prospective purchase /// @return refund Wei refund the purchaser will get if amount is excess and MET supply is less function calcPurchase(uint _wei, uint _t) internal view returns (uint weiPerToken, uint tokens, uint refund) { require(_t >= lastPurchaseTick); uint numTicks = _t - lastPurchaseTick; if (isInitialAuctionEnded()) { weiPerToken = priceAt(lastPurchasePrice, numTicks); } else { weiPerToken = priceAtInitialAuction(lastPurchasePrice, numTicks); } uint calctokens = METDECMULT.mul(_wei).div(weiPerToken); tokens = calctokens; if (calctokens > mintable) { tokens = mintable; uint ethPaying = mintable.mul(weiPerToken).div(METDECMULT); refund = _wei.sub(ethPaying); } } /// @notice MET supply for next Auction also considering carry forward met. /// @param totalAuctionMissed auction count when no purchase done. function nextAuctionSupply(uint totalAuctionMissed) internal view returns (uint supply) { uint thisAuction = currentAuction(); uint tokensHere = token.totalSupply().add(mintable); supply = INITIAL_GLOBAL_DAILY_SUPPLY; uint dailySupplyAtLastPurchase; if (thisAuction > AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS) { supply = globalDailySupply(); if (totalAuctionMissed > 1) { dailySupplyAtLastPurchase = globalSupplyAfterPercentageLogic.mul(2).div(36525); supply = dailySupplyAtLastPurchase.add(supply).mul(totalAuctionMissed).div(2); } supply = (supply.mul(tokensHere)).div(globalSupplyAfterPercentageLogic); } else { if (totalAuctionMissed > 1) { supply = supply.mul(totalAuctionMissed); } uint previousGlobalMetSupply = INITIAL_SUPPLY.add(INITIAL_GLOBAL_DAILY_SUPPLY.mul(whichAuction(lastPurchaseTick))); supply = (supply.mul(tokensHere)).div(previousGlobalMetSupply); } } /// @notice price at a number of minutes out in Initial auction and daily auction /// @param _tick Metronome tick /// @return weiPerToken function calcPriceAt(uint _tick) internal constant returns (uint weiPerToken) { uint recentAuction = whichAuction(lastPurchaseTick); uint totalAuctions = whichAuction(_tick).sub(recentAuction); uint prevPrice; uint numTicks = 0; // Auction is sold out and metronome clock is in same auction if (mintable == 0 && totalAuctions == 0) { return lastPurchasePrice; } // Metronome has missed one auction ie no purchase in last auction if (totalAuctions > 1) { prevPrice = lastPurchasePrice / 100 + 1; numTicks = numTicksSinceAuctionStart(_tick); } else if (totalAuctions == 1) { // Metronome clock is in new auction, next auction // previous auction sold out if (mintable == 0) { prevPrice = lastPurchasePrice * 2; } else { // previous auctions timed out // first daily auction if (whichAuction(_tick) == 1) { prevPrice = minimumPrice * 2; } else { prevPrice = priceAt(lastPurchasePrice, numTicksTillAuctionStart(_tick)) * 2; } } numTicks = numTicksSinceAuctionStart(_tick); } else { //Auction is running prevPrice = lastPurchasePrice; numTicks = _tick - lastPurchaseTick; } require(numTicks >= 0); if (isInitialAuctionEnded()) { weiPerToken = priceAt(prevPrice, numTicks); } else { weiPerToken = priceAtInitialAuction(prevPrice, numTicks); } } /// @notice Calculate number of ticks elapsed between auction start time and given tick. /// @param _tick Given metronome tick function numTicksSinceAuctionStart(uint _tick) private view returns (uint ) { uint currentAuctionStartTime = auctionStartTime(_tick); return _tick - whichTick(currentAuctionStartTime); } /// @notice Calculate number of ticks elapsed between lastPurchaseTick and auctions start time of given tick. /// @param _tick Given metronome tick function numTicksTillAuctionStart(uint _tick) private view returns (uint) { uint currentAuctionStartTime = auctionStartTime(_tick); return whichTick(currentAuctionStartTime) - lastPurchaseTick; } /// @notice First calculate the auction which contains the given tick and then calculate /// auction start time of given tick. /// @param _tick Metronome tick function auctionStartTime(uint _tick) private view returns (uint) { return ((whichAuction(_tick)) * 1 days) / timeScale + dailyAuctionStartTime - 1 days; } /// @notice start the next day's auction function restartAuction() private { uint time; uint price; uint auctionTokens; (time, price, auctionTokens) = nextAuction(); uint thisAuction = currentAuction(); if (thisAuction > AUCTION_WHEN_PERCENTAGE_LOGIC_STARTS) { globalSupplyAfterPercentageLogic = globalSupplyAfterPercentageLogic.add(globalDailySupply()); } mintable = mintable.add(auctionTokens); lastPurchasePrice = price; lastPurchaseTick = whichTick(time); } } /// @title This contract serves as a locker for a founder's tokens contract TokenLocker is Ownable { using SafeMath for uint; uint internal constant QUARTER = 91 days + 450 minutes; Auctions public auctions; METToken public token; bool public locked = false; uint public deposited; uint public lastWithdrawTime; uint public quarterlyWithdrawable; event Withdrawn(address indexed who, uint amount); event Deposited(address indexed who, uint amount); modifier onlyAuction() { require(msg.sender == address(auctions)); _; } modifier preLock() { require(!locked); _; } modifier postLock() { require(locked); _; } /// @notice Constructor to initialize TokenLocker contract. /// @param _auctions Address of auctions contract /// @param _token Address of METToken contract function TokenLocker(address _auctions, address _token) public { require(_auctions != 0x0); require(_token != 0x0); auctions = Auctions(_auctions); token = METToken(_token); } /// @notice If auctions is initialized, call to this function will result in /// locking of deposited tokens and further deposit of tokens will not be allowed. function lockTokenLocker() public onlyAuction { require(auctions.initialAuctionEndTime() != 0); require(auctions.initialAuctionEndTime() >= auctions.genesisTime()); locked = true; } /// @notice It will deposit tokens into the locker for given beneficiary. /// @param beneficiary Address of the beneficiary, whose tokens are being locked. /// @param amount Amount of tokens being locked function deposit (address beneficiary, uint amount ) public onlyAuction preLock { uint totalBalance = token.balanceOf(this); require(totalBalance.sub(deposited) >= amount); deposited = deposited.add(amount); emit Deposited(beneficiary, amount); } /// @notice This function will allow token withdraw from locker. /// 25% of total deposited tokens can be withdrawn after initial auction end. /// Remaining 75% can be withdrawn in equal amount over 12 quarters. function withdraw() public onlyOwner postLock { require(deposited > 0); uint withdrawable = 0; uint withdrawTime = auctions.initialAuctionEndTime(); if (lastWithdrawTime == 0 && auctions.isInitialAuctionEnded()) { withdrawable = withdrawable.add((deposited.mul(25)).div(100)); quarterlyWithdrawable = (deposited.sub(withdrawable)).div(12); lastWithdrawTime = withdrawTime; } require(lastWithdrawTime != 0); if (now >= lastWithdrawTime.add(QUARTER)) { uint daysSinceLastWithdraw = now.sub(lastWithdrawTime); uint totalQuarters = daysSinceLastWithdraw.div(QUARTER); require(totalQuarters > 0); withdrawable = withdrawable.add(quarterlyWithdrawable.mul(totalQuarters)); if (now >= withdrawTime.add(QUARTER.mul(12))) { withdrawable = deposited; } lastWithdrawTime = lastWithdrawTime.add(totalQuarters.mul(QUARTER)); } if (withdrawable > 0) { deposited = deposited.sub(withdrawable); token.transfer(msg.sender, withdrawable); emit Withdrawn(msg.sender, withdrawable); } } } /// @title Interface for TokenPorter contract. /// Define events and functions for TokenPorter contract interface ITokenPorter { event ExportOnChainClaimedReceiptLog(address indexed destinationMetronomeAddr, address indexed destinationRecipientAddr, uint amount); event ExportReceiptLog(bytes8 destinationChain, address destinationMetronomeAddr, address indexed destinationRecipientAddr, uint amountToBurn, uint fee, bytes extraData, uint currentTick, uint indexed burnSequence, bytes32 indexed currentBurnHash, bytes32 prevBurnHash, uint dailyMintable, uint[] supplyOnAllChains, uint genesisTime, uint blockTimestamp, uint dailyAuctionStartTime); event ImportReceiptLog(address indexed destinationRecipientAddr, uint amountImported, uint fee, bytes extraData, uint currentTick, uint indexed importSequence, bytes32 indexed currentHash, bytes32 prevHash, uint dailyMintable, uint blockTimestamp, address caller); function export(address tokenOwner, bytes8 _destChain, address _destMetronomeAddr, address _destRecipAddr, uint _amount, uint _fee, bytes _extraData) public returns (bool); function importMET(bytes8 _originChain, bytes8 _destinationChain, address[] _addresses, bytes _extraData, bytes32[] _burnHashes, uint[] _supplyOnAllChains, uint[] _importData, bytes _proof) public returns (bool); } /// @title This contract will provide export functionality for tokens. contract TokenPorter is ITokenPorter, Owned { using SafeMath for uint; Auctions public auctions; METToken public token; Validator public validator; ChainLedger public chainLedger; uint public burnSequence = 1; uint public importSequence = 1; bytes32[] public exportedBurns; uint[] public supplyOnAllChains = new uint[](6); /// @notice mapping that tracks valid destination chains for export mapping(bytes8 => address) public destinationChains; /// @notice Initialize TokenPorter contract. /// @param _tokenAddr Address of metToken contract /// @param _auctionsAddr Address of auctions contract function initTokenPorter(address _tokenAddr, address _auctionsAddr) public onlyOwner { require(_tokenAddr != 0x0); require(_auctionsAddr != 0x0); auctions = Auctions(_auctionsAddr); token = METToken(_tokenAddr); } /// @notice set address of validator contract /// @param _validator address of validator contract function setValidator(address _validator) public onlyOwner returns (bool) { require(_validator != 0x0); validator = Validator(_validator); return true; } /// @notice set address of chainLedger contract /// @param _chainLedger address of chainLedger contract function setChainLedger(address _chainLedger) public onlyOwner returns (bool) { require(_chainLedger != 0x0); chainLedger = ChainLedger(_chainLedger); return true; } /// @notice only owner can add destination chains /// @param _chainName string of destination blockchain name /// @param _contractAddress address of destination MET token to import to function addDestinationChain(bytes8 _chainName, address _contractAddress) public onlyOwner returns (bool) { require(_chainName != 0 && _contractAddress != address(0)); destinationChains[_chainName] = _contractAddress; return true; } /// @notice only owner can remove destination chains /// @param _chainName string of destination blockchain name function removeDestinationChain(bytes8 _chainName) public onlyOwner returns (bool) { require(_chainName != 0); require(destinationChains[_chainName] != address(0)); destinationChains[_chainName] = address(0); return true; } /// @notice holds claims from users that have exported on-chain /// @param key is address of destination MET token contract /// @param subKey is address of users account that burned their original MET token mapping (address => mapping(address => uint)) public claimables; /// @notice destination MET token contract calls claimReceivables to record burned /// tokens have been minted in new chain /// @param recipients array of addresses of each user that has exported from /// original chain. These can be generated by ExportReceiptLog function claimReceivables(address[] recipients) public returns (uint) { require(recipients.length > 0); uint total; for (uint i = 0; i < recipients.length; i++) { address recipient = recipients[i]; uint amountBurned = claimables[msg.sender][recipient]; if (amountBurned > 0) { claimables[msg.sender][recipient] = 0; emit ExportOnChainClaimedReceiptLog(msg.sender, recipient, amountBurned); total = total.add(1); } } return total; } /// @notice import MET tokens from another chain to this chain. /// @param _destinationChain destination chain name /// @param _addresses _addresses[0] is destMetronomeAddr and _addresses[1] is recipientAddr /// @param _extraData extra information for import /// @param _burnHashes _burnHashes[0] is previous burnHash, _burnHashes[1] is current burnHash /// @param _supplyOnAllChains MET supply on all supported chains /// @param _importData _importData[0] is _blockTimestamp, _importData[1] is _amount, _importData[2] is _fee /// _importData[3] is _burnedAtTick, _importData[4] is _genesisTime, _importData[5] is _dailyMintable /// _importData[6] is _burnSequence, _importData[7] is _dailyAuctionStartTime /// @param _proof proof /// @return true/false function importMET(bytes8 _originChain, bytes8 _destinationChain, address[] _addresses, bytes _extraData, bytes32[] _burnHashes, uint[] _supplyOnAllChains, uint[] _importData, bytes _proof) public returns (bool) { require(msg.sender == address(token)); require(_importData.length == 8); require(_addresses.length == 2); require(_burnHashes.length == 2); require(validator.isReceiptClaimable(_originChain, _destinationChain, _addresses, _extraData, _burnHashes, _supplyOnAllChains, _importData, _proof)); validator.claimHash(_burnHashes[1]); require(_destinationChain == auctions.chain()); uint amountToImport = _importData[1].add(_importData[2]); require(amountToImport.add(token.totalSupply()) <= auctions.globalMetSupply()); require(_addresses[0] == address(token)); if (_importData[1] == 0) { return false; } if (importSequence == 1 && token.totalSupply() == 0) { auctions.prepareAuctionForNonOGChain(); } token.mint(_addresses[1], _importData[1]); emit ImportReceiptLog(_addresses[1], _importData[1], _importData[2], _extraData, auctions.currentTick(), importSequence, _burnHashes[1], _burnHashes[0], auctions.dailyMintable(), now, msg.sender); importSequence++; chainLedger.registerImport(_originChain, _destinationChain, _importData[1]); return true; } /// @notice Export MET tokens from this chain to another chain. /// @param tokenOwner Owner of the token, whose tokens are being exported. /// @param _destChain Destination chain for exported tokens /// @param _destMetronomeAddr Metronome address on destination chain /// @param _destRecipAddr Recipient address on the destination chain /// @param _amount Amount of token being exported /// @param _extraData Extra data for this export /// @return boolean true/false based on the outcome of export function export(address tokenOwner, bytes8 _destChain, address _destMetronomeAddr, address _destRecipAddr, uint _amount, uint _fee, bytes _extraData) public returns (bool) { require(msg.sender == address(token)); require(_destChain != 0x0 && _destMetronomeAddr != 0x0 && _destRecipAddr != 0x0 && _amount != 0); require(destinationChains[_destChain] == _destMetronomeAddr); require(token.balanceOf(tokenOwner) >= _amount.add(_fee)); token.destroy(tokenOwner, _amount.add(_fee)); uint dailyMintable = auctions.dailyMintable(); uint currentTick = auctions.currentTick(); if (burnSequence == 1) { exportedBurns.push(keccak256(uint8(0))); } if (_destChain == auctions.chain()) { claimables[_destMetronomeAddr][_destRecipAddr] = claimables[_destMetronomeAddr][_destRecipAddr].add(_amount); } uint blockTime = block.timestamp; bytes32 currentBurn = keccak256( blockTime, auctions.chain(), _destChain, _destMetronomeAddr, _destRecipAddr, _amount, currentTick, auctions.genesisTime(), dailyMintable, token.totalSupply(), _extraData, exportedBurns[burnSequence - 1]); exportedBurns.push(currentBurn); supplyOnAllChains[0] = token.totalSupply(); emit ExportReceiptLog(_destChain, _destMetronomeAddr, _destRecipAddr, _amount, _fee, _extraData, currentTick, burnSequence, currentBurn, exportedBurns[burnSequence - 1], dailyMintable, supplyOnAllChains, auctions.genesisTime(), blockTime, auctions.dailyAuctionStartTime()); burnSequence = burnSequence + 1; chainLedger.registerExport(auctions.chain(), _destChain, _amount); return true; } } contract ChainLedger is Owned { using SafeMath for uint; mapping (bytes8 => uint) public balance; mapping (bytes8 => bool) public validChain; bytes8[] public chains; address public tokenPorter; Auctions public auctions; event LogRegisterChain(address indexed caller, bytes8 indexed chain, uint supply, bool outcome); event LogRegisterExport(address indexed caller, bytes8 indexed originChain, bytes8 indexed destChain, uint amount); event LogRegisterImport(address indexed caller, bytes8 indexed originChain, bytes8 indexed destChain, uint amount); function initChainLedger(address _tokenPorter, address _auctionsAddr) public onlyOwner returns (bool) { require(_tokenPorter != 0x0); require(_auctionsAddr != 0x0); tokenPorter = _tokenPorter; auctions = Auctions(_auctionsAddr); return true; } function registerChain(bytes8 chain, uint supply) public onlyOwner returns (bool) { require(!validChain[chain]); validChain[chain] = true; chains.push(chain); balance[chain] = supply; emit LogRegisterChain(msg.sender, chain, supply, true); } function registerExport(bytes8 originChain, bytes8 destChain, uint amount) public { require(msg.sender == tokenPorter || msg.sender == owner); require(validChain[originChain] && validChain[destChain]); require(balance[originChain] >= amount); balance[originChain] = balance[originChain].sub(amount); balance[destChain] = balance[destChain].add(amount); emit LogRegisterExport(msg.sender, originChain, destChain, amount); } function registerImport(bytes8 originChain, bytes8 destChain, uint amount) public { require(msg.sender == tokenPorter || msg.sender == owner); require(validChain[originChain] && validChain[destChain]); balance[originChain] = balance[originChain].sub(amount); balance[destChain] = balance[destChain].add(amount); emit LogRegisterImport(msg.sender, originChain, destChain, amount); } } contract Validator is Owned { mapping (bytes32 => mapping (address => bool)) public hashAttestations; mapping (address => bool) public isValidator; mapping (address => uint8) public validatorNum; address[] public validators; address public metToken; address public tokenPorter; mapping (bytes32 => bool) public hashClaimed; uint8 public threshold = 2; event LogAttestation(bytes32 indexed hash, address indexed who, bool isValid); /// @param _validator1 first validator /// @param _validator2 second validator /// @param _validator3 third validator function initValidator(address _validator1, address _validator2, address _validator3) public onlyOwner { // Clear old validators. Validators can be updated multiple times for (uint8 i = 0; i < validators.length; i++) { delete isValidator[validators[i]]; delete validatorNum[validators[i]]; } delete validators; validators.push(_validator1); validators.push(_validator2); validators.push(_validator3); // TODO: This will be NA, Bloq and a third party (escrow or company) at launch, // and should be scripted into deploy isValidator[_validator1] = true; isValidator[_validator2] = true; isValidator[_validator3] = true; validatorNum[_validator1] = 0; validatorNum[_validator2] = 1; validatorNum[_validator3] = 2; } /// @notice set address of token porter /// @param _tokenPorter address of token porter function setTokenPorter(address _tokenPorter) public onlyOwner returns (bool) { require(_tokenPorter != 0x0); tokenPorter = _tokenPorter; return true; } function validateHash(bytes32 hash) public { require(isValidator[msg.sender]); hashAttestations[hash][msg.sender] = true; emit LogAttestation(hash, msg.sender, true); } function invalidateHash(bytes32 hash) public { require(isValidator[msg.sender]); hashAttestations[hash][msg.sender] = false; emit LogAttestation(hash, msg.sender, false); } function hashClaimable(bytes32 hash) public view returns(bool) { if (hashClaimed[hash]) { return false; } uint8 count = 0; for (uint8 i = 0; i < validators.length; i++) { if (hashAttestations[hash][validators[i]]) { count++;} } if (count >= threshold) { return true; } return false; } function claimHash(bytes32 hash) public { require(msg.sender == tokenPorter); require(hashClaimable(hash)); hashClaimed[hash] = true; } function isReceiptClaimable(bytes8 _originChain, bytes8 _destinationChain, address[] _addresses, bytes _extraData, bytes32[] _burnHashes, uint[] _supplyOnAllChain, uint[] _importData, bytes _proof) public view returns(bool) { // We want to validate that these hash to the provided hash as a safety check, // then we want to know if the hash is Claimable. // Due to stack too deep error and limitation in using number of local // variables we have to use uint array here. // _importData[0] is _blockTimestamp, _importData[1] is _amount, _importData[2] is _fee, // _importData[3] is _burnedAtTick, _importData[4] is _genesisTime, // _importData[5] is _dailyMintable, _importData[6] is _burnSequence, // _addresses[0] is _destMetronomeAddr and _addresses[1] is _recipAddr require(_burnHashes[1] == keccak256(_importData[0], _originChain, _destinationChain, _addresses[0], _addresses[1], _importData[1], _importData[3], _importData[4], _importData[5], _supplyOnAllChain[0], _extraData, _burnHashes[0])); if (hashClaimable(_burnHashes[1])) { return true; } return false; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"getRoot","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_autonomousConverter","type":"address"},{"name":"_minter","type":"address"},{"name":"_initialSupply","type":"uint256"},{"name":"_decmult","type":"uint256"}],"name":"initMETToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenPorter","type":"address"}],"name":"setTokenPorter","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"changeOwnership","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transferAllowed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_autonomousConverter","type":"address"},{"name":"_minter","type":"address"},{"name":"_initialSupply","type":"uint256"},{"name":"_decmult","type":"uint256"}],"name":"initToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_destChain","type":"bytes8"},{"name":"_destMetronomeAddr","type":"address"},{"name":"_destRecipAddr","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"export","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenPorter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approveMore","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"enableMETTransfers","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"autonomousConverter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_recipient","type":"address"}],"name":"getSubscription","outputs":[{"name":"startTime","type":"uint256"},{"name":"payPerWeek","type":"uint256"},{"name":"lastWithdrawTime","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_originChain","type":"bytes8"},{"name":"_destinationChain","type":"bytes8"},{"name":"_addresses","type":"address[]"},{"name":"_extraData","type":"bytes"},{"name":"_burnHashes","type":"bytes32[]"},{"name":"_supplyOnAllChains","type":"uint256[]"},{"name":"_importData","type":"uint256[]"},{"name":"_proof","type":"bytes"}],"name":"importMET","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approveLess","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"subWithdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"}],"name":"cancelSubscription","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_value","type":"uint256"}],"name":"destroy","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"roots","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_startTime","type":"uint256"},{"name":"_payPerWeek","type":"uint256"},{"name":"_recipient","type":"address"}],"name":"subscribe","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"bits","type":"uint256[]"}],"name":"multiTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owners","type":"address[]"}],"name":"multiSubWithdraw","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_autonomousConverter","type":"address"},{"name":"_minter","type":"address"},{"name":"_initialSupply","type":"uint256"},{"name":"_decmult","type":"uint256"}],"name":"initMintable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"subs","outputs":[{"name":"startTime","type":"uint256"},{"name":"payPerWeek","type":"uint256"},{"name":"lastWithdrawTime","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"address"},{"name":"b","type":"address"}],"name":"rootsMatch","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"data","type":"bytes32"}],"name":"setRoot","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owners","type":"address[]"},{"name":"_recipients","type":"address[]"}],"name":"multiSubWithdrawFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"subscriber","type":"address"},{"indexed":true,"name":"subscribesTo","type":"address"}],"name":"LogSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"subscriber","type":"address"},{"indexed":true,"name":"subscribesTo","type":"address"}],"name":"LogCancelSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Destroy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"prevOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]
Contract Creation Code
606060405260008054600160a060020a033316600160a060020a03199091161790556120bf806100306000396000f3006060604052600436106101d45763ffffffff60e060020a60003504166306fdde0381146101d95780630754617214610263578063079cf76e14610292578063095ea7b3146102c357806318160ddd146102f9578063195629de1461030c5780631987b8871461033957806323b872dd146103585780632af4c31e14610380578063313ce5671461039f57806334fec467146103c85780633bf11a6c146103db57806340c10f191461040657806346be2310146104285780634892f0af146104b85780634cef0ff6146104cb5780634ee4d731146104ed57806350b48c5e146105005780635b75dd8d146105135780636ffbff9c1461055c57806370a08231146107195780637240eccf1461073857806379ba50971461075a5780638da5cb5b1461076d57806393b212bc1461078057806393d81d581461079f57806395d89b41146107be578063a24835d1146107d1578063a4546876146107f3578063a9059cbb14610812578063aa4925d714610834578063b33fcc7a14610859578063bae1cc74146108a8578063c3f51fca146108f7578063cd755b4114610922578063d2d85cf214610947578063d4ee1d901461096c578063dab5f3401461097f578063dd62ed3e14610995578063e6f47613146109ba575b600080fd5b34156101e457600080fd5b6101ec610a49565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610228578082015183820152602001610210565b50505050905090810190601f1680156102555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561026e57600080fd5b610276610a80565b604051600160a060020a03909116815260200160405180910390f35b341561029d57600080fd5b6102b1600160a060020a0360043516610a8f565b60405190815260200160405180910390f35b34156102ce57600080fd5b6102e5600160a060020a0360043516602435610aaa565b604051901515815260200160405180910390f35b341561030457600080fd5b6102b1610b36565b341561031757600080fd5b610337600160a060020a0360043581169060243516604435606435610b3c565b005b341561034457600080fd5b6102e5600160a060020a0360043516610b69565b341561036357600080fd5b6102e5600160a060020a0360043581169060243516604435610bcc565b341561038b57600080fd5b6102e5600160a060020a0360043516610bf3565b34156103aa57600080fd5b6103b2610c5a565b60405160ff909116815260200160405180910390f35b34156103d357600080fd5b6102e5610c5f565b34156103e657600080fd5b610337600160a060020a0360043581169060243516604435606435610c68565b341561041157600080fd5b6102e5600160a060020a0360043516602435610c8f565b341561043357600080fd5b6102e56004803577ffffffffffffffffffffffffffffffffffffffffffffffff19169060248035600160a060020a039081169260443590911691606435916084359160c49060a43590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610d9395505050505050565b34156104c357600080fd5b610276610ed8565b34156104d657600080fd5b6102e5600160a060020a0360043516602435610ee7565b34156104f857600080fd5b6102e5610f90565b341561050b57600080fd5b610276611017565b341561051e57600080fd5b610538600160a060020a0360043581169060243516611026565b60405180848152602001838152602001828152602001935050505060405180910390f35b341561056757600080fd5b6102e577ffffffffffffffffffffffffffffffffffffffffffffffff1960048035821691602480359091169190606490604435908101908301358060208181020160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284375094965061105e95505050505050565b341561072457600080fd5b6102b1600160a060020a0360043516611345565b341561074357600080fd5b6102e5600160a060020a0360043516602435611360565b341561076557600080fd5b6102e5611399565b341561077857600080fd5b61027661142a565b341561078b57600080fd5b6102e5600160a060020a0360043516611439565b34156107aa57600080fd5b6102e5600160a060020a036004351661146a565b34156107c957600080fd5b6101ec61153e565b34156107dc57600080fd5b6102e5600160a060020a0360043516602435611575565b34156107fe57600080fd5b6102b1600160a060020a0360043516611679565b341561081d57600080fd5b6102e5600160a060020a036004351660243561168b565b341561083f57600080fd5b6102e5600435602435600160a060020a03604435166116b0565b341561086457600080fd5b6102e5600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061178295505050505050565b34156108b357600080fd5b6102b160046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437509496506117a595505050505050565b341561090257600080fd5b610337600160a060020a03600435811690602435166044356064356117ed565b341561092d57600080fd5b610538600160a060020a03600435811690602435166118d4565b341561095257600080fd5b6102e5600160a060020a0360043581169060243516611900565b341561097757600080fd5b610276611927565b341561098a57600080fd5b610337600435611936565b34156109a057600080fd5b6102b1600160a060020a0360043581169060243516611951565b34156109c557600080fd5b6102b160046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284375094965061197c95505050505050565b60408051908101604052600981527f4d6574726f6e6f6d650000000000000000000000000000000000000000000000602082015281565b600554600160a060020a031681565b600160a060020a031660009081526009602052604090205490565b600030600160a060020a031683600160a060020a031614151515610acd57600080fd5b600160a060020a03338116600081815260076020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60025490565b60005433600160a060020a03908116911614610b5757600080fd5b610b6384848484610c68565b50505050565b6000805433600160a060020a03908116911614610b8557600080fd5b600160a060020a0382161515610b9a57600080fd5b5060068054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff199091161790556001919050565b60085460009060ff161515610be057600080fd5b610beb8484846119ef565b949350505050565b6000805433600160a060020a03908116911614610c0f57600080fd5b600054600160a060020a0383811691161415610c2a57600080fd5b5060018054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff19909116178155919050565b601281565b60085460ff1681565b60005433600160a060020a03908116911614610c8357600080fd5b610b63848484846117ed565b60055460009033600160a060020a0390811691161480610cbd575060065433600160a060020a039081169116145b1515610cc857600080fd5b600160a060020a038316600090815260036020526040902054610cf1908363ffffffff611c6516565b600160a060020a038416600090815260036020526040902055600254610d1d908363ffffffff611c6516565b600255600160a060020a0383167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858360405190815260200160405180910390a282600160a060020a031660006000805160206120748339815191528460405190815260200160405180910390a350600192915050565b600654600090600160a060020a03161515610dad57600080fd5b600654600160a060020a031663f29b20403389898989898960405160e060020a63ffffffff8a16028152600160a060020a038089166004830190815277ffffffffffffffffffffffffffffffffffffffffffffffff1989166024840152878216604484015290861660648301526084820185905260a4820184905260e060c48301908152909160e40183818151815260200191508051906020019080838360005b83811015610e66578082015183820152602001610e4e565b50505050905090810190601f168015610e935780820380516001836020036101000a031916815260200191505b5098505050505050505050602060405180830381600087803b1515610eb757600080fd5b5af11515610ec457600080fd5b505050604051805198975050505050505050565b600654600160a060020a031681565b600160a060020a03338116600090815260076020908152604080832093861683529290529081205481610f20828563ffffffff611c6516565b600160a060020a033381166000818152600760209081526040808320948b16808452949091529081902084905592935090917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084905190815260200160405180910390a3506001949350505050565b60085460009060ff16158015610ff85750600554600160a060020a0316631d38bebd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515610fe057600080fd5b5af11515610fed57600080fd5b505050604051805190505b151561100357600080fd5b506008805460ff1916600190811790915590565b600454600160a060020a031681565b600160a060020a039182166000908152600a602090815260408083209390941682529190915220805460018201546002909201549092565b600654600090600160a060020a0316151561107857600080fd5b600654600160a060020a0316636ffbff9c8a8a8a8a8a8a8a8a6040518963ffffffff1660e060020a028152600401808977ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff191681526020018877ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff1916815260200180602001806020018060200180602001806020018060200187810387528d818151815260200191508051906020019060200280838360005b8381101561116f578082015183820152602001611157565b5050505090500187810386528c818151815260200191508051906020019080838360005b838110156111ab578082015183820152602001611193565b50505050905090810190601f1680156111d85780820380516001836020036101000a031916815260200191505b5087810385528b818151815260200191508051906020019060200280838360005b838110156112115780820151838201526020016111f9565b5050505090500187810384528a818151815260200191508051906020019060200280838360005b83811015611250578082015183820152602001611238565b50505050905001878103835289818151815260200191508051906020019060200280838360005b8381101561128f578082015183820152602001611277565b50505050905001878103825288818151815260200191508051906020019080838360005b838110156112cb5780820151838201526020016112b3565b50505050905090810190601f1680156112f85780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050602060405180830381600087803b151561132257600080fd5b5af1151561132f57600080fd5b50505060405180519a9950505050505050505050565b600160a060020a031660009081526003602052604090205490565b600160a060020a03338116600090815260076020908152604080832093861683529290529081205481610f20828563ffffffff611c7416565b60015460009033600160a060020a039081169116146113b757600080fd5b600154600054600160a060020a0391821691167f0384899bd253d83b23daa4d29aaa2efe0563d1132b43101e9ad667235aeb951b60405160405180910390a350600180546000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905590565b600054600160a060020a031681565b60085460009060ff16151561144d57600080fd5b6114578233611c86565b151561146257600080fd5b506001919050565b600160a060020a033381166000908152600a60209081526040808320938516835292905290812054151561149d57600080fd5b600160a060020a033381166000908152600a602090815260408083209386168352929052206001015415156114d157600080fd5b600160a060020a033381166000818152600a602090815260408083209487168084529490915280822082815560018101839055600201919091557f4bc04e574b4f2b061a663b3328263978d3adeab9e4ea9526441c159cdee4eca8905160405180910390a3506001919050565b60408051908101604052600381527f4d45540000000000000000000000000000000000000000000000000000000000602082015281565b60045460009033600160a060020a03908116911614806115a3575060065433600160a060020a039081169116145b15156115ae57600080fd5b600160a060020a0383166000908152600360205260409020546115d7908363ffffffff611c7416565b600160a060020a038416600090815260036020526040902055600254611603908363ffffffff611c7416565b600255600160a060020a0383167f81325e2a6c442af9d36e4ee9697f38d5f4bf0837ade0f6c411c6a40af7c057ee8360405190815260200160405180910390a2600083600160a060020a03166000805160206120748339815191528460405190815260200160405180910390a350600192915050565b60096020526000908152604090205481565b60085460009060ff16151561169f57600080fd5b6116a98383611e24565b9392505050565b6000428410156116bf57600080fd5b8215156116cb57600080fd5b600160a060020a03821615156116e057600080fd5b606060405190810160409081528582526020808301869052818301879052600160a060020a033381166000908152600a8352838120918716815291522081518155602082015181600101556040820151816002015590505081600160a060020a031633600160a060020a03167f5c632ccb5c42002836e0c49ef1f6d67e925c5e77c1048ddbb47a9bf6a0f2d01260405160405180910390a35060019392505050565b60085460009060ff16151561179657600080fd5b61179f82611fb1565b92915050565b600080805b83518110156117e6576117d28482815181106117c257fe5b9060200190602002015133611c86565b156117de576001909101905b6001016117aa565b5092915050565b60005433600160a060020a0390811691161461180857600080fd5b600454600160a060020a03161580156118295750600160a060020a03841615155b151561183457600080fd5b600554600160a060020a03161580156118555750600160a060020a03831615155b151561186057600080fd5b60048054600160a060020a0380871673ffffffffffffffffffffffffffffffffffffffff199283161790925560058054928616929091169190911790556118ad828263ffffffff61203116565b6002819055600160a060020a03909416600090815260036020526040902093909355505050565b600a60209081526000928352604080842090915290825290208054600182015460029092015490919083565b600160a060020a039081166000908152600960205260408082205493909216815220541490565b600154600160a060020a031681565b600160a060020a033316600090815260096020526040902055565b600160a060020a03918216600090815260076020908152604080832093909416825291909152205490565b6000806000835185511461198f57600080fd5b5060009050805b84518110156119e7576119d38582815181106119ae57fe5b906020019060200201518583815181106119c457fe5b90602001906020020151611c86565b156119df576001909101905b600101611996565b509392505050565b600080600160a060020a0384161515611a0757600080fd5b600554600160a060020a03858116911614801590611a335750600554600160a060020a03868116911614155b1515611a3e57600080fd5b30600160a060020a031684600160a060020a031614158015611a72575030600160a060020a031685600160a060020a031614155b1515611a7d57600080fd5b600554600160a060020a03166355b5ec646040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611abc57600080fd5b5af11515611ac957600080fd5b50505060405180519050905080600160a060020a031684600160a060020a031614158015611b09575080600160a060020a031685600160a060020a031614155b1515611b1457600080fd5b600454600160a060020a0386811691161415611b2f57600080fd5b600160a060020a038086166000908152600760209081526040808320339094168352929052205483901015611b6357600080fd5b600160a060020a038516600090815260036020526040902054611b8c908463ffffffff611c7416565b600160a060020a038087166000908152600360205260408082209390935590861681522054611bc1908463ffffffff611c6516565b600160a060020a03808616600090815260036020908152604080832094909455888316825260078152838220339093168252919091522054611c09908463ffffffff611c7416565b600160a060020a03808716600081815260076020908152604080832033861684529091529081902093909355908616916000805160206120748339815191529086905190815260200160405180910390a3506001949350505050565b6000828201838110156116a957fe5b600082821115611c8057fe5b50900390565b600160a060020a038083166000908152600a6020908152604080832093851683529290529081208054829081908190118015611cc3575082544290105b8015611cd3575060008360010154115b15611e1657611d0262093a80611cf6856002015442611c7490919063ffffffff16565b9063ffffffff61205c16565b9150611d1b83600101548361203190919063ffffffff16565b9050600082118015611d465750600160a060020a038616600090815260036020526040902054819010155b15611e1657600160a060020a038087166000818152600a60209081526040808320948a1683529381528382204260029091015591815260039091522054611d93908263ffffffff611c7416565b600160a060020a038088166000908152600360205260408082209390935590871681522054611dc8908263ffffffff611c6516565b600160a060020a03808716600081815260036020526040908190209390935591908816906000805160206120748339815191529084905190815260200160405180910390a360019350611e1b565b600093505b50505092915050565b600080600160a060020a0384161515611e3c57600080fd5b600554600160a060020a0385811691161415611e5757600080fd5b30600160a060020a031684600160a060020a031614151515611e7857600080fd5b600454600160a060020a0385811691161415611e9357600080fd5b600554600160a060020a03166355b5ec646040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611ed257600080fd5b5af11515611edf57600080fd5b5050506040518051915050600160a060020a038481169082161415611f0357600080fd5b600160a060020a033316600090815260036020526040902054611f2c908463ffffffff611c7416565b600160a060020a033381166000908152600360205260408082209390935590861681522054611f61908463ffffffff611c6516565b600160a060020a0380861660008181526003602052604090819020939093559133909116906000805160206120748339815191529086905190815260200160405180910390a35060019392505050565b60008080805b8451831015612026576060858481518110611fce57fe5b906020019060200201519060020a90049150848381518110611fec57fe5b906020019060200201516bffffffffffffffffffffffff169050612010828261168b565b151561201b57600080fd5b600190920191611fb7565b506001949350505050565b60008083151561204457600091506117e6565b5082820282848281151561205457fe5b04146116a957fe5b600080828481151561206a57fe5b049493505050505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a7230582062ffa3d2c04263654dbffc8876e9fb51bf446bbfa2c43a5d01b62f8b0a66f1bb0029
Deployed Bytecode
0x6060604052600436106101d45763ffffffff60e060020a60003504166306fdde0381146101d95780630754617214610263578063079cf76e14610292578063095ea7b3146102c357806318160ddd146102f9578063195629de1461030c5780631987b8871461033957806323b872dd146103585780632af4c31e14610380578063313ce5671461039f57806334fec467146103c85780633bf11a6c146103db57806340c10f191461040657806346be2310146104285780634892f0af146104b85780634cef0ff6146104cb5780634ee4d731146104ed57806350b48c5e146105005780635b75dd8d146105135780636ffbff9c1461055c57806370a08231146107195780637240eccf1461073857806379ba50971461075a5780638da5cb5b1461076d57806393b212bc1461078057806393d81d581461079f57806395d89b41146107be578063a24835d1146107d1578063a4546876146107f3578063a9059cbb14610812578063aa4925d714610834578063b33fcc7a14610859578063bae1cc74146108a8578063c3f51fca146108f7578063cd755b4114610922578063d2d85cf214610947578063d4ee1d901461096c578063dab5f3401461097f578063dd62ed3e14610995578063e6f47613146109ba575b600080fd5b34156101e457600080fd5b6101ec610a49565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610228578082015183820152602001610210565b50505050905090810190601f1680156102555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561026e57600080fd5b610276610a80565b604051600160a060020a03909116815260200160405180910390f35b341561029d57600080fd5b6102b1600160a060020a0360043516610a8f565b60405190815260200160405180910390f35b34156102ce57600080fd5b6102e5600160a060020a0360043516602435610aaa565b604051901515815260200160405180910390f35b341561030457600080fd5b6102b1610b36565b341561031757600080fd5b610337600160a060020a0360043581169060243516604435606435610b3c565b005b341561034457600080fd5b6102e5600160a060020a0360043516610b69565b341561036357600080fd5b6102e5600160a060020a0360043581169060243516604435610bcc565b341561038b57600080fd5b6102e5600160a060020a0360043516610bf3565b34156103aa57600080fd5b6103b2610c5a565b60405160ff909116815260200160405180910390f35b34156103d357600080fd5b6102e5610c5f565b34156103e657600080fd5b610337600160a060020a0360043581169060243516604435606435610c68565b341561041157600080fd5b6102e5600160a060020a0360043516602435610c8f565b341561043357600080fd5b6102e56004803577ffffffffffffffffffffffffffffffffffffffffffffffff19169060248035600160a060020a039081169260443590911691606435916084359160c49060a43590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610d9395505050505050565b34156104c357600080fd5b610276610ed8565b34156104d657600080fd5b6102e5600160a060020a0360043516602435610ee7565b34156104f857600080fd5b6102e5610f90565b341561050b57600080fd5b610276611017565b341561051e57600080fd5b610538600160a060020a0360043581169060243516611026565b60405180848152602001838152602001828152602001935050505060405180910390f35b341561056757600080fd5b6102e577ffffffffffffffffffffffffffffffffffffffffffffffff1960048035821691602480359091169190606490604435908101908301358060208181020160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284375094965061105e95505050505050565b341561072457600080fd5b6102b1600160a060020a0360043516611345565b341561074357600080fd5b6102e5600160a060020a0360043516602435611360565b341561076557600080fd5b6102e5611399565b341561077857600080fd5b61027661142a565b341561078b57600080fd5b6102e5600160a060020a0360043516611439565b34156107aa57600080fd5b6102e5600160a060020a036004351661146a565b34156107c957600080fd5b6101ec61153e565b34156107dc57600080fd5b6102e5600160a060020a0360043516602435611575565b34156107fe57600080fd5b6102b1600160a060020a0360043516611679565b341561081d57600080fd5b6102e5600160a060020a036004351660243561168b565b341561083f57600080fd5b6102e5600435602435600160a060020a03604435166116b0565b341561086457600080fd5b6102e5600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061178295505050505050565b34156108b357600080fd5b6102b160046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437509496506117a595505050505050565b341561090257600080fd5b610337600160a060020a03600435811690602435166044356064356117ed565b341561092d57600080fd5b610538600160a060020a03600435811690602435166118d4565b341561095257600080fd5b6102e5600160a060020a0360043581169060243516611900565b341561097757600080fd5b610276611927565b341561098a57600080fd5b610337600435611936565b34156109a057600080fd5b6102b1600160a060020a0360043581169060243516611951565b34156109c557600080fd5b6102b160046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284375094965061197c95505050505050565b60408051908101604052600981527f4d6574726f6e6f6d650000000000000000000000000000000000000000000000602082015281565b600554600160a060020a031681565b600160a060020a031660009081526009602052604090205490565b600030600160a060020a031683600160a060020a031614151515610acd57600080fd5b600160a060020a03338116600081815260076020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60025490565b60005433600160a060020a03908116911614610b5757600080fd5b610b6384848484610c68565b50505050565b6000805433600160a060020a03908116911614610b8557600080fd5b600160a060020a0382161515610b9a57600080fd5b5060068054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff199091161790556001919050565b60085460009060ff161515610be057600080fd5b610beb8484846119ef565b949350505050565b6000805433600160a060020a03908116911614610c0f57600080fd5b600054600160a060020a0383811691161415610c2a57600080fd5b5060018054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff19909116178155919050565b601281565b60085460ff1681565b60005433600160a060020a03908116911614610c8357600080fd5b610b63848484846117ed565b60055460009033600160a060020a0390811691161480610cbd575060065433600160a060020a039081169116145b1515610cc857600080fd5b600160a060020a038316600090815260036020526040902054610cf1908363ffffffff611c6516565b600160a060020a038416600090815260036020526040902055600254610d1d908363ffffffff611c6516565b600255600160a060020a0383167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858360405190815260200160405180910390a282600160a060020a031660006000805160206120748339815191528460405190815260200160405180910390a350600192915050565b600654600090600160a060020a03161515610dad57600080fd5b600654600160a060020a031663f29b20403389898989898960405160e060020a63ffffffff8a16028152600160a060020a038089166004830190815277ffffffffffffffffffffffffffffffffffffffffffffffff1989166024840152878216604484015290861660648301526084820185905260a4820184905260e060c48301908152909160e40183818151815260200191508051906020019080838360005b83811015610e66578082015183820152602001610e4e565b50505050905090810190601f168015610e935780820380516001836020036101000a031916815260200191505b5098505050505050505050602060405180830381600087803b1515610eb757600080fd5b5af11515610ec457600080fd5b505050604051805198975050505050505050565b600654600160a060020a031681565b600160a060020a03338116600090815260076020908152604080832093861683529290529081205481610f20828563ffffffff611c6516565b600160a060020a033381166000818152600760209081526040808320948b16808452949091529081902084905592935090917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084905190815260200160405180910390a3506001949350505050565b60085460009060ff16158015610ff85750600554600160a060020a0316631d38bebd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515610fe057600080fd5b5af11515610fed57600080fd5b505050604051805190505b151561100357600080fd5b506008805460ff1916600190811790915590565b600454600160a060020a031681565b600160a060020a039182166000908152600a602090815260408083209390941682529190915220805460018201546002909201549092565b600654600090600160a060020a0316151561107857600080fd5b600654600160a060020a0316636ffbff9c8a8a8a8a8a8a8a8a6040518963ffffffff1660e060020a028152600401808977ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff191681526020018877ffffffffffffffffffffffffffffffffffffffffffffffff191677ffffffffffffffffffffffffffffffffffffffffffffffff1916815260200180602001806020018060200180602001806020018060200187810387528d818151815260200191508051906020019060200280838360005b8381101561116f578082015183820152602001611157565b5050505090500187810386528c818151815260200191508051906020019080838360005b838110156111ab578082015183820152602001611193565b50505050905090810190601f1680156111d85780820380516001836020036101000a031916815260200191505b5087810385528b818151815260200191508051906020019060200280838360005b838110156112115780820151838201526020016111f9565b5050505090500187810384528a818151815260200191508051906020019060200280838360005b83811015611250578082015183820152602001611238565b50505050905001878103835289818151815260200191508051906020019060200280838360005b8381101561128f578082015183820152602001611277565b50505050905001878103825288818151815260200191508051906020019080838360005b838110156112cb5780820151838201526020016112b3565b50505050905090810190601f1680156112f85780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050602060405180830381600087803b151561132257600080fd5b5af1151561132f57600080fd5b50505060405180519a9950505050505050505050565b600160a060020a031660009081526003602052604090205490565b600160a060020a03338116600090815260076020908152604080832093861683529290529081205481610f20828563ffffffff611c7416565b60015460009033600160a060020a039081169116146113b757600080fd5b600154600054600160a060020a0391821691167f0384899bd253d83b23daa4d29aaa2efe0563d1132b43101e9ad667235aeb951b60405160405180910390a350600180546000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905590565b600054600160a060020a031681565b60085460009060ff16151561144d57600080fd5b6114578233611c86565b151561146257600080fd5b506001919050565b600160a060020a033381166000908152600a60209081526040808320938516835292905290812054151561149d57600080fd5b600160a060020a033381166000908152600a602090815260408083209386168352929052206001015415156114d157600080fd5b600160a060020a033381166000818152600a602090815260408083209487168084529490915280822082815560018101839055600201919091557f4bc04e574b4f2b061a663b3328263978d3adeab9e4ea9526441c159cdee4eca8905160405180910390a3506001919050565b60408051908101604052600381527f4d45540000000000000000000000000000000000000000000000000000000000602082015281565b60045460009033600160a060020a03908116911614806115a3575060065433600160a060020a039081169116145b15156115ae57600080fd5b600160a060020a0383166000908152600360205260409020546115d7908363ffffffff611c7416565b600160a060020a038416600090815260036020526040902055600254611603908363ffffffff611c7416565b600255600160a060020a0383167f81325e2a6c442af9d36e4ee9697f38d5f4bf0837ade0f6c411c6a40af7c057ee8360405190815260200160405180910390a2600083600160a060020a03166000805160206120748339815191528460405190815260200160405180910390a350600192915050565b60096020526000908152604090205481565b60085460009060ff16151561169f57600080fd5b6116a98383611e24565b9392505050565b6000428410156116bf57600080fd5b8215156116cb57600080fd5b600160a060020a03821615156116e057600080fd5b606060405190810160409081528582526020808301869052818301879052600160a060020a033381166000908152600a8352838120918716815291522081518155602082015181600101556040820151816002015590505081600160a060020a031633600160a060020a03167f5c632ccb5c42002836e0c49ef1f6d67e925c5e77c1048ddbb47a9bf6a0f2d01260405160405180910390a35060019392505050565b60085460009060ff16151561179657600080fd5b61179f82611fb1565b92915050565b600080805b83518110156117e6576117d28482815181106117c257fe5b9060200190602002015133611c86565b156117de576001909101905b6001016117aa565b5092915050565b60005433600160a060020a0390811691161461180857600080fd5b600454600160a060020a03161580156118295750600160a060020a03841615155b151561183457600080fd5b600554600160a060020a03161580156118555750600160a060020a03831615155b151561186057600080fd5b60048054600160a060020a0380871673ffffffffffffffffffffffffffffffffffffffff199283161790925560058054928616929091169190911790556118ad828263ffffffff61203116565b6002819055600160a060020a03909416600090815260036020526040902093909355505050565b600a60209081526000928352604080842090915290825290208054600182015460029092015490919083565b600160a060020a039081166000908152600960205260408082205493909216815220541490565b600154600160a060020a031681565b600160a060020a033316600090815260096020526040902055565b600160a060020a03918216600090815260076020908152604080832093909416825291909152205490565b6000806000835185511461198f57600080fd5b5060009050805b84518110156119e7576119d38582815181106119ae57fe5b906020019060200201518583815181106119c457fe5b90602001906020020151611c86565b156119df576001909101905b600101611996565b509392505050565b600080600160a060020a0384161515611a0757600080fd5b600554600160a060020a03858116911614801590611a335750600554600160a060020a03868116911614155b1515611a3e57600080fd5b30600160a060020a031684600160a060020a031614158015611a72575030600160a060020a031685600160a060020a031614155b1515611a7d57600080fd5b600554600160a060020a03166355b5ec646040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611abc57600080fd5b5af11515611ac957600080fd5b50505060405180519050905080600160a060020a031684600160a060020a031614158015611b09575080600160a060020a031685600160a060020a031614155b1515611b1457600080fd5b600454600160a060020a0386811691161415611b2f57600080fd5b600160a060020a038086166000908152600760209081526040808320339094168352929052205483901015611b6357600080fd5b600160a060020a038516600090815260036020526040902054611b8c908463ffffffff611c7416565b600160a060020a038087166000908152600360205260408082209390935590861681522054611bc1908463ffffffff611c6516565b600160a060020a03808616600090815260036020908152604080832094909455888316825260078152838220339093168252919091522054611c09908463ffffffff611c7416565b600160a060020a03808716600081815260076020908152604080832033861684529091529081902093909355908616916000805160206120748339815191529086905190815260200160405180910390a3506001949350505050565b6000828201838110156116a957fe5b600082821115611c8057fe5b50900390565b600160a060020a038083166000908152600a6020908152604080832093851683529290529081208054829081908190118015611cc3575082544290105b8015611cd3575060008360010154115b15611e1657611d0262093a80611cf6856002015442611c7490919063ffffffff16565b9063ffffffff61205c16565b9150611d1b83600101548361203190919063ffffffff16565b9050600082118015611d465750600160a060020a038616600090815260036020526040902054819010155b15611e1657600160a060020a038087166000818152600a60209081526040808320948a1683529381528382204260029091015591815260039091522054611d93908263ffffffff611c7416565b600160a060020a038088166000908152600360205260408082209390935590871681522054611dc8908263ffffffff611c6516565b600160a060020a03808716600081815260036020526040908190209390935591908816906000805160206120748339815191529084905190815260200160405180910390a360019350611e1b565b600093505b50505092915050565b600080600160a060020a0384161515611e3c57600080fd5b600554600160a060020a0385811691161415611e5757600080fd5b30600160a060020a031684600160a060020a031614151515611e7857600080fd5b600454600160a060020a0385811691161415611e9357600080fd5b600554600160a060020a03166355b5ec646040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611ed257600080fd5b5af11515611edf57600080fd5b5050506040518051915050600160a060020a038481169082161415611f0357600080fd5b600160a060020a033316600090815260036020526040902054611f2c908463ffffffff611c7416565b600160a060020a033381166000908152600360205260408082209390935590861681522054611f61908463ffffffff611c6516565b600160a060020a0380861660008181526003602052604090819020939093559133909116906000805160206120748339815191529086905190815260200160405180910390a35060019392505050565b60008080805b8451831015612026576060858481518110611fce57fe5b906020019060200201519060020a90049150848381518110611fec57fe5b906020019060200201516bffffffffffffffffffffffff169050612010828261168b565b151561201b57600080fd5b600190920191611fb7565b506001949350505050565b60008083151561204457600091506117e6565b5082820282848281151561205457fe5b04146116a957fe5b600080828481151561206a57fe5b049493505050505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a7230582062ffa3d2c04263654dbffc8876e9fb51bf446bbfa2c43a5d01b62f8b0a66f1bb0029
Swarm Source
bzzr://62ffa3d2c04263654dbffc8876e9fb51bf446bbfa2c43a5d01b62f8b0a66f1bb
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.