* remove assetDataUtils everywhere * export IAssetDataContract from @0x/contract-wrappers to allow @0x/instant to decode asset data synchronously * export generic function `decodeAssetDataOrThrow` and add ERC20Bridge support * export `hexUtils` from order-utils instead of contracts-test-utils
		
			
				
	
	
		
			336 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import {
 | |
|     blockchainTests,
 | |
|     constants,
 | |
|     expect,
 | |
|     getRandomInteger,
 | |
|     randomAddress,
 | |
|     verifyEventsFromLogs,
 | |
| } from '@0x/contracts-test-utils';
 | |
| import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
 | |
| 
 | |
| import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
 | |
| 
 | |
| import { artifacts } from './artifacts';
 | |
| 
 | |
| blockchainTests('LibERC20Token', env => {
 | |
|     let testContract: TestLibERC20TokenContract;
 | |
|     const REVERT_STRING = 'WHOOPSIE';
 | |
|     const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
 | |
|     const ENCODED_TRUE = hexUtils.leftPad(1);
 | |
|     const ENCODED_FALSE = hexUtils.leftPad(0);
 | |
|     const ENCODED_TWO = hexUtils.leftPad(2);
 | |
|     const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
 | |
|     const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
 | |
| 
 | |
|     before(async () => {
 | |
|         testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
 | |
|             artifacts.TestLibERC20Token,
 | |
|             env.provider,
 | |
|             env.txDefaults,
 | |
|             artifacts,
 | |
|         );
 | |
|     });
 | |
| 
 | |
|     describe('approve()', () => {
 | |
|         it('calls the target with the correct arguments', async () => {
 | |
|             const spender = randomAddress();
 | |
|             const allowance = getRandomInteger(0, 100e18);
 | |
|             const { logs } = await testContract
 | |
|                 .testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('succeeds if the target returns nothing', async () => {
 | |
|             const spender = randomAddress();
 | |
|             const allowance = getRandomInteger(0, 100e18);
 | |
|             await testContract
 | |
|                 .testApprove(false, ENCODED_REVERT, constants.NULL_BYTES, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('fails if the target returns false', async () => {
 | |
|             const spender = randomAddress();
 | |
|             const allowance = getRandomInteger(0, 100e18);
 | |
|             const tx = testContract
 | |
|                 .testApprove(false, ENCODED_REVERT, ENCODED_FALSE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TWO, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_LONG_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, constants.NULL_BYTES, ENCODED_TRUE, spender, allowance)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('succeeds if the target returns nothing', async () => {
 | |
|             const to = randomAddress();
 | |
|             const amount = getRandomInteger(0, 100e18);
 | |
|             await testContract
 | |
|                 .testTransfer(false, ENCODED_REVERT, constants.NULL_BYTES, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('fails if the target returns false', async () => {
 | |
|             const to = randomAddress();
 | |
|             const amount = getRandomInteger(0, 100e18);
 | |
|             const tx = testContract
 | |
|                 .testTransfer(false, ENCODED_REVERT, ENCODED_FALSE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TWO, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_LONG_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, constants.NULL_BYTES, ENCODED_TRUE, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('succeeds if the target returns nothing', async () => {
 | |
|             const owner = randomAddress();
 | |
|             const to = randomAddress();
 | |
|             const amount = getRandomInteger(0, 100e18);
 | |
|             await testContract
 | |
|                 .testTransferFrom(false, ENCODED_REVERT, constants.NULL_BYTES, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|         });
 | |
| 
 | |
|         it('fails if the target returns false', async () => {
 | |
|             const owner = randomAddress();
 | |
|             const to = randomAddress();
 | |
|             const amount = getRandomInteger(0, 100e18);
 | |
|             const tx = testContract
 | |
|                 .testTransferFrom(false, ENCODED_REVERT, ENCODED_FALSE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_TWO, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(false, ENCODED_REVERT, ENCODED_LONG_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             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(true, constants.NULL_BYTES, ENCODED_TRUE, owner, to, amount)
 | |
|                 .awaitTransactionSuccessAsync();
 | |
|             return expect(tx).to.be.rejectedWith('revert');
 | |
|         });
 | |
|     });
 | |
| 
 | |
|     describe('decimals()', () => {
 | |
|         const DEFAULT_DECIMALS = 18;
 | |
|         const ENCODED_ZERO = hexUtils.leftPad(0);
 | |
|         const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
 | |
|         const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
 | |
|         const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
 | |
| 
 | |
|         it('returns the number of decimals defined by the token', async () => {
 | |
|             const decimals = randomDecimals();
 | |
|             const encodedDecimals = hexUtils.leftPad(decimals);
 | |
|             const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
 | |
|             return expect(result).to.bignumber.eq(decimals);
 | |
|         });
 | |
| 
 | |
|         it('returns 0 if the token returns 0', async () => {
 | |
|             const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_ZERO).callAsync();
 | |
|             return expect(result).to.bignumber.eq(0);
 | |
|         });
 | |
| 
 | |
|         it('returns 18 if the token returns less than 32 bytes', async () => {
 | |
|             const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_SHORT_ZERO).callAsync();
 | |
|             return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | |
|         });
 | |
| 
 | |
|         it('returns 18 if the token returns greater than 32 bytes', async () => {
 | |
|             const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_LONG_ZERO).callAsync();
 | |
|             return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | |
|         });
 | |
| 
 | |
|         it('returns 18 if the token reverts', async () => {
 | |
|             const result = await testContract.testDecimals(true, ENCODED_REVERT, ENCODED_ZERO).callAsync();
 | |
|             return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | |
|         });
 | |
|     });
 | |
| });
 |