Skip to content
This repository was archived by the owner on Mar 19, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/LoopringProtocol.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ contract LoopringProtocol {
uint8 public constant MARGIN_SPLIT_PERCENTAGE_BASE = 100;

uint8 public constant OPTION_MASK_CAP_BY_AMOUNTB = 0x01;
uint8 public constant OPTION_MASK_ALL_OR_NONE = 0x02;

struct Fill {
bytes32 orderHash;
Expand Down
91 changes: 65 additions & 26 deletions contracts/LoopringProtocolImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ contract LoopringProtocolImpl is LoopringProtocol {
uint validUntil;
uint lrcFee;
uint8 option;
bool capByAmountB;
bool optCapByAmountB;
bool optAllOrNone;
bool marginSplitAsFee;
bytes32 orderHash;
address trackerAddr;
Expand Down Expand Up @@ -164,6 +165,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
orderValues[4],
option,
option & OPTION_MASK_CAP_BY_AMOUNTB > 0 ? true : false,
option & OPTION_MASK_ALL_OR_NONE > 0 ? true : false,
false,
0x0,
0x0,
Expand Down Expand Up @@ -199,6 +201,10 @@ contract LoopringProtocolImpl is LoopringProtocol {
require(registered, "invalid broker");
}

// For AON orders, must cancel it as a whole.
if (order.optAllOrNone) {
cancelAmount = order.optCapByAmountB ? order.amountB : order.amountS;
}
TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);
delegate.addCancelled(orderHash, cancelAmount);
delegate.addCancelledOrFilled(orderHash, cancelAmount);
Expand Down Expand Up @@ -298,7 +304,7 @@ contract LoopringProtocolImpl is LoopringProtocol {

verifyMinerSuppliedFillRates(ctx);

scaleRingBasedOnHistoricalRecords(ctx);
scaleOrders(ctx);

calculateRingFillAmount(ctx);

Expand Down Expand Up @@ -378,6 +384,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
uintArgs[4],
ctx.optionList[i],
ctx.optionList[i] & OPTION_MASK_CAP_BY_AMOUNTB > 0 ? true : false,
ctx.optionList[i] & OPTION_MASK_ALL_OR_NONE > 0 ? true : false,
marginSplitAsFee,
0x0,
0x0, // brokderTracker
Expand Down Expand Up @@ -528,7 +535,7 @@ contract LoopringProtocolImpl is LoopringProtocol {

/// @dev Scale down all orders based on historical fill or cancellation
/// stats but key the order's original exchange rate.
function scaleRingBasedOnHistoricalRecords(
function scaleOrders(
Context ctx
)
private
Expand All @@ -539,26 +546,34 @@ contract LoopringProtocolImpl is LoopringProtocol {

for (uint i = 0; i < ringSize; i++) {
Order memory order = orders[i];
uint amount;

if (order.capByAmountB) {
amount = order.amountB.tolerantSub(
ctx.delegate.cancelledOrFilled(order.orderHash)
if (order.optAllOrNone) {
require(
ctx.delegate.cancelledOrFilled(order.orderHash) == 0,
"AON filled or cancelled already"
);
} else {
uint amount;

order.amountS = amount.mul(order.amountS) / order.amountB;
order.lrcFee = amount.mul(order.lrcFee) / order.amountB;
if (order.optCapByAmountB) {
amount = order.amountB.tolerantSub(
ctx.delegate.cancelledOrFilled(order.orderHash)
);

order.amountB = amount;
} else {
amount = order.amountS.tolerantSub(
ctx.delegate.cancelledOrFilled(order.orderHash)
);
order.amountS = amount.mul(order.amountS) / order.amountB;
order.lrcFee = amount.mul(order.lrcFee) / order.amountB;

order.amountB = amount.mul(order.amountB) / order.amountS;
order.lrcFee = amount.mul(order.lrcFee) / order.amountS;
order.amountB = amount;
} else {
amount = order.amountS.tolerantSub(
ctx.delegate.cancelledOrFilled(order.orderHash)
);

order.amountB = amount.mul(order.amountB) / order.amountS;
order.lrcFee = amount.mul(order.lrcFee) / order.amountS;

order.amountS = amount;
order.amountS = amount;
}
}

require(order.amountS > 0, "amountS scaled to 0");
Expand All @@ -571,12 +586,21 @@ contract LoopringProtocolImpl is LoopringProtocol {
order.signer,
order.trackerAddr
);
require(availableAmountS > 0, "spendable is 0");

order.fillAmountS = (
order.amountS < availableAmountS ?
order.amountS : availableAmountS
);
// This check is more strict than it needs to be, in case the
// `optCapByAmountB`is true.
if (order.optAllOrNone) {
require(
availableAmountS >= order.amountS,
"AON spendable"
);
} else {
require(availableAmountS > 0, "spendable is 0");
order.fillAmountS = (
order.amountS < availableAmountS ?
order.amountS : availableAmountS
);
}
}
}

Expand Down Expand Up @@ -698,7 +722,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
if (minerLrcSpendable >= order.lrcFeeState) {
nextFillAmountS = ctx.orders[(i + 1) % ringSize].fillAmountS;
uint split;
if (order.capByAmountB) {
if (order.optCapByAmountB) {
split = (nextFillAmountS.mul(
order.amountS
) / order.amountB).sub(
Expand All @@ -712,7 +736,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
) / 2;
}

if (order.capByAmountB) {
if (order.optCapByAmountB) {
order.splitS = split;
} else {
order.splitB = split;
Expand Down Expand Up @@ -763,7 +787,7 @@ contract LoopringProtocolImpl is LoopringProtocol {

historyBatch[q++] = order.orderHash;
historyBatch[q++] = bytes32(
order.capByAmountB ? nextFillAmountS : order.fillAmountS
order.optCapByAmountB ? nextFillAmountS : order.fillAmountS
);

fills[i] = Fill(
Expand Down Expand Up @@ -811,7 +835,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
order.rateB
) / order.rateS;

if (order.capByAmountB) {
if (order.optCapByAmountB) {
if (fillAmountB > order.amountB) {
fillAmountB = order.amountB;

Expand All @@ -830,6 +854,21 @@ contract LoopringProtocolImpl is LoopringProtocol {
) / order.amountS;
}

// Check All-or-None orders
if (order.optAllOrNone){
if (order.optCapByAmountB) {
require(
fillAmountB >= order.amountB,
"AON failed on amountB"
);
} else {
require(
order.fillAmountS >= order.amountS,
"AON failed on amountS"
);
}
}

if (fillAmountB <= next.fillAmountS) {
next.fillAmountS = fillAmountB;
} else {
Expand Down