diff --git a/contracts/Exchange.sol b/contracts/Exchange.sol index 1b6be0b3..d6545601 100644 --- a/contracts/Exchange.sol +++ b/contracts/Exchange.sol @@ -67,7 +67,7 @@ contract Exchange is IExchange { struct Order { address owner; - address signer; + address broker; address tokenS; address tokenB; address wallet; @@ -100,7 +100,7 @@ contract Exchange is IExchange { uint[6][] valuesList; uint8[] optionList; bytes[] sigList; - address miner; + address feeRecipient; address interceptor; uint8 feeSelections; uint64 ringIndex; @@ -181,28 +181,22 @@ contract Exchange is IExchange { 0 ); require( - msg.sender == order.signer, - "cancelOrder not submitted by signer" + tx.origin == order.broker, + "cancelOrder not submitted by broker" ); bytes32 orderHash = calculateOrderHash(order); MultihashUtil.verifySignature( - order.signer, + order.broker, orderHash, sig ); - if (order.signer != order.owner) { - IBrokerRegistry brokerRegistry = IBrokerRegistry(brokerRegistryAddress); - bool registered; - address tracker; - (registered, tracker) = brokerRegistry.getBroker( - order.owner, - order.signer - ); - require(registered, "invalid broker"); - } + order.brokerInterceptor = verifyAuthenticationGetInterceptor( + order.owner, + order.broker + ); // For AON orders, must cancel it as a whole. if (order.optAllOrNone) { @@ -214,31 +208,41 @@ contract Exchange is IExchange { emit OrderCancelled( order.owner, + tx.origin, orderHash, cancelAmount ); } function cancelAllOrdersByTradingPair( + address owner, address token1, address token2, uint cutoff ) external { + verifyAuthenticationGetInterceptor(owner, tx.origin); + uint t = (cutoff == 0 || cutoff >= block.timestamp) ? block.timestamp : cutoff; bytes20 tokenPair = bytes20(token1) ^ bytes20(token2); ITokenTransferDelegate delegate = ITokenTransferDelegate(delegateAddress); require( - delegate.tradingPairCutoffs(msg.sender, tokenPair) < t, + delegate.tradingPairCutoffs(owner, tokenPair) < t, "cutoff too small" ); - delegate.setTradingPairCutoffs(tokenPair, t); + delegate.setTradingPairCutoffs( + owner, + tokenPair, + t + ); + emit OrdersCancelled( - msg.sender, + owner, + tx.origin, token1, token2, t @@ -246,20 +250,27 @@ contract Exchange is IExchange { } function cancelAllOrders( - uint cutoff + address owner, + uint cutoff ) external { + verifyAuthenticationGetInterceptor(owner, tx.origin); + uint t = (cutoff == 0 || cutoff >= block.timestamp) ? block.timestamp : cutoff; ITokenTransferDelegate delegate = ITokenTransferDelegate(delegateAddress); require( - delegate.cutoffs(msg.sender) < t, + delegate.cutoffs(owner) < t, "cutoff too small" ); - delegate.setCutoffs(t); - emit AllOrdersCancelled(msg.sender, t); + delegate.setCutoffs(owner, t); + emit AllOrdersCancelled( + owner, + tx.origin, + t + ); } function submitRing( @@ -267,7 +278,7 @@ contract Exchange is IExchange { uint[6][] valuesList, uint8[] optionList, bytes[] sigList, - address miner, + address feeRecipient, address interceptor, uint8 feeSelections ) @@ -278,7 +289,7 @@ contract Exchange is IExchange { valuesList, optionList, sigList, - miner, + feeRecipient, interceptor, feeSelections, ringIndex, @@ -325,9 +336,11 @@ contract Exchange is IExchange { Context ctx ) private - pure + view { - require(ctx.miner != 0x0, "bad miner"); + if (ctx.feeRecipient == 0x0) { + ctx.feeRecipient = tx.origin; + } require( ctx.ringSize == ctx.addressesList.length, @@ -408,21 +421,15 @@ contract Exchange is IExchange { order.orderHash = calculateOrderHash(order); MultihashUtil.verifySignature( - order.signer, + order.broker, order.orderHash, ctx.sigList[i] ); - if (order.signer != order.owner) { - IBrokerRegistry brokerRegistry = IBrokerRegistry(brokerRegistryAddress); - bool authenticated; - (authenticated, order.brokerInterceptor) = brokerRegistry.getBroker( - order.owner, - order.signer - ); - - require(authenticated, "invalid broker"); - } + order.brokerInterceptor = verifyAuthenticationGetInterceptor( + order.owner, + order.broker + ); ctx.orders[i] = order; ctx.ringHash ^= order.orderHash; @@ -430,7 +437,7 @@ contract Exchange is IExchange { ctx.ringHash = keccak256( ctx.ringHash, - ctx.miner, + ctx.feeRecipient, ctx.feeSelections ); } @@ -459,7 +466,7 @@ contract Exchange is IExchange { } /// @dev Verify the ringHash has been signed with each order's auth private - /// keys as well as the miner's private key. + /// keys. function verifyRingSignatures( Context ctx ) @@ -589,7 +596,7 @@ contract Exchange is IExchange { ctx.delegate, order.tokenS, order.owner, - order.signer, + order.broker, order.brokerInterceptor ); @@ -646,7 +653,7 @@ contract Exchange is IExchange { } /// @dev Calculate each order's `lrcFee` and `lrcRewrard` and splict how much - /// of `fillAmountS` shall be paid to matching order or miner as margin + /// of `fillAmountS` shall be paid to matching order or fee recipient as margin /// split. function calculateRingFees( Context ctx @@ -672,7 +679,7 @@ contract Exchange is IExchange { ctx.delegate, lrcTokenAddress, order.owner, - order.signer, + order.broker, order.brokerInterceptor ); @@ -718,7 +725,7 @@ contract Exchange is IExchange { minerLrcSpendable = getSpendable( ctx.delegate, lrcTokenAddress, - ctx.miner, + tx.origin, 0x0, 0x0 ); @@ -781,7 +788,7 @@ contract Exchange is IExchange { // Store owner and tokenS of every order batch[p++] = bytes32(order.owner); - batch[p++] = bytes32(order.signer); + batch[p++] = bytes32(order.broker); batch[p++] = bytes32(order.brokerInterceptor); batch[p++] = bytes32(order.tokenS); @@ -811,14 +818,16 @@ contract Exchange is IExchange { ctx.delegate.batchUpdateHistoryAndTransferTokens( lrcTokenAddress, - ctx.miner, + tx.origin, + ctx.feeRecipient, historyBatch, batch ); emit RingMined( ctx.ringIndex, - ctx.miner, + tx.origin, + ctx.feeRecipient, fills ); } @@ -951,7 +960,7 @@ contract Exchange is IExchange { return keccak256( delegateAddress, order.owner, - order.signer, + order.broker, order.tokenS, order.tokenB, order.wallet, @@ -978,4 +987,22 @@ contract Exchange is IExchange { ITokenTransferDelegate delegate = ITokenTransferDelegate(delegateAddress); return delegate.tradingPairCutoffs(orderOwner, tokenPair); } + + function verifyAuthenticationGetInterceptor( + address owner, + address signer + ) + private + view + returns (address brokerInterceptor) + { + if (signer == owner) { + brokerInterceptor = 0x0; + } else { + IBrokerRegistry brokerRegistry = IBrokerRegistry(brokerRegistryAddress); + bool authenticated; + (authenticated, brokerInterceptor) = brokerRegistry.getBroker(owner, signer); + require(authenticated, "broker unauthenticated"); + } + } } diff --git a/contracts/IExchange.sol b/contracts/IExchange.sol index 04dbd68b..2074ff23 100644 --- a/contracts/IExchange.sol +++ b/contracts/IExchange.sol @@ -39,23 +39,27 @@ contract IExchange { event RingMined( uint _ringIndex, - address indexed _miner, + address indexed _broker, + address indexed _feeRecipient, Fill[] _fills ); event OrderCancelled( - address indexed _address, + address indexed _owner, + address indexed _broker, bytes32 _orderHash, uint _amountCancelled ); event AllOrdersCancelled( - address indexed _address, + address indexed _owner, + address indexed _broker, uint _cutoff ); event OrdersCancelled( - address indexed _address, + address indexed _owner, + address indexed _broker, address _token1, address _token2, uint _cutoff @@ -63,7 +67,7 @@ contract IExchange { /// @dev Cancel a order. cancel amount(amountS or amountB) can be specified /// in values. - /// @param addresses owner, signer, tokenS, tokenB, wallet, authAddr, + /// @param addresses owner, broker, tokenS, tokenB, wallet, authAddr, /// and order interceptor /// @param values amountS, amountB, validSince (second), /// validUntil (second), lrcFee, and cancelAmount. @@ -84,6 +88,7 @@ contract IExchange { /// @param cutoff The cutoff timestamp, will default to `block.timestamp` /// if it is 0. function cancelAllOrdersByTradingPair( + address owner, address token1, address token2, uint cutoff @@ -96,12 +101,13 @@ contract IExchange { /// @param cutoff The cutoff timestamp, will default to `block.timestamp` /// if it is 0. function cancelAllOrders( - uint cutoff + address owner, + uint cutoff ) external; /// @dev Submit a order-ring for validation and settlement. - /// @param addressesList List of each order's owner, signer, tokenS, wallet, + /// @param addressesList List of each order's owner, broker, tokenS, wallet, /// authAddr, and order interceptor. /// Note that next order's `tokenS` equals this order's /// `tokenB`. @@ -110,7 +116,7 @@ contract IExchange { /// validUntil (second), lrcFee, and rateAmountS. /// @param optionList Options associated with each order. /// @param sigList Signature lists. - /// @param miner Miner address. + /// @param feeRecipient Mineing fee recipient address. /// @param inteceptor Ring interceptor address. /// @param feeSelections - /// Bits to indicate fee selections. `1` represents margin @@ -120,7 +126,7 @@ contract IExchange { uint[6][] valuesList, uint8[] optionList, bytes[] sigList, - address miner, + address feeRecipient, address inteceptor, uint8 feeSelections ) diff --git a/contracts/ITokenTransferDelegate.sol b/contracts/ITokenTransferDelegate.sol index 46aa535c..905ff109 100644 --- a/contracts/ITokenTransferDelegate.sol +++ b/contracts/ITokenTransferDelegate.sol @@ -83,7 +83,8 @@ contract ITokenTransferDelegate { function batchUpdateHistoryAndTransferTokens( address lrcTokenAddress, - address minerFeeRecipient, + address miner, + address feeRecipient, bytes32[] historyBatch, bytes32[] transferBatch ) @@ -109,11 +110,13 @@ contract ITokenTransferDelegate { external; function setCutoffs( + address owner, uint cutoff ) external; function setTradingPairCutoffs( + address owner, bytes20 tokenPair, uint cutoff ) diff --git a/contracts/TokenTransferDelegate.sol b/contracts/TokenTransferDelegate.sol index db4da789..c32d0ef8 100644 --- a/contracts/TokenTransferDelegate.sol +++ b/contracts/TokenTransferDelegate.sol @@ -31,18 +31,12 @@ import "./ITokenTransferDelegate.sol"; contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { using MathUint for uint; - uint8 public walletSplitPercentage = 0; + address private latestAddress = 0x0; - constructor( - uint8 _walletSplitPercentage - ) - public - { - require(_walletSplitPercentage >= 0 && _walletSplitPercentage <= 100); - walletSplitPercentage = _walletSplitPercentage; - } - - bool public suspended = false; + uint8 public walletSplitPercentage = 0; + bool public suspended = false; + mapping(address => AddressInfo) public addressInfos; + struct AddressInfo { address previous; @@ -50,8 +44,14 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { bool authorized; } - mapping(address => AddressInfo) public addressInfos; - address public latestAddress; + constructor( + uint8 _walletSplitPercentage + ) + public + { + require(_walletSplitPercentage >= 0 && _walletSplitPercentage <= 100); + walletSplitPercentage = _walletSplitPercentage; + } modifier onlyAuthorized() { @@ -96,11 +96,9 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { address prev = latestAddress; if (prev == 0x0) { addrInfo.index = 1; - addrInfo.authorized = true; } else { addrInfo.previous = prev; addrInfo.index = addressInfos[prev].index + 1; - } addrInfo.authorized = true; latestAddress = addr; @@ -138,7 +136,9 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { if (addrInfo.index == 0) { break; } - addresses[count++] = addr; + if (addrInfo.authorized) { + addresses[count++] = addr; + } addr = addrInfo.previous; } } @@ -163,7 +163,8 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { function batchUpdateHistoryAndTransferTokens( address lrcAddr, - address miner, + address miner, + address feeRecipient, bytes32[] historyBatch, bytes32[] batch ) @@ -184,10 +185,10 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { for (i = 0; i < batch.length; i += 9) { address owner = address(batch[i]); - address signer = address(batch[i + 1]); + address broker = address(batch[i + 1]); address brokerInterceptor = address(batch[i + 2]); - // Pay token to previous order, or to miner as previous order's + // Pay token to previous order, or to feeRecipient as previous order's // margin split or/and this order's margin split. address token = address(batch[i + 3]); uint amount; @@ -210,7 +211,7 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { require( IBrokerInterceptor(brokerInterceptor).onTokenSpent( owner, - signer, + broker, token, amount ), @@ -219,7 +220,7 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { } } - // Miner pays LRx fee to order owner + // Miner pays LRC award to order owner amount = uint(batch[i + 6]); if (amount != 0 && miner != owner) { require( @@ -232,23 +233,23 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { ); } - // Split margin-split income between miner and wallet + // Split margin-split income between feeRecipient and wallet splitPayFee( token, owner, - miner, - signer, + feeRecipient, + broker, brokerInterceptor, address(batch[i + 8]), uint(batch[i + 5]) ); - // Split LRC fee income between miner and wallet + // Split LRC fee income between feeRecipient and wallet splitPayFee( lrcAddr, owner, - miner, - signer, + feeRecipient, + broker, brokerInterceptor, address(batch[i + 8]), uint(batch[i + 7]) @@ -271,7 +272,7 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { function splitPayFee( address token, address owner, - address miner, + address feeRecipient, address broker, address brokerInterceptor, address wallet, @@ -284,7 +285,7 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { } uint walletFee = (wallet == 0x0) ? 0 : fee.mul(walletSplitPercentage) / 100; - uint minerFee = fee.sub(walletFee); + uint feeRecipientFee = fee.sub(walletFee); if (walletFee > 0 && wallet != owner) { require( @@ -297,12 +298,12 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { ); } - if (minerFee > 0 && miner != 0x0 && miner != owner) { + if (feeRecipientFee > 0 && feeRecipient != 0x0 && feeRecipient != owner) { require( ERC20(token).transferFrom( owner, - miner, - minerFee + feeRecipient, + feeRecipientFee ), "token transfer failure" ); @@ -346,16 +347,18 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { function setCutoffs( - uint cutoff + address owner, + uint cutoff ) onlyAuthorized notSuspended external { - cutoffs[tx.origin] = cutoff; + cutoffs[owner] = cutoff; } function setTradingPairCutoffs( + address owner, bytes20 tokenPair, uint cutoff ) @@ -363,7 +366,7 @@ contract TokenTransferDelegate is ITokenTransferDelegate, Claimable { notSuspended external { - tradingPairCutoffs[tx.origin][tokenPair] = cutoff; + tradingPairCutoffs[owner][tokenPair] = cutoff; } function checkCutoffsBatch(