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

Commit

Permalink
Version1.3 (#277)
Browse files Browse the repository at this point in the history
* new feature implementation: split ring mining fee to wallet

* bug fix for fee split

* unit test update

* fix a bug in nameRegistry and unit test update

* fix all unit test
  • Loading branch information
kongliangzhong authored and dong77 committed Mar 25, 2018
1 parent 8b0f7fa commit 411f4a8
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 46 deletions.
16 changes: 13 additions & 3 deletions contracts/LoopringProtocolImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ contract LoopringProtocolImpl is LoopringProtocol {
bytes32[] memory orderHashList,
uint[6][] memory amountsList)
{
bytes32[] memory batch = new bytes32[](ringSize * 6); // ringSize * (owner + tokenS + 4 amounts)
bytes32[] memory batch = new bytes32[](ringSize * 7); // ringSize * (owner + tokenS + 4 amounts)
orderHashList = new bytes32[](ringSize);
amountsList = new uint[6][](ringSize);

Expand All @@ -531,7 +531,12 @@ contract LoopringProtocolImpl is LoopringProtocol {
batch[p + 3] = bytes32(prevSplitB + state.splitS);
batch[p + 4] = bytes32(state.lrcReward);
batch[p + 5] = bytes32(state.lrcFee);
p += 6;
if (order.walletId != 0) {
batch[p + 6] = bytes32(NameRegistry(nameRegistryAddress).getFeeRecipientById(order.walletId));
} else {
batch[p + 6] = bytes32(0x0);
}
p += 7;

// Update fill records
if (order.buyNoMoreThanAmountB) {
Expand All @@ -550,7 +555,12 @@ contract LoopringProtocolImpl is LoopringProtocol {
}

// Do all transactions
delegate.batchTransferToken(_lrcTokenAddress, feeRecipient, batch);
delegate.batchTransferToken(
_lrcTokenAddress,
feeRecipient,
walletSplitPercentage,
batch
);
}

/// @dev Verify miner has calculte the rates correctly.
Expand Down
10 changes: 10 additions & 0 deletions contracts/NameRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ contract NameRegistry {
signer = addressSet.signer;
}

function getFeeRecipientById(uint id)
external
view
returns (address feeRecipient)
{
Participant storage addressSet = participantMap[id];

feeRecipient = addressSet.feeRecipient;
}

function getParticipantIds(string name, uint start, uint count)
external
view
Expand Down
57 changes: 45 additions & 12 deletions contracts/TokenTransferDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,21 @@ contract TokenTransferDelegate is Claimable {

function batchTransferToken(
address lrcTokenAddress,
address feeRecipient,
address minerFeeRecipient,
uint8 walletSplitPercentage,
bytes32[] batch)
onlyAuthorized
external
{
uint len = batch.length;
require(len % 6 == 0);
require(len % 7 == 0);
require(walletSplitPercentage >= 0 && walletSplitPercentage <= 100);

ERC20 lrc = ERC20(lrcTokenAddress);

for (uint i = 0; i < len; i += 6) {
for (uint i = 0; i < len; i += 7) {
address owner = address(batch[i]);
address prevOwner = address(batch[(i + len - 6) % len]);
address prevOwner = address(batch[(i + len - 7) % len]);

// Pay token to previous order, or to miner as previous order's
// margin split or/and this order's margin split.
Expand All @@ -187,26 +189,57 @@ contract TokenTransferDelegate is Claimable {
);
}

if (feeRecipient != 0x0 && owner != feeRecipient) {
if (minerFeeRecipient != 0x0 && owner != minerFeeRecipient) {
bytes32 item = batch[i + 3];
// address walletFeeRecipient = address(batch[i + 6]);
if (item != 0) {
require(
token.transferFrom(owner, feeRecipient, uint(item))
);
if (address(batch[i + 6]) != 0x0 && walletSplitPercentage > 0) {
require(
token.transferFrom(owner,
minerFeeRecipient,
uint(item).mul(100 - walletSplitPercentage) / 100
)
);
require(
token.transferFrom(owner,
address(batch[i + 6]),
uint(item).mul(walletSplitPercentage) / 100
)
);
} else {
require(
token.transferFrom(owner, minerFeeRecipient, uint(item))
);
}
}

item = batch[i + 4];
if (item != 0) {
require(
lrc.transferFrom(feeRecipient, owner, uint(item))
lrc.transferFrom(minerFeeRecipient, owner, uint(item))
);
}

item = batch[i + 5];
if (item != 0) {
require(
lrc.transferFrom(owner, feeRecipient, uint(item))
);
if (address(batch[i + 6]) != 0x0 && walletSplitPercentage > 0) {
require(
lrc.transferFrom(owner,
minerFeeRecipient,
uint(item).mul(100 - walletSplitPercentage) / 100
)
);
require(
lrc.transferFrom(owner,
address(batch[i + 6]),
uint(item).mul(walletSplitPercentage) / 100
)
);
} else {
require(
lrc.transferFrom(owner, minerFeeRecipient, uint(item))
);
}
}
}
}
Expand Down
34 changes: 24 additions & 10 deletions test/testLoopringProtocolImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const orderAuthAddr = accounts[7]; // should generate each time in front-end. we just mock it here.
const ringOwner = accounts[0];
const feeRecepient = accounts[6];
const walletAddr = accounts[8];

let loopringProtocolImpl: any;
let tokenRegistry: any;
Expand All @@ -46,6 +47,8 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {

let participantId: number;
let currBlockTimeStamp: number;
let walletSplitPercentage: number;
let walletId: BigNumber;

let ringFactory: RingFactory;

Expand Down Expand Up @@ -102,6 +105,16 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const pids = await nameRegistry.getParticipantIds("test001", 0, 1);
participantId = pids[0].toNumber();

await nameRegistry.registerName("wallet03", {from: walletAddr});
await nameRegistry.addParticipant(walletAddr, walletAddr, {from: walletAddr});
const walletIds = await nameRegistry.getParticipantIds("wallet03", 0, 1);
walletId = walletIds[0];
// console.log("walletId", walletId);

const walletSplitPercentageBN = await loopringProtocolImpl.walletSplitPercentage();
walletSplitPercentage = walletSplitPercentageBN.toNumber();
// console.log("walletSplitPercentage:", walletSplitPercentage);

tokenTransferDelegate.authorizeAddress(LoopringProtocolImpl.address);

[lrc, eos, neo, qtum] = await Promise.all([
Expand All @@ -121,6 +134,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
qtumAddress,
orderAuthAddr,
currBlockTimeStamp);
ringFactory.walletId = new BigNumber(walletId.toNumber());

// approve only once for all test cases.
const allTokens = [lrc, eos, neo, qtum];
Expand Down Expand Up @@ -185,7 +199,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
assert.equal(eosBalance22.toNumber(), 1000e18, "eos balance not match for order2Owner");
assert.equal(neoBalance22.toNumber(), 900e18, "neo balance not match for order2Owner");

assert.equal(lrcBalance23.toNumber(), 15e18, "lrc balance not match for feeRecepient");
assert.equal(lrcBalance23.toNumber(), 12e18, "lrc balance not match for feeRecepient");

await clear([eos, neo, lrc], [order1Owner, order2Owner, feeRecepient]);
});
Expand Down Expand Up @@ -225,7 +239,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const eosBalance23 = await getTokenBalanceAsync(eos, feeRecepient);
const neoBalance23 = await getTokenBalanceAsync(neo, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();

Expand Down Expand Up @@ -278,7 +292,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const neoBalance23 = await getTokenBalanceAsync(neo, feeRecepient);
const lrcBalance23 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();

Expand Down Expand Up @@ -343,7 +357,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const qtumBalance24 = await getTokenBalanceAsync(qtum, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();

Expand All @@ -358,7 +372,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
assertNumberEqualsWithPrecision(eosBalance24.toNumber(), feeAndBalanceExpected.totalFees[eosAddress]);
assertNumberEqualsWithPrecision(neoBalance24.toNumber(), feeAndBalanceExpected.totalFees[neoAddress]);
assertNumberEqualsWithPrecision(qtumBalance24.toNumber(), feeAndBalanceExpected.totalFees[qtumAddress]);
assertNumberEqualsWithPrecision(lrcBalance24.toNumber(), 5e18);
assertNumberEqualsWithPrecision(lrcBalance24.toNumber(), 4e18);

await clear([eos, neo, lrc, qtum], [order1Owner, order2Owner, order3Owner, feeRecepient]);
});
Expand Down Expand Up @@ -415,7 +429,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const qtumBalance24 = await getTokenBalanceAsync(qtum, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.availableAmountSList = availableAmountSList;
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();
Expand Down Expand Up @@ -491,7 +505,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const qtumBalance24 = await getTokenBalanceAsync(qtum, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.availableAmountSList = availableAmountSList;
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();
Expand Down Expand Up @@ -559,7 +573,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const neoBalance24 = await getTokenBalanceAsync(neo, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.availableAmountSList = availableAmountSList;
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();
Expand Down Expand Up @@ -638,7 +652,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const neoBalance24 = await getTokenBalanceAsync(neo, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.availableAmountSList = availableAmountSList;
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();
Expand Down Expand Up @@ -706,7 +720,7 @@ contract("LoopringProtocolImpl", (accounts: string[]) => {
const neoBalance24 = await getTokenBalanceAsync(neo, feeRecepient);
const lrcBalance24 = await getTokenBalanceAsync(lrc, feeRecepient);

const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList);
const simulator = new ProtocolSimulator(ring, lrcAddress, feeSelectionList, walletSplitPercentage);
simulator.availableAmountSList = availableAmountSList;
simulator.spendableLrcFeeList = spendableLrcFeeList;
const feeAndBalanceExpected = simulator.caculateRingFeesAndBalances();
Expand Down
12 changes: 9 additions & 3 deletions test/testTokenTransferDelegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ contract("TokenTransferDelegate", (accounts: string[]) => {
const loopringProtocolV3 = accounts[3]; // mock loopring protocol v3
const trader1 = accounts[3];
const trader2 = accounts[4];
const walletAddr1 = accounts[5];
const walletAddr2 = accounts[6];

let tokenRegistry: any;
let tokenTransferDelegate: any;
Expand Down Expand Up @@ -129,15 +131,17 @@ contract("TokenTransferDelegate", (accounts: string[]) => {
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(5e18));
batch.push(walletAddr1);

batch.push(addressToBytes32Str(trader2));
batch.push(addressToBytes32Str(neoAddress));
batch.push(numberToBytes32Str(10e18));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(5e18));
batch.push(walletAddr2);

const tx = await tokenTransferDelegate.batchTransferToken(lrcAddress, owner, batch,
const tx = await tokenTransferDelegate.batchTransferToken(lrcAddress, owner, 20, batch,
{from: loopringProtocolV1});

const trader1NeoBalance = await getTokenBalanceAsync(neo, trader1);
Expand All @@ -146,7 +150,7 @@ contract("TokenTransferDelegate", (accounts: string[]) => {

assert.equal(trader1NeoBalance.toNumber(), 10e18, "trade amount incorrect");
assert.equal(trader2EosBalance.toNumber(), 100e18, "trade amount incorrect");
assert.equal(ownerLrcBalance.toNumber(), 10e18, "lrc fee amount incorrect");
assert.equal(ownerLrcBalance.toNumber(), 8e18, "lrc fee amount incorrect");
});

it("should not be able to transfer token in batch if msg.sender not authorized", async () => {
Expand Down Expand Up @@ -174,15 +178,17 @@ contract("TokenTransferDelegate", (accounts: string[]) => {
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(5e18));
batch.push(walletAddr1);

batch.push(addressToBytes32Str(trader2));
batch.push(addressToBytes32Str(neoAddress));
batch.push(numberToBytes32Str(10e18));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(0));
batch.push(numberToBytes32Str(5e18));
batch.push(walletAddr2);

const tx = await tokenTransferDelegate.batchTransferToken(lrcAddress, owner, batch,
const tx = await tokenTransferDelegate.batchTransferToken(lrcAddress, owner, 20, batch,
{from: loopringProtocolV2});
} catch (err) {
const errMsg = `${err}`;
Expand Down
12 changes: 11 additions & 1 deletion util/protocol_simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ export class ProtocolSimulator {
public spendableLrcFeeList: number[];
public orderCancelled: number[];
public orderFilled: number[];
public walletSplitPercentage: number;

constructor(ring: Ring,
lrcAddress: string,
feeSelectionList: number[]) {
feeSelectionList: number[],
walletSplitPercentage: number) {
this.ring = ring;
this.lrcAddress = lrcAddress;
this.feeSelectionList = feeSelectionList;
this.walletSplitPercentage = walletSplitPercentage;
}

public caculateRateAmountS() {
Expand Down Expand Up @@ -175,6 +178,13 @@ export class ProtocolSimulator {
const balanceItem = balances[i];
const tokenS = order.params.tokenS;
const tokenB = order.params.tokenB;
const walletId = order.params.walletId.toNumber();

if (walletId > 0) {
feeItem.feeLrc = feeItem.feeLrc * (100 - this.walletSplitPercentage) / 100;
feeItem.feeS = feeItem.feeS * (100 - this.walletSplitPercentage) / 100;
feeItem.feeB = feeItem.feeB * (100 - this.walletSplitPercentage) / 100;
}

feeTotals[this.lrcAddress] = this.sumFeeItem(feeTotals, this.lrcAddress, feeItem.feeLrc);
feeTotals[this.lrcAddress] = this.sumFeeItem(feeTotals,
Expand Down
Loading

0 comments on commit 411f4a8

Please sign in to comment.