Reduce code duplication in unit tests
This commit is contained in:
@@ -15,7 +15,7 @@ import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestTransactionsContract, TestTransactionsTransactionExecutionEventArgs } from '../src';
|
||||
|
||||
blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper, txDefaults }) => {
|
||||
blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDefaults }) => {
|
||||
let transactionsContract: TestTransactionsContract;
|
||||
let accounts: string[];
|
||||
let domain: EIP712DomainWithDefaultSchema;
|
||||
@@ -26,6 +26,7 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
const EMPTY_ZERO_EX_TRANSACTION = {
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
expirationTimeSeconds: constants.ZERO_AMOUNT,
|
||||
gasPrice: constants.ZERO_AMOUNT,
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
data: constants.NULL_BYTES,
|
||||
domain: {
|
||||
@@ -67,23 +68,53 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
);
|
||||
}
|
||||
|
||||
interface GenerateZeroExTransactionParams {
|
||||
salt?: BigNumber;
|
||||
expirationTimeSeconds?: BigNumber;
|
||||
gasPrice?: BigNumber;
|
||||
signerAddress?: string;
|
||||
data?: string;
|
||||
domain?: EIP712DomainWithDefaultSchema;
|
||||
shouldSucceed?: boolean;
|
||||
callData?: string;
|
||||
returnData?: string;
|
||||
}
|
||||
|
||||
async function generateZeroExTransactionAsync(
|
||||
opts: GenerateZeroExTransactionParams = {},
|
||||
): Promise<ZeroExTransaction> {
|
||||
const shouldSucceed = opts.shouldSucceed === undefined ? true : opts.shouldSucceed;
|
||||
const callData = opts.callData === undefined ? constants.NULL_BYTES : opts.callData;
|
||||
const returnData = opts.returnData === undefined ? constants.NULL_BYTES : opts.returnData;
|
||||
const data = opts.data === undefined ? getExecutableCallData(shouldSucceed, callData, returnData) : opts.data;
|
||||
const gasPrice = opts.gasPrice === undefined ? new BigNumber(constants.DEFAULT_GAS_PRICE) : opts.gasPrice;
|
||||
const _domain = opts.domain === undefined ? domain : opts.domain;
|
||||
const expirationTimeSeconds =
|
||||
opts.expirationTimeSeconds === undefined
|
||||
? new BigNumber(await getLatestBlockTimestampAsync()).plus(10)
|
||||
: opts.expirationTimeSeconds;
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
...opts,
|
||||
data,
|
||||
expirationTimeSeconds,
|
||||
domain: _domain,
|
||||
gasPrice,
|
||||
};
|
||||
return transaction;
|
||||
}
|
||||
|
||||
describe('batchExecuteTransaction', () => {
|
||||
it('should revert if the only call to executeTransaction fails', async () => {
|
||||
// Create an expired transaction that will fail when used to call `batchExecuteTransactions()`.
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), // Set the expiration time to before the current timestamp
|
||||
data: getExecutableCallData(false, constants.NULL_BYTES, constants.NULL_BYTES),
|
||||
domain,
|
||||
};
|
||||
const transaction = await generateZeroExTransactionAsync({ shouldSucceed: false });
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
|
||||
// We expect a `TransactionError` to be returned because that is the error that will be triggered in the call to
|
||||
// `executeTransaction`.
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
// Create the StringRevertError that reflects the returndata that will be returned by the failed transaction.
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
executableError.encode(),
|
||||
);
|
||||
|
||||
// Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error.
|
||||
@@ -96,21 +127,10 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
|
||||
it('should revert if the second call to executeTransaction fails', async () => {
|
||||
// Create a transaction that will succeed when used to call `batchExecuteTransactions()`.
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES), // This call should succeed
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync();
|
||||
|
||||
// Create a transaction that will fail when used to call `batchExecuteTransactions()` because the call to executable will fail.
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: getExecutableCallData(false, constants.NULL_BYTES, constants.NULL_BYTES), // This call should fail
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = await generateZeroExTransactionAsync({ shouldSucceed: false });
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
|
||||
// Create the StringRevertError that reflects the returndata that will be returned by the failed transaction.
|
||||
@@ -130,21 +150,10 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
|
||||
it('should revert if the first call to executeTransaction fails', async () => {
|
||||
// Create a transaction that will fail when used to call `batchExecuteTransactions()` because the call to executable will fail.
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: getExecutableCallData(false, constants.NULL_BYTES, constants.NULL_BYTES), // This call should fail
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ shouldSucceed: false });
|
||||
|
||||
// Create a transaction that will succeed when used to call `batchExecuteTransactions()`.
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES),
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = await generateZeroExTransactionAsync();
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
|
||||
// Create the StringRevertError that reflects the returndata that will be returned by the failed transaction.
|
||||
@@ -164,24 +173,11 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
|
||||
it('should revert if the same transaction is executed twice in a batch', async () => {
|
||||
// Create a transaction that will succeed when used to call `batchExecuteTransactions()`.
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1],
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES),
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[1] });
|
||||
|
||||
// Duplicate the first transaction. This should cause the call to `batchExecuteTransactions()` to fail
|
||||
// because this transaction will have the same order hash as transaction1.
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1],
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = transaction1;
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
|
||||
// Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error.
|
||||
@@ -200,16 +196,11 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
});
|
||||
|
||||
it('should succeed if the only call to executeTransaction succeeds', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
|
||||
// Create a transaction that will succeed when used to call `batchExecuteTransactions()`.
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
const transaction = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[1],
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, '0xdeadbeef'),
|
||||
domain,
|
||||
};
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const validSignature = randomSignature();
|
||||
|
||||
@@ -258,23 +249,15 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
});
|
||||
|
||||
it('should succeed if the both calls to executeTransaction succeed', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
|
||||
// Create two transactions that will succeed when used to call `batchExecuteTransactions()`.
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[0], // This is different than the account that will be used to send.
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, '0xdeadbeef'),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1], // Different than transaction1's signer address
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, '0xbeefdead'),
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[0],
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transaction2 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[1],
|
||||
returnData: '0xbeefdead',
|
||||
});
|
||||
const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
|
||||
@@ -347,14 +330,11 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
signature,
|
||||
);
|
||||
}
|
||||
|
||||
it('should revert if the current time is past the expiration time', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
const transaction = await generateZeroExTransactionAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), // Set the expiration time to before the current timestamp
|
||||
domain,
|
||||
};
|
||||
});
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
@@ -363,185 +343,100 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction, randomSignature());
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
// FIXME - This should be unskipped when the contracts have been updated to fix this problem.
|
||||
it.skip('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender == signer for both calls', async () => {
|
||||
const validSignature = randomSignature();
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES), // This should never get called
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[0] });
|
||||
const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
|
||||
const callData = getExecutableCallData(
|
||||
true,
|
||||
getExecuteTransactionCallData(transaction1, validSignature),
|
||||
'0xdeadbeef',
|
||||
);
|
||||
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: callData,
|
||||
const transaction2 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
callData: getExecuteTransactionCallData(transaction1, validSignature),
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const abiEncoder = AbiEncoder.createMethod('TransactionError', ['uint8', 'bytes32']);
|
||||
const errorData = abiEncoder.encode([
|
||||
ExchangeRevertErrors.TransactionErrorCode.NoReentrancy,
|
||||
transactionHash1,
|
||||
]);
|
||||
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(transactionHash2, errorData);
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction2, validSignature, {
|
||||
from: accounts[0],
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender != signer for both calls', async () => {
|
||||
const validSignature = randomSignature();
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES), // This should never get called
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[0] });
|
||||
const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
|
||||
const callData = getExecutableCallData(
|
||||
true,
|
||||
getExecuteTransactionCallData(transaction1, validSignature),
|
||||
'0xdeadbeef',
|
||||
);
|
||||
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: callData,
|
||||
const transaction2 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
callData: getExecuteTransactionCallData(transaction1, validSignature),
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const abiEncoder = AbiEncoder.createMethod('TransactionError', ['uint8', 'bytes32']);
|
||||
const errorData = abiEncoder.encode([
|
||||
ExchangeRevertErrors.TransactionErrorCode.NoReentrancy,
|
||||
transactionHash1,
|
||||
]);
|
||||
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(transactionHash2, errorData);
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction2, validSignature, {
|
||||
from: accounts[1], // Different then the signing addresses
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender != signer and then msg.sender == sender', async () => {
|
||||
const validSignature = randomSignature();
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES), // This should never get called
|
||||
signerAddress: accounts[1],
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[1] });
|
||||
const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
|
||||
const callData = getExecutableCallData(
|
||||
true,
|
||||
getExecuteTransactionCallData(transaction1, validSignature),
|
||||
'0xdeadbeef',
|
||||
);
|
||||
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: callData,
|
||||
const transaction2 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
callData: getExecuteTransactionCallData(transaction1, validSignature),
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const abiEncoder = AbiEncoder.createMethod('TransactionError', ['uint8', 'bytes32']);
|
||||
const errorData = abiEncoder.encode([
|
||||
ExchangeRevertErrors.TransactionErrorCode.NoReentrancy,
|
||||
transactionHash1,
|
||||
]);
|
||||
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(transactionHash2, errorData);
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction2, validSignature, {
|
||||
from: accounts[1], // Different then the signing addresses
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
// FIXME - This should be unskipped when the contracts have been updated to fix this problem.
|
||||
it.skip('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender == signer and then msg.sender != sender', async () => {
|
||||
const validSignature = randomSignature();
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES), // This should never get called
|
||||
signerAddress: accounts[0],
|
||||
domain,
|
||||
};
|
||||
const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[0] });
|
||||
const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
|
||||
const callData = getExecutableCallData(
|
||||
true,
|
||||
getExecuteTransactionCallData(transaction1, validSignature),
|
||||
'0xdeadbeef',
|
||||
);
|
||||
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: callData,
|
||||
signerAddress: accounts[1],
|
||||
domain,
|
||||
};
|
||||
const transaction2 = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[0],
|
||||
callData: getExecuteTransactionCallData(transaction1, validSignature),
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const abiEncoder = AbiEncoder.createMethod('TransactionError', ['uint8', 'bytes32']);
|
||||
const errorData = abiEncoder.encode([
|
||||
ExchangeRevertErrors.TransactionErrorCode.NoReentrancy,
|
||||
transactionHash1,
|
||||
]);
|
||||
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(transactionHash2, errorData);
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction2, validSignature, {
|
||||
from: accounts[1], // Different then the signing addresses
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the transaction has been executed previously', async () => {
|
||||
const validSignature = randomSignature();
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
data: getExecutableCallData(true, constants.NULL_BYTES, constants.NULL_BYTES),
|
||||
domain,
|
||||
};
|
||||
const transaction = await generateZeroExTransactionAsync();
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
|
||||
// Use the transaction in execute transaction.
|
||||
await expect(
|
||||
transactionsContract.executeTransaction.sendTransactionAsync(transaction, validSignature),
|
||||
).to.be.fulfilled('');
|
||||
|
||||
// Use the same transaction to make another call
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted,
|
||||
@@ -550,15 +445,8 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
const tx = transactionsContract.executeTransaction.sendTransactionAsync(transaction, validSignature);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the signer != msg.sender and the signature is not valid', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1], // This is different than the account that will be used to send.
|
||||
domain,
|
||||
};
|
||||
const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[1] });
|
||||
const signature = '0x0000'; // This is the invalid signature
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionSignatureError(
|
||||
@@ -571,18 +459,12 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the signer == msg.sender but the delegatecall fails', async () => {
|
||||
// This calldata is encoded to fail when it hits the executable function.
|
||||
const callData = getExecutableCallData(false, constants.NULL_BYTES, constants.NULL_BYTES);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
const transaction = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[1],
|
||||
data: callData,
|
||||
domain,
|
||||
};
|
||||
shouldSucceed: false,
|
||||
});
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
@@ -594,18 +476,12 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the signer != msg.sender and the signature is valid but the delegatecall fails', async () => {
|
||||
// This calldata is encoded to fail when it hits the executable function.
|
||||
const callData = getExecutableCallData(false, constants.NULL_BYTES, constants.NULL_BYTES);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1], // This is different than the account that will be used to send.
|
||||
data: callData,
|
||||
domain,
|
||||
};
|
||||
const transaction = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[1],
|
||||
shouldSucceed: false,
|
||||
});
|
||||
const validSignature = randomSignature(); // Valid because length != 2
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const executableError = new StringRevertError('EXECUTABLE_FAILED');
|
||||
@@ -618,30 +494,21 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed with the correct return hash and event emitted', async () => {
|
||||
// This calldata is encoded to succeed when it hits the executable function.
|
||||
const callData = getExecutableCallData(true, constants.NULL_BYTES, '0xdeadbeef');
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const validSignature = randomSignature(); // Valid because length != 2
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
signerAddress: accounts[1], // This is different than the account that will be used to send.
|
||||
data: callData,
|
||||
domain,
|
||||
};
|
||||
const transaction = await generateZeroExTransactionAsync({
|
||||
signerAddress: accounts[1],
|
||||
returnData: '0xdeadbeef',
|
||||
});
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
|
||||
// Verify that the returndata of the transaction is 0xDEADBEEF
|
||||
const result = await transactionsContract.executeTransaction.callAsync(transaction, validSignature, {
|
||||
from: accounts[0],
|
||||
});
|
||||
|
||||
// Create an abiEncoder for bytes. This will be used to decode the result and encode what
|
||||
// is expected.
|
||||
const abiEncoder = AbiEncoder.create('bytes');
|
||||
|
||||
// Ensure that the result contains the abi-encoded bytes "0xdeadbeef"
|
||||
const encodedDeadbeef = abiEncoder.encode('0xdeadbeef');
|
||||
expect(
|
||||
@@ -650,18 +517,15 @@ blockchainTests.resets.only('Transaction Unit Tests', ({ provider, web3Wrapper,
|
||||
encodedDeadbeef.slice(2, encodedDeadbeef.length),
|
||||
),
|
||||
).to.be.true();
|
||||
|
||||
// Verify that the logs returned from the call are correct.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await transactionsContract.executeTransaction.sendTransactionAsync(transaction, validSignature, {
|
||||
from: accounts[0],
|
||||
}),
|
||||
);
|
||||
|
||||
// Ensure that the correct number of events were logged.
|
||||
const logs = receipt.logs as Array<LogWithDecodedArgs<TestTransactionsTransactionExecutionEventArgs>>;
|
||||
expect(logs.length).to.be.eq(2);
|
||||
|
||||
// Ensure that the correct events were logged.
|
||||
expect(logs[0].event).to.be.eq('ExecutableCalled');
|
||||
expect(logs[0].args.data).to.be.eq(constants.NULL_BYTES);
|
||||
|
||||
Reference in New Issue
Block a user