Skip to content

Commit

Permalink
[Protocol3] Test signature-based whitelist implementation (#599)
Browse files Browse the repository at this point in the history
  • Loading branch information
yueawang authored and dong77 committed Oct 18, 2019
1 parent 426901c commit 0f7e195
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract SignatureBasedAddressWhitelist is Claimable, IAddressWhitelist
}

assembly {
t := mload(add(permission, 8)) // first 8 bytes as time in second since epoch
t := and(mload(add(permission, 8)), 0xFFFFFFFFFFFFFFFF) // first 8 bytes as time in second since epoch
r := mload(add(permission, 40))
s := mload(add(permission, 72))
v := and(mload(add(permission, 73)), 255)
Expand All @@ -56,15 +56,18 @@ contract SignatureBasedAddressWhitelist is Claimable, IAddressWhitelist
return false;
}

if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return false;
}

if (v < 27) {
v += 27;
}

if (v != 27 && v != 28) {
return false;
}

bytes32 hash = keccak256(abi.encode("LOOPRING_DEX_ACCOUNT_CREATION", addr, t));
bytes32 msgBase = keccak256(abi.encodePacked("LOOPRING_DEX_ACCOUNT_CREATION", addr, t));
bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", msgBase));
return owner == ecrecover(hash, v, r, s);
}
}
171 changes: 171 additions & 0 deletions packages/loopring_v3/test/testExchangeWhiteList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { Bitstream } from "loopringV3.js";
import { ExchangeTestUtil } from "./testExchangeUtil";
import BN = require("bn.js");
import Contract from "web3/eth/contract";
const fs = require("fs");
const abi = require("ethereumjs-abi");

contract("Exchange", (accounts: string[]) => {
let exchangeTestUtil: ExchangeTestUtil;
let newAddressWhitelist: any;
let addressWhiteListABI: any;
let addressWhiteListContract: Contract;

before(async () => {
exchangeTestUtil = new ExchangeTestUtil();
await exchangeTestUtil.initialize(accounts);
newAddressWhitelist = await exchangeTestUtil.contracts.AddressWhitelist.new();
assert(
newAddressWhitelist.address != 0,
"newAddressWhitelist.address == 0."
);

const ABIPath = "ABI/version30/";
addressWhiteListABI = fs.readFileSync(
ABIPath + "IAddressWhitelist.abi",
"ascii"
);
addressWhiteListContract = new web3.eth.Contract(
JSON.parse(addressWhiteListABI),
newAddressWhitelist.address
);
});

const generatePermissionBytes = async (
now: any,
address: any,
signer: any
) => {
const bitstream = new Bitstream();
bitstream.addNumber(now, 8);
const hashMsg =
"0x" +
abi
.soliditySHA3(
["string", "address", "uint"],
["LOOPRING_DEX_ACCOUNT_CREATION", address, now]
)
.toString("hex");
// console.log('hashMsg :', hashMsg);
const rsv = await web3.eth.sign(hashMsg, signer);
bitstream.addHex(rsv);

// console.log("permission data:", bitstream.getData());
const permission = web3.utils.hexToBytes(bitstream.getData());
assert(
permission.length == 73,
"permission.length should be 73(t8+sign65)"
);
return permission;
};

describe("AddressWhitelist functionality unit test", () => {
it("check isAddressWhitelisted basic logic", async () => {
const deployer = exchangeTestUtil.testContext.deployer;
const realAccount = exchangeTestUtil.testContext.orderOwners[0];
const fakeAccount = exchangeTestUtil.testContext.orderOwners[1];
const now = Math.floor(Date.now() / 1000);
const permission = await generatePermissionBytes(
now,
realAccount,
deployer
);

addressWhiteListContract.methods
.isAddressWhitelisted(realAccount, permission)
.call()
.then((ret: any) => {
assert(ret, "Corrent whitelist signature should pass");
});

addressWhiteListContract.methods
.isAddressWhitelisted(fakeAccount, permission)
.call()
.then((ret: any) => {
assert(!ret, "Corrent whitelist signature should not pass");
});
});

it("check isAddressWhitelisted fail conditions", async () => {
const deployer = exchangeTestUtil.testContext.deployer;
const realAccount = exchangeTestUtil.testContext.orderOwners[0];

var date = new Date();
var past = Math.floor(date.setDate(date.getHours() - 25) / 1000);
var permission = await generatePermissionBytes(
past,
realAccount,
deployer
);

addressWhiteListContract.methods
.isAddressWhitelisted(realAccount, [])
.call()
.then((ret: any) => {
assert(!ret, "Wrong permission should not pass check.");
});

addressWhiteListContract.methods
.isAddressWhitelisted(realAccount, permission)
.call()
.then((ret: any) => {
assert(!ret, "Requests happened 1 day ago should not pass.");
});

var now = Math.floor(Date.now() / 1000);
var permission = await generatePermissionBytes(
now,
realAccount,
deployer
);
permission[72] = 2;

addressWhiteListContract.methods
.isAddressWhitelisted(realAccount, permission)
.call()
.then((ret: any) => {
assert(!ret, "v is not in [0, 1] should not pass.");
});
});

it("check malicious permission", async () => {
const deployer = exchangeTestUtil.testContext.deployer;
const realAccount = exchangeTestUtil.testContext.orderOwners[0];
var now = Math.floor(Date.now() / 1000);
var permission = await generatePermissionBytes(
now,
realAccount,
deployer
);

var permStr = await web3.utils.bytesToHex(permission);
var t = permStr.slice(2, 18);
var r = permStr.slice(18, 82);
var s = permStr.slice(82, 146);
var v = permStr.slice(146);

var curveN = new BN(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
16
);
var maliciousS = curveN.sub(new BN(s, 16));
var maliciousV = new BN(v, 16).add(new BN(1)).mod(new BN(2));

const bitstream = new Bitstream();
bitstream.addBN(new BN(t, 16), 8);
bitstream.addBN(new BN(r, 16), 32);
bitstream.addBN(maliciousS, 32);
bitstream.addBN(maliciousV, 1);

var maliciousPermission = bitstream.getData();

var maliciousPermBytes = await web3.utils.hexToBytes(maliciousPermission);
addressWhiteListContract.methods
.isAddressWhitelisted(realAccount, maliciousPermBytes)
.call()
.then((ret: any) => {
assert(!ret, "malicious permission should not pass");
});
});
});
});
4 changes: 4 additions & 0 deletions packages/loopring_v3/util/Artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class Artifacts {
public UserStakingPool: any;
public ProtocolFeeVault: any;
public UniswapTokenSeller: any;
public AddressWhitelist: any;

constructor(artifacts: any) {
this.MockContract = artifacts.require("thirdparty/MockContract.sol");
Expand All @@ -49,6 +50,9 @@ export class Artifacts {
this.TransferContract = artifacts.require("test/TransferContract");
this.PoseidonContract = artifacts.require("test/PoseidonContract");
this.UserStakingPool = artifacts.require("impl/UserStakingPool");
this.AddressWhitelist = artifacts.require(
"./impl/SignatureBasedAddressWhitelist.sol"
);
this.ProtocolFeeVault = artifacts.require("impl/ProtocolFeeVault");
this.UniswapTokenSeller = artifacts.require("impl/UniswapTokenSeller");
}
Expand Down

0 comments on commit 0f7e195

Please sign in to comment.