Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 14 from a total of 14 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 18692642 | 323 days ago | IN | 0 ETH | 0.00369167 | ||||
Withdraw | 9526406 | 1702 days ago | IN | 0 ETH | 0.00021041 | ||||
Withdraw | 9526400 | 1702 days ago | IN | 0 ETH | 0.00014854 | ||||
Withdraw | 8816012 | 1820 days ago | IN | 0 ETH | 0.00053187 | ||||
Deposit ERC20Tok... | 8723472 | 1835 days ago | IN | 0 ETH | 0.00027901 | ||||
Withdraw | 8713757 | 1836 days ago | IN | 0 ETH | 0.00076078 | ||||
Deposit ERC20Tok... | 8713749 | 1836 days ago | IN | 0 ETH | 0.00069754 | ||||
Deposit Ether | 8610588 | 1852 days ago | IN | 67 ETH | 0.00098708 | ||||
Deposit ERC20Tok... | 8610579 | 1852 days ago | IN | 0 ETH | 0.00084712 | ||||
Withdraw | 8610571 | 1852 days ago | IN | 0 ETH | 0.00214601 | ||||
Withdraw | 8610506 | 1852 days ago | IN | 0 ETH | 0.00126637 | ||||
Update Exchange | 8296309 | 1901 days ago | IN | 0 ETH | 0.00028706 | ||||
Deposit ERC20Tok... | 8078436 | 1935 days ago | IN | 0 ETH | 0.00061349 | ||||
Deposit Ether | 8078432 | 1935 days ago | IN | 29.95 ETH | 0.0005074 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18692642 | 323 days ago | 0.2453015 ETH | ||||
9526406 | 1702 days ago | 81.95618606 ETH | ||||
9466951 | 1711 days ago | 0.21000002 ETH | ||||
9460149 | 1712 days ago | 0.21000002 ETH | ||||
9450807 | 1714 days ago | 0.50243845 ETH | ||||
9437903 | 1716 days ago | 0.2086248 ETH | ||||
9437828 | 1716 days ago | 0.20000002 ETH | ||||
9437828 | 1716 days ago | 0.20000002 ETH | ||||
9431064 | 1717 days ago | 0.21000002 ETH | ||||
9429497 | 1717 days ago | 0.99400509 ETH | ||||
9423377 | 1718 days ago | 0.21233107 ETH | ||||
9404438 | 1721 days ago | 1.10912 ETH | ||||
9378273 | 1725 days ago | 0.78621229 ETH | ||||
9378069 | 1725 days ago | 0.3648472 ETH | ||||
9378065 | 1725 days ago | 0.3648472 ETH | ||||
9378062 | 1725 days ago | 0.3648472 ETH | ||||
9378060 | 1725 days ago | 0.3648472 ETH | ||||
9377764 | 1725 days ago | 3.01485 ETH | ||||
9377764 | 1725 days ago | 3.01485 ETH | ||||
9377764 | 1725 days ago | 0.66669607 ETH | ||||
9287712 | 1739 days ago | 0.2144262 ETH | ||||
9287712 | 1739 days ago | 1.07514962 ETH | ||||
9280559 | 1740 days ago | 0.22201667 ETH | ||||
9214374 | 1750 days ago | 0.63894156 ETH | ||||
9214032 | 1750 days ago | 0.23531858 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
WalletV2
Compiler Version
v0.4.24+commit.e67f0147
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-12-01 */ /** *Submitted for verification at Etherscan.io on 2019-01-15 */ pragma solidity ^0.4.24; /** * @title Log Various Error Types * @author Adam Lemmon <[email protected]> * @dev Inherit this contract and your may now log errors easily * To support various error types, params, etc. */ contract LoggingErrors { /** * Events */ event LogErrorString(string errorString); /** * Error cases */ /** * @dev Default error to simply log the error message and return * @param _errorMessage The error message to log * @return ALWAYS false */ function error(string _errorMessage) internal returns(bool) { LogErrorString(_errorMessage); return false; } } /** * @title Wallet Connector * @dev Connect the wallet contract to the correct Wallet Logic version */ contract WalletConnector is LoggingErrors { /** * Storage */ address public owner_; address public latestLogic_; uint256 public latestVersion_; mapping(uint256 => address) public logicVersions_; uint256 public birthBlock_; /** * Events */ event LogLogicVersionAdded(uint256 version); event LogLogicVersionRemoved(uint256 version); /** * @dev Constructor to set the latest logic address * @param _latestVersion Latest version of the wallet logic * @param _latestLogic Latest address of the wallet logic contract */ function WalletConnector ( uint256 _latestVersion, address _latestLogic ) public { owner_ = msg.sender; latestLogic_ = _latestLogic; latestVersion_ = _latestVersion; logicVersions_[_latestVersion] = _latestLogic; birthBlock_ = block.number; } /** * Add a new version of the logic contract * @param _version The version to be associated with the new contract. * @param _logic New logic contract. * @return Success of the transaction. */ function addLogicVersion ( uint256 _version, address _logic ) external returns(bool) { if (msg.sender != owner_) return error('msg.sender != owner, WalletConnector.addLogicVersion()'); if (logicVersions_[_version] != 0) return error('Version already exists, WalletConnector.addLogicVersion()'); // Update latest if this is the latest version if (_version > latestVersion_) { latestLogic_ = _logic; latestVersion_ = _version; } logicVersions_[_version] = _logic; LogLogicVersionAdded(_version); return true; } /** * @dev Remove a version. Cannot remove the latest version. * @param _version The version to remove. */ function removeLogicVersion(uint256 _version) external { require(msg.sender == owner_); require(_version != latestVersion_); delete logicVersions_[_version]; LogLogicVersionRemoved(_version); } /** * Constants */ /** * Called from user wallets in order to upgrade their logic. * @param _version The version to upgrade to. NOTE pass in 0 to upgrade to latest. * @return The address of the logic contract to upgrade to. */ function getLogic(uint256 _version) external constant returns(address) { if (_version == 0) return latestLogic_; else return logicVersions_[_version]; } } /** * @title Wallet to hold and trade ERC20 tokens and ether * @author Adam Lemmon <[email protected]> * @dev User wallet to interact with the exchange. * all tokens and ether held in this wallet, 1 to 1 mapping to user EOAs. */ contract WalletV2 is LoggingErrors { /** * Storage */ // Vars included in wallet logic "lib", the order must match between Wallet and Logic address public owner_; address public exchange_; mapping(address => uint256) public tokenBalances_; address public logic_; // storage location 0x3 loaded for delegatecalls so this var must remain at index 3 uint256 public birthBlock_; WalletConnector private connector_; /** * Events */ event LogDeposit(address token, uint256 amount, uint256 balance); event LogWithdrawal(address token, uint256 amount, uint256 balance); /** * @dev Contract constructor. Set user as owner and connector address. * @param _owner The address of the user's EOA, wallets created from the exchange * so must past in the owner address, msg.sender == exchange. * @param _connector The wallet connector to be used to retrieve the wallet logic */ function WalletV2(address _owner, address _connector) public { owner_ = _owner; connector_ = WalletConnector(_connector); exchange_ = msg.sender; logic_ = connector_.latestLogic_(); birthBlock_ = block.number; } /** * @dev Fallback - Only enable funds to be sent from the exchange. * Ensures balances will be consistent. */ function () external payable { require(msg.sender == exchange_); } /** * External */ /** * @dev Deposit ether into this wallet, default to address 0 for consistent token lookup. */ function depositEther() external payable { require(logic_.delegatecall(bytes4(sha3('deposit(address,uint256)')), 0, msg.value)); } /** * @dev Deposit any ERC20 token into this wallet. * @param _token The address of the existing token contract. * @param _amount The amount of tokens to deposit. * @return Bool if the deposit was successful. */ function depositERC20Token ( address _token, uint256 _amount ) external returns(bool) { // ether if (_token == 0) return error('Cannot deposit ether via depositERC20, Wallet.depositERC20Token()'); require(logic_.delegatecall(bytes4(sha3('deposit(address,uint256)')), _token, _amount)); return true; } /** * @dev The result of an order, update the balance of this wallet. * @param _token The address of the token balance to update. * @param _amount The amount to update the balance by. * @param _subtractionFlag If true then subtract the token amount else add. * @return Bool if the update was successful. */ function updateBalance ( address _token, uint256 _amount, bool _subtractionFlag ) external returns(bool) { assembly { calldatacopy(0x40, 0, calldatasize) delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32) return(0, 32) pop } } /** * User may update to the latest version of the exchange contract. * Note that multiple versions are NOT supported at this time and therefore if a * user does not wish to update they will no longer be able to use the exchange. * @param _exchange The new exchange. * @return Success of this transaction. */ function updateExchange(address _exchange) external returns(bool) { if (msg.sender != owner_) return error('msg.sender != owner_, Wallet.updateExchange()'); // If subsequent messages are not sent from this address all orders will fail exchange_ = _exchange; return true; } /** * User may update to a new or older version of the logic contract. * @param _version The versin to update to. * @return Success of this transaction. */ function updateLogic(uint256 _version) external returns(bool) { if (msg.sender != owner_) return error('msg.sender != owner_, Wallet.updateLogic()'); address newVersion = connector_.getLogic(_version); // Invalid version as defined by connector if (newVersion == 0) return error('Invalid version, Wallet.updateLogic()'); logic_ = newVersion; return true; } /** * @dev Verify an order that the Exchange has received involving this wallet. * Internal checks and then authorize the exchange to move the tokens. * If sending ether will transfer to the exchange to broker the trade. * @param _token The address of the token contract being sold. * @param _amount The amount of tokens the order is for. * @param _fee The fee for the current trade. * @param _feeToken The token of which the fee is to be paid in. * @return If the order was verified or not. */ function verifyOrder ( address _token, uint256 _amount, uint256 _fee, address _feeToken ) external returns(bool) { assembly { calldatacopy(0x40, 0, calldatasize) delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32) return(0, 32) pop } } /** * @dev Withdraw any token, including ether from this wallet to an EOA. * @param _token The address of the token to withdraw. * @param _amount The amount to withdraw. * @return Success of the withdrawal. */ function withdraw(address _token, uint256 _amount) external returns(bool) { if(msg.sender != owner_) return error('msg.sender != owner, Wallet.withdraw()'); assembly { calldatacopy(0x40, 0, calldatasize) delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32) return(0, 32) pop } } /** * Constants */ /** * @dev Get the balance for a specific token. * @param _token The address of the token contract to retrieve the balance of. * @return The current balance within this contract. */ function balanceOf(address _token) public view returns(uint) { return tokenBalances_[_token]; } } /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { function mul(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal constant 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; } function sub(uint256 a, uint256 b) internal constant returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal constant returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } contract Token { /// @return total amount of tokens function totalSupply() constant returns (uint256 supply) {} /// @param _owner The address from which the balance will be retrieved /// @return The balance function balanceOf(address _owner) constant returns (uint256 balance) {} /// @notice send `_value` token to `_to` from `msg.sender` /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transfer(address _to, uint256 _value) returns (bool success) {} /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` /// @param _from The address of the sender /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {} /// @notice `msg.sender` approves `_addr` to spend `_value` tokens /// @param _spender The address of the account able to transfer the tokens /// @param _value The amount of wei to be approved for transfer /// @return Whether the approval was successful or not function approve(address _spender, uint256 _value) returns (bool success) {} /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent function allowance(address _owner, address _spender) constant returns (uint256 remaining) {} event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); uint public decimals; string public name; } interface ExchangeV1 { function userAccountToWallet_(address) external returns(address); } interface BadERC20 { function transfer(address to, uint value) external; function transferFrom(address from, address to, uint256 value) external; } /** * @title Decentralized exchange for ether and ERC20 tokens. * @author Eidoo SAGL. * @dev All trades brokered by this contract. * Orders submitted by off chain order book and this contract handles * verification and execution of orders. * All value between parties is transferred via this exchange. * Methods arranged by visibility; external, public, internal, private and alphabatized within. * * New Exchange SC with eventually no fee and ERC20 tokens as quote */ contract ExchangeV2 is LoggingErrors { using SafeMath for uint256; /** * Data Structures */ struct Order { address offerToken_; uint256 offerTokenTotal_; uint256 offerTokenRemaining_; // Amount left to give address wantToken_; uint256 wantTokenTotal_; uint256 wantTokenReceived_; // Amount received, note this may exceed want total } struct OrderStatus { uint256 expirationBlock_; uint256 wantTokenReceived_; // Amount received, note this may exceed want total uint256 offerTokenRemaining_; // Amount left to give } /** * Storage */ address public previousExchangeAddress_; address private orderBookAccount_; address public owner_; uint256 public birthBlock_; address public edoToken_; address public walletConnector; mapping (address => uint256) public feeEdoPerQuote; mapping (address => uint256) public feeEdoPerQuoteDecimals; address public eidooWallet_; // Define if fee calculation must be skipped for a given trade. By default (false) fee must not be skipped. mapping(address => mapping(address => bool)) public mustSkipFee; /** * @dev Define in a trade who is the quote using a priority system: * values example * 0: not used as quote * >0: used as quote * if wanted and offered tokens have value > 0 the quote is the token with the bigger value */ mapping(address => uint256) public quotePriority; mapping(bytes32 => OrderStatus) public orders_; // Map order hashes to order data struct mapping(address => address) public userAccountToWallet_; // User EOA to wallet addresses /** * Events */ event LogFeeRateSet(address indexed token, uint256 rate, uint256 decimals); event LogQuotePrioritySet(address indexed quoteToken, uint256 priority); event LogMustSkipFeeSet(address indexed base, address indexed quote, bool mustSkipFee); event LogUserAdded(address indexed user, address walletAddress); event LogWalletDeposit(address indexed walletAddress, address token, uint256 amount, uint256 balance); event LogWalletWithdrawal(address indexed walletAddress, address token, uint256 amount, uint256 balance); event LogOrderExecutionSuccess( bytes32 indexed makerOrderId, bytes32 indexed takerOrderId, uint256 toMaker, uint256 toTaker ); event LogOrderFilled(bytes32 indexed orderId, uint256 totalOfferRemaining, uint256 totalWantReceived); /** * @dev Contract constructor - CONFIRM matches contract name. Set owner and addr of order book. * @param _bookAccount The EOA address for the order book, will submit ALL orders. * @param _edoToken Deployed edo token. * @param _edoPerWei Rate of edo tokens per wei. * @param _edoPerWeiDecimals Decimlas carried in edo rate. * @param _eidooWallet Wallet to pay fees to. * @param _previousExchangeAddress Previous exchange smart contract address. */ constructor ( address _bookAccount, address _edoToken, uint256 _edoPerWei, uint256 _edoPerWeiDecimals, address _eidooWallet, address _previousExchangeAddress, address _walletConnector ) public { orderBookAccount_ = _bookAccount; owner_ = msg.sender; birthBlock_ = block.number; edoToken_ = _edoToken; feeEdoPerQuote[address(0)] = _edoPerWei; feeEdoPerQuoteDecimals[address(0)] = _edoPerWeiDecimals; eidooWallet_ = _eidooWallet; quotePriority[address(0)] = 10; previousExchangeAddress_ = _previousExchangeAddress; require(_walletConnector != address (0), "WalletConnector address == 0"); walletConnector = _walletConnector; } /** * @dev Fallback. wallets utilize to send ether in order to broker trade. */ function () external payable { } /** * External */ /** * @dev Returns the Wallet contract address associated to a user account. If the user account is not known, try to * migrate the wallet address from the old exchange instance. This function is equivalent to getWallet(), in addition * it stores the wallet address fetched from old the exchange instance. * @param userAccount The user account address * @return The address of the Wallet instance associated to the user account */ function retrieveWallet(address userAccount) public returns(address walletAddress) { walletAddress = userAccountToWallet_[userAccount]; if (walletAddress == address(0) && previousExchangeAddress_ != 0) { // Retrieve the wallet address from the old exchange. walletAddress = ExchangeV1(previousExchangeAddress_).userAccountToWallet_(userAccount); // TODO: in the future versions of the exchange the above line must be replaced with the following one //walletAddress = ExchangeV2(previousExchangeAddress_).retrieveWallet(userAccount); if (walletAddress != address(0)) { userAccountToWallet_[userAccount] = walletAddress; } } } /** * @dev Add a new user to the exchange, create a wallet for them. * Map their account address to the wallet contract for lookup. * @param userExternalOwnedAccount The address of the user"s EOA. * @return Success of the transaction, false if error condition met. */ function addNewUser(address userExternalOwnedAccount) public returns (bool) { if (retrieveWallet(userExternalOwnedAccount) != address(0)) { return error("User already exists, Exchange.addNewUser()"); } // Pass the userAccount address to wallet constructor so owner is not the exchange contract address userTradingWallet = new WalletV2(userExternalOwnedAccount, walletConnector); userAccountToWallet_[userExternalOwnedAccount] = userTradingWallet; emit LogUserAdded(userExternalOwnedAccount, userTradingWallet); return true; } /** * Execute orders in batches. * @param ownedExternalAddressesAndTokenAddresses Tokan and user addresses. * @param amountsExpirationsAndSalts Offer and want token amount and expiration and salt values. * @param vSignatures All order signature v values. * @param rAndSsignatures All order signature r and r values. * @return The success of this transaction. */ function batchExecuteOrder( address[4][] ownedExternalAddressesAndTokenAddresses, uint256[8][] amountsExpirationsAndSalts, // Packing to save stack size uint8[2][] vSignatures, bytes32[4][] rAndSsignatures ) external returns(bool) { for (uint256 i = 0; i < amountsExpirationsAndSalts.length; i++) { require( executeOrder( ownedExternalAddressesAndTokenAddresses[i], amountsExpirationsAndSalts[i], vSignatures[i], rAndSsignatures[i] ), "Cannot execute order, Exchange.batchExecuteOrder()" ); } return true; } /** * @dev Execute an order that was submitted by the external order book server. * The order book server believes it to be a match. * There are components for both orders, maker and taker, 2 signatures as well. * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts. * [ * makerEOA * makerOfferToken * takerEOA * takerOfferToken * ] * @param amountsExpirationsAndSalts The amount of tokens and the block number at which this order expires and a random number to mitigate replay. * [ * makerOffer * makerWant * takerOffer * takerWant * makerExpiry * makerSalt * takerExpiry * takerSalt * ] * @param vSignatures ECDSA signature parameter. * [ * maker V * taker V * ] * @param rAndSsignatures ECDSA signature parameters r ans s, maker 0, 1 and taker 2, 3. * [ * maker R * maker S * taker R * taker S * ] * @return Success of the transaction, false if error condition met. * Like types grouped to eliminate stack depth error. */ function executeOrder ( address[4] ownedExternalAddressesAndTokenAddresses, uint256[8] amountsExpirationsAndSalts, // Packing to save stack size uint8[2] vSignatures, bytes32[4] rAndSsignatures ) public returns(bool) { // Only read wallet addresses from storage once // Need one more stack slot so squashing into array WalletV2[2] memory makerAndTakerTradingWallets = [ WalletV2(retrieveWallet(ownedExternalAddressesAndTokenAddresses[0])), // maker WalletV2(retrieveWallet(ownedExternalAddressesAndTokenAddresses[2])) // taker ]; // Basic pre-conditions, return if any input data is invalid if(!__executeOrderInputIsValid__( ownedExternalAddressesAndTokenAddresses, amountsExpirationsAndSalts, makerAndTakerTradingWallets[0], // maker makerAndTakerTradingWallets[1] // taker )) { return error("Input is invalid, Exchange.executeOrder()"); } // Verify Maker and Taker signatures bytes32[2] memory makerAndTakerOrderHash = generateOrderHashes( ownedExternalAddressesAndTokenAddresses, amountsExpirationsAndSalts ); // Check maker order signature if (!__signatureIsValid__( ownedExternalAddressesAndTokenAddresses[0], makerAndTakerOrderHash[0], vSignatures[0], rAndSsignatures[0], rAndSsignatures[1] )) { return error("Maker signature is invalid, Exchange.executeOrder()"); } // Check taker order signature if (!__signatureIsValid__( ownedExternalAddressesAndTokenAddresses[2], makerAndTakerOrderHash[1], vSignatures[1], rAndSsignatures[2], rAndSsignatures[3] )) { return error("Taker signature is invalid, Exchange.executeOrder()"); } // Exchange Order Verification and matching OrderStatus memory makerOrderStatus = orders_[makerAndTakerOrderHash[0]]; OrderStatus memory takerOrderStatus = orders_[makerAndTakerOrderHash[1]]; Order memory makerOrder; Order memory takerOrder; makerOrder.offerToken_ = ownedExternalAddressesAndTokenAddresses[1]; makerOrder.offerTokenTotal_ = amountsExpirationsAndSalts[0]; makerOrder.wantToken_ = ownedExternalAddressesAndTokenAddresses[3]; makerOrder.wantTokenTotal_ = amountsExpirationsAndSalts[1]; if (makerOrderStatus.expirationBlock_ > 0) { // Check for existence // Orders still active if (makerOrderStatus.offerTokenRemaining_ == 0) { return error("Maker order is inactive, Exchange.executeOrder()"); } makerOrder.offerTokenRemaining_ = makerOrderStatus.offerTokenRemaining_; // Amount to give makerOrder.wantTokenReceived_ = makerOrderStatus.wantTokenReceived_; // Amount received } else { makerOrder.offerTokenRemaining_ = amountsExpirationsAndSalts[0]; // Amount to give makerOrder.wantTokenReceived_ = 0; // Amount received makerOrderStatus.expirationBlock_ = amountsExpirationsAndSalts[4]; // maker order expiration block } takerOrder.offerToken_ = ownedExternalAddressesAndTokenAddresses[3]; takerOrder.offerTokenTotal_ = amountsExpirationsAndSalts[2]; takerOrder.wantToken_ = ownedExternalAddressesAndTokenAddresses[1]; takerOrder.wantTokenTotal_ = amountsExpirationsAndSalts[3]; if (takerOrderStatus.expirationBlock_ > 0) { // Check for existence if (takerOrderStatus.offerTokenRemaining_ == 0) { return error("Taker order is inactive, Exchange.executeOrder()"); } takerOrder.offerTokenRemaining_ = takerOrderStatus.offerTokenRemaining_; // Amount to give takerOrder.wantTokenReceived_ = takerOrderStatus.wantTokenReceived_; // Amount received } else { takerOrder.offerTokenRemaining_ = amountsExpirationsAndSalts[2]; // Amount to give takerOrder.wantTokenReceived_ = 0; // Amount received takerOrderStatus.expirationBlock_ = amountsExpirationsAndSalts[6]; // taker order expiration block } // Check if orders are matching and are valid if (!__ordersMatch_and_AreVaild__(makerOrder, takerOrder)) { return error("Orders do not match, Exchange.executeOrder()"); } // Trade amounts // [0] => toTakerAmount // [1] => toMakerAmount uint[2] memory toTakerAndToMakerAmount; toTakerAndToMakerAmount = __getTradeAmounts__(makerOrder, takerOrder); // TODO consider removing. Can this condition be met? if (toTakerAndToMakerAmount[0] < 1 || toTakerAndToMakerAmount[1] < 1) { return error("Token amount < 1, price ratio is invalid! Token value < 1, Exchange.executeOrder()"); } uint calculatedFee = __calculateFee__(makerOrder, toTakerAndToMakerAmount[0], toTakerAndToMakerAmount[1]); // Check taker has sufficent EDO token balance to pay the fee if ( takerOrder.offerToken_ == edoToken_ && Token(edoToken_).balanceOf(makerAndTakerTradingWallets[1]) < calculatedFee.add(toTakerAndToMakerAmount[1]) ) { return error("Taker has an insufficient EDO token balance to cover the fee AND the offer, Exchange.executeOrder()"); } else if (Token(edoToken_).balanceOf(makerAndTakerTradingWallets[1]) < calculatedFee) { return error("Taker has an insufficient EDO token balance to cover the fee, Exchange.executeOrder()"); } // Wallet Order Verification, reach out to the maker and taker wallets. if ( !__ordersVerifiedByWallets__( ownedExternalAddressesAndTokenAddresses, toTakerAndToMakerAmount[1], toTakerAndToMakerAmount[0], makerAndTakerTradingWallets[0], makerAndTakerTradingWallets[1], calculatedFee )) { return error("Order could not be verified by wallets, Exchange.executeOrder()"); } // Write to storage then external calls makerOrderStatus.offerTokenRemaining_ = makerOrder.offerTokenRemaining_.sub(toTakerAndToMakerAmount[0]); makerOrderStatus.wantTokenReceived_ = makerOrder.wantTokenReceived_.add(toTakerAndToMakerAmount[1]); takerOrderStatus.offerTokenRemaining_ = takerOrder.offerTokenRemaining_.sub(toTakerAndToMakerAmount[1]); takerOrderStatus.wantTokenReceived_ = takerOrder.wantTokenReceived_.add(toTakerAndToMakerAmount[0]); // Finally write orders to storage orders_[makerAndTakerOrderHash[0]] = makerOrderStatus; orders_[makerAndTakerOrderHash[1]] = takerOrderStatus; // Transfer the external value, ether <> tokens require( __executeTokenTransfer__( ownedExternalAddressesAndTokenAddresses, toTakerAndToMakerAmount[0], toTakerAndToMakerAmount[1], calculatedFee, makerAndTakerTradingWallets[0], makerAndTakerTradingWallets[1] ), "Cannot execute token transfer, Exchange.__executeTokenTransfer__()" ); // Log the order id(hash), amount of offer given, amount of offer remaining emit LogOrderFilled(makerAndTakerOrderHash[0], makerOrderStatus.offerTokenRemaining_, makerOrderStatus.wantTokenReceived_); emit LogOrderFilled(makerAndTakerOrderHash[1], takerOrderStatus.offerTokenRemaining_, takerOrderStatus.wantTokenReceived_); emit LogOrderExecutionSuccess(makerAndTakerOrderHash[0], makerAndTakerOrderHash[1], toTakerAndToMakerAmount[1], toTakerAndToMakerAmount[0]); return true; } /** * @dev Set the fee rate for a specific quote * @param _quoteToken Quote token. * @param _edoPerQuote EdoPerQuote. * @param _edoPerQuoteDecimals EdoPerQuoteDecimals. * @return Success of the transaction. */ function setFeeRate( address _quoteToken, uint256 _edoPerQuote, uint256 _edoPerQuoteDecimals ) external returns(bool) { if (msg.sender != owner_) { return error("msg.sender != owner, Exchange.setFeeRate()"); } if (quotePriority[_quoteToken] == 0) { return error("quotePriority[_quoteToken] == 0, Exchange.setFeeRate()"); } feeEdoPerQuote[_quoteToken] = _edoPerQuote; feeEdoPerQuoteDecimals[_quoteToken] = _edoPerQuoteDecimals; emit LogFeeRateSet(_quoteToken, _edoPerQuote, _edoPerQuoteDecimals); return true; } /** * @dev Set the wallet for fees to be paid to. * @param eidooWallet Wallet to pay fees to. * @return Success of the transaction. */ function setEidooWallet( address eidooWallet ) external returns(bool) { if (msg.sender != owner_) { return error("msg.sender != owner, Exchange.setEidooWallet()"); } eidooWallet_ = eidooWallet; return true; } /** * @dev Set a new order book account. * @param account The new order book account. */ function setOrderBookAcount ( address account ) external returns(bool) { if (msg.sender != owner_) { return error("msg.sender != owner, Exchange.setOrderBookAcount()"); } orderBookAccount_ = account; return true; } /** * @dev Set if a base must skip fee calculation. * @param _baseTokenAddress The trade base token address that must skip fee calculation. * @param _quoteTokenAddress The trade quote token address that must skip fee calculation. * @param _mustSkipFee The trade base token address that must skip fee calculation. */ function setMustSkipFee ( address _baseTokenAddress, address _quoteTokenAddress, bool _mustSkipFee ) external returns(bool) { // Preserving same owner check style if (msg.sender != owner_) { return error("msg.sender != owner, Exchange.setMustSkipFee()"); } mustSkipFee[_baseTokenAddress][_quoteTokenAddress] = _mustSkipFee; emit LogMustSkipFeeSet(_baseTokenAddress, _quoteTokenAddress, _mustSkipFee); return true; } /** * @dev Set quote priority token. * Set the sorting of token quote based on a priority. * @param _token The address of the token that was deposited. * @param _priority The amount of the token that was deposited. * @return Operation success. */ function setQuotePriority(address _token, uint256 _priority) external returns(bool) { if (msg.sender != owner_) { return error("msg.sender != owner, Exchange.setQuotePriority()"); } quotePriority[_token] = _priority; emit LogQuotePrioritySet(_token, _priority); return true; } /* Methods to catch events from external contracts, user wallets primarily */ /** * @dev Simply log the event to track wallet interaction off-chain. * @param tokenAddress The address of the token that was deposited. * @param amount The amount of the token that was deposited. * @param tradingWalletBalance The updated balance of the wallet after deposit. */ function walletDeposit( address tokenAddress, uint256 amount, uint256 tradingWalletBalance ) external { emit LogWalletDeposit(msg.sender, tokenAddress, amount, tradingWalletBalance); } /** * @dev Simply log the event to track wallet interaction off-chain. * @param tokenAddress The address of the token that was deposited. * @param amount The amount of the token that was deposited. * @param tradingWalletBalance The updated balance of the wallet after deposit. */ function walletWithdrawal( address tokenAddress, uint256 amount, uint256 tradingWalletBalance ) external { emit LogWalletWithdrawal(msg.sender, tokenAddress, amount, tradingWalletBalance); } /** * Private */ /** * Calculate the fee for the given trade. Calculated as the set % of the wei amount * converted into EDO tokens using the manually set conversion ratio. * @param makerOrder The maker order object. * @param toTakerAmount The amount of tokens going to the taker. * @param toMakerAmount The amount of tokens going to the maker. * @return The total fee to be paid in EDO tokens. */ function __calculateFee__( Order makerOrder, uint256 toTakerAmount, uint256 toMakerAmount ) private view returns(uint256) { // weiAmount * (fee %) * (EDO/Wei) / (decimals in edo/wei) / (decimals in percentage) if (!__isSell__(makerOrder)) { // buy -> the quote is the offered token by the maker return mustSkipFee[makerOrder.wantToken_][makerOrder.offerToken_] ? 0 : toTakerAmount.mul(feeEdoPerQuote[makerOrder.offerToken_]).div(10**feeEdoPerQuoteDecimals[makerOrder.offerToken_]); } else { // sell -> the quote is the wanted token by the maker return mustSkipFee[makerOrder.offerToken_][makerOrder.wantToken_] ? 0 : toMakerAmount.mul(feeEdoPerQuote[makerOrder.wantToken_]).div(10**feeEdoPerQuoteDecimals[makerOrder.wantToken_]); } } /** * @dev Verify the input to order execution is valid. * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts. * [ * makerEOA * makerOfferToken * takerEOA * takerOfferToken * ] * @param amountsExpirationsAndSalts The amount of tokens and the block number at which this order expires and a random number to mitigate replay. * [ * makerOffer * makerWant * takerOffer * takerWant * makerExpiry * makerSalt * takerExpiry * takerSalt * ] * @return Success if all checks pass. */ function __executeOrderInputIsValid__( address[4] ownedExternalAddressesAndTokenAddresses, uint256[8] amountsExpirationsAndSalts, address makerTradingWallet, address takerTradingWallet ) private returns(bool) { // msg.send needs to be the orderBookAccount if (msg.sender != orderBookAccount_) { return error("msg.sender != orderBookAccount, Exchange.__executeOrderInputIsValid__()"); } // Check expirations base on the block number if (block.number > amountsExpirationsAndSalts[4]) { return error("Maker order has expired, Exchange.__executeOrderInputIsValid__()"); } if (block.number > amountsExpirationsAndSalts[6]) { return error("Taker order has expired, Exchange.__executeOrderInputIsValid__()"); } // Operating on existing tradingWallets if (makerTradingWallet == address(0)) { return error("Maker wallet does not exist, Exchange.__executeOrderInputIsValid__()"); } if (takerTradingWallet == address(0)) { return error("Taker wallet does not exist, Exchange.__executeOrderInputIsValid__()"); } if (quotePriority[ownedExternalAddressesAndTokenAddresses[1]] == quotePriority[ownedExternalAddressesAndTokenAddresses[3]]) { return error("Quote token is omitted! Is not offered by either the Taker or Maker, Exchange.__executeOrderInputIsValid__()"); } // Check that none of the amounts is = to 0 if ( amountsExpirationsAndSalts[0] == 0 || amountsExpirationsAndSalts[1] == 0 || amountsExpirationsAndSalts[2] == 0 || amountsExpirationsAndSalts[3] == 0 ) return error("May not execute an order where token amount == 0, Exchange.__executeOrderInputIsValid__()"); // // Confirm order ether amount >= min amount // // Maker // uint256 minOrderEthAmount = minOrderEthAmount_; // Single storage read // if (_token_and_EOA_Addresses[1] == 0 && _amountsExpirationAndSalt[0] < minOrderEthAmount) // return error('Maker order does not meet the minOrderEthAmount_ of ether, Exchange.__executeOrderInputIsValid__()'); // // Taker // if (_token_and_EOA_Addresses[3] == 0 && _amountsExpirationAndSalt[2] < minOrderEthAmount) // return error('Taker order does not meet the minOrderEthAmount_ of ether, Exchange.__executeOrderInputIsValid__()'); return true; } /** * @dev Execute the external transfer of tokens. * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts. * [ * makerEOA * makerOfferToken * takerEOA * takerOfferToken * ] * @param toTakerAmount The amount of tokens to transfer to the taker. * @param toMakerAmount The amount of tokens to transfer to the maker. * @return Success if both wallets verify the order. */ function __executeTokenTransfer__( address[4] ownedExternalAddressesAndTokenAddresses, uint256 toTakerAmount, uint256 toMakerAmount, uint256 fee, WalletV2 makerTradingWallet, WalletV2 takerTradingWallet ) private returns (bool) { // Wallet mapping balances address makerOfferTokenAddress = ownedExternalAddressesAndTokenAddresses[1]; address takerOfferTokenAddress = ownedExternalAddressesAndTokenAddresses[3]; // Taker to pay fee before trading if(fee != 0) { require( takerTradingWallet.updateBalance(edoToken_, fee, true), "Taker trading wallet cannot update balance with fee, Exchange.__executeTokenTransfer__()" ); require( Token(edoToken_).transferFrom(takerTradingWallet, eidooWallet_, fee), "Cannot transfer fees from taker trading wallet to eidoo wallet, Exchange.__executeTokenTransfer__()" ); } // Updating makerTradingWallet balance by the toTaker require( makerTradingWallet.updateBalance(makerOfferTokenAddress, toTakerAmount, true), "Maker trading wallet cannot update balance subtracting toTakerAmount, Exchange.__executeTokenTransfer__()" ); // return error("Unable to subtract maker token from maker wallet, Exchange.__executeTokenTransfer__()"); // Updating takerTradingWallet balance by the toTaker require( takerTradingWallet.updateBalance(makerOfferTokenAddress, toTakerAmount, false), "Taker trading wallet cannot update balance adding toTakerAmount, Exchange.__executeTokenTransfer__()" ); // return error("Unable to add maker token to taker wallet, Exchange.__executeTokenTransfer__()"); // Updating takerTradingWallet balance by the toMaker amount require( takerTradingWallet.updateBalance(takerOfferTokenAddress, toMakerAmount, true), "Taker trading wallet cannot update balance subtracting toMakerAmount, Exchange.__executeTokenTransfer__()" ); // return error("Unable to subtract taker token from taker wallet, Exchange.__executeTokenTransfer__()"); // Updating makerTradingWallet balance by the toMaker amount require( makerTradingWallet.updateBalance(takerOfferTokenAddress, toMakerAmount, false), "Maker trading wallet cannot update balance adding toMakerAmount, Exchange.__executeTokenTransfer__()" ); // return error("Unable to add taker token to maker wallet, Exchange.__executeTokenTransfer__()"); // Ether to the taker and tokens to the maker if (makerOfferTokenAddress == address(0)) { address(takerTradingWallet).transfer(toTakerAmount); } else { require( safeTransferFrom(makerOfferTokenAddress, makerTradingWallet, takerTradingWallet, toTakerAmount), "Token transfership from makerTradingWallet to takerTradingWallet failed, Exchange.__executeTokenTransfer__()" ); assert( __tokenAndWalletBalancesMatch__( makerTradingWallet, takerTradingWallet, makerOfferTokenAddress ) ); } if (takerOfferTokenAddress == address(0)) { address(makerTradingWallet).transfer(toMakerAmount); } else { require( safeTransferFrom(takerOfferTokenAddress, takerTradingWallet, makerTradingWallet, toMakerAmount), "Token transfership from takerTradingWallet to makerTradingWallet failed, Exchange.__executeTokenTransfer__()" ); assert( __tokenAndWalletBalancesMatch__( makerTradingWallet, takerTradingWallet, takerOfferTokenAddress ) ); } return true; } /** * @dev Calculates Keccak-256 hash of order with specified parameters. * @param ownedExternalAddressesAndTokenAddresses The orders maker EOA and current exchange address. * @param amountsExpirationsAndSalts The orders offer and want amounts and expirations with salts. * @return Keccak-256 hash of the passed order. */ function generateOrderHashes( address[4] ownedExternalAddressesAndTokenAddresses, uint256[8] amountsExpirationsAndSalts ) public view returns (bytes32[2]) { bytes32 makerOrderHash = keccak256( address(this), ownedExternalAddressesAndTokenAddresses[0], // _makerEOA ownedExternalAddressesAndTokenAddresses[1], // offerToken amountsExpirationsAndSalts[0], // offerTokenAmount ownedExternalAddressesAndTokenAddresses[3], // wantToken amountsExpirationsAndSalts[1], // wantTokenAmount amountsExpirationsAndSalts[4], // expiry amountsExpirationsAndSalts[5] // salt ); bytes32 takerOrderHash = keccak256( address(this), ownedExternalAddressesAndTokenAddresses[2], // _makerEOA ownedExternalAddressesAndTokenAddresses[3], // offerToken amountsExpirationsAndSalts[2], // offerTokenAmount ownedExternalAddressesAndTokenAddresses[1], // wantToken amountsExpirationsAndSalts[3], // wantTokenAmount amountsExpirationsAndSalts[6], // expiry amountsExpirationsAndSalts[7] // salt ); return [makerOrderHash, takerOrderHash]; } /** * @dev Returns a bool representing a SELL or BUY order based on quotePriority. * @param _order The maker order data structure. * @return The bool indicating if the order is a SELL or BUY. */ function __isSell__(Order _order) internal view returns (bool) { return quotePriority[_order.offerToken_] < quotePriority[_order.wantToken_]; } /** * @dev Compute the tradeable amounts of the two verified orders. * Token amount is the __min__ remaining between want and offer of the two orders that isn"t ether. * Ether amount is then: etherAmount = tokenAmount * priceRatio, as ratio = eth / token. * @param makerOrder The maker order data structure. * @param takerOrder The taker order data structure. * @return The amount moving from makerOfferRemaining to takerWantRemaining and vice versa. */ function __getTradeAmounts__( Order makerOrder, Order takerOrder ) internal view returns (uint256[2]) { bool isMakerBuy = __isSell__(takerOrder); // maker buy = taker sell uint256 priceRatio; uint256 makerAmountLeftToReceive; uint256 takerAmountLeftToReceive; uint toTakerAmount; uint toMakerAmount; if (makerOrder.offerTokenTotal_ >= makerOrder.wantTokenTotal_) { priceRatio = makerOrder.offerTokenTotal_.mul(2**128).div(makerOrder.wantTokenTotal_); if (isMakerBuy) { // MP > 1 makerAmountLeftToReceive = makerOrder.wantTokenTotal_.sub(makerOrder.wantTokenReceived_); toMakerAmount = __min__(takerOrder.offerTokenRemaining_, makerAmountLeftToReceive); // add 2**128-1 in order to obtain a round up toTakerAmount = toMakerAmount.mul(priceRatio).add(2**128-1).div(2**128); } else { // MP < 1 takerAmountLeftToReceive = takerOrder.wantTokenTotal_.sub(takerOrder.wantTokenReceived_); toTakerAmount = __min__(makerOrder.offerTokenRemaining_, takerAmountLeftToReceive); toMakerAmount = toTakerAmount.mul(2**128).div(priceRatio); } } else { priceRatio = makerOrder.wantTokenTotal_.mul(2**128).div(makerOrder.offerTokenTotal_); if (isMakerBuy) { // MP < 1 makerAmountLeftToReceive = makerOrder.wantTokenTotal_.sub(makerOrder.wantTokenReceived_); toMakerAmount = __min__(takerOrder.offerTokenRemaining_, makerAmountLeftToReceive); toTakerAmount = toMakerAmount.mul(2**128).div(priceRatio); } else { // MP > 1 takerAmountLeftToReceive = takerOrder.wantTokenTotal_.sub(takerOrder.wantTokenReceived_); toTakerAmount = __min__(makerOrder.offerTokenRemaining_, takerAmountLeftToReceive); // add 2**128-1 in order to obtain a round up toMakerAmount = toTakerAmount.mul(priceRatio).add(2**128-1).div(2**128); } } return [toTakerAmount, toMakerAmount]; } /** * @dev Return the maximum of two uints * @param a Uint 1 * @param b Uint 2 * @return The grater value or a if equal */ function __max__(uint256 a, uint256 b) private pure returns (uint256) { return a < b ? b : a; } /** * @dev Return the minimum of two uints * @param a Uint 1 * @param b Uint 2 * @return The smallest value or b if equal */ function __min__(uint256 a, uint256 b) private pure returns (uint256) { return a < b ? a : b; } /** * @dev Confirm that the orders do match and are valid. * @param makerOrder The maker order data structure. * @param takerOrder The taker order data structure. * @return Bool if the orders passes all checks. */ function __ordersMatch_and_AreVaild__( Order makerOrder, Order takerOrder ) private returns (bool) { // Confirm tokens match // NOTE potentially omit as matching handled upstream? if (makerOrder.wantToken_ != takerOrder.offerToken_) { return error("Maker wanted token does not match taker offer token, Exchange.__ordersMatch_and_AreVaild__()"); } if (makerOrder.offerToken_ != takerOrder.wantToken_) { return error("Maker offer token does not match taker wanted token, Exchange.__ordersMatch_and_AreVaild__()"); } // Price Ratios, to x decimal places hence * decimals, dependent on the size of the denominator. // Ratios are relative to eth, amount of ether for a single token, ie. ETH / GNO == 0.2 Ether per 1 Gnosis uint256 orderPrice; // The price the maker is willing to accept uint256 offeredPrice; // The offer the taker has given // Ratio = larger amount / smaller amount if (makerOrder.offerTokenTotal_ >= makerOrder.wantTokenTotal_) { orderPrice = makerOrder.offerTokenTotal_.mul(2**128).div(makerOrder.wantTokenTotal_); offeredPrice = takerOrder.wantTokenTotal_.mul(2**128).div(takerOrder.offerTokenTotal_); // ie. Maker is offering 10 ETH for 100 GNO but taker is offering 100 GNO for 20 ETH, no match! // The taker wants more ether than the maker is offering. if (orderPrice < offeredPrice) { return error("Taker price is greater than maker price, Exchange.__ordersMatch_and_AreVaild__()"); } } else { orderPrice = makerOrder.wantTokenTotal_.mul(2**128).div(makerOrder.offerTokenTotal_); offeredPrice = takerOrder.offerTokenTotal_.mul(2**128).div(takerOrder.wantTokenTotal_); // ie. Maker is offering 100 GNO for 10 ETH but taker is offering 5 ETH for 100 GNO, no match! // The taker is not offering enough ether for the maker if (orderPrice > offeredPrice) { return error("Taker price is less than maker price, Exchange.__ordersMatch_and_AreVaild__()"); } } return true; } /** * @dev Ask each wallet to verify this order. * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts. * [ * makerEOA * makerOfferToken * takerEOA * takerOfferToken * ] * @param toMakerAmount The amount of tokens to be sent to the maker. * @param toTakerAmount The amount of tokens to be sent to the taker. * @param makerTradingWallet The maker trading wallet contract. * @param takerTradingWallet The taker trading wallet contract. * @param fee The fee to be paid for this trade, paid in full by taker. * @return Success if both wallets verify the order. */ function __ordersVerifiedByWallets__( address[4] ownedExternalAddressesAndTokenAddresses, uint256 toMakerAmount, uint256 toTakerAmount, WalletV2 makerTradingWallet, WalletV2 takerTradingWallet, uint256 fee ) private returns (bool) { // Have the transaction verified by both maker and taker wallets // confirm sufficient balance to transfer, offerToken and offerTokenAmount if(!makerTradingWallet.verifyOrder(ownedExternalAddressesAndTokenAddresses[1], toTakerAmount, 0, 0)) { return error("Maker wallet could not verify the order, Exchange.____ordersVerifiedByWallets____()"); } if(!takerTradingWallet.verifyOrder(ownedExternalAddressesAndTokenAddresses[3], toMakerAmount, fee, edoToken_)) { return error("Taker wallet could not verify the order, Exchange.____ordersVerifiedByWallets____()"); } return true; } /** * @dev On chain verification of an ECDSA ethereum signature. * @param signer The EOA address of the account that supposedly signed the message. * @param orderHash The on-chain generated hash for the order. * @param v ECDSA signature parameter v. * @param r ECDSA signature parameter r. * @param s ECDSA signature parameter s. * @return Bool if the signature is valid or not. */ function __signatureIsValid__( address signer, bytes32 orderHash, uint8 v, bytes32 r, bytes32 s ) private pure returns (bool) { address recoveredAddr = ecrecover( keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", orderHash)), v, r, s ); return recoveredAddr == signer; } /** * @dev Confirm wallet local balances and token balances match. * @param makerTradingWallet Maker wallet address. * @param takerTradingWallet Taker wallet address. * @param token Token address to confirm balances match. * @return If the balances do match. */ function __tokenAndWalletBalancesMatch__( address makerTradingWallet, address takerTradingWallet, address token ) private view returns(bool) { if (Token(token).balanceOf(makerTradingWallet) != WalletV2(makerTradingWallet).balanceOf(token)) { return false; } if (Token(token).balanceOf(takerTradingWallet) != WalletV2(takerTradingWallet).balanceOf(token)) { return false; } return true; } /** * @dev Wrapping the ERC20 transfer function to avoid missing returns. * @param _token The address of bad formed ERC20 token. * @param _from Transfer sender. * @param _to Transfer receiver. * @param _value Amount to be transfered. * @return Success of the safeTransfer. */ function safeTransferFrom( address _token, address _from, address _to, uint256 _value ) public returns (bool result) { BadERC20(_token).transferFrom(_from, _to, _value); assembly { switch returndatasize() case 0 { // This is our BadToken result := not(0) // result is true } case 32 { // This is our GoodToken returndatacopy(0, 0, 32) result := mload(0) // result == returndata of external call } default { // This is not an ERC20 token revert(0, 0) } } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"depositERC20Token","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"logic_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_subtractionFlag","type":"bool"}],"name":"updateBalance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_feeToken","type":"address"}],"name":"verifyOrder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_exchange","type":"address"}],"name":"updateExchange","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"birthBlock_","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"depositEther","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"exchange_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_version","type":"uint256"}],"name":"updateLogic","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":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"tokenBalances_","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"},{"name":"_connector","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"errorString","type":"string"}],"name":"LogErrorString","type":"event"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405160408061099d833981016040818152825160209384015160008054600160a060020a03808516600160a060020a03199283161783556005805482861690841617908190556001805490931633179092557facfdd2c500000000000000000000000000000000000000000000000000000000875294519396929594169363acfdd2c5936004808301949391928390030190829087803b1580156100b557600080fd5b505af11580156100c9573d6000803e3d6000fd5b505050506040513d60208110156100df57600080fd5b505160038054600160a060020a031916600160a060020a03909216919091179055505043600455610888806101156000396000f3006080604052600436106100ab5763ffffffff60e060020a6000350416632039d9fd81146100c457806322d40b13146100fc578063412288031461012d5780634e7343ea14610156578063648a0c911461018557806369820a80146101a657806370a08231146101cd57806398ea5fca146101ee578063c0668179146101f6578063d767ee4d1461020b578063e766307914610223578063f3fef3a314610238578063f6b1b18b1461025c575b600154600160a060020a031633146100c257600080fd5b005b3480156100d057600080fd5b506100e8600160a060020a036004351660243561027d565b604080519115158252519081900360200190f35b34801561010857600080fd5b506101116103b7565b60408051600160a060020a039092168252519081900360200190f35b34801561013957600080fd5b506100e8600160a060020a036004351660243560443515156103c6565b34801561016257600080fd5b506100e8600160a060020a036004358116906024359060443590606435166103c6565b34801561019157600080fd5b506100e8600160a060020a03600435166103e0565b3480156101b257600080fd5b506101bb61048e565b60408051918252519081900360200190f35b3480156101d957600080fd5b506101bb600160a060020a0360043516610494565b6100c26104af565b34801561020257600080fd5b5061011161053b565b34801561021757600080fd5b506100e860043561054a565b34801561022f57600080fd5b50610111610708565b34801561024457600080fd5b506100e8600160a060020a0360043516602435610717565b34801561026857600080fd5b506101bb600160a060020a03600435166107a7565b6000600160a060020a03831615156103215761031a608060405190810160405280604181526020017f43616e6e6f74206465706f73697420657468657220766961206465706f73697481526020017f45524332302c2057616c6c65742e6465706f7369744552433230546f6b656e2881526020017f29000000000000000000000000000000000000000000000000000000000000008152506107b9565b90506103b1565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a918290049081169091028252600160a060020a03878116600484015260248301879052925192909316929160448083019260009291908290030181865af49250505015156103ad57600080fd5b5060015b92915050565b600354600160a060020a031681565b6000366000604037602060003660406003545af460206000f35b60008054600160a060020a0316331461045f57610458606060405190810160405280602d81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f61746545786368616e67652829000000000000000000000000000000000000008152506107b9565b9050610489565b506001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161781555b919050565b60045481565b600160a060020a031660009081526002602052604090205490565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a9182900490811690910282526000600483018190523460248401529251600160a060020a039094169390926044808401939192918290030181865af492505050151561053957600080fd5b565b600154600160a060020a031681565b600080548190600160a060020a031633146105cb576105c4606060405190810160405280602a81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f6174654c6f6769632829000000000000000000000000000000000000000000008152506107b9565b9150610702565b600554604080517fd526d332000000000000000000000000000000000000000000000000000000008152600481018690529051600160a060020a039092169163d526d332916024808201926020929091908290030181600087803b15801561063257600080fd5b505af1158015610646573d6000803e3d6000fd5b505050506040513d602081101561065c57600080fd5b50519050600160a060020a03811615156106d5576105c4606060405190810160405280602581526020017f496e76616c69642076657273696f6e2c2057616c6c65742e7570646174654c6f81526020017f67696328290000000000000000000000000000000000000000000000000000008152506107b9565b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055600191505b50919050565b600054600160a060020a031681565b60008054600160a060020a0316331461078f5761031a606060405190810160405280602681526020017f6d73672e73656e64657220213d206f776e65722c2057616c6c65742e7769746881526020017f64726177282900000000000000000000000000000000000000000000000000008152506107b9565b366000604037602060003660406003545af460206000f35b60026020526000908152604090205481565b60007f551303dd5f39cbfe6daba6b3e27754b8a7d72f519756a2cde2b92c2bbde159a7826040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081a578181015183820152602001610802565b50505050905090810190601f1680156108475780820380516001836020036101000a031916815260200191505b509250505060405180910390a15060009190505600a165627a7a7230582043b086d6774163e8090d8e83bbedc2efb6cd81da046f89c36eadd97a129028950029000000000000000000000000e0e92fbcb79f6fdf729f6fa3fa4415a12704aa3200000000000000000000000003d6e7b2f48120fd57a89ff0bbd56e9ec39af21c
Deployed Bytecode
0x6080604052600436106100ab5763ffffffff60e060020a6000350416632039d9fd81146100c457806322d40b13146100fc578063412288031461012d5780634e7343ea14610156578063648a0c911461018557806369820a80146101a657806370a08231146101cd57806398ea5fca146101ee578063c0668179146101f6578063d767ee4d1461020b578063e766307914610223578063f3fef3a314610238578063f6b1b18b1461025c575b600154600160a060020a031633146100c257600080fd5b005b3480156100d057600080fd5b506100e8600160a060020a036004351660243561027d565b604080519115158252519081900360200190f35b34801561010857600080fd5b506101116103b7565b60408051600160a060020a039092168252519081900360200190f35b34801561013957600080fd5b506100e8600160a060020a036004351660243560443515156103c6565b34801561016257600080fd5b506100e8600160a060020a036004358116906024359060443590606435166103c6565b34801561019157600080fd5b506100e8600160a060020a03600435166103e0565b3480156101b257600080fd5b506101bb61048e565b60408051918252519081900360200190f35b3480156101d957600080fd5b506101bb600160a060020a0360043516610494565b6100c26104af565b34801561020257600080fd5b5061011161053b565b34801561021757600080fd5b506100e860043561054a565b34801561022f57600080fd5b50610111610708565b34801561024457600080fd5b506100e8600160a060020a0360043516602435610717565b34801561026857600080fd5b506101bb600160a060020a03600435166107a7565b6000600160a060020a03831615156103215761031a608060405190810160405280604181526020017f43616e6e6f74206465706f73697420657468657220766961206465706f73697481526020017f45524332302c2057616c6c65742e6465706f7369744552433230546f6b656e2881526020017f29000000000000000000000000000000000000000000000000000000000000008152506107b9565b90506103b1565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a918290049081169091028252600160a060020a03878116600484015260248301879052925192909316929160448083019260009291908290030181865af49250505015156103ad57600080fd5b5060015b92915050565b600354600160a060020a031681565b6000366000604037602060003660406003545af460206000f35b60008054600160a060020a0316331461045f57610458606060405190810160405280602d81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f61746545786368616e67652829000000000000000000000000000000000000008152506107b9565b9050610489565b506001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161781555b919050565b60045481565b600160a060020a031660009081526002602052604090205490565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a9182900490811690910282526000600483018190523460248401529251600160a060020a039094169390926044808401939192918290030181865af492505050151561053957600080fd5b565b600154600160a060020a031681565b600080548190600160a060020a031633146105cb576105c4606060405190810160405280602a81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f6174654c6f6769632829000000000000000000000000000000000000000000008152506107b9565b9150610702565b600554604080517fd526d332000000000000000000000000000000000000000000000000000000008152600481018690529051600160a060020a039092169163d526d332916024808201926020929091908290030181600087803b15801561063257600080fd5b505af1158015610646573d6000803e3d6000fd5b505050506040513d602081101561065c57600080fd5b50519050600160a060020a03811615156106d5576105c4606060405190810160405280602581526020017f496e76616c69642076657273696f6e2c2057616c6c65742e7570646174654c6f81526020017f67696328290000000000000000000000000000000000000000000000000000008152506107b9565b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055600191505b50919050565b600054600160a060020a031681565b60008054600160a060020a0316331461078f5761031a606060405190810160405280602681526020017f6d73672e73656e64657220213d206f776e65722c2057616c6c65742e7769746881526020017f64726177282900000000000000000000000000000000000000000000000000008152506107b9565b366000604037602060003660406003545af460206000f35b60026020526000908152604090205481565b60007f551303dd5f39cbfe6daba6b3e27754b8a7d72f519756a2cde2b92c2bbde159a7826040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081a578181015183820152602001610802565b50505050905090810190601f1680156108475780820380516001836020036101000a031916815260200191505b509250505060405180910390a15060009190505600a165627a7a7230582043b086d6774163e8090d8e83bbedc2efb6cd81da046f89c36eadd97a129028950029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e0e92fbcb79f6fdf729f6fa3fa4415a12704aa3200000000000000000000000003d6e7b2f48120fd57a89ff0bbd56e9ec39af21c
-----Decoded View---------------
Arg [0] : _owner (address): 0xE0E92FbcB79f6fdf729f6fA3Fa4415a12704aa32
Arg [1] : _connector (address): 0x03d6e7B2F48120Fd57a89ff0bBd56e9Ec39af21C
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e0e92fbcb79f6fdf729f6fa3fa4415a12704aa32
Arg [1] : 00000000000000000000000003d6e7b2f48120fd57a89ff0bbd56e9ec39af21c
Deployed Bytecode Sourcemap
3583:5985:0:-;;;;;;;;-1:-1:-1;;;3583:5985:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4958:9;;-1:-1:-1;;;;;4958:9:0;4944:10;:23;4936:32;;;;;;3583:5985;5508:353;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;5508:353:0;;;-1:-1:-1;;;;;5508:353:0;;;;;;;;;;;;;;;;;;;;;;;3851:21;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3851:21:0;;;;;;;;-1:-1:-1;;;;;3851:21:0;;;;;;;;;;;;;;6201:299;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;6201:299:0;;;-1:-1:-1;;;;;6201:299:0;;;;;;;;;8304:312;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;8304:312:0;-1:-1:-1;;;;;8304:312:0;;;;;;;;;;;;;;;;6842:319;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;6842:319:0;;;-1:-1:-1;;;;;6842:319:0;;;3961:26;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3961:26:0;;;;;;;;;;;;;;;;;;;;9444:121;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;9444:121:0;;;-1:-1:-1;;;;;9444:121:0;;;5116:151;;;;3766:24;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3766:24:0;;;;7342:422;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;7342:422:0;;;;;3740:21;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3740:21:0;;;;8855:350;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;8855:350:0;;;-1:-1:-1;;;;;8855:350:0;;;;;3795:49;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3795:49:0;;;-1:-1:-1;;;;;3795:49:0;;;5508:353;5606:4;-1:-1:-1;;;;;5640:11:0;;;5636:105;;;5667:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:5;:74::i;:::-;5660:81;;;;5636:105;5758:6;;5785:32;;;;;;;;;;;;;;;;5758:78;-1:-1:-1;;;5758:78:0;;;;;;;;;;;;-1:-1:-1;;;;;5758:78:0;;;;;;;;;;;;;;;:6;;;;;:78;;;;;;-1:-1:-1;;5758:78:0;;;;;;;:6;:78;;;;;;5750:87;;;;;;;;-1:-1:-1;5851:4:0;5508:353;;;;;:::o;3851:21::-;;;-1:-1:-1;;;;;3851:21:0;;:::o;6201:299::-;6323:4;6379:12;6376:1;6370:4;6357:35;6453:2;6450:1;6436:12;6430:4;6424:3;6418:10;6413:3;6400:56;6474:2;6471:1;6464:13;6842:319;6912:4;6946:6;;-1:-1:-1;;;;;6946:6:0;6932:10;:20;6928:94;;6968:54;;;;;;;;;;;;;;;;;;;;;;;;:5;:54::i;:::-;6961:61;;;;6928:94;-1:-1:-1;7114:9:0;:21;;-1:-1:-1;;7114:21:0;-1:-1:-1;;;;;7114:21:0;;;;;6842:319;;;;:::o;3961:26::-;;;;:::o;9444:121::-;-1:-1:-1;;;;;9537:22:0;9514:4;9537:22;;;-1:-1:-1;9537:22:0;;;;;;;9444:121::o;5116:151::-;5185:6;;5212:32;;;;;;;;;;;;;;;;5185:75;-1:-1:-1;;;5185:75:0;;;;;;;;;;;;:6;:75;;;;;;5250:9;5185:75;;;;;;-1:-1:-1;;;;;5185:6:0;;;;:75;;;;;;;:6;;:75;;;;;;:6;:75;;;;;;5177:84;;;;;;;;5116:151::o;3766:24::-;;;-1:-1:-1;;;;;3766:24:0;;:::o;7342:422::-;7408:4;7442:6;;7408:4;;-1:-1:-1;;;;;7442:6:0;7428:10;:20;7424:91;;7464:51;;;;;;;;;;;;;;;;;;;;;;;;:5;:51::i;:::-;7457:58;;;;7424:91;7545:10;;:29;;;;;;;;;;;;;;-1:-1:-1;;;;;7545:10:0;;;;:19;;:29;;;;;;;;;;;;;;;-1:-1:-1;7545:10:0;:29;;;5:2:-1;;;;30:1;27;20:12;5:2;7545:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7545:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;7545:29:0;;-1:-1:-1;;;;;;7635:15:0;;;7631:81;;;7666:46;;;;;;;;;;;;;;;;;;;;;;;;:5;:46::i;7631:81::-;7721:6;:19;;-1:-1:-1;;7721:19:0;-1:-1:-1;;;;;7721:19:0;;;;;-1:-1:-1;;;7342:422:0;;;;;:::o;3740:21::-;;;-1:-1:-1;;;;;3740:21:0;;:::o;8855:350::-;8933:4;8966:6;;-1:-1:-1;;;;;8966:6:0;8952:10;:20;8949:86;;8988:47;;;;;;;;;;;;;;;;;;;;;;;;:5;:47::i;8949:86::-;9084:12;9081:1;9075:4;9062:35;9158:2;9155:1;9141:12;9135:4;9129:3;9123:10;9118:3;9105:56;9179:2;9176:1;9169:13;3795:49;;;;;;;;;;;;;:::o;595:121::-;649:4;662:29;677:13;662:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;662:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;705:5:0;595:121;;;:::o
Swarm Source
bzzr://43b086d6774163e8090d8e83bbedc2efb6cd81da046f89c36eadd97a12902895
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.