More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 45 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Cntr | 9324379 | 1702 days ago | IN | 0 ETH | 0.00002305 | ||||
Withdraw Cntr | 9324356 | 1702 days ago | IN | 0 ETH | 0.00002242 | ||||
Create Order | 9324332 | 1702 days ago | IN | 0 ETH | 0.00030066 | ||||
Transfer From Ba... | 9324285 | 1702 days ago | IN | 0 ETH | 0.00004713 | ||||
Withdraw Cntr | 5999459 | 2251 days ago | IN | 0 ETH | 0.0001902 | ||||
Deposit Cntr | 5970567 | 2256 days ago | IN | 0.011 ETH | 0.0004315 | ||||
Withdraw Cntr | 5889191 | 2270 days ago | IN | 0 ETH | 0.00067131 | ||||
Cancel Order | 5889185 | 2270 days ago | IN | 0 ETH | 0.00133782 | ||||
Withdraw Cntr | 5889176 | 2270 days ago | IN | 0 ETH | 0.00069275 | ||||
Create Order | 5888850 | 2270 days ago | IN | 0 ETH | 0.00816502 | ||||
Deposit Cntr | 5888721 | 2270 days ago | IN | 0.03 ETH | 0.00130639 | ||||
Deposit Cntr | 5888671 | 2270 days ago | IN | 0.08 ETH | 0.00158511 | ||||
Withdraw Cntr | 5575477 | 2325 days ago | IN | 0 ETH | 0.00002244 | ||||
Cancel Order | 5575464 | 2325 days ago | IN | 0 ETH | 0.00004989 | ||||
Withdraw Cntr | 5575314 | 2325 days ago | IN | 0 ETH | 0.00002237 | ||||
Create Order | 5575301 | 2325 days ago | IN | 0 ETH | 0.00024809 | ||||
Cancel Order | 5575294 | 2325 days ago | IN | 0 ETH | 0.00003483 | ||||
Create Order | 5575283 | 2325 days ago | IN | 0 ETH | 0.00024803 | ||||
Deposit Cntr | 5575267 | 2325 days ago | IN | 0.107 ETH | 0.00004403 | ||||
Withdraw Cntr | 5060123 | 2412 days ago | IN | 0 ETH | 0.00044754 | ||||
Cancel Order | 5060096 | 2412 days ago | IN | 0 ETH | 0.00089188 | ||||
Create Order | 5000705 | 2422 days ago | IN | 0 ETH | 0.0049485 | ||||
Deposit Cntr | 5000667 | 2422 days ago | IN | 0.00804 ETH | 0.00058062 | ||||
Deposit Cntr | 5000640 | 2422 days ago | IN | 0.00201 ETH | 0.00180527 | ||||
Withdraw Cntr | 4994373 | 2423 days ago | IN | 0 ETH | 0.00046991 |
Latest 8 internal transactions
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xc36b7ce1...371921a69 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
BookERC20EthV1p1
Compiler Version
v0.4.11+commit.68ef5810
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2017-11-26 */ pragma solidity ^0.4.11; // NB: this is the newer ERC20 returning bool, need different book contract for older style tokens contract ERC20 { function totalSupply() constant returns (uint); function balanceOf(address _owner) constant returns (uint balance); function transfer(address _to, uint _value) returns (bool success); function transferFrom(address _from, address _to, uint _value) returns (bool success); function approve(address _spender, uint _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint remaining); event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); } // UbiTok.io on-chain continuous limit order book matching engine. // This variation is for a "nice" ERC20 token as base, ETH as quoted, and standard fees with reward token. // Copyright (c) Bonnag Limited. All Rights Reserved. // Version 1.1.0. // This contract allows minPriceExponent, baseMinInitialSize, and baseMinRemainingSize // to be set at init() time appropriately for the token decimals and likely value. // contract BookERC20EthV1p1 { enum BookType { ERC20EthV1 } enum Direction { Invalid, Buy, Sell } enum Status { Unknown, Rejected, Open, Done, NeedsGas, Sending, // not used by contract - web only FailedSend, // not used by contract - web only FailedTxn // not used by contract - web only } enum ReasonCode { None, InvalidPrice, InvalidSize, InvalidTerms, InsufficientFunds, WouldTake, Unmatched, TooManyMatches, ClientCancel } enum Terms { GTCNoGasTopup, GTCWithGasTopup, ImmediateOrCancel, MakerOnly } struct Order { // these are immutable once placed: address client; uint16 price; // packed representation of side + price uint sizeBase; Terms terms; // these are mutable until Done or Rejected: Status status; ReasonCode reasonCode; uint128 executedBase; // gross amount executed in base currency (before fee deduction) uint128 executedCntr; // gross amount executed in counter currency (before fee deduction) uint128 feesBaseOrCntr; // base for buy, cntr for sell uint128 feesRwrd; } struct OrderChain { uint128 firstOrderId; uint128 lastOrderId; } struct OrderChainNode { uint128 nextOrderId; uint128 prevOrderId; } // It should be possible to reconstruct the expected state of the contract given: // - ClientPaymentEvent log history // - ClientOrderEvent log history // - Calling getOrder for the other immutable order fields of orders referenced by ClientOrderEvent enum ClientPaymentEventType { Deposit, Withdraw, TransferFrom, Transfer } enum BalanceType { Base, Cntr, Rwrd } event ClientPaymentEvent( address indexed client, ClientPaymentEventType clientPaymentEventType, BalanceType balanceType, int clientBalanceDelta ); enum ClientOrderEventType { Create, Continue, Cancel } event ClientOrderEvent( address indexed client, ClientOrderEventType clientOrderEventType, uint128 orderId, uint maxMatches ); enum MarketOrderEventType { // orderCount++, depth += depthBase Add, // orderCount--, depth -= depthBase Remove, // orderCount--, depth -= depthBase, traded += tradeBase // (depth change and traded change differ when tiny remaining amount refunded) CompleteFill, // orderCount unchanged, depth -= depthBase, traded += tradeBase PartialFill } // Technically not needed but these events can be used to maintain an order book or // watch for fills. Note that the orderId and price are those of the maker. event MarketOrderEvent( uint256 indexed eventTimestamp, uint128 indexed orderId, MarketOrderEventType marketOrderEventType, uint16 price, uint depthBase, uint tradeBase ); // the base token (e.g. TEST) ERC20 baseToken; // minimum order size (inclusive) uint baseMinInitialSize; // set at init // if following partial match, the remaning gets smaller than this, remove from book and refund: // generally we make this 10% of baseMinInitialSize uint baseMinRemainingSize; // set at init // maximum order size (exclusive) // chosen so that even multiplied by the max price (or divided by the min price), // and then multiplied by ethRwrdRate, it still fits in 2^127, allowing us to save // some gas by storing executed + fee fields as uint128. // even with 18 decimals, this still allows order sizes up to 1,000,000,000. // if we encounter a token with e.g. 36 decimals we'll have to revisit ... uint constant baseMaxSize = 10 ** 30; // the counter currency (ETH) // (no address because it is ETH) // avoid the book getting cluttered up with tiny amounts not worth the gas uint constant cntrMinInitialSize = 10 finney; // see comments for baseMaxSize uint constant cntrMaxSize = 10 ** 30; // the reward token that can be used to pay fees (UBI) ERC20 rwrdToken; // set at init // used to convert ETH amount to reward tokens when paying fee with reward tokens uint constant ethRwrdRate = 1000; // funds that belong to clients (base, counter, and reward) mapping (address => uint) balanceBaseForClient; mapping (address => uint) balanceCntrForClient; mapping (address => uint) balanceRwrdForClient; // fee charged on liquidity taken, expressed as a divisor // (e.g. 2000 means 1/2000, or 0.05%) uint constant feeDivisor = 2000; // fees charged are given to: address feeCollector; // set at init // all orders ever created mapping (uint128 => Order) orderForOrderId; // Effectively a compact mapping from price to whether there are any open orders at that price. // See "Price Calculation Constants" below as to why 85. uint256[85] occupiedPriceBitmaps; // These allow us to walk over the orders in the book at a given price level (and add more). mapping (uint16 => OrderChain) orderChainForOccupiedPrice; mapping (uint128 => OrderChainNode) orderChainNodeForOpenOrderId; // These allow a client to (reasonably) efficiently find their own orders // without relying on events (which even indexed are a bit expensive to search // and cannot be accessed from smart contracts). See walkOrders. mapping (address => uint128) mostRecentOrderIdForClient; mapping (uint128 => uint128) clientPreviousOrderIdBeforeOrderId; // Price Calculation Constants. // // We pack direction and price into a crafty decimal floating point representation // for efficient indexing by price, the main thing we lose by doing so is precision - // we only have 3 significant figures in our prices. // // An unpacked price consists of: // // direction - invalid / buy / sell // mantissa - ranges from 100 to 999 representing 0.100 to 0.999 // exponent - ranges from minimumPriceExponent to minimumPriceExponent + 11 // (e.g. -5 to +6 for a typical pair where minPriceExponent = -5) // // The packed representation has 21601 different price values: // // 0 = invalid (can be used as marker value) // 1 = buy at maximum price (0.999 * 10 ** 6) // ... = other buy prices in descending order // 5400 = buy at 1.00 // ... = other buy prices in descending order // 10800 = buy at minimum price (0.100 * 10 ** -5) // 10801 = sell at minimum price (0.100 * 10 ** -5) // ... = other sell prices in descending order // 16201 = sell at 1.00 // ... = other sell prices in descending order // 21600 = sell at maximum price (0.999 * 10 ** 6) // 21601+ = do not use // // If we want to map each packed price to a boolean value (which we do), // we require 85 256-bit words. Or 42.5 for each side of the book. int8 minPriceExponent; // set at init uint constant invalidPrice = 0; // careful: max = largest unpacked value, not largest packed value uint constant maxBuyPrice = 1; uint constant minBuyPrice = 10800; uint constant minSellPrice = 10801; uint constant maxSellPrice = 21600; // Constructor. // // Sets feeCollector to the creator. Creator needs to call init() to finish setup. // function BookERC20EthV1p1() { address creator = msg.sender; feeCollector = creator; } // "Public" Management - set address of base and reward tokens. // // Can only be done once (normally immediately after creation) by the fee collector. // // Used instead of a constructor to make deployment easier. // // baseMinInitialSize is the minimum order size in token-wei; // the minimum resting size will be one tenth of that. // // minPriceExponent controls the range of prices supported by the contract; // the range will be 0.100*10**minPriceExponent to 0.999*10**(minPriceExponent + 11) // but careful; this is in token-wei : wei, ignoring the number of decimals of the token // e.g. -5 implies 1 token-wei worth between 0.100e-5 to 0.999e+6 wei // which implies same token:eth exchange rate if token decimals are 18 like eth, // but if token decimals are 8, that would imply 1 token worth 10 wei to 0.000999 ETH. // function init(ERC20 _baseToken, ERC20 _rwrdToken, uint _baseMinInitialSize, int8 _minPriceExponent) public { require(msg.sender == feeCollector); require(address(baseToken) == 0); require(address(_baseToken) != 0); require(address(rwrdToken) == 0); require(address(_rwrdToken) != 0); require(_baseMinInitialSize >= 10); require(_baseMinInitialSize < baseMaxSize / 1000000); require(_minPriceExponent >= -20 && _minPriceExponent <= 20); if (_minPriceExponent < 2) { require(_baseMinInitialSize >= 10 ** uint(3-int(minPriceExponent))); } baseMinInitialSize = _baseMinInitialSize; // dust prevention. truncation ok, know >= 10 baseMinRemainingSize = _baseMinInitialSize / 10; minPriceExponent = _minPriceExponent; // attempt to catch bad tokens: require(_baseToken.totalSupply() > 0); baseToken = _baseToken; require(_rwrdToken.totalSupply() > 0); rwrdToken = _rwrdToken; } // "Public" Management - change fee collector // // The new fee collector only gets fees charged after this point. // function changeFeeCollector(address newFeeCollector) public { address oldFeeCollector = feeCollector; require(msg.sender == oldFeeCollector); require(newFeeCollector != oldFeeCollector); feeCollector = newFeeCollector; } // Public Info View - what is being traded here, what are the limits? // function getBookInfo() public constant returns ( BookType _bookType, address _baseToken, address _rwrdToken, uint _baseMinInitialSize, uint _cntrMinInitialSize, int8 _minPriceExponent, uint _feeDivisor, address _feeCollector ) { return ( BookType.ERC20EthV1, address(baseToken), address(rwrdToken), baseMinInitialSize, // can assume min resting size is one tenth of this cntrMinInitialSize, minPriceExponent, feeDivisor, feeCollector ); } // Public Funds View - get balances held by contract on behalf of the client, // or balances approved for deposit but not yet claimed by the contract. // // Excludes funds in open orders. // // Helps a web ui get a consistent snapshot of balances. // // It would be nice to return the off-exchange ETH balance too but there's a // bizarre bug in geth (and apparently as a result via MetaMask) that leads // to unpredictable behaviour when looking up client balances in constant // functions - see e.g. https://github.com/ethereum/solidity/issues/2325 . // function getClientBalances(address client) public constant returns ( uint bookBalanceBase, uint bookBalanceCntr, uint bookBalanceRwrd, uint approvedBalanceBase, uint approvedBalanceRwrd, uint ownBalanceBase, uint ownBalanceRwrd ) { bookBalanceBase = balanceBaseForClient[client]; bookBalanceCntr = balanceCntrForClient[client]; bookBalanceRwrd = balanceRwrdForClient[client]; approvedBalanceBase = baseToken.allowance(client, address(this)); approvedBalanceRwrd = rwrdToken.allowance(client, address(this)); ownBalanceBase = baseToken.balanceOf(client); ownBalanceRwrd = rwrdToken.balanceOf(client); } // Public Funds Manipulation - deposit previously-approved base tokens. // function transferFromBase() public { address client = msg.sender; address book = address(this); // we trust the ERC20 token contract not to do nasty things like call back into us - // if we cannot trust the token then why are we allowing it to be traded? uint amountBase = baseToken.allowance(client, book); require(amountBase > 0); // NB: needs change for older ERC20 tokens that don't return bool require(baseToken.transferFrom(client, book, amountBase)); // belt and braces assert(baseToken.allowance(client, book) == 0); balanceBaseForClient[client] += amountBase; ClientPaymentEvent(client, ClientPaymentEventType.TransferFrom, BalanceType.Base, int(amountBase)); } // Public Funds Manipulation - withdraw base tokens (as a transfer). // function transferBase(uint amountBase) public { address client = msg.sender; require(amountBase > 0); require(amountBase <= balanceBaseForClient[client]); // overflow safe since we checked less than balance above balanceBaseForClient[client] -= amountBase; // we trust the ERC20 token contract not to do nasty things like call back into us - // if we cannot trust the token then why are we allowing it to be traded? // NB: needs change for older ERC20 tokens that don't return bool require(baseToken.transfer(client, amountBase)); ClientPaymentEvent(client, ClientPaymentEventType.Transfer, BalanceType.Base, -int(amountBase)); } // Public Funds Manipulation - deposit counter currency (ETH). // function depositCntr() public payable { address client = msg.sender; uint amountCntr = msg.value; require(amountCntr > 0); // overflow safe - if someone owns pow(2,255) ETH we have bigger problems balanceCntrForClient[client] += amountCntr; ClientPaymentEvent(client, ClientPaymentEventType.Deposit, BalanceType.Cntr, int(amountCntr)); } // Public Funds Manipulation - withdraw counter currency (ETH). // function withdrawCntr(uint amountCntr) public { address client = msg.sender; require(amountCntr > 0); require(amountCntr <= balanceCntrForClient[client]); // overflow safe - checked less than balance above balanceCntrForClient[client] -= amountCntr; // safe - not enough gas to do anything interesting in fallback, already adjusted balance client.transfer(amountCntr); ClientPaymentEvent(client, ClientPaymentEventType.Withdraw, BalanceType.Cntr, -int(amountCntr)); } // Public Funds Manipulation - deposit previously-approved reward tokens. // function transferFromRwrd() public { address client = msg.sender; address book = address(this); uint amountRwrd = rwrdToken.allowance(client, book); require(amountRwrd > 0); // we wrote the reward token so we know it supports ERC20 properly and is not evil require(rwrdToken.transferFrom(client, book, amountRwrd)); // belt and braces assert(rwrdToken.allowance(client, book) == 0); balanceRwrdForClient[client] += amountRwrd; ClientPaymentEvent(client, ClientPaymentEventType.TransferFrom, BalanceType.Rwrd, int(amountRwrd)); } // Public Funds Manipulation - withdraw base tokens (as a transfer). // function transferRwrd(uint amountRwrd) public { address client = msg.sender; require(amountRwrd > 0); require(amountRwrd <= balanceRwrdForClient[client]); // overflow safe - checked less than balance above balanceRwrdForClient[client] -= amountRwrd; // we wrote the reward token so we know it supports ERC20 properly and is not evil require(rwrdToken.transfer(client, amountRwrd)); ClientPaymentEvent(client, ClientPaymentEventType.Transfer, BalanceType.Rwrd, -int(amountRwrd)); } // Public Order View - get full details of an order. // // If the orderId does not exist, status will be Unknown. // function getOrder(uint128 orderId) public constant returns ( address client, uint16 price, uint sizeBase, Terms terms, Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr, uint feesBaseOrCntr, uint feesRwrd) { Order storage order = orderForOrderId[orderId]; return (order.client, order.price, order.sizeBase, order.terms, order.status, order.reasonCode, order.executedBase, order.executedCntr, order.feesBaseOrCntr, order.feesRwrd); } // Public Order View - get mutable details of an order. // // If the orderId does not exist, status will be Unknown. // function getOrderState(uint128 orderId) public constant returns ( Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr, uint feesBaseOrCntr, uint feesRwrd) { Order storage order = orderForOrderId[orderId]; return (order.status, order.reasonCode, order.executedBase, order.executedCntr, order.feesBaseOrCntr, order.feesRwrd); } // Public Order View - enumerate all recent orders + all open orders for one client. // // Not really designed for use from a smart contract transaction. // // Idea is: // - client ensures order ids are generated so that most-signficant part is time-based; // - client decides they want all orders after a certain point-in-time, // and chooses minClosedOrderIdCutoff accordingly; // - before that point-in-time they just get open and needs gas orders // - client calls walkClientOrders with maybeLastOrderIdReturned = 0 initially; // - then repeats with the orderId returned by walkClientOrders; // - (and stops if it returns a zero orderId); // // Note that client is only used when maybeLastOrderIdReturned = 0. // function walkClientOrders( address client, uint128 maybeLastOrderIdReturned, uint128 minClosedOrderIdCutoff ) public constant returns ( uint128 orderId, uint16 price, uint sizeBase, Terms terms, Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr, uint feesBaseOrCntr, uint feesRwrd) { if (maybeLastOrderIdReturned == 0) { orderId = mostRecentOrderIdForClient[client]; } else { orderId = clientPreviousOrderIdBeforeOrderId[maybeLastOrderIdReturned]; } while (true) { if (orderId == 0) return; Order storage order = orderForOrderId[orderId]; if (orderId >= minClosedOrderIdCutoff) break; if (order.status == Status.Open || order.status == Status.NeedsGas) break; orderId = clientPreviousOrderIdBeforeOrderId[orderId]; } return (orderId, order.price, order.sizeBase, order.terms, order.status, order.reasonCode, order.executedBase, order.executedCntr, order.feesBaseOrCntr, order.feesRwrd); } // Internal Price Calculation - turn packed price into a friendlier unpacked price. // function unpackPrice(uint16 price) internal constant returns ( Direction direction, uint16 mantissa, int8 exponent ) { uint sidedPriceIndex = uint(price); uint priceIndex; if (sidedPriceIndex < 1 || sidedPriceIndex > maxSellPrice) { direction = Direction.Invalid; mantissa = 0; exponent = 0; return; } else if (sidedPriceIndex <= minBuyPrice) { direction = Direction.Buy; priceIndex = minBuyPrice - sidedPriceIndex; } else { direction = Direction.Sell; priceIndex = sidedPriceIndex - minSellPrice; } uint zeroBasedMantissa = priceIndex % 900; uint zeroBasedExponent = priceIndex / 900; mantissa = uint16(zeroBasedMantissa + 100); exponent = int8(zeroBasedExponent) + minPriceExponent; return; } // Internal Price Calculation - is a packed price on the buy side? // // Throws an error if price is invalid. // function isBuyPrice(uint16 price) internal constant returns (bool isBuy) { // yes, this looks odd, but max here is highest _unpacked_ price return price >= maxBuyPrice && price <= minBuyPrice; } // Internal Price Calculation - turn a packed buy price into a packed sell price. // // Invalid price remains invalid. // function computeOppositePrice(uint16 price) internal constant returns (uint16 opposite) { if (price < maxBuyPrice || price > maxSellPrice) { return uint16(invalidPrice); } else if (price <= minBuyPrice) { return uint16(maxSellPrice - (price - maxBuyPrice)); } else { return uint16(maxBuyPrice + (maxSellPrice - price)); } } // Internal Price Calculation - compute amount in counter currency that would // be obtained by selling baseAmount at the given unpacked price (if no fees). // // Notes: // - Does not validate price - caller must ensure valid. // - Could overflow producing very unexpected results if baseAmount very // large - caller must check this. // - This rounds the amount towards zero. // - May truncate to zero if baseAmount very small - potentially allowing // zero-cost buys or pointless sales - caller must check this. // function computeCntrAmountUsingUnpacked( uint baseAmount, uint16 mantissa, int8 exponent ) internal constant returns (uint cntrAmount) { if (exponent < 0) { return baseAmount * uint(mantissa) / 1000 / 10 ** uint(-exponent); } else { return baseAmount * uint(mantissa) / 1000 * 10 ** uint(exponent); } } // Internal Price Calculation - compute amount in counter currency that would // be obtained by selling baseAmount at the given packed price (if no fees). // // Notes: // - Does not validate price - caller must ensure valid. // - Direction of the packed price is ignored. // - Could overflow producing very unexpected results if baseAmount very // large - caller must check this. // - This rounds the amount towards zero (regardless of Buy or Sell). // - May truncate to zero if baseAmount very small - potentially allowing // zero-cost buys or pointless sales - caller must check this. // function computeCntrAmountUsingPacked( uint baseAmount, uint16 price ) internal constant returns (uint) { var (, mantissa, exponent) = unpackPrice(price); return computeCntrAmountUsingUnpacked(baseAmount, mantissa, exponent); } // Public Order Placement - create order and try to match it and/or add it to the book. // function createOrder( uint128 orderId, uint16 price, uint sizeBase, Terms terms, uint maxMatches ) public { address client = msg.sender; require(orderId != 0 && orderForOrderId[orderId].client == 0); ClientOrderEvent(client, ClientOrderEventType.Create, orderId, maxMatches); orderForOrderId[orderId] = Order(client, price, sizeBase, terms, Status.Unknown, ReasonCode.None, 0, 0, 0, 0); uint128 previousMostRecentOrderIdForClient = mostRecentOrderIdForClient[client]; mostRecentOrderIdForClient[client] = orderId; clientPreviousOrderIdBeforeOrderId[orderId] = previousMostRecentOrderIdForClient; Order storage order = orderForOrderId[orderId]; var (direction, mantissa, exponent) = unpackPrice(price); if (direction == Direction.Invalid) { order.status = Status.Rejected; order.reasonCode = ReasonCode.InvalidPrice; return; } if (sizeBase < baseMinInitialSize || sizeBase > baseMaxSize) { order.status = Status.Rejected; order.reasonCode = ReasonCode.InvalidSize; return; } uint sizeCntr = computeCntrAmountUsingUnpacked(sizeBase, mantissa, exponent); if (sizeCntr < cntrMinInitialSize || sizeCntr > cntrMaxSize) { order.status = Status.Rejected; order.reasonCode = ReasonCode.InvalidSize; return; } if (terms == Terms.MakerOnly && maxMatches != 0) { order.status = Status.Rejected; order.reasonCode = ReasonCode.InvalidTerms; return; } if (!debitFunds(client, direction, sizeBase, sizeCntr)) { order.status = Status.Rejected; order.reasonCode = ReasonCode.InsufficientFunds; return; } processOrder(orderId, maxMatches); } // Public Order Placement - cancel order // function cancelOrder(uint128 orderId) public { address client = msg.sender; Order storage order = orderForOrderId[orderId]; require(order.client == client); Status status = order.status; if (status != Status.Open && status != Status.NeedsGas) { return; } ClientOrderEvent(client, ClientOrderEventType.Cancel, orderId, 0); if (status == Status.Open) { removeOpenOrderFromBook(orderId); MarketOrderEvent(block.timestamp, orderId, MarketOrderEventType.Remove, order.price, order.sizeBase - order.executedBase, 0); } refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.ClientCancel); } // Public Order Placement - continue placing an order in 'NeedsGas' state // function continueOrder(uint128 orderId, uint maxMatches) public { address client = msg.sender; Order storage order = orderForOrderId[orderId]; require(order.client == client); if (order.status != Status.NeedsGas) { return; } ClientOrderEvent(client, ClientOrderEventType.Continue, orderId, maxMatches); order.status = Status.Unknown; processOrder(orderId, maxMatches); } // Internal Order Placement - remove a still-open order from the book. // // Caller's job to update/refund the order + raise event, this just // updates the order chain and bitmask. // // Too expensive to do on each resting order match - we only do this for an // order being cancelled. See matchWithOccupiedPrice for similar logic. // function removeOpenOrderFromBook(uint128 orderId) internal { Order storage order = orderForOrderId[orderId]; uint16 price = order.price; OrderChain storage orderChain = orderChainForOccupiedPrice[price]; OrderChainNode storage orderChainNode = orderChainNodeForOpenOrderId[orderId]; uint128 nextOrderId = orderChainNode.nextOrderId; uint128 prevOrderId = orderChainNode.prevOrderId; if (nextOrderId != 0) { OrderChainNode storage nextOrderChainNode = orderChainNodeForOpenOrderId[nextOrderId]; nextOrderChainNode.prevOrderId = prevOrderId; } else { orderChain.lastOrderId = prevOrderId; } if (prevOrderId != 0) { OrderChainNode storage prevOrderChainNode = orderChainNodeForOpenOrderId[prevOrderId]; prevOrderChainNode.nextOrderId = nextOrderId; } else { orderChain.firstOrderId = nextOrderId; } if (nextOrderId == 0 && prevOrderId == 0) { uint bmi = price / 256; // index into array of bitmaps uint bti = price % 256; // bit position within bitmap // we know was previously occupied so XOR clears occupiedPriceBitmaps[bmi] ^= 2 ** bti; } } // Internal Order Placement - credit funds received when taking liquidity from book // function creditExecutedFundsLessFees(uint128 orderId, uint originalExecutedBase, uint originalExecutedCntr) internal { Order storage order = orderForOrderId[orderId]; uint liquidityTakenBase = order.executedBase - originalExecutedBase; uint liquidityTakenCntr = order.executedCntr - originalExecutedCntr; // Normally we deduct the fee from the currency bought (base for buy, cntr for sell), // however we also accept reward tokens from the reward balance if it covers the fee, // with the reward amount converted from the ETH amount (the counter currency here) // at a fixed exchange rate. // Overflow safe since we ensure order size < 10^30 in both currencies (see baseMaxSize). // Can truncate to zero, which is fine. uint feesRwrd = liquidityTakenCntr / feeDivisor * ethRwrdRate; uint feesBaseOrCntr; address client = order.client; uint availRwrd = balanceRwrdForClient[client]; if (feesRwrd <= availRwrd) { balanceRwrdForClient[client] = availRwrd - feesRwrd; balanceRwrdForClient[feeCollector] = feesRwrd; // Need += rather than = because could have paid some fees earlier in NeedsGas situation. // Overflow safe since we ensure order size < 10^30 in both currencies (see baseMaxSize). // Can truncate to zero, which is fine. order.feesRwrd += uint128(feesRwrd); if (isBuyPrice(order.price)) { balanceBaseForClient[client] += liquidityTakenBase; } else { balanceCntrForClient[client] += liquidityTakenCntr; } } else if (isBuyPrice(order.price)) { // See comments in branch above re: use of += and overflow safety. feesBaseOrCntr = liquidityTakenBase / feeDivisor; balanceBaseForClient[order.client] += (liquidityTakenBase - feesBaseOrCntr); order.feesBaseOrCntr += uint128(feesBaseOrCntr); balanceBaseForClient[feeCollector] += feesBaseOrCntr; } else { // See comments in branch above re: use of += and overflow safety. feesBaseOrCntr = liquidityTakenCntr / feeDivisor; balanceCntrForClient[order.client] += (liquidityTakenCntr - feesBaseOrCntr); order.feesBaseOrCntr += uint128(feesBaseOrCntr); balanceCntrForClient[feeCollector] += feesBaseOrCntr; } } // Internal Order Placement - process a created and sanity checked order. // // Used both for new orders and for gas topup. // function processOrder(uint128 orderId, uint maxMatches) internal { Order storage order = orderForOrderId[orderId]; uint ourOriginalExecutedBase = order.executedBase; uint ourOriginalExecutedCntr = order.executedCntr; var (ourDirection,) = unpackPrice(order.price); uint theirPriceStart = (ourDirection == Direction.Buy) ? minSellPrice : maxBuyPrice; uint theirPriceEnd = computeOppositePrice(order.price); MatchStopReason matchStopReason = matchAgainstBook(orderId, theirPriceStart, theirPriceEnd, maxMatches); creditExecutedFundsLessFees(orderId, ourOriginalExecutedBase, ourOriginalExecutedCntr); if (order.terms == Terms.ImmediateOrCancel) { if (matchStopReason == MatchStopReason.Satisfied) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None); return; } else if (matchStopReason == MatchStopReason.MaxMatches) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.TooManyMatches); return; } else if (matchStopReason == MatchStopReason.BookExhausted) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.Unmatched); return; } } else if (order.terms == Terms.MakerOnly) { if (matchStopReason == MatchStopReason.MaxMatches) { refundUnmatchedAndFinish(orderId, Status.Rejected, ReasonCode.WouldTake); return; } else if (matchStopReason == MatchStopReason.BookExhausted) { enterOrder(orderId); return; } } else if (order.terms == Terms.GTCNoGasTopup) { if (matchStopReason == MatchStopReason.Satisfied) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None); return; } else if (matchStopReason == MatchStopReason.MaxMatches) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.TooManyMatches); return; } else if (matchStopReason == MatchStopReason.BookExhausted) { enterOrder(orderId); return; } } else if (order.terms == Terms.GTCWithGasTopup) { if (matchStopReason == MatchStopReason.Satisfied) { refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None); return; } else if (matchStopReason == MatchStopReason.MaxMatches) { order.status = Status.NeedsGas; return; } else if (matchStopReason == MatchStopReason.BookExhausted) { enterOrder(orderId); return; } } assert(false); // should not be possible to reach here } // Used internally to indicate why we stopped matching an order against the book. enum MatchStopReason { None, MaxMatches, Satisfied, PriceExhausted, BookExhausted } // Internal Order Placement - Match the given order against the book. // // Resting orders matched will be updated, removed from book and funds credited to their owners. // // Only updates the executedBase and executedCntr of the given order - caller is responsible // for crediting matched funds, charging fees, marking order as done / entering it into the book. // // matchStopReason returned will be one of MaxMatches, Satisfied or BookExhausted. // // Calling with maxMatches == 0 is ok - and expected when the order is a maker-only order. // function matchAgainstBook( uint128 orderId, uint theirPriceStart, uint theirPriceEnd, uint maxMatches ) internal returns ( MatchStopReason matchStopReason ) { Order storage order = orderForOrderId[orderId]; uint bmi = theirPriceStart / 256; // index into array of bitmaps uint bti = theirPriceStart % 256; // bit position within bitmap uint bmiEnd = theirPriceEnd / 256; // last bitmap to search uint btiEnd = theirPriceEnd % 256; // stop at this bit in the last bitmap uint cbm = occupiedPriceBitmaps[bmi]; // original copy of current bitmap uint dbm = cbm; // dirty version of current bitmap where we may have cleared bits uint wbm = cbm >> bti; // working copy of current bitmap which we keep shifting // these loops are pretty ugly, and somewhat unpredicatable in terms of gas, // ... but no-one else has come up with a better matching engine yet! bool removedLastAtPrice; matchStopReason = MatchStopReason.None; while (bmi < bmiEnd) { if (wbm == 0 || bti == 256) { if (dbm != cbm) { occupiedPriceBitmaps[bmi] = dbm; } bti = 0; bmi++; cbm = occupiedPriceBitmaps[bmi]; wbm = cbm; dbm = cbm; } else { if ((wbm & 1) != 0) { // careful - copy-and-pasted in loop below ... (removedLastAtPrice, maxMatches, matchStopReason) = matchWithOccupiedPrice(order, uint16(bmi * 256 + bti), maxMatches); if (removedLastAtPrice) { dbm ^= 2 ** bti; } if (matchStopReason == MatchStopReason.PriceExhausted) { matchStopReason = MatchStopReason.None; } else if (matchStopReason != MatchStopReason.None) { // we might still have changes in dbm to write back - see later break; } } bti += 1; wbm /= 2; } } if (matchStopReason == MatchStopReason.None) { // we've reached the last bitmap we need to search, // we'll stop at btiEnd not 256 this time. while (bti <= btiEnd && wbm != 0) { if ((wbm & 1) != 0) { // careful - copy-and-pasted in loop above ... (removedLastAtPrice, maxMatches, matchStopReason) = matchWithOccupiedPrice(order, uint16(bmi * 256 + bti), maxMatches); if (removedLastAtPrice) { dbm ^= 2 ** bti; } if (matchStopReason == MatchStopReason.PriceExhausted) { matchStopReason = MatchStopReason.None; } else if (matchStopReason != MatchStopReason.None) { break; } } bti += 1; wbm /= 2; } } // Careful - if we exited the first loop early, or we went into the second loop, // (luckily can't both happen) then we haven't flushed the dirty bitmap back to // storage - do that now if we need to. if (dbm != cbm) { occupiedPriceBitmaps[bmi] = dbm; } if (matchStopReason == MatchStopReason.None) { matchStopReason = MatchStopReason.BookExhausted; } } // Internal Order Placement. // // Match our order against up to maxMatches resting orders at the given price (which // is known by the caller to have at least one resting order). // // The matches (partial or complete) of the resting orders are recorded, and their // funds are credited. // // The order chain for the resting orders is updated, but the occupied price bitmap is NOT - // the caller must clear the relevant bit if removedLastAtPrice = true is returned. // // Only updates the executedBase and executedCntr of our order - caller is responsible // for e.g. crediting our matched funds, updating status. // // Calling with maxMatches == 0 is ok - and expected when the order is a maker-only order. // // Returns: // removedLastAtPrice: // true iff there are no longer any resting orders at this price - caller will need // to update the occupied price bitmap. // // matchesLeft: // maxMatches passed in minus the number of matches made by this call // // matchStopReason: // If our order is completely matched, matchStopReason will be Satisfied. // If our order is not completely matched, matchStopReason will be either: // MaxMatches (we are not allowed to match any more times) // or: // PriceExhausted (nothing left on the book at this exact price) // function matchWithOccupiedPrice( Order storage ourOrder, uint16 theirPrice, uint maxMatches ) internal returns ( bool removedLastAtPrice, uint matchesLeft, MatchStopReason matchStopReason) { matchesLeft = maxMatches; uint workingOurExecutedBase = ourOrder.executedBase; uint workingOurExecutedCntr = ourOrder.executedCntr; uint128 theirOrderId = orderChainForOccupiedPrice[theirPrice].firstOrderId; matchStopReason = MatchStopReason.None; while (true) { if (matchesLeft == 0) { matchStopReason = MatchStopReason.MaxMatches; break; } uint matchBase; uint matchCntr; (theirOrderId, matchBase, matchCntr, matchStopReason) = matchWithTheirs((ourOrder.sizeBase - workingOurExecutedBase), theirOrderId, theirPrice); workingOurExecutedBase += matchBase; workingOurExecutedCntr += matchCntr; matchesLeft -= 1; if (matchStopReason != MatchStopReason.None) { break; } } ourOrder.executedBase = uint128(workingOurExecutedBase); ourOrder.executedCntr = uint128(workingOurExecutedCntr); if (theirOrderId == 0) { orderChainForOccupiedPrice[theirPrice].firstOrderId = 0; orderChainForOccupiedPrice[theirPrice].lastOrderId = 0; removedLastAtPrice = true; } else { // NB: in some cases (e.g. maxMatches == 0) this is a no-op. orderChainForOccupiedPrice[theirPrice].firstOrderId = theirOrderId; orderChainNodeForOpenOrderId[theirOrderId].prevOrderId = 0; removedLastAtPrice = false; } } // Internal Order Placement. // // Match up to our remaining amount against a resting order in the book. // // The match (partial, complete or effectively-complete) of the resting order // is recorded, and their funds are credited. // // Their order is NOT removed from the book by this call - the caller must do that // if the nextTheirOrderId returned is not equal to the theirOrderId passed in. // // Returns: // // nextTheirOrderId: // If we did not completely match their order, will be same as theirOrderId. // If we completely matched their order, will be orderId of next order at the // same price - or zero if this was the last order and we've now filled it. // // matchStopReason: // If our order is completely matched, matchStopReason will be Satisfied. // If our order is not completely matched, matchStopReason will be either // PriceExhausted (if nothing left at this exact price) or None (if can continue). // function matchWithTheirs( uint ourRemainingBase, uint128 theirOrderId, uint16 theirPrice) internal returns ( uint128 nextTheirOrderId, uint matchBase, uint matchCntr, MatchStopReason matchStopReason) { Order storage theirOrder = orderForOrderId[theirOrderId]; uint theirRemainingBase = theirOrder.sizeBase - theirOrder.executedBase; if (ourRemainingBase < theirRemainingBase) { matchBase = ourRemainingBase; } else { matchBase = theirRemainingBase; } matchCntr = computeCntrAmountUsingPacked(matchBase, theirPrice); // It may seem a bit odd to stop here if our remaining amount is very small - // there could still be resting orders we can match it against. But the gas // cost of matching each order is quite high - potentially high enough to // wipe out the profit the taker hopes for from trading the tiny amount left. if ((ourRemainingBase - matchBase) < baseMinRemainingSize) { matchStopReason = MatchStopReason.Satisfied; } else { matchStopReason = MatchStopReason.None; } bool theirsDead = recordTheirMatch(theirOrder, theirOrderId, theirPrice, matchBase, matchCntr); if (theirsDead) { nextTheirOrderId = orderChainNodeForOpenOrderId[theirOrderId].nextOrderId; if (matchStopReason == MatchStopReason.None && nextTheirOrderId == 0) { matchStopReason = MatchStopReason.PriceExhausted; } } else { nextTheirOrderId = theirOrderId; } } // Internal Order Placement. // // Record match (partial or complete) of resting order, and credit them their funds. // // If their order is completely matched, the order is marked as done, // and "theirsDead" is returned as true. // // The order is NOT removed from the book by this call - the caller // must do that if theirsDead is true. // // No sanity checks are made - the caller must be sure the order is // not already done and has sufficient remaining. (Yes, we'd like to // check here too but we cannot afford the gas). // function recordTheirMatch( Order storage theirOrder, uint128 theirOrderId, uint16 theirPrice, uint matchBase, uint matchCntr ) internal returns (bool theirsDead) { // they are a maker so no fees // overflow safe - see comments about baseMaxSize // executedBase cannot go > sizeBase due to logic in matchWithTheirs theirOrder.executedBase += uint128(matchBase); theirOrder.executedCntr += uint128(matchCntr); if (isBuyPrice(theirPrice)) { // they have bought base (using the counter they already paid when creating the order) balanceBaseForClient[theirOrder.client] += matchBase; } else { // they have bought counter (using the base they already paid when creating the order) balanceCntrForClient[theirOrder.client] += matchCntr; } uint stillRemainingBase = theirOrder.sizeBase - theirOrder.executedBase; // avoid leaving tiny amounts in the book - refund remaining if too small if (stillRemainingBase < baseMinRemainingSize) { refundUnmatchedAndFinish(theirOrderId, Status.Done, ReasonCode.None); // someone building an UI on top needs to know how much was match and how much was refund MarketOrderEvent(block.timestamp, theirOrderId, MarketOrderEventType.CompleteFill, theirPrice, matchBase + stillRemainingBase, matchBase); return true; } else { MarketOrderEvent(block.timestamp, theirOrderId, MarketOrderEventType.PartialFill, theirPrice, matchBase, matchBase); return false; } } // Internal Order Placement. // // Refund any unmatched funds in an order (based on executed vs size) and move to a final state. // // The order is NOT removed from the book by this call and no event is raised. // // No sanity checks are made - the caller must be sure the order has not already been refunded. // function refundUnmatchedAndFinish(uint128 orderId, Status status, ReasonCode reasonCode) internal { Order storage order = orderForOrderId[orderId]; uint16 price = order.price; if (isBuyPrice(price)) { uint sizeCntr = computeCntrAmountUsingPacked(order.sizeBase, price); balanceCntrForClient[order.client] += sizeCntr - order.executedCntr; } else { balanceBaseForClient[order.client] += order.sizeBase - order.executedBase; } order.status = status; order.reasonCode = reasonCode; } // Internal Order Placement. // // Enter a not completely matched order into the book, marking the order as open. // // This updates the occupied price bitmap and chain. // // No sanity checks are made - the caller must be sure the order // has some unmatched amount and has been paid for! // function enterOrder(uint128 orderId) internal { Order storage order = orderForOrderId[orderId]; uint16 price = order.price; OrderChain storage orderChain = orderChainForOccupiedPrice[price]; OrderChainNode storage orderChainNode = orderChainNodeForOpenOrderId[orderId]; if (orderChain.firstOrderId == 0) { orderChain.firstOrderId = orderId; orderChain.lastOrderId = orderId; orderChainNode.nextOrderId = 0; orderChainNode.prevOrderId = 0; uint bitmapIndex = price / 256; uint bitIndex = price % 256; occupiedPriceBitmaps[bitmapIndex] |= (2 ** bitIndex); } else { uint128 existingLastOrderId = orderChain.lastOrderId; OrderChainNode storage existingLastOrderChainNode = orderChainNodeForOpenOrderId[existingLastOrderId]; orderChainNode.nextOrderId = 0; orderChainNode.prevOrderId = existingLastOrderId; existingLastOrderChainNode.nextOrderId = orderId; orderChain.lastOrderId = orderId; } MarketOrderEvent(block.timestamp, orderId, MarketOrderEventType.Add, price, order.sizeBase - order.executedBase, 0); order.status = Status.Open; } // Internal Order Placement. // // Charge the client for the cost of placing an order in the given direction. // // Return true if successful, false otherwise. // function debitFunds( address client, Direction direction, uint sizeBase, uint sizeCntr ) internal returns (bool success) { if (direction == Direction.Buy) { uint availableCntr = balanceCntrForClient[client]; if (availableCntr < sizeCntr) { return false; } balanceCntrForClient[client] = availableCntr - sizeCntr; return true; } else if (direction == Direction.Sell) { uint availableBase = balanceBaseForClient[client]; if (availableBase < sizeBase) { return false; } balanceBaseForClient[client] = availableBase - sizeBase; return true; } else { return false; } } // Public Book View // // Intended for public book depth enumeration from web3 (or similar). // // Not suitable for use from a smart contract transaction - gas usage // could be very high if we have many orders at the same price. // // Start at the given inclusive price (and side) and walk down the book // (getting less aggressive) until we find some open orders or reach the // least aggressive price. // // Returns the price where we found the order(s), the depth at that price // (zero if none found), order count there, and the current blockNumber. // // (The blockNumber is handy if you're taking a snapshot which you intend // to keep up-to-date with the market order events). // // To walk the book, the caller should start by calling walkBook with the // most aggressive buy price (Buy @ 999000). // If the price returned is the least aggressive buy price (Buy @ 0.000001), // the side is complete. // Otherwise, call walkBook again with the (packed) price returned + 1. // Then repeat for the sell side, starting with Sell @ 0.000001 and stopping // when Sell @ 999000 is returned. // function walkBook(uint16 fromPrice) public constant returns ( uint16 price, uint depthBase, uint orderCount, uint blockNumber ) { uint priceStart = fromPrice; uint priceEnd = (isBuyPrice(fromPrice)) ? minBuyPrice : maxSellPrice; // See comments in matchAgainstBook re: how these crazy loops work. uint bmi = priceStart / 256; uint bti = priceStart % 256; uint bmiEnd = priceEnd / 256; uint btiEnd = priceEnd % 256; uint wbm = occupiedPriceBitmaps[bmi] >> bti; while (bmi < bmiEnd) { if (wbm == 0 || bti == 256) { bti = 0; bmi++; wbm = occupiedPriceBitmaps[bmi]; } else { if ((wbm & 1) != 0) { // careful - copy-pasted in below loop price = uint16(bmi * 256 + bti); (depthBase, orderCount) = sumDepth(orderChainForOccupiedPrice[price].firstOrderId); return (price, depthBase, orderCount, block.number); } bti += 1; wbm /= 2; } } // we've reached the last bitmap we need to search, stop at btiEnd not 256 this time. while (bti <= btiEnd && wbm != 0) { if ((wbm & 1) != 0) { // careful - copy-pasted in above loop price = uint16(bmi * 256 + bti); (depthBase, orderCount) = sumDepth(orderChainForOccupiedPrice[price].firstOrderId); return (price, depthBase, orderCount, block.number); } bti += 1; wbm /= 2; } return (uint16(priceEnd), 0, 0, block.number); } // Internal Book View. // // See walkBook - adds up open depth at a price starting from an // order which is assumed to be open. Careful - unlimited gas use. // function sumDepth(uint128 orderId) internal constant returns (uint depth, uint orderCount) { while (true) { Order storage order = orderForOrderId[orderId]; depth += order.sizeBase - order.executedBase; orderCount++; orderId = orderChainNodeForOpenOrderId[orderId].nextOrderId; if (orderId == 0) { return (depth, orderCount); } } } } // helper for automating book creation contract BookERC20EthV1p1Factory { event BookCreated (address bookAddress); function BookERC20EthV1p1Factory() { } function createBook(ERC20 _baseToken, ERC20 _rwrdToken, address _feeCollector, uint _baseMinInitialSize, int8 _minPriceExponent) public { BookERC20EthV1p1 book = new BookERC20EthV1p1(); book.init(_baseToken, _rwrdToken, _baseMinInitialSize, _minPriceExponent); book.changeFeeCollector(_feeCollector); BookCreated(address(book)); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"fromPrice","type":"uint16"}],"name":"walkBook","outputs":[{"name":"price","type":"uint16"},{"name":"depthBase","type":"uint256"},{"name":"orderCount","type":"uint256"},{"name":"blockNumber","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"orderId","type":"uint128"}],"name":"getOrder","outputs":[{"name":"client","type":"address"},{"name":"price","type":"uint16"},{"name":"sizeBase","type":"uint256"},{"name":"terms","type":"uint8"},{"name":"status","type":"uint8"},{"name":"reasonCode","type":"uint8"},{"name":"executedBase","type":"uint256"},{"name":"executedCntr","type":"uint256"},{"name":"feesBaseOrCntr","type":"uint256"},{"name":"feesRwrd","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"amountCntr","type":"uint256"}],"name":"withdrawCntr","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getBookInfo","outputs":[{"name":"_bookType","type":"uint8"},{"name":"_baseToken","type":"address"},{"name":"_rwrdToken","type":"address"},{"name":"_baseMinInitialSize","type":"uint256"},{"name":"_cntrMinInitialSize","type":"uint256"},{"name":"_minPriceExponent","type":"int8"},{"name":"_feeDivisor","type":"uint256"},{"name":"_feeCollector","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"orderId","type":"uint128"}],"name":"getOrderState","outputs":[{"name":"status","type":"uint8"},{"name":"reasonCode","type":"uint8"},{"name":"executedBase","type":"uint256"},{"name":"executedCntr","type":"uint256"},{"name":"feesBaseOrCntr","type":"uint256"},{"name":"feesRwrd","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"amountBase","type":"uint256"}],"name":"transferBase","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_baseToken","type":"address"},{"name":"_rwrdToken","type":"address"},{"name":"_baseMinInitialSize","type":"uint256"},{"name":"_minPriceExponent","type":"int8"}],"name":"init","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"amountRwrd","type":"uint256"}],"name":"transferRwrd","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"depositCntr","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[],"name":"transferFromBase","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"client","type":"address"}],"name":"getClientBalances","outputs":[{"name":"bookBalanceBase","type":"uint256"},{"name":"bookBalanceCntr","type":"uint256"},{"name":"bookBalanceRwrd","type":"uint256"},{"name":"approvedBalanceBase","type":"uint256"},{"name":"approvedBalanceRwrd","type":"uint256"},{"name":"ownBalanceBase","type":"uint256"},{"name":"ownBalanceRwrd","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newFeeCollector","type":"address"}],"name":"changeFeeCollector","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"transferFromRwrd","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"client","type":"address"},{"name":"maybeLastOrderIdReturned","type":"uint128"},{"name":"minClosedOrderIdCutoff","type":"uint128"}],"name":"walkClientOrders","outputs":[{"name":"orderId","type":"uint128"},{"name":"price","type":"uint16"},{"name":"sizeBase","type":"uint256"},{"name":"terms","type":"uint8"},{"name":"status","type":"uint8"},{"name":"reasonCode","type":"uint8"},{"name":"executedBase","type":"uint256"},{"name":"executedCntr","type":"uint256"},{"name":"feesBaseOrCntr","type":"uint256"},{"name":"feesRwrd","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"orderId","type":"uint128"},{"name":"price","type":"uint16"},{"name":"sizeBase","type":"uint256"},{"name":"terms","type":"uint8"},{"name":"maxMatches","type":"uint256"}],"name":"createOrder","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"orderId","type":"uint128"},{"name":"maxMatches","type":"uint256"}],"name":"continueOrder","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"orderId","type":"uint128"}],"name":"cancelOrder","outputs":[],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"client","type":"address"},{"indexed":false,"name":"clientPaymentEventType","type":"uint8"},{"indexed":false,"name":"balanceType","type":"uint8"},{"indexed":false,"name":"clientBalanceDelta","type":"int256"}],"name":"ClientPaymentEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"client","type":"address"},{"indexed":false,"name":"clientOrderEventType","type":"uint8"},{"indexed":false,"name":"orderId","type":"uint128"},{"indexed":false,"name":"maxMatches","type":"uint256"}],"name":"ClientOrderEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"eventTimestamp","type":"uint256"},{"indexed":true,"name":"orderId","type":"uint128"},{"indexed":false,"name":"marketOrderEventType","type":"uint8"},{"indexed":false,"name":"price","type":"uint16"},{"indexed":false,"name":"depthBase","type":"uint256"},{"indexed":false,"name":"tradeBase","type":"uint256"}],"name":"MarketOrderEvent","type":"event"}]
Deployed Bytecode
0x606060405236156100ee5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166303adcbd281146100f0578063117d412814610132578063199f0791146101db57806322ea2d96146101f057806331f9a2111461026a5780633c13fc33146102db5780633e325589146102f05780634dc7d31b1461031d578063604451421461033257806361ea6ed71461033c5780636f03e4f91461034e5780639245290d146103a2578063929ba8bf146103c0578063a87d8b6b146103d2578063bbec37681461048d578063bd5acbd6146104be578063dbc91396146104df575bfe5b34156100f857fe5b61010761ffff600435166104fd565b6040805161ffff90951685526020850193909352838301919091526060830152519081900360800190f35b341561013a57fe5b61014e6001608060020a036004351661068a565b60408051600160a060020a038c16815261ffff8b1660208201529081018990526060810188600381111561017e57fe5b60ff16815260200187600781111561019257fe5b60ff1681526020018660088111156101a657fe5b60ff1681526020018581526020018481526020018381526020018281526020019a505050505050505050505060405180910390f35b34156101e357fe5b6101ee600435610716565b005b34156101f857fe5b6102006107ef565b6040518089600081111561021057fe5b60ff168152600160a060020a0398891660208201529688166040808901919091526060880196909652506080860193909352600091820b90910b60a085015260c084015290921660e0820152905190819003610100019150f35b341561027257fe5b6102866001608060020a036004351661082b565b6040518087600781111561029657fe5b60ff1681526020018660088111156102aa57fe5b60ff168152602001858152602001848152602001838152602001828152602001965050505050505060405180910390f35b34156102e357fe5b6101ee60043561088f565b005b34156102f857fe5b6101ee600160a060020a036004358116906024351660443560643560000b6109d3565b005b341561032557fe5b6101ee600435610c43565b005b6101ee610d84565b005b341561034457fe5b6101ee610e05565b005b341561035657fe5b61036a600160a060020a036004351661100e565b604080519788526020880196909652868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34156103aa57fe5b6101ee600160a060020a0360043516611231565b005b34156103c857fe5b6101ee611295565b005b34156103da57fe5b610400600160a060020a03600435166001608060020a03602435811690604435166114ab565b604080516001608060020a038c16815261ffff8b1660208201529081018990526060810188600381111561017e57fe5b60ff16815260200187600781111561019257fe5b60ff1681526020018660088111156101a657fe5b60ff1681526020018581526020018481526020018381526020018281526020019a505050505050505050505060405180910390f35b341561049557fe5b6101ee6001608060020a036004351661ffff6024351660443560ff60643516608435611632565b005b34156104c657fe5b6101ee6001608060020a0360043516602435611c01565b005b34156104e757fe5b6101ee6001608060020a0360043516611cee565b005b600080808061ffff85168180808080806105168c611e7c565b61052257615460610526565b612a305b9550610100875b049450610100875b069350610100865b049250610100865b069150836009866055811061055657fe5b0160005b50549060020a900490505b828510156105fe5780158061057b575083610100145b156105a457600190940193600093506009856055811061059757fe5b0160005b505490506105f9565b60018116156105ea576101008502840161ffff81166000908152605e6020526040902054909b506105dd906001608060020a0316611ea1565b909a50985043975061067c565b600193909301926002815b0490505b610565565b5b81841115801561060e57508015155b1561066c576001811615610659576101008502840161ffff81166000908152605e6020526040902054909b506105dd906001608060020a0316611ea1565b909a50985043975061067c565b600193909301926002815b0490506105fe565b9499506000985088975043965089945b505050505050509193509193565b6001608060020a03818116600090815260086020526040902080546001820154600283015460038401546004850154600160a060020a0385169660a060020a90950461ffff1695939460ff80851695610100860482169562010000810490921694630100000090920483169382841693608060020a90930483169216905b509193959799509193959799565b33600082116107255760006000fd5b600160a060020a03811660009081526005602052604090205482111561074b5760006000fd5b600160a060020a038116600081815260056020526040808220805486900390555184156108fc0291859190818181858888f19350505050151561078a57fe5b80600160a060020a03166000805160206130d08339815191526001600185600003604051808460038111156107bb57fe5b60ff1681526020018360028111156107cf57fe5b60ff168152602001828152602001935050505060405180910390a25b5050565b60008054600354600154606254600754600160a060020a039485169493841693662386f26fc1000092870b916107d091165b9091929394959697565b6001608060020a03808216600090815260086020526040902060028101546003820154600483015460ff610100840481169562010000850490911694630100000090940481169383821693608060020a9004821692909116905b5091939550919395565b336000821161089e5760006000fd5b600160a060020a0381166000908152600460205260409020548211156108c45760006000fd5b600160a060020a0380821660008181526004602081815260408084208054899003905583548151830185905281517fa9059cbb000000000000000000000000000000000000000000000000000000008152938401959095526024830188905251939094169363a9059cbb9360448084019492939192918390030190829087803b151561094c57fe5b6102c65a03f1151561095a57fe5b5050604051511515905061096e5760006000fd5b80600160a060020a03166000805160206130d08339815191526003600085600003604051808460038111156107bb57fe5b60ff1681526020018360028111156107cf57fe5b60ff168152602001828152602001935050505060405180910390a25b5050565b60075433600160a060020a039081169116146109ef5760006000fd5b600054600160a060020a031615610a065760006000fd5b600160a060020a0384161515610a1c5760006000fd5b600354600160a060020a031615610a335760006000fd5b600160a060020a0383161515610a495760006000fd5b600a821015610a585760006000fd5b620f42406c0c9f2c9cd04674edea400000005b048210610a785760006000fd5b6013198160000b12158015610a91575060148160000b13155b1515610a9d5760006000fd5b60028160000b1215610ac657606254600090810b900b600303600a0a821015610ac65760006000fd5b5b6001829055600a825b0460025560628054600083810b60ff1660ff199092169190911790915560408051602090810183905281517f18160ddd0000000000000000000000000000000000000000000000000000000081529151600160a060020a038816926318160ddd92600480830193919282900301818787803b1515610b4a57fe5b6102c65a03f11515610b5857fe5b505060405151919091119050610b6e5760006000fd5b6000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0386811691909117825560408051602090810184905281517f18160ddd0000000000000000000000000000000000000000000000000000000081529151928716926318160ddd92600480820193929182900301818787803b1515610bf057fe5b6102c65a03f11515610bfe57fe5b505060405151919091119050610c145760006000fd5b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0385161790555b50505050565b3360008211610c525760006000fd5b600160a060020a038116600090815260066020526040902054821115610c785760006000fd5b600160a060020a038082166000818152600660209081526040808320805488900390556003548151830184905281517fa9059cbb000000000000000000000000000000000000000000000000000000008152600481019590955260248501889052905194169363a9059cbb93604480820194918390030190829087803b1515610cfd57fe5b6102c65a03f11515610d0b57fe5b50506040515115159050610d1f5760006000fd5b80600160a060020a03166000805160206130d08339815191526003600285600003604051808460038111156107bb57fe5b60ff1681526020018360028111156107cf57fe5b60ff168152602001828152602001935050505060405180910390a25b5050565b333460008111610d945760006000fd5b600160a060020a038216600081815260056020526040808220805485019055516000805160206130d08339815191529190600190859080846107bb565b60ff1681526020018360028111156107cf57fe5b60ff168152602001828152602001935050505060405180910390a25b5050565b60008054604080516020908101849052815160e160020a636eb1769f02815233600160a060020a038181166004840152308082166024850152945191969495169263dd62ed3e926044808201939182900301818787803b1515610e6457fe5b6102c65a03f11515610e7257fe5b50506040515191505060008111610e895760006000fd5b6000805460408051602090810184905281517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a038881166004830152878116602483015260448201879052925192909316936323b872dd9360648082019492918390030190829087803b1515610f0457fe5b6102c65a03f11515610f1257fe5b50506040515115159050610f265760006000fd5b60008054604080516020908101849052815160e160020a636eb1769f028152600160a060020a03888116600483015287811660248301529251929093169363dd62ed3e9360448082019492918390030190829087803b1515610f8457fe5b6102c65a03f11515610f9257fe5b505060405151159050610fa157fe5b600160a060020a038316600081815260046020526040808220805485019055516000805160206130d083398151915291600291859080845b60ff168152602001836002811115610fed57fe5b60ff168152602001828152602001935050505060405180910390a25b505050565b600160a060020a0380821660008181526004602081815260408084205460058352818520546006845282862054865484518601889052845160e160020a636eb1769f02815296870198909852308916602487015292519197909692959485948594859493169263dd62ed3e92604480820193929182900301818787803b151561109357fe5b6102c65a03f115156110a157fe5b505060408051805160035460006020938401819052845160e160020a636eb1769f028152600160a060020a038f8116600483015230811660248301529551939a5094909116945063dd62ed3e936044808201949392918390030190829087803b151561110957fe5b6102c65a03f1151561111757fe5b505060408051805160008054602093840182905284517f70a08231000000000000000000000000000000000000000000000000000000008152600160a060020a038f811660048301529551939950941694506370a08231936024808201949392918390030190829087803b151561118a57fe5b6102c65a03f1151561119857fe5b50506040805180516003546000602093840181905284517f70a08231000000000000000000000000000000000000000000000000000000008152600160a060020a038f8116600483015295519398509490911694506370a08231936024808201949392918390030190829087803b151561120e57fe5b6102c65a03f1151561121c57fe5b5050604051519150505b919395979092949650565b600754600160a060020a03908116903316811461124e5760006000fd5b600160a060020a0382811690821614156112685760006000fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5050565b6003546040805160006020918201819052825160e160020a636eb1769f02815233600160a060020a03818116600484015230808216602485015295519196939493169263dd62ed3e926044808201939182900301818787803b15156112f657fe5b6102c65a03f1151561130457fe5b5050604051519150506000811161131b5760006000fd5b600354604080516000602091820181905282517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a038881166004830152878116602483015260448201879052935193909416936323b872dd936064808301949391928390030190829087803b151561139857fe5b6102c65a03f115156113a657fe5b505060405151151590506113ba5760006000fd5b6003546040805160006020918201819052825160e160020a636eb1769f028152600160a060020a03888116600483015287811660248301529351939094169363dd62ed3e936044808301949391928390030190829087803b151561141a57fe5b6102c65a03f1151561142857fe5b50506040515115905061143757fe5b600160a060020a03831660008181526006602052604090819020805484019055516000805160206130d083398151915290600290819085908083610fd9565b60ff168152602001836002811115610fed57fe5b60ff168152602001828152602001935050505060405180910390a25b505050565b6000808080808080808080806001608060020a038d1615156114f057600160a060020a038e166000908152606060205260409020546001608060020a03169a5061150e565b6001608060020a03808e16600090815260616020526040902054169a505b5b6001608060020a038b16151561152457611621565b506001608060020a03808b166000818152600860205260409020918d16901061154c576115b8565b60025b6002820154610100900460ff16600781111561156757fe5b148061158b575060045b6002820154610100900460ff16600781111561158957fe5b145b15611595576115b8565b6001608060020a039a8b16600090815260616020526040902054909a169961150e565b8054600182015460028301546003840154600485015460a060020a90940461ffff169d50919b5060ff8082169b50610100820481169a50620100008204169850630100000090046001608060020a0390811697508082169650608060020a909104811694501691505b5093979b5093979b91959950939750565b33600080808080806001608060020a038c161580159061167157506001608060020a038c16600090815260086020526040902054600160a060020a0316155b151561167d5760006000fd5b86600160a060020a03167f98f28571fb2c7cab95fb6ca13908a1ba4a08e2b417317f72037ea2fafd2bca4760008e8b604051808460028111156116bc57fe5b60ff1681526001608060020a0390931660208401525060408083019190915251908190036060019150a26101406040519081016040528088600160a060020a031681526020018c61ffff1681526020018b81526020018a600381111561171e57fe5b815260200160005b815260200160005b815260200160006001608060020a0316815260200160006001608060020a0316815260200160006001608060020a0316815260200160006001608060020a0316815250600860008e6001608060020a03166001608060020a0316815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160000160146101000a81548161ffff021916908361ffff1602179055506040820151816001015560608201518160020160006101000a81548160ff0219169083600381111561181457fe5b0217905550608082015160028201805461ff00191661010083600781111561183857fe5b021790555060a082015160028201805462ff000019166201000083600881111561185e57fe5b021790555060c08201518160020160036101000a8154816001608060020a0302191690836001608060020a0316021790555060e08201518160030160006101000a8154816001608060020a0302191690836001608060020a031602179055506101008201518160030160106101000a8154816001608060020a0302191690836001608060020a031602179055506101208201518160040160006101000a8154816001608060020a0302191690836001608060020a031602179055509050506060600088600160a060020a0316600160a060020a0316815260200190815260200160002060009054906101000a90046001608060020a031695508b6060600089600160a060020a0316600160a060020a0316815260200190815260200160002060006101000a8154816001608060020a0302191690836001608060020a0316021790555085606160008e6001608060020a03166001608060020a0316815260200190815260200160002060006101000a8154816001608060020a0302191690836001608060020a03160217905550600860008d6001608060020a03166001608060020a031681526020019081526020016000209450611a1b8b611f0d565b9195509350915060005b846002811115611a3157fe5b1415611a70576002850180546001919061ff001916610100835b02179055506002850180546001919062ff0000191662010000835b0217905550611bf2565b6001548a1080611a8c57506c0c9f2c9cd04674edea400000008a115b15611acb576002850180546001919061ff001916610100835b02179055506002858101805462ff000019166201000083611a66565b0217905550611bf2565b611ad68a8484611f94565b9050662386f26fc10000811080611af957506c0c9f2c9cd04674edea4000000081115b15611b3c576002850180546001919061ff00191661010083611aa5565b02179055506002858101805462ff000019166201000083611a66565b0217905550611bf2565b60035b896003811115611b4b57fe5b148015611b5757508715155b15611b99576002850180546001919061ff001916610100835b02179055506002850180546003919062ff000019166201000083611a66565b0217905550611bf2565b611ba587858c84611fe9565b1515611be8576002850180546001919061ff001916610100835b02179055506002850180546004919062ff000019166201000083611a66565b0217905550611bf2565b611bf28c896120cb565b5b505050505050505050505050565b6001608060020a03821660009081526008602052604090208054339190600160a060020a03808416911614611c365760006000fd5b60045b6002820154610100900460ff166007811115611c5157fe5b14611c5b57610c3d565b81600160a060020a03167f98f28571fb2c7cab95fb6ca13908a1ba4a08e2b417317f72037ea2fafd2bca476001868660405180846002811115611c9a57fe5b60ff1681526001608060020a0390931660208401525060408083019190915251908190036060019150a26002810180546000919061ff001916610100835b0217905550610c3d84846120cb565b5b50505050565b6001608060020a03811660009081526008602052604081208054339290600160a060020a03808516911614611d235760006000fd5b50600281810154610100900460ff16905b816007811115611d4057fe5b14158015611d5b575060045b816007811115611d5857fe5b14155b15611d6557610c3d565b82600160a060020a03167f98f28571fb2c7cab95fb6ca13908a1ba4a08e2b417317f72037ea2fafd2bca47600286600060405180846002811115611da557fe5b60ff1681526001608060020a0390931660208401525060408083019190915251908190036060019150a260025b816007811115611dde57fe5b1415611e6857611ded846123c0565b815460028301546001808501546040516001608060020a038981169542956000805160206130f0833981519152959460a060020a90920461ffff1693630100000090910490921690039060009080855b60ff16815261ffff909416602085015250604080840192909252606083015251908190036080019150a35b610c3d8460036008612540565b5b50505050565b600060018261ffff1610158015611e995750612a308261ffff1611155b90505b919050565b6000600060005b506001608060020a0392831660009081526008602090815260408083206002810154600180830154605f9095529290942054871696630100000090940490931690910393909301929190910190831515611f0157611f06565b611ea8565b5b50915091565b6000808061ffff84168180806001841080611f29575061546084115b15611f3f57600096506000955060009450611f89565b612a308411611f58576001965083612a30039250611f64565b60029650612a31840392505b5b610384835b069150610384835b60625460648501985060000b919004908101955090505b505050509193909250565b600060008260000b1215611fc9576000828103900b600a0a6103e861ffff851686025b04811515611fc157fe5b049050611fe1565b600082900b600a0a6103e861ffff851686025b040290505b5b9392505050565b6000808060015b866002811115611ffc57fe5b141561205457600160a060020a03871660009081526005602052604090205491508382101561202e57600092506120bf565b600160a060020a03871660009081526005602052604090208483039055600192506120bf565b60025b86600281111561206357fe5b14156120ba5750600160a060020a0386166000908152600460205260409020548481101561209457600092506120bf565b600160a060020a03871660009081526004602052604090208582039055600192506120bf565b600092505b5b5b5050949350505050565b6001608060020a0382811660009081526008602052604081206002810154600382015482549294630100000090920482169391169181908190819061211a9060a060020a900461ffff16611f0d565b50909450600190505b84600281111561212f57fe5b1461213b57600161213f565b612a315b87549093506121589060a060020a900461ffff1661264c565b61ffff16915061216a8984848b6126ab565b90506121778987876128de565b60025b600288015460ff16600381111561218d57fe5b141561220f5760025b8160048111156121a257fe5b14156121ba576121b58960036000612540565b6123b4565b60015b8160048111156121c957fe5b14156121e1576121b58960036007612540565b6123b4565b60045b8160048111156121f057fe5b1415612208576121b58960036006612540565b6123b4565b5b5b6100ee565b60035b600288015460ff16600381111561222557fe5b141561227b5760015b81600481111561223a57fe5b1415612252576121b58960016005612540565b6123b4565b60045b81600481111561226157fe5b1415612208576121b589612afa565b6123b4565b5b6100ee565b60005b600288015460ff16600381111561229157fe5b14156123135760025b8160048111156122a657fe5b14156122be576121b58960036000612540565b6123b4565b60015b8160048111156122cd57fe5b1415612252576121b58960036007612540565b6123b4565b6004612255565b81600481111561226157fe5b1415612208576121b589612afa565b6123b4565b5b5b6100ee565b60015b600288015460ff16600381111561232957fe5b14156100ee5760025b81600481111561233e57fe5b1415612356576121b58960036000612540565b6123b4565b60015b81600481111561236557fe5b1415612389576002870180546004919061ff001916610100835b02179055506123b4565b60045b81600481111561239857fe5b14156100ee576121b589612afa565b6123b4565b5b5b5b5b5b5bfe5b5b505050505050505050565b6001608060020a038181166000818152600860209081526040808320805460a060020a900461ffff16808552605e8452828520958552605f90935290832080549195929493909282811692608060020a900416908080808515612450576001608060020a038087166000908152605f602052604090208054878316608060020a0292169190911781559350612469565b87546001608060020a03808716608060020a0291161788555b6001608060020a038516156124ad576001608060020a038581166000908152605f6020526040902080546001608060020a03191691881691909117815592506124c7565b87546001608060020a0319166001608060020a0387161788555b6001608060020a0386161580156124e557506001608060020a038516155b156125325761010061ffff8a165b0461ffff1691506101008961ffff1681151561250b57fe5b0661ffff1690508060020a60098360558110151561252557fe5b0160005b50805490911890555b5b5050505050505050505050565b6001608060020a03831660009081526008602052604081208054909160a060020a90910461ffff169061257282611e7c565b156125be57612585836001015483612ca3565b60038401548454600160a060020a0316600090815260056020526040902080546001608060020a039092168303909101905590506125fd565b600283015460018401548454600160a060020a03166000908152600460205260409020805463010000009093046001608060020a031690910390910190555b60028301805486919061ff00191661010083600781111561261a57fe5b021790555060028301805485919062ff000019166201000083600881111561263e57fe5b02179055505b505050505050565b600060018261ffff16108061266657506154608261ffff16115b1561267357506000611e9c565b612a3061ffff831611612692575061ffff811661546003600101611e9c565b50600161ffff82166154600301611e9c565b5b5b919050565b6001608060020a038416600090815260086020526040812081808080808080806101008d5b0497506101008d5b0696506101008c5b0495506101008c5b069450600988605581106126f857fe5b0160005b505460009a509350839250600287900a830491505b858810156127ef57811580612727575086610100145b156127725782841461274857826009896055811061274157fe5b0160005b50555b600190970196600096506009886055811061275f57fe5b0160005b505493508391508392506127ea565b60018216156127d95761278c89888a61010002018d612ccd565b909c509a50905080156127a2578660020a831892505b60035b8a60048111156127b157fe5b14156127c057600099506127d9565b60005b8a60048111156127cf57fe5b146127d9576127ef565b5b5b600196909601956002825b0491505b612711565b60005b8a60048111156127fe57fe5b1415612895575b84871115801561281457508115155b156128955760018216156128805761283389888a61010002018d612ccd565b909c509a5090508015612849578660020a831892505b60035b8a600481111561285857fe5b14156128675760009950612880565b60005b8a600481111561287657fe5b1461288057612895565b5b5b600196909601956002825b049150612805565b5b8284146128b25782600989605581106128ab57fe5b0160005b50555b60005b8a60048111156128c157fe5b14156128cc57600499505b5b505050505050505050949350505050565b6001608060020a03808416600090815260086020526040812060028101546003820154919363010000009091048116869003929116849003908080806103e86107d0865b8954600160a060020a0316600081815260066020526040902054929091049290920295509092509050808411612a0357600160a060020a0380831660009081526006602052604080822087850390556007549092168152208490556004870180546001608060020a038082168701166001608060020a031990911617905586546129b79061ffff60a060020a90910416611e7c565b156129df57600160a060020a03821660009081526004602052604090208054870190556129fe565b600160a060020a03821660009081526005602052604090208054860190555b612aec565b8654612a199060a060020a900461ffff16611e7c565b15612a87576107d0865b8854600160a060020a03908116600090815260046020526040808220805495909404808c039590950190935560038b0180546001608060020a03608060020a8083048216880182160291161790556007549091168152208054820190559250612aec565b6107d0855b8854600160a060020a03908116600090815260056020526040808220805495909404808b039590950190935560038b0180546001608060020a03608060020a80830482168801821602911617905560075490911681522080548201905592505b5b5b50505050505050505050565b6001608060020a038181166000818152600860209081526040808320805460a060020a900461ffff16808552605e8452828520958552605f9093529083208454919592949390929091829182918291161515612bc75785546001608060020a0319166001608060020a038a811691821716608060020a919091021786556000855561010061ffff88165b0461ffff1693506101008761ffff16811515612b9c57fe5b0661ffff1692508260020a600985605581101515612bb657fe5b0160005b5080549091179055612c16565b505083546001608060020a03608060020a9182900481166000818152605f60205260409020818402875580548b84166001608060020a0319919091168117825588549402939092169290921786555b600288015460018901546040516001608060020a03808d169342936000805160206130f0833981519152936000938e93630100000090041690910390839080825b60ff16815261ffff909416602085015250604080840192909252606083015251908190036080019150a36002888101805461ff001916610100835b02179055505b505050505050505050565b600060006000612cb284611f0d565b9250925050612cc2858383611f94565b92505b505092915050565b6002830154600384015461ffff84166000908152605e60205260408120549092849284926001608060020a036301000000909304831692918216911683805b861515612d1c5760019550612d63565b612d2d858c6001015403848c612e2a565b600019909a0199985096810196958601959194509250905060005b866004811115612d5457fe5b14612d5e57612d63565b612d0c565b60028b01805472ffffffffffffffffffffffffffffffff000000191663010000006001608060020a03888116919091029190911790915560038c0180546001608060020a03191686831617905583161515612dd55761ffff8a166000908152605e602052604081205560019750612e1b565b61ffff8a166000908152605e6020908152604080832080546001608060020a0319166001608060020a038881169182179092558452605f90925282208054909116905597505b5b505050505093509350939050565b6001608060020a0380831660009081526008602052604081206002810154600182015492938493849384939092630100000090910416900382818a1015612e7357899550612e77565b8195505b612e818689612ca3565b9450600254868b031015612e985760029350612e9d565b600093505b612eaa838a8a8989612f12565b90508015612f01576001608060020a03808a166000908152605f602052604081205490911697505b846004811115612ede57fe5b148015612ef257506001608060020a038716155b15612efc57600393505b612f05565b8896505b5b50505093509350935093565b60028501805472ffffffffffffffffffffffffffffffff0000001981166301000000918290046001608060020a0390811686018116909202179091556003860180546001608060020a031981169083168401909216919091179055600080612f7985611e7c565b15612fa2578654600160a060020a03166000908152600460205260409020805485019055612fc2565b8654600160a060020a031660009081526005602052604090208054840190555b8660020160039054906101000a90046001608060020a03166001608060020a03168760010154039050600254811015613066576130028660036000612540565b856001608060020a0316426000805160206130f0833981519152600288858901896040518085600381111561303357fe5b60ff16815261ffff909416602085015250604080840192909252606083015251908190036080019150a3600191506130c4565b856001608060020a0316426000805160206130f083398151915260038888896040518085600381111561309557fe5b60ff16815261ffff909416602085015250604080840192909252606083015251908190036080019150a3600091505b5b50959450505050505600caa7be131f5091d6ed32c02b2ba1f45c6721442175b1c8e1a9a5b453e54efe7540d0a103f9440846844f8f9a0d6968bb70b1a10f7ce225d40eb8796c4993258da165627a7a723058201b30f80ed00802b1385ff591272852defaea43bd8763e3ddf874557c67b2fb9d0029
Swarm Source
bzzr://1b30f80ed00802b1385ff591272852defaea43bd8763e3ddf874557c67b2fb9d
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $2,297.1 | 0.0339 | $77.77 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.