Skip to content
This repository has been archived by the owner on Mar 19, 2019. It is now read-only.

Commit

Permalink
Merge pull request #308 from Loopring/order-sign-change
Browse files Browse the repository at this point in the history
Order sign change
  • Loading branch information
kongliangzhong authored Apr 19, 2018
2 parents 4b80de6 + ddbdc27 commit 2462a3c
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 37 deletions.
74 changes: 41 additions & 33 deletions contracts/LoopringProtocolImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,6 @@ contract LoopringProtocolImpl is LoopringProtocol {

uint public constant RATE_RATIO_SCALE = 10000;

// The following map is used to keep trace of order fill and cancellation
// history.
mapping (bytes32 => uint) public cancelledOrFilled;

// This map is used to keep trace of order's cancellation history.
mapping (bytes32 => uint) public cancelled;

// A map from address to its cutoff timestamp.
mapping (address => uint) public cutoffs;

// A map from address to its trading-pair cutoff timestamp.
mapping (address => mapping (bytes20 => uint)) public tradingPairCutoffs;

/// @param orderHash The order's hash
/// @param feeSelection -
/// A miner-supplied value indicating if LRC (value = 0)
Expand Down Expand Up @@ -204,8 +191,9 @@ contract LoopringProtocolImpl is LoopringProtocol {
s
);

cancelled[orderHash] = cancelled[orderHash].add(cancelAmount);
cancelledOrFilled[orderHash] = cancelledOrFilled[orderHash].add(cancelAmount);
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);
delegate.addCancelled(orderHash, cancelAmount);
delegate.addCancelledOrFilled(orderHash, cancelAmount);

emit OrderCancelled(orderHash, cancelAmount);
}
Expand All @@ -220,10 +208,12 @@ contract LoopringProtocolImpl is LoopringProtocol {
uint t = (cutoff == 0 || cutoff >= block.timestamp) ? block.timestamp : cutoff;

bytes20 tokenPair = bytes20(token1) ^ bytes20(token2);
require(tradingPairCutoffs[msg.sender][tokenPair] < t);
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);

require(delegate.tradingPairCutoffs(msg.sender, tokenPair) < t);
// "attempted to set cutoff to a smaller value"

tradingPairCutoffs[msg.sender][tokenPair] = t;
delegate.setTradingPairCutoffs(tokenPair, t);
emit OrdersCancelled(
msg.sender,
token1,
Expand All @@ -238,10 +228,11 @@ contract LoopringProtocolImpl is LoopringProtocol {
external
{
uint t = (cutoff == 0 || cutoff >= block.timestamp) ? block.timestamp : cutoff;
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);

require(cutoffs[msg.sender] < t); // "attempted to set cutoff to a smaller value"
require(delegate.cutoffs(msg.sender) < t); // "attempted to set cutoff to a smaller value"

cutoffs[msg.sender] = t;
delegate.setCutoffs(t);
emit AllOrdersCancelled(msg.sender, t);
}

Expand Down Expand Up @@ -287,8 +278,10 @@ contract LoopringProtocolImpl is LoopringProtocol {
// Assemble input data into structs so we can pass them to other functions.
// This method also calculates ringHash, therefore it must be called before
// calling `verifyRingSignatures`.
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);
OrderState[] memory orders = assembleOrders(
params,
delegate,
addressList,
uintArgsList,
uint8ArgsList,
Expand All @@ -299,7 +292,7 @@ contract LoopringProtocolImpl is LoopringProtocol {

verifyTokensRegistered(params, orders);

handleRing(_ringIndex, params, orders);
handleRing(_ringIndex, params, orders, delegate);

ringIndex = _ringIndex + 1;
}
Expand Down Expand Up @@ -366,12 +359,12 @@ contract LoopringProtocolImpl is LoopringProtocol {
function handleRing(
uint64 _ringIndex,
RingParams params,
OrderState[] orders
OrderState[] orders,
TokenTransferDelegate delegate
)
private
{
address _lrcTokenAddress = lrcTokenAddress;
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);

// Do the hard work.
verifyRingHasNoSubRing(params.ringSize, orders);
Expand Down Expand Up @@ -460,9 +453,9 @@ contract LoopringProtocolImpl is LoopringProtocol {

// Update fill records
if (state.buyNoMoreThanAmountB) {
cancelledOrFilled[state.orderHash] += nextFillAmountS;
delegate.addCancelledOrFilled(state.orderHash, nextFillAmountS);
} else {
cancelledOrFilled[state.orderHash] += state.fillAmountS;
delegate.addCancelledOrFilled(state.orderHash, state.fillAmountS);
}

orderHashList[i] = state.orderHash;
Expand Down Expand Up @@ -724,7 +717,7 @@ contract LoopringProtocolImpl is LoopringProtocol {

if (state.buyNoMoreThanAmountB) {
amount = state.amountB.tolerantSub(
cancelledOrFilled[state.orderHash]
delegate.cancelledOrFilled(state.orderHash)
);

state.amountS = amount.mul(state.amountS) / state.amountB;
Expand All @@ -733,7 +726,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
state.amountB = amount;
} else {
amount = state.amountS.tolerantSub(
cancelledOrFilled[state.orderHash]
delegate.cancelledOrFilled(state.orderHash)
);

state.amountB = amount.mul(state.amountB) / state.amountS;
Expand Down Expand Up @@ -809,6 +802,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
/// @return A list of orders.
function assembleOrders(
RingParams params,
TokenTransferDelegate delegate,
address[4][] addressList,
uint[6][] uintArgsList,
uint8[1][] uint8ArgsList,
Expand All @@ -821,7 +815,6 @@ contract LoopringProtocolImpl is LoopringProtocol {
orders = new OrderState[](params.ringSize);

for (uint i = 0; i < params.ringSize; i++) {

bool marginSplitAsFee = (params.feeSelections & (uint16(1) << i)) > 0;
orders[i] = OrderState(
addressList[i][0],
Expand Down Expand Up @@ -863,6 +856,8 @@ contract LoopringProtocolImpl is LoopringProtocol {
params.ringHash ^= orderHash;
}

validateOrdersCutoffs(orders, delegate);

params.ringHash = keccak256(
params.ringHash,
params.miner,
Expand All @@ -887,11 +882,23 @@ contract LoopringProtocolImpl is LoopringProtocol {

require(order.validSince <= block.timestamp); // order is too early to match
require(order.validUntil > block.timestamp); // order is expired
}

bytes20 tradingPair = bytes20(order.tokenS) ^ bytes20(order.tokenB);
require(order.validSince > tradingPairCutoffs[order.owner][tradingPair]);
// order trading pair is cut off
require(order.validSince > cutoffs[order.owner]); // order is cut off
function validateOrdersCutoffs(OrderState[] orders, TokenTransferDelegate delegate)
private
view
{
address[] memory owners = new address[](orders.length);
bytes20[] memory tradingPairs = new bytes20[](orders.length);
uint[] memory validSinceTimes = new uint[](orders.length);

for (uint i = 0; i < orders.length; i++) {
owners[i] = orders[i].owner;
tradingPairs[i] = bytes20(orders[i].tokenS) ^ bytes20(orders[i].tokenB);
validSinceTimes[i] = orders[i].validSince;
}

delegate.checkCutoffsBatch(owners, tradingPairs, validSinceTimes);
}

/// @dev Get the Keccak-256 hash of order with specified parameters.
Expand All @@ -903,7 +910,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
returns (bytes32)
{
return keccak256(
address(this),
delegateAddress,
order.owner,
order.tokenS,
order.tokenB,
Expand Down Expand Up @@ -950,6 +957,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
returns (uint)
{
bytes20 tokenPair = bytes20(token1) ^ bytes20(token2);
return tradingPairCutoffs[orderOwner][tokenPair];
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);
return delegate.tradingPairCutoffs(orderOwner, tokenPair);
}
}
29 changes: 29 additions & 0 deletions contracts/TokenTransferDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ contract TokenTransferDelegate {
event AddressAuthorized(address indexed addr, uint32 number);
event AddressDeauthorized(address indexed addr, uint32 number);

// The following map is used to keep trace of order fill and cancellation
// history.
mapping (bytes32 => uint) public cancelledOrFilled;

// This map is used to keep trace of order's cancellation history.
mapping (bytes32 => uint) public cancelled;

// A map from address to its cutoff timestamp.
mapping (address => uint) public cutoffs;

// A map from address to its trading-pair cutoff timestamp.
mapping (address => mapping (bytes20 => uint)) public tradingPairCutoffs;

/// @dev Add a Loopring protocol address.
/// @param addr A loopring protocol address.
function authorizeAddress(
Expand Down Expand Up @@ -73,4 +86,20 @@ contract TokenTransferDelegate {
public
view
returns (bool);

function addCancelled(bytes32 orderHash, uint cancelAmount)
external;

function addCancelledOrFilled(bytes32 orderHash, uint cancelOrFillAmount)
external;

function setCutoffs(uint t)
external;

function setTradingPairCutoffs(bytes20 tokenPair, uint t)
external;

function checkCutoffsBatch(address[] owners, bytes20[] tradingPairs, uint[] validSince)
external
view;
}
43 changes: 43 additions & 0 deletions contracts/TokenTransferDelegateImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,47 @@ contract TokenTransferDelegateImpl is TokenTransferDelegate, Claimable {
);
}
}

function addCancelled(bytes32 orderHash, uint cancelAmount)
onlyAuthorized
external
{
cancelled[orderHash] = cancelled[orderHash].add(cancelAmount);
}

function addCancelledOrFilled(bytes32 orderHash, uint cancelOrFillAmount)
onlyAuthorized
external
{
cancelledOrFilled[orderHash] = cancelledOrFilled[orderHash].add(cancelOrFillAmount);
}

function setCutoffs(uint t)
onlyAuthorized
external
{
cutoffs[tx.origin] = t;
}

function setTradingPairCutoffs(bytes20 tokenPair, uint t)
onlyAuthorized
external
{
tradingPairCutoffs[tx.origin][tokenPair] = t;
}

function checkCutoffsBatch(address[] owners, bytes20[] tradingPairs, uint[] validSince)
external
view
{
uint len = owners.length;
require(len == tradingPairs.length);
require(len == validSince.length);

for(uint i = 0; i < len; i++) {
require(validSince[i] > tradingPairCutoffs[owners[i]][tradingPairs[i]]); // order trading pair is cut off
require(validSince[i] > cutoffs[owners[i]]); // order is cut off
}
}

}
8 changes: 4 additions & 4 deletions test/testLoopringProtocolImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const currBlockNumber = web3.eth.blockNumber;
currBlockTimeStamp = web3.eth.getBlock(currBlockNumber).timestamp;

ringFactory = new RingFactory(LoopringProtocolImpl.address,
ringFactory = new RingFactory(TokenTransferDelegate.address,
eosAddress,
neoAddress,
lrcAddress,
Expand Down Expand Up @@ -856,7 +856,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
order.params.lrcFee,
cancelAmount];

const cancelledOrFilledAmount0 = await loopringProtocolImpl.cancelledOrFilled(order.params.orderHashHex);
const cancelledOrFilledAmount0 = await tokenTransferDelegate.cancelledOrFilled(order.params.orderHashHex);
const tx = await loopringProtocolImpl.cancelOrder(addresses,
orderValues,
order.params.buyNoMoreThanAmountB,
Expand All @@ -866,7 +866,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
order.params.s,
{from: order.owner});

const cancelledOrFilledAmount1 = await loopringProtocolImpl.cancelledOrFilled(order.params.orderHashHex);
const cancelledOrFilledAmount1 = await tokenTransferDelegate.cancelledOrFilled(order.params.orderHashHex);
assert.equal(cancelledOrFilledAmount1.minus(cancelledOrFilledAmount0).toNumber(),
cancelAmount.toNumber(), "cancelled amount not match");
});
Expand Down Expand Up @@ -913,7 +913,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
describe("cancelAllOrders", () => {
it("should be able to set cutoffs", async () => {
await loopringProtocolImpl.cancelAllOrders(new BigNumber(1508566125), {from: order2Owner});
const cutoff = await loopringProtocolImpl.cutoffs(order2Owner);
const cutoff = await tokenTransferDelegate.cutoffs(order2Owner);
assert.equal(cutoff.toNumber(), 1508566125, "cutoff not set correctly");
});

Expand Down

0 comments on commit 2462a3c

Please sign in to comment.