@0x:contracts-exchange Added unit tests for batchExecuteTransactions
This commit is contained in:
committed by
Amir Bandeali
parent
1724ecd4c3
commit
907771f084
@@ -57,4 +57,4 @@ contract MixinTransferSimulator is
|
||||
}
|
||||
revert("TRANSFERS_SUCCESSFUL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ contract TestTransactions is
|
||||
bool success = shouldSucceedCall;
|
||||
bytes memory returnData = fallbackReturnData;
|
||||
assembly {
|
||||
if iszero(success) {
|
||||
if or(iszero(success), gt(calldatasize, 0x0)) {
|
||||
revert(add(0x20, returnData), mload(returnData))
|
||||
}
|
||||
return(add(0x20, returnData), mload(returnData))
|
||||
|
||||
@@ -56,8 +56,244 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
};
|
||||
});
|
||||
|
||||
describe('batchExecuteTransaction', () => {
|
||||
it('should revert if the only call to executeTransaction fails', async () => {
|
||||
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
|
||||
domain,
|
||||
};
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
transactionHash,
|
||||
);
|
||||
const tx = transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction],
|
||||
[randomSignature()],
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the second call to executeTransaction fails', async () => {
|
||||
// Set the contract to accept signatures.
|
||||
await expect(transactionsContract.setShouldBeValid.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract to fail on calls to the fallback function. Note: This call is unnecessary but is kept for readability.
|
||||
await expect(transactionsContract.setShouldCallSucceed.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: '0x', // This call should succeed
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: '0x32', // This call should fail because the calldata is invalid
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
constants.NULL_BYTES,
|
||||
);
|
||||
const tx = transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction1, transaction2],
|
||||
[randomSignature(), randomSignature()],
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the first call to executeTransaction fails', async () => {
|
||||
// Set the contract to accept signatures.
|
||||
await expect(transactionsContract.setShouldBeValid.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract to fail on calls to the fallback function. Note: This call is unnecessary but is kept for readability.
|
||||
await expect(transactionsContract.setShouldCallSucceed.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: '0x32', // This call should fail because the calldata is invalid
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transaction2 = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
data: '0x', // This call should succeed
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).plus(10),
|
||||
domain,
|
||||
};
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHash,
|
||||
constants.NULL_BYTES,
|
||||
);
|
||||
const tx = transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction1, transaction2],
|
||||
[randomSignature(), randomSignature()],
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if the same transaction is executed twice in a batch', async () => {
|
||||
// Set the contract to accept signatures.
|
||||
await expect(transactionsContract.setShouldBeValid.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract to fail on calls to the fallback function. Note: This call is unnecessary but is kept for readability.
|
||||
await expect(transactionsContract.setShouldCallSucceed.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract fallbackReturnData to the recognizable string of bytes 0xDEADBEEF
|
||||
await expect(transactionsContract.setFallbackReturnData.sendTransactionAsync('0xdeadbeef')).to.be.fulfilled(
|
||||
'',
|
||||
);
|
||||
|
||||
// Set up the necessary data for the transactions and tests
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = {
|
||||
...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 transaction2 = {
|
||||
...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 transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
|
||||
// Verify that the transaction reverts
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted,
|
||||
transactionHash2,
|
||||
);
|
||||
const tx = transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction1, transaction2],
|
||||
[randomSignature(), randomSignature()],
|
||||
{
|
||||
from: accounts[0],
|
||||
},
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed if the only call to executeTransaction succeeds', async () => {
|
||||
// Set the contract to accept signatures.
|
||||
await expect(transactionsContract.setShouldBeValid.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract to fail on calls to the fallback function. Note: This call is unnecessary but is kept for readability.
|
||||
await expect(transactionsContract.setShouldCallSucceed.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract fallbackReturnData to the recognizable string of bytes 0xDEADBEEF
|
||||
await expect(transactionsContract.setFallbackReturnData.sendTransactionAsync('0xdeadbeef')).to.be.fulfilled(
|
||||
'',
|
||||
);
|
||||
|
||||
// Set up the necessary data for the transactions and tests
|
||||
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 transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
|
||||
// Verify that the returndata of the transaction is 0xDEADBEEF
|
||||
const result = await transactionsContract.batchExecuteTransactions.callAsync(
|
||||
[transaction],
|
||||
[randomSignature()],
|
||||
{
|
||||
from: accounts[0],
|
||||
},
|
||||
);
|
||||
expect(result.length).to.be.eq(1);
|
||||
expect(result[0] === '0xdeadbeef').to.be.true();
|
||||
|
||||
// Verify that the logs returned from the call are correct.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction],
|
||||
[randomSignature()],
|
||||
{
|
||||
from: accounts[0],
|
||||
},
|
||||
),
|
||||
);
|
||||
const logs = receipt.logs as Array<LogWithDecodedArgs<TestTransactionsTransactionExecutionEventArgs>>;
|
||||
expect(logs.length).to.be.eq(1);
|
||||
expect(logs[0].event === 'TransactionExecution').to.be.true();
|
||||
expect(logs[0].args.transactionHash).to.eq(transactionHash);
|
||||
});
|
||||
|
||||
it('should succeed if the both calls to executeTransaction succeed', async () => {
|
||||
// Set the contract to accept signatures.
|
||||
await expect(transactionsContract.setShouldBeValid.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract to fail on calls to the fallback function. Note: This call is unnecessary but is kept for readability.
|
||||
await expect(transactionsContract.setShouldCallSucceed.sendTransactionAsync(true)).to.be.fulfilled('');
|
||||
|
||||
// Set the contract fallbackReturnData to the recognizable string of bytes 0xDEADBEEF
|
||||
await expect(transactionsContract.setFallbackReturnData.sendTransactionAsync('0xdeadbeef')).to.be.fulfilled(
|
||||
'',
|
||||
);
|
||||
|
||||
// Set up the necessary data for the transactions and tests
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
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.
|
||||
domain,
|
||||
};
|
||||
const transaction2 = {
|
||||
...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 transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1);
|
||||
const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
|
||||
// Verify that the returndata of the transaction is 0xDEADBEEF
|
||||
const result = await transactionsContract.batchExecuteTransactions.callAsync(
|
||||
[transaction1, transaction2],
|
||||
[randomSignature(), randomSignature()],
|
||||
{
|
||||
from: accounts[0],
|
||||
},
|
||||
);
|
||||
expect(result.length).to.be.eq(2);
|
||||
expect(result[0] === '0xdeadbeef').to.be.true();
|
||||
expect(result[1] === '0xdeadbeef').to.be.true();
|
||||
|
||||
// Verify that the logs returned from the call are correct.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await transactionsContract.batchExecuteTransactions.sendTransactionAsync(
|
||||
[transaction1, transaction2],
|
||||
[randomSignature(), randomSignature()],
|
||||
{
|
||||
from: accounts[0],
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const logs = receipt.logs as Array<LogWithDecodedArgs<TestTransactionsTransactionExecutionEventArgs>>;
|
||||
expect(logs.length).to.be.eq(2);
|
||||
logs.map(log => expect(log.event === 'TransactionExecution').to.be.true());
|
||||
expect(logs[0].args.transactionHash).to.eq(transactionHash1);
|
||||
expect(logs[1].args.transactionHash).to.eq(transactionHash2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('executeTransaction', () => {
|
||||
it('should revert if the current time is past the expiration time of the metatransaction', async () => {
|
||||
it('should revert if the current time is past the expiration time', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = {
|
||||
...EMPTY_ZERO_EX_TRANSACTION,
|
||||
@@ -250,6 +486,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
}),
|
||||
);
|
||||
const logs = receipt.logs as Array<LogWithDecodedArgs<TestTransactionsTransactionExecutionEventArgs>>;
|
||||
expect(logs.length).to.be.eq(1);
|
||||
expect(logs[0].event === 'TransactionExecution').to.be.true();
|
||||
expect(logs[0].args.transactionHash).to.eq(transactionHash);
|
||||
});
|
||||
@@ -275,3 +512,4 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable-line:max-file-line-count
|
||||
|
||||
Reference in New Issue
Block a user