Add TEC integration tests
This commit is contained in:
@@ -178,6 +178,7 @@ contract MixinTECApprovalVerifier is
|
||||
selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||
) {
|
||||
// Decode all orders
|
||||
// solhint-disable indent
|
||||
(orders) = abi.decode(
|
||||
data.slice(4, data.length),
|
||||
(LibOrder.Order[])
|
||||
|
@@ -23,6 +23,7 @@ import "../src/MixinSignatureValidator.sol";
|
||||
import "../src/MixinTECApprovalVerifier.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract TestMixins is
|
||||
MixinSignatureValidator,
|
||||
MixinTECApprovalVerifier
|
||||
|
@@ -69,6 +69,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^4.0.3",
|
||||
"@0x/contracts-asset-proxy": "1.0.2",
|
||||
"@0x/contracts-exchange-libs": "^1.0.5",
|
||||
"@0x/contracts-exchange": "1.0.2",
|
||||
"@0x/contracts-erc20": "1.0.2",
|
||||
|
@@ -27,7 +27,6 @@ import {
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
const timeBuffer = new BigNumber(1000);
|
||||
|
||||
describe('Mixins tests', () => {
|
||||
let transactionSignerAddress: string;
|
||||
@@ -64,12 +63,13 @@ describe('Mixins tests', () => {
|
||||
salt: devConstants.ZERO_AMOUNT,
|
||||
signature: devConstants.NULL_BYTES,
|
||||
};
|
||||
const transactionSignerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[0];
|
||||
const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[1];
|
||||
const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[2];
|
||||
const transactionSignerPrivateKey =
|
||||
devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)];
|
||||
const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)];
|
||||
const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)];
|
||||
transactionFactory = new TECTransactionFactory(transactionSignerPrivateKey, mixins.address);
|
||||
approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1);
|
||||
approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2);
|
||||
approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address);
|
||||
approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -130,21 +130,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -157,21 +157,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -196,21 +196,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
);
|
||||
});
|
||||
@@ -235,19 +235,16 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approvalSignature = `${approval.approvalSignature.slice(
|
||||
0,
|
||||
4,
|
||||
)}FFFFFFFF${approval.approvalSignature.slice(12)}`;
|
||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approvalSignature],
|
||||
[signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -257,7 +254,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approvalSignature],
|
||||
[signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -268,7 +265,7 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
@@ -276,7 +273,7 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -286,7 +283,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -297,7 +294,7 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
@@ -305,7 +302,7 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: approvalSignerAddress2 },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
@@ -315,7 +312,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: approvalSignerAddress2 },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
@@ -334,21 +331,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -360,21 +357,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -402,21 +399,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.approvalSignature],
|
||||
[approval.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -425,7 +422,7 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
@@ -433,14 +430,14 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature, approval2.approvalSignature],
|
||||
[approval1.signature, approval2.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature, approval2.approvalSignature],
|
||||
[approval1.signature, approval2.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
);
|
||||
});
|
||||
@@ -465,21 +462,21 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval2.approvalSignature],
|
||||
[approval2.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
);
|
||||
await mixins.assertValidTECApprovals.callAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval2.approvalSignature],
|
||||
[approval2.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
);
|
||||
});
|
||||
@@ -510,19 +507,16 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approvalSignature = `${approval.approvalSignature.slice(
|
||||
0,
|
||||
4,
|
||||
)}FFFFFFFF${approval.approvalSignature.slice(12)}`;
|
||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approvalSignature],
|
||||
[signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -532,7 +526,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approvalSignature],
|
||||
[signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -543,20 +537,17 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approvalSignature2 = `${approval2.approvalSignature.slice(
|
||||
0,
|
||||
4,
|
||||
)}FFFFFFFF${approval2.approvalSignature.slice(12)}`;
|
||||
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature, approvalSignature2],
|
||||
[approval1.signature, approvalSignature2],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -566,7 +557,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature, approvalSignature2],
|
||||
[approval1.signature, approvalSignature2],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -577,12 +568,9 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const approvalSignature2 = `${approval2.approvalSignature.slice(
|
||||
0,
|
||||
4,
|
||||
)}FFFFFFFF${approval2.approvalSignature.slice(12)}`;
|
||||
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
transaction,
|
||||
@@ -610,8 +598,8 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds1);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds2);
|
||||
expectContractCallFailedAsync(
|
||||
@@ -620,7 +608,7 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2],
|
||||
[approval1.approvalSignature, approval2.approvalSignature],
|
||||
[approval1.signature, approval2.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -630,7 +618,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2],
|
||||
[approval1.approvalSignature, approval2.approvalSignature],
|
||||
[approval1.signature, approval2.signature],
|
||||
{ from: transactionSignerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -641,7 +629,7 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
@@ -649,7 +637,7 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval2.approvalSignature],
|
||||
[approval2.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -659,7 +647,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval2.approvalSignature],
|
||||
[approval2.signature],
|
||||
{ from: approvalSignerAddress1 },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
@@ -670,7 +658,7 @@ describe('Mixins tests', () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(timeBuffer);
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidTransactionOrdersApproval.callAsync(
|
||||
@@ -678,7 +666,7 @@ describe('Mixins tests', () => {
|
||||
orders,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature],
|
||||
[approval1.signature],
|
||||
{ from: approvalSignerAddress2 },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
@@ -688,7 +676,7 @@ describe('Mixins tests', () => {
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval1.approvalSignature],
|
||||
[approval1.signature],
|
||||
{ from: approvalSignerAddress2 },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
@@ -723,3 +711,4 @@ describe('Mixins tests', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
|
@@ -1,25 +1,56 @@
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { ExchangeContract } from '@0x/contracts-exchange';
|
||||
import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import {
|
||||
artifacts as exchangeArtifacts,
|
||||
ExchangeCancelEventArgs,
|
||||
ExchangeCancelUpToEventArgs,
|
||||
ExchangeContract,
|
||||
ExchangeFillEventArgs,
|
||||
} from '@0x/contracts-exchange';
|
||||
import {
|
||||
chaiSetup,
|
||||
constants as devConstants,
|
||||
expectContractCallFailedAsync,
|
||||
getLatestBlockTimestampAsync,
|
||||
OrderFactory,
|
||||
provider,
|
||||
TransactionFactory,
|
||||
txDefaults,
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||
import { RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { TECContract } from '../src';
|
||||
import { ApprovalFactory, artifacts, constants, exchangeDataEncoder, TECContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('TEC tests', () => {
|
||||
let makerAddress: string;
|
||||
let owner: string;
|
||||
let takerAddress: string;
|
||||
let feeRecipientAddress: string;
|
||||
|
||||
// let erc20Proxy: ERC20ProxyContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc20TokenA: DummyERC20TokenContract;
|
||||
let erc20TokenB: DummyERC20TokenContract;
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let tecContract: TECContract;
|
||||
let exchange: ExchangeContract;
|
||||
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
let orderFactory: OrderFactory;
|
||||
let takerTransactionFactory: TransactionFactory;
|
||||
let makerTransactionFactory: TransactionFactory;
|
||||
let approvalFactory: ApprovalFactory;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
@@ -28,9 +59,58 @@ describe('TEC tests', () => {
|
||||
});
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
|
||||
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4));
|
||||
|
||||
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||
const numDummyErc20ToDeploy = 3;
|
||||
[erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
devConstants.DUMMY_TOKEN_DECIMALS,
|
||||
);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
tecContract = await TECContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TEC,
|
||||
provider,
|
||||
txDefaults,
|
||||
exchange.address,
|
||||
);
|
||||
|
||||
// Configure order defaults
|
||||
const defaultOrderParams = {
|
||||
...devConstants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
senderAddress: tecContract.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||
};
|
||||
const makerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
const takerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
const feeRecipientPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)];
|
||||
orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
|
||||
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
|
||||
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
|
||||
approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, tecContract.address);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -38,4 +118,332 @@ describe('TEC tests', () => {
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('single order fills', () => {
|
||||
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||
it(`${fnName} should fill the order with a signed approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it(`${fnName} should fill the order if called by approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[],
|
||||
[],
|
||||
{ from: feeRecipientAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it(`${fnName} should revert with no approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(transaction, transaction.signature, [], [], {
|
||||
from: takerAddress,
|
||||
}),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert with an expired approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert if not called by tx signer or approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: owner },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
describe('batch order fills', () => {
|
||||
for (const fnName of [...constants.MARKET_FILL_FN_NAMES, ...constants.BATCH_FILL_FN_NAMES]) {
|
||||
it(`${fnName} should fill the orders with a signed approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(orders.length);
|
||||
orders.forEach((order, index) => {
|
||||
const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
|
||||
});
|
||||
});
|
||||
it(`${fnName} should fill the orders if called by approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[],
|
||||
[],
|
||||
{ from: feeRecipientAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(orders.length);
|
||||
orders.forEach((order, index) => {
|
||||
const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
|
||||
});
|
||||
});
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert with an expired approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
RevertReason.ApprovalExpired,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert if not called by tx signer or approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(transaction, approvalExpirationTimeSeconds);
|
||||
await expectContractCallFailedAsync(
|
||||
tecContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: owner },
|
||||
),
|
||||
RevertReason.InvalidSender,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
describe('cancels', () => {
|
||||
it('cancelOrder call should be successful without an approval', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(transaction, transaction.signature, [], [], {
|
||||
from: makerAddress,
|
||||
}),
|
||||
);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it('batchCancelOrders call should be successful without an approval', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(transaction, transaction.signature, [], [], {
|
||||
from: makerAddress,
|
||||
}),
|
||||
);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(orders.length);
|
||||
orders.forEach((order, index) => {
|
||||
const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
|
||||
});
|
||||
});
|
||||
it('cancelOrdersUpTo call should be successful without an approval', async () => {
|
||||
const orders: SignedOrder[] = [];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await tecContract.executeTransaction.sendTransactionAsync(transaction, transaction.signature, [], [], {
|
||||
from: makerAddress,
|
||||
}),
|
||||
);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).event === 'CancelUpTo',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(tecContract.address);
|
||||
expect(cancelLogArgs.orderEpoch).to.bignumber.eq(new BigNumber(1));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -6,22 +6,26 @@ import { hashUtils, SignedTECApproval, signingUtils, TECSignatureType } from './
|
||||
|
||||
export class ApprovalFactory {
|
||||
private readonly _privateKey: Buffer;
|
||||
constructor(privateKey: Buffer) {
|
||||
private readonly _verifyingContractAddress: string;
|
||||
constructor(privateKey: Buffer, verifyingContractAddress: string) {
|
||||
this._privateKey = privateKey;
|
||||
this._verifyingContractAddress = verifyingContractAddress;
|
||||
}
|
||||
public newSignedApproval(
|
||||
transaction: SignedZeroExTransaction,
|
||||
approvalExpirationTimeSeconds: BigNumber,
|
||||
signatureType: TECSignatureType = TECSignatureType.EthSign,
|
||||
): SignedTECApproval {
|
||||
const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, approvalExpirationTimeSeconds);
|
||||
const tecTransaction = {
|
||||
...transaction,
|
||||
verifyingContractAddress: this._verifyingContractAddress,
|
||||
};
|
||||
const approvalHashBuff = hashUtils.getApprovalHashBuffer(tecTransaction, approvalExpirationTimeSeconds);
|
||||
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
const signedApproval = {
|
||||
transactionHash,
|
||||
transaction: tecTransaction,
|
||||
approvalExpirationTimeSeconds,
|
||||
transactionSignature: transaction.signature,
|
||||
approvalSignature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
|
||||
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
|
||||
};
|
||||
return signedApproval;
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
export const constants = {
|
||||
TEC_DOMAIN_NAME: '0x Protocol Trade Execution Coordinator',
|
||||
TEC_DOMAIN_VERSION: '1.0.0',
|
||||
@@ -16,4 +18,5 @@ export const constants = {
|
||||
CANCEL_ORDERS: 'cancelOrders',
|
||||
BATCH_CANCEL_ORDERS: 'batchCancelOrders',
|
||||
CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo',
|
||||
TIME_BUFFER: new BigNumber(1000),
|
||||
};
|
||||
|
@@ -27,7 +27,7 @@ export const exchangeDataEncoder = {
|
||||
} else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
||||
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
||||
orders,
|
||||
orders[0].takerAssetAmount,
|
||||
orders.map(order => order.takerAssetAmount).reduce((prev, curr) => prev.plus(curr)),
|
||||
orders.map(order => order.signature),
|
||||
);
|
||||
} else if (fnName === constants.MATCH_ORDERS) {
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { SignedZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
export interface TECApproval {
|
||||
transactionHash: string;
|
||||
transactionSignature: string;
|
||||
transaction: SignedZeroExTransaction;
|
||||
approvalExpirationTimeSeconds: BigNumber;
|
||||
}
|
||||
|
||||
export interface SignedTECApproval extends TECApproval {
|
||||
approvalSignature: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export enum TECSignatureType {
|
||||
|
Reference in New Issue
Block a user