`@0x/contracts-erc20`: Move `LibERC20Token` in. `@0x/contracts-erc20`: Use `LibBytes` and `LibRichErrors` in `LibERC20Token`. `@0x/contracts-erc20`: Use `verifyEventsFromLogs` in `LibERC20Token` unit tests.
420 lines
15 KiB
TypeScript
420 lines
15 KiB
TypeScript
import {
|
|
blockchainTests,
|
|
constants,
|
|
expect,
|
|
getRandomInteger,
|
|
hexLeftPad,
|
|
randomAddress,
|
|
verifyEventsFromLogs,
|
|
} from '@0x/contracts-test-utils';
|
|
import { RawRevertError, StringRevertError } from '@0x/utils';
|
|
|
|
import { artifacts, TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from '../src';
|
|
|
|
blockchainTests('LibERC20Token', env => {
|
|
let testContract: TestLibERC20TokenContract;
|
|
const REVERT_STRING = 'WHOOPSIE';
|
|
const ENCODED_TRUE = hexLeftPad(1);
|
|
const ENCODED_FALSE = hexLeftPad(0);
|
|
const ENCODED_TWO = hexLeftPad(2);
|
|
const ENCODED_SHORT_TRUE = hexLeftPad(2, 31);
|
|
const ENCODED_LONG_TRUE = hexLeftPad(2, 33);
|
|
|
|
before(async () => {
|
|
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestLibERC20Token,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
});
|
|
|
|
function encodeRevert(message: string): string {
|
|
return new StringRevertError(message).encode();
|
|
}
|
|
|
|
describe('approve()', () => {
|
|
it('calls the target with the correct arguments', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const { logs } = await testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
expect(logs).to.be.length(1);
|
|
verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
|
|
});
|
|
|
|
it('succeeds if the target returns true', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
await testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
});
|
|
|
|
it('succeeds if the target returns nothing', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
await testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
constants.NULL_BYTES,
|
|
spender,
|
|
allowance,
|
|
);
|
|
});
|
|
|
|
it('fails if the target returns false', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_FALSE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns nonzero and not true', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TWO,
|
|
spender,
|
|
allowance,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns less than 32 bytes', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_SHORT_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns greater than 32 bytes', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_LONG_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target reverts', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
true,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
return expect(tx).to.revertWith(REVERT_STRING);
|
|
});
|
|
|
|
it('fails if the target reverts with no data', async () => {
|
|
const spender = randomAddress();
|
|
const allowance = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
|
true,
|
|
constants.NULL_BYTES,
|
|
ENCODED_TRUE,
|
|
spender,
|
|
allowance,
|
|
);
|
|
return expect(tx).to.be.rejectedWith('revert');
|
|
});
|
|
});
|
|
|
|
describe('transfer()', () => {
|
|
it('calls the target with the correct arguments', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const { logs } = await testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
expect(logs).to.be.length(1);
|
|
verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
|
|
});
|
|
|
|
it('succeeds if the target returns true', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
await testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
});
|
|
|
|
it('succeeds if the target returns nothing', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
await testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
constants.NULL_BYTES,
|
|
to,
|
|
amount,
|
|
);
|
|
});
|
|
|
|
it('fails if the target returns false', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_FALSE,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns nonzero and not true', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TWO,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns less than 32 bytes', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_SHORT_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns greater than 32 bytes', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_LONG_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target reverts', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
true,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
return expect(tx).to.revertWith(REVERT_STRING);
|
|
});
|
|
|
|
it('fails if the target reverts with no data', async () => {
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
|
true,
|
|
constants.NULL_BYTES,
|
|
ENCODED_TRUE,
|
|
to,
|
|
amount,
|
|
);
|
|
return expect(tx).to.be.rejectedWith('revert');
|
|
});
|
|
});
|
|
|
|
describe('transferFrom()', () => {
|
|
it('calls the target with the correct arguments', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const { logs } = await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
expect(logs).to.be.length(1);
|
|
verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
|
|
});
|
|
|
|
it('succeeds if the target returns true', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
});
|
|
|
|
it('succeeds if the target returns nothing', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
constants.NULL_BYTES,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
});
|
|
|
|
it('fails if the target returns false', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_FALSE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_FALSE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns nonzero and not true', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TWO,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_TWO);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns less than 32 bytes', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_SHORT_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target returns greater than 32 bytes', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
false,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_LONG_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('fails if the target reverts', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
true,
|
|
encodeRevert(REVERT_STRING),
|
|
ENCODED_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
return expect(tx).to.revertWith(REVERT_STRING);
|
|
});
|
|
|
|
it('fails if the target reverts with no data', async () => {
|
|
const owner = randomAddress();
|
|
const to = randomAddress();
|
|
const amount = getRandomInteger(0, 100e18);
|
|
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
|
true,
|
|
constants.NULL_BYTES,
|
|
ENCODED_TRUE,
|
|
owner,
|
|
to,
|
|
amount,
|
|
);
|
|
return expect(tx).to.be.rejectedWith('revert');
|
|
});
|
|
});
|
|
});
|