Refactor ERC20 token wrapper and it's tests
This commit is contained in:
parent
9c8701f5f6
commit
a655cd046c
@ -1,7 +1,7 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { ContractAbi, LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@ -17,23 +17,23 @@ import { assert } from '../utils/assert';
|
||||
import { constants } from '../utils/constants';
|
||||
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import { TokenContract, TokenContractEventArgs, TokenEvents } from './generated/token';
|
||||
import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
|
||||
import { ERC20ProxyWrapper } from './erc20_proxy_wrapper';
|
||||
import { ERC20TokenContract, ERC20TokenEventArgs, ERC20TokenEvents } from './generated/erc20_token';
|
||||
|
||||
/**
|
||||
* This class includes all the functionality related to interacting with ERC20 token contracts.
|
||||
* All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances
|
||||
* to the 0x Proxy smart contract.
|
||||
* to the 0x ERC20 Proxy smart contract.
|
||||
*/
|
||||
export class TokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Token.abi;
|
||||
export class ERC20TokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.ERC20Token.compilerOutput.abi;
|
||||
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
private _tokenContractsByAddress: { [address: string]: TokenContract };
|
||||
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
|
||||
private _tokenContractsByAddress: { [address: string]: ERC20TokenContract };
|
||||
private _erc20ProxyWrapper: ERC20ProxyWrapper;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, erc20ProxyWrapper: ERC20ProxyWrapper) {
|
||||
super(web3Wrapper, networkId);
|
||||
this._tokenContractsByAddress = {};
|
||||
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
||||
this._erc20ProxyWrapper = erc20ProxyWrapper;
|
||||
}
|
||||
/**
|
||||
* Retrieves an owner's ERC20 token balance.
|
||||
@ -177,7 +177,7 @@ export class TokenWrapper extends ContractWrapper {
|
||||
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||
|
||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||
const proxyAddress = this._erc20ProxyWrapper.getContractAddress();
|
||||
const allowanceInBaseUnits = await this.getAllowanceAsync(
|
||||
normalizedTokenAddress,
|
||||
normalizedOwnerAddress,
|
||||
@ -208,7 +208,7 @@ export class TokenWrapper extends ContractWrapper {
|
||||
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||
|
||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||
const proxyAddress = this._erc20ProxyWrapper.getContractAddress();
|
||||
const txHash = await this.setAllowanceAsync(
|
||||
normalizedTokenAddress,
|
||||
normalizedOwnerAddress,
|
||||
@ -353,22 +353,22 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param callback Callback that gets called when a log is added/removed
|
||||
* @return Subscription token used later to unsubscribe
|
||||
*/
|
||||
public subscribe<ArgsType extends TokenContractEventArgs>(
|
||||
public subscribe<ArgsType extends ERC20TokenEventArgs>(
|
||||
tokenAddress: string,
|
||||
eventName: TokenEvents,
|
||||
eventName: ERC20TokenEvents,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>,
|
||||
): string {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||
assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
assert.isFunction('callback', callback);
|
||||
const subscriptionToken = this._subscribe<ArgsType>(
|
||||
normalizedTokenAddress,
|
||||
eventName,
|
||||
indexFilterValues,
|
||||
artifacts.Token.abi,
|
||||
artifacts.ERC20Token.compilerOutput.abi,
|
||||
callback,
|
||||
);
|
||||
return subscriptionToken;
|
||||
@ -395,15 +395,15 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
|
||||
* @return Array of logs that match the parameters
|
||||
*/
|
||||
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
|
||||
public async getLogsAsync<ArgsType extends ERC20TokenEventArgs>(
|
||||
tokenAddress: string,
|
||||
eventName: TokenEvents,
|
||||
eventName: ERC20TokenEvents,
|
||||
blockRange: BlockRange,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||
assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents);
|
||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
const logs = await this._getLogsAsync<ArgsType>(
|
||||
@ -411,7 +411,7 @@ export class TokenWrapper extends ContractWrapper {
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
artifacts.Token.abi,
|
||||
artifacts.ERC20Token.compilerOutput.abi,
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
@ -420,17 +420,17 @@ export class TokenWrapper extends ContractWrapper {
|
||||
this.unsubscribeAll();
|
||||
this._tokenContractsByAddress = {};
|
||||
}
|
||||
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
|
||||
private async _getTokenContractAsync(tokenAddress: string): Promise<ERC20TokenContract> {
|
||||
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||
let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
|
||||
if (!_.isUndefined(tokenContract)) {
|
||||
return tokenContract;
|
||||
}
|
||||
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||
artifacts.Token,
|
||||
artifacts.ERC20Token,
|
||||
normalizedTokenAddress,
|
||||
);
|
||||
const contractInstance = new TokenContract(
|
||||
const contractInstance = new ERC20TokenContract(
|
||||
abi,
|
||||
address,
|
||||
this._web3Wrapper.getProvider(),
|
@ -1,37 +1,37 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { EmptyWalletSubprovider } from '@0xproject/subproviders';
|
||||
import { DoneCallback, Provider } from '@0xproject/types';
|
||||
import { DoneCallback } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import 'make-promises-safe';
|
||||
import 'mocha';
|
||||
import Web3ProviderEngine = require('web3-provider-engine');
|
||||
|
||||
import {
|
||||
ApprovalContractEventArgs,
|
||||
BlockParamLiteral,
|
||||
BlockRange,
|
||||
ContractWrappers,
|
||||
ContractWrappersError,
|
||||
DecodedLogEvent,
|
||||
Token,
|
||||
TokenEvents,
|
||||
TransferContractEventArgs,
|
||||
ERC20TokenApprovalEventArgs,
|
||||
ERC20TokenEvents,
|
||||
ERC20TokenTransferEventArgs,
|
||||
} from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { tokenUtils } from './utils/token_utils';
|
||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('TokenWrapper', () => {
|
||||
describe('ERC20Wrapper', () => {
|
||||
let contractWrappers: ContractWrappers;
|
||||
let userAddresses: string[];
|
||||
let tokens: Token[];
|
||||
let tokenUtils: TokenUtils;
|
||||
let tokens: string[];
|
||||
let coinbase: string;
|
||||
let addressWithoutFunds: string;
|
||||
const config = {
|
||||
@ -40,8 +40,7 @@ describe('TokenWrapper', () => {
|
||||
before(async () => {
|
||||
contractWrappers = new ContractWrappers(provider, config);
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
tokens = await contractWrappers.tokenRegistry.getTokensAsync();
|
||||
tokenUtils = new TokenUtils(tokens);
|
||||
tokens = tokenUtils.getDummyERC20TokenAddresses();
|
||||
coinbase = userAddresses[0];
|
||||
addressWithoutFunds = userAddresses[1];
|
||||
});
|
||||
@ -52,26 +51,26 @@ describe('TokenWrapper', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('#transferAsync', () => {
|
||||
let token: Token;
|
||||
let tokenAddress: string;
|
||||
let transferAmount: BigNumber;
|
||||
before(() => {
|
||||
token = tokens[0];
|
||||
tokenAddress = tokens[0];
|
||||
transferAmount = new BigNumber(42);
|
||||
});
|
||||
it('should successfully transfer tokens', async () => {
|
||||
const fromAddress = coinbase;
|
||||
const toAddress = addressWithoutFunds;
|
||||
const preBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress);
|
||||
const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress);
|
||||
expect(preBalance).to.be.bignumber.equal(0);
|
||||
await contractWrappers.token.transferAsync(token.address, fromAddress, toAddress, transferAmount);
|
||||
const postBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress);
|
||||
await contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount);
|
||||
const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress);
|
||||
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
||||
});
|
||||
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
||||
const fromAddress = addressWithoutFunds;
|
||||
const toAddress = coinbase;
|
||||
return expect(
|
||||
contractWrappers.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
|
||||
contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount),
|
||||
).to.be.rejectedWith(ContractWrappersError.InsufficientBalanceForTransfer);
|
||||
});
|
||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||
@ -79,16 +78,21 @@ describe('TokenWrapper', () => {
|
||||
const fromAddress = coinbase;
|
||||
const toAddress = coinbase;
|
||||
return expect(
|
||||
contractWrappers.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
|
||||
).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist);
|
||||
contractWrappers.erc20Token.transferAsync(
|
||||
nonExistentTokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
transferAmount,
|
||||
),
|
||||
).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
|
||||
});
|
||||
});
|
||||
describe('#transferFromAsync', () => {
|
||||
let token: Token;
|
||||
let tokenAddress: string;
|
||||
let toAddress: string;
|
||||
let senderAddress: string;
|
||||
before(async () => {
|
||||
token = tokens[0];
|
||||
tokenAddress = tokens[0];
|
||||
toAddress = addressWithoutFunds;
|
||||
senderAddress = userAddresses[2];
|
||||
});
|
||||
@ -96,19 +100,19 @@ describe('TokenWrapper', () => {
|
||||
const fromAddress = coinbase;
|
||||
const transferAmount = new BigNumber(42);
|
||||
|
||||
const fromAddressBalance = await contractWrappers.token.getBalanceAsync(token.address, fromAddress);
|
||||
const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress);
|
||||
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
||||
|
||||
const fromAddressAllowance = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
);
|
||||
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
||||
|
||||
return expect(
|
||||
contractWrappers.token.transferFromAsync(
|
||||
token.address,
|
||||
contractWrappers.erc20Token.transferFromAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
@ -120,11 +124,11 @@ describe('TokenWrapper', () => {
|
||||
const fromAddress = coinbase;
|
||||
const transferAmount = new BigNumber(42);
|
||||
|
||||
await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(tokenAddress, fromAddress, toAddress, transferAmount);
|
||||
|
||||
return expect(
|
||||
contractWrappers.token.transferFromAsync(
|
||||
token.address,
|
||||
contractWrappers.erc20Token.transferFromAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
@ -136,20 +140,25 @@ describe('TokenWrapper', () => {
|
||||
const fromAddress = addressWithoutFunds;
|
||||
const transferAmount = new BigNumber(42);
|
||||
|
||||
const fromAddressBalance = await contractWrappers.token.getBalanceAsync(token.address, fromAddress);
|
||||
const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress);
|
||||
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
||||
|
||||
await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||
const fromAddressAllowance = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
senderAddress,
|
||||
transferAmount,
|
||||
);
|
||||
const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
senderAddress,
|
||||
);
|
||||
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
||||
|
||||
return expect(
|
||||
contractWrappers.token.transferFromAsync(
|
||||
token.address,
|
||||
contractWrappers.erc20Token.transferFromAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
@ -160,42 +169,47 @@ describe('TokenWrapper', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
const fromAddress = coinbase;
|
||||
|
||||
const preBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress);
|
||||
const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress);
|
||||
expect(preBalance).to.be.bignumber.equal(0);
|
||||
|
||||
const transferAmount = new BigNumber(42);
|
||||
await contractWrappers.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
senderAddress,
|
||||
transferAmount,
|
||||
);
|
||||
|
||||
await contractWrappers.token.transferFromAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.transferFromAsync(
|
||||
tokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
transferAmount,
|
||||
);
|
||||
const postBalance = await contractWrappers.token.getBalanceAsync(token.address, toAddress);
|
||||
const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress);
|
||||
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
||||
});
|
||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||
const fromAddress = coinbase;
|
||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||
return expect(
|
||||
contractWrappers.token.transferFromAsync(
|
||||
contractWrappers.erc20Token.transferFromAsync(
|
||||
nonExistentTokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
new BigNumber(42),
|
||||
),
|
||||
).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist);
|
||||
).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
|
||||
});
|
||||
});
|
||||
describe('#getBalanceAsync', () => {
|
||||
describe('With provider with accounts', () => {
|
||||
it('should return the balance for an existing ERC20 token', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const balance = await contractWrappers.token.getBalanceAsync(token.address, ownerAddress);
|
||||
const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, ownerAddress);
|
||||
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
||||
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
||||
});
|
||||
@ -203,13 +217,13 @@ describe('TokenWrapper', () => {
|
||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||
const ownerAddress = coinbase;
|
||||
return expect(
|
||||
contractWrappers.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress),
|
||||
).to.be.rejectedWith(ContractWrappersError.TokenContractDoesNotExist);
|
||||
contractWrappers.erc20Token.getBalanceAsync(nonExistentTokenAddress, ownerAddress),
|
||||
).to.be.rejectedWith(ContractWrappersError.ERC20TokenContractDoesNotExist);
|
||||
});
|
||||
it('should return a balance of 0 for a non-existent owner address', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593';
|
||||
const balance = await contractWrappers.token.getBalanceAsync(token.address, nonExistentOwner);
|
||||
const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, nonExistentOwner);
|
||||
const expectedBalance = new BigNumber(0);
|
||||
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
||||
});
|
||||
@ -221,9 +235,12 @@ describe('TokenWrapper', () => {
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
it('should return balance even when called with provider instance without addresses', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const balance = await zeroExContractWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
|
||||
const balance = await zeroExContractWithoutAccounts.erc20Token.getBalanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
);
|
||||
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
||||
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
||||
});
|
||||
@ -231,12 +248,12 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
describe('#setAllowanceAsync', () => {
|
||||
it("should set the spender's allowance", async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
|
||||
const allowanceBeforeSet = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const allowanceBeforeSet = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
@ -244,15 +261,15 @@ describe('TokenWrapper', () => {
|
||||
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
||||
|
||||
const amountInBaseUnits = new BigNumber(50);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
amountInBaseUnits,
|
||||
);
|
||||
|
||||
const allowanceAfterSet = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const allowanceAfterSet = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
@ -262,44 +279,50 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
describe('#setUnlimitedAllowanceAsync', () => {
|
||||
it("should set the unlimited spender's allowance", async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
|
||||
await contractWrappers.token.setUnlimitedAllowanceAsync(token.address, ownerAddress, spenderAddress);
|
||||
const allowance = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.setUnlimitedAllowanceAsync(tokenAddress, ownerAddress, spenderAddress);
|
||||
const allowance = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
return expect(allowance).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||
return expect(allowance).to.be.bignumber.equal(
|
||||
contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||
);
|
||||
});
|
||||
it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => {
|
||||
const transferAmount = new BigNumber(5);
|
||||
const zrx = tokenUtils.getProtocolTokenOrThrow();
|
||||
const zrxAddress = tokenUtils.getProtocolTokenAddress();
|
||||
const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses;
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
zrx.address,
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
zrxAddress,
|
||||
coinbase,
|
||||
userWithNormalAllowance,
|
||||
transferAmount,
|
||||
);
|
||||
await contractWrappers.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance);
|
||||
await contractWrappers.erc20Token.setUnlimitedAllowanceAsync(
|
||||
zrxAddress,
|
||||
coinbase,
|
||||
userWithUnlimitedAllowance,
|
||||
);
|
||||
|
||||
const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
||||
const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
|
||||
userWithUnlimitedAllowance,
|
||||
);
|
||||
|
||||
await contractWrappers.token.transferFromAsync(
|
||||
zrx.address,
|
||||
await contractWrappers.erc20Token.transferFromAsync(
|
||||
zrxAddress,
|
||||
coinbase,
|
||||
userWithNormalAllowance,
|
||||
userWithNormalAllowance,
|
||||
transferAmount,
|
||||
);
|
||||
await contractWrappers.token.transferFromAsync(
|
||||
zrx.address,
|
||||
await contractWrappers.erc20Token.transferFromAsync(
|
||||
zrxAddress,
|
||||
coinbase,
|
||||
userWithUnlimitedAllowance,
|
||||
userWithUnlimitedAllowance,
|
||||
@ -323,20 +346,20 @@ describe('TokenWrapper', () => {
|
||||
describe('#getAllowanceAsync', () => {
|
||||
describe('With provider with accounts', () => {
|
||||
it('should get the proxy allowance', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
|
||||
const amountInBaseUnits = new BigNumber(50);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
amountInBaseUnits,
|
||||
);
|
||||
|
||||
const allowance = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const allowance = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
@ -344,11 +367,11 @@ describe('TokenWrapper', () => {
|
||||
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
||||
});
|
||||
it('should return 0 if no allowance set yet', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
const allowance = await contractWrappers.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const allowance = await contractWrappers.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
@ -363,20 +386,20 @@ describe('TokenWrapper', () => {
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
it('should get the proxy allowance', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
|
||||
const amountInBaseUnits = new BigNumber(50);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
token.address,
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
amountInBaseUnits,
|
||||
);
|
||||
|
||||
const allowance = await zeroExContractWithoutAccounts.token.getAllowanceAsync(
|
||||
token.address,
|
||||
const allowance = await zeroExContractWithoutAccounts.erc20Token.getAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
@ -387,42 +410,50 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
describe('#getProxyAllowanceAsync', () => {
|
||||
it('should get the proxy allowance', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
|
||||
const amountInBaseUnits = new BigNumber(50);
|
||||
await contractWrappers.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
|
||||
await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits);
|
||||
|
||||
const allowance = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress);
|
||||
const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||
const expectedAllowance = amountInBaseUnits;
|
||||
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
||||
});
|
||||
});
|
||||
describe('#setProxyAllowanceAsync', () => {
|
||||
it('should set the proxy allowance', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
|
||||
const allowanceBeforeSet = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress);
|
||||
const allowanceBeforeSet = await contractWrappers.erc20Token.getProxyAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
);
|
||||
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
||||
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
||||
|
||||
const amountInBaseUnits = new BigNumber(50);
|
||||
await contractWrappers.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
|
||||
await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits);
|
||||
|
||||
const allowanceAfterSet = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress);
|
||||
const allowanceAfterSet = await contractWrappers.erc20Token.getProxyAllowanceAsync(
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
);
|
||||
const expectedAllowanceAfterAllowanceSet = amountInBaseUnits;
|
||||
return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet);
|
||||
});
|
||||
});
|
||||
describe('#setUnlimitedProxyAllowanceAsync', () => {
|
||||
it('should set the unlimited proxy allowance', async () => {
|
||||
const token = tokens[0];
|
||||
const tokenAddress = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
|
||||
await contractWrappers.token.setUnlimitedProxyAllowanceAsync(token.address, ownerAddress);
|
||||
const allowance = await contractWrappers.token.getProxyAllowanceAsync(token.address, ownerAddress);
|
||||
return expect(allowance).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||
await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||
const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||
return expect(allowance).to.be.bignumber.equal(
|
||||
contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#subscribe', () => {
|
||||
@ -431,11 +462,10 @@ describe('TokenWrapper', () => {
|
||||
const transferAmount = new BigNumber(42);
|
||||
const allowanceAmount = new BigNumber(42);
|
||||
before(() => {
|
||||
const token = tokens[0];
|
||||
tokenAddress = token.address;
|
||||
tokenAddress = tokens[0];
|
||||
});
|
||||
afterEach(() => {
|
||||
contractWrappers.token.unsubscribeAll();
|
||||
contractWrappers.erc20Token.unsubscribeAll();
|
||||
});
|
||||
// Hack: Mocha does not allow a test to be both async and have a `done` callback
|
||||
// Since we need to await the receipt of the event in the `subscribe` callback,
|
||||
@ -445,7 +475,7 @@ describe('TokenWrapper', () => {
|
||||
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||
(logEvent: DecodedLogEvent<ERC20TokenTransferEventArgs>) => {
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
expect(logEvent.log.logIndex).to.be.equal(0);
|
||||
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
||||
@ -456,14 +486,24 @@ describe('TokenWrapper', () => {
|
||||
expect(args._value).to.be.bignumber.equal(transferAmount);
|
||||
},
|
||||
);
|
||||
contractWrappers.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
|
||||
await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||
contractWrappers.erc20Token.subscribe(
|
||||
tokenAddress,
|
||||
ERC20TokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callback,
|
||||
);
|
||||
await contractWrappers.erc20Token.transferAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
transferAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
(logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
const args = logEvent.log.args;
|
||||
@ -472,8 +512,13 @@ describe('TokenWrapper', () => {
|
||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||
},
|
||||
);
|
||||
contractWrappers.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
await contractWrappers.token.setAllowanceAsync(
|
||||
contractWrappers.erc20Token.subscribe(
|
||||
tokenAddress,
|
||||
ERC20TokenEvents.Approval,
|
||||
indexFilterValues,
|
||||
callback,
|
||||
);
|
||||
await contractWrappers.erc20Token.setAllowanceAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
@ -484,42 +529,52 @@ describe('TokenWrapper', () => {
|
||||
it('Outstanding subscriptions are cancelled when contractWrappers.setProvider called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
(logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
},
|
||||
);
|
||||
contractWrappers.token.subscribe(
|
||||
contractWrappers.erc20Token.subscribe(
|
||||
tokenAddress,
|
||||
TokenEvents.Transfer,
|
||||
ERC20TokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)();
|
||||
contractWrappers.setProvider(provider, constants.TESTRPC_NETWORK_ID);
|
||||
contractWrappers.token.subscribe(
|
||||
contractWrappers.erc20Token.subscribe(
|
||||
tokenAddress,
|
||||
TokenEvents.Transfer,
|
||||
ERC20TokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackToBeCalled,
|
||||
);
|
||||
await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||
await contractWrappers.erc20Token.transferAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
transferAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
(logEvent: DecodedLogEvent<ERC20TokenApprovalEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
},
|
||||
);
|
||||
const subscriptionToken = contractWrappers.token.subscribe(
|
||||
const subscriptionToken = contractWrappers.erc20Token.subscribe(
|
||||
tokenAddress,
|
||||
TokenEvents.Transfer,
|
||||
ERC20TokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
contractWrappers.token.unsubscribe(subscriptionToken);
|
||||
await contractWrappers.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||
contractWrappers.erc20Token.unsubscribe(subscriptionToken);
|
||||
await contractWrappers.erc20Token.transferAsync(
|
||||
tokenAddress,
|
||||
coinbase,
|
||||
addressWithoutFunds,
|
||||
transferAmount,
|
||||
);
|
||||
done();
|
||||
})().catch(done);
|
||||
});
|
||||
@ -533,16 +588,15 @@ describe('TokenWrapper', () => {
|
||||
};
|
||||
let txHash: string;
|
||||
before(() => {
|
||||
const token = tokens[0];
|
||||
tokenAddress = token.address;
|
||||
tokenTransferProxyAddress = contractWrappers.proxy.getContractAddress();
|
||||
tokenAddress = tokens[0];
|
||||
tokenTransferProxyAddress = contractWrappers.erc20Proxy.getContractAddress();
|
||||
});
|
||||
it('should get logs with decoded args emitted by Approval', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const eventName = ERC20TokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
const logs = await contractWrappers.erc20Token.getLogsAsync<ERC20TokenApprovalEventArgs>(
|
||||
tokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
@ -553,14 +607,14 @@ describe('TokenWrapper', () => {
|
||||
expect(logs[0].event).to.be.equal(eventName);
|
||||
expect(args._owner).to.be.equal(coinbase);
|
||||
expect(args._spender).to.be.equal(tokenTransferProxyAddress);
|
||||
expect(args._value).to.be.bignumber.equal(contractWrappers.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||
expect(args._value).to.be.bignumber.equal(contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const differentEventName = TokenEvents.Transfer;
|
||||
const differentEventName = ERC20TokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync(
|
||||
const logs = await contractWrappers.erc20Token.getLogsAsync(
|
||||
tokenAddress,
|
||||
differentEventName,
|
||||
blockRange,
|
||||
@ -569,15 +623,18 @@ describe('TokenWrapper', () => {
|
||||
expect(logs).to.have.length(0);
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds);
|
||||
txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(
|
||||
tokenAddress,
|
||||
addressWithoutFunds,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const eventName = ERC20TokenEvents.Approval;
|
||||
const indexFilterValues = {
|
||||
_owner: coinbase,
|
||||
};
|
||||
const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
const logs = await contractWrappers.erc20Token.getLogsAsync<ERC20TokenApprovalEventArgs>(
|
||||
tokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
Loading…
x
Reference in New Issue
Block a user