138 lines
5.6 KiB
TypeScript
138 lines
5.6 KiB
TypeScript
import {
|
|
blockchainTests,
|
|
expect,
|
|
getRandomInteger,
|
|
randomAddress,
|
|
verifyEventsFromLogs,
|
|
} from '@0x/contracts-test-utils';
|
|
import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/utils';
|
|
|
|
import { IZeroExContract, TokenSpenderFeatureContract } from '../../src/wrappers';
|
|
import { artifacts } from '../artifacts';
|
|
import { abis } from '../utils/abis';
|
|
import { fullMigrateAsync } from '../utils/migration';
|
|
import { TestTokenSpenderERC20TokenContract, TestTokenSpenderERC20TokenEvents } from '../wrappers';
|
|
|
|
blockchainTests.resets('TokenSpender feature', env => {
|
|
let zeroEx: IZeroExContract;
|
|
let feature: TokenSpenderFeatureContract;
|
|
let token: TestTokenSpenderERC20TokenContract;
|
|
let allowanceTarget: string;
|
|
|
|
before(async () => {
|
|
const [owner] = await env.getAccountAddressesAsync();
|
|
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
|
|
tokenSpender: (await TokenSpenderFeatureContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestTokenSpender,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
)).address,
|
|
});
|
|
feature = new TokenSpenderFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis);
|
|
token = await TestTokenSpenderERC20TokenContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestTokenSpenderERC20Token,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
allowanceTarget = await feature.getAllowanceTarget().callAsync();
|
|
});
|
|
|
|
describe('_spendERC20Tokens()', () => {
|
|
const EMPTY_RETURN_AMOUNT = 1337;
|
|
const FALSE_RETURN_AMOUNT = 1338;
|
|
const REVERT_RETURN_AMOUNT = 1339;
|
|
|
|
it('_spendERC20Tokens() successfully calls compliant ERC20 token', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(123456);
|
|
const receipt = await feature
|
|
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
verifyEventsFromLogs(
|
|
receipt.logs,
|
|
[
|
|
{
|
|
sender: allowanceTarget,
|
|
from: tokenFrom,
|
|
to: tokenTo,
|
|
amount: tokenAmount,
|
|
},
|
|
],
|
|
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
|
|
);
|
|
});
|
|
|
|
it('_spendERC20Tokens() successfully calls non-compliant ERC20 token', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(EMPTY_RETURN_AMOUNT);
|
|
const receipt = await feature
|
|
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
verifyEventsFromLogs(
|
|
receipt.logs,
|
|
[
|
|
{
|
|
sender: allowanceTarget,
|
|
from: tokenFrom,
|
|
to: tokenTo,
|
|
amount: tokenAmount,
|
|
},
|
|
],
|
|
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
|
|
);
|
|
});
|
|
|
|
it('_spendERC20Tokens() reverts if ERC20 token reverts', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(REVERT_RETURN_AMOUNT);
|
|
const tx = feature
|
|
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
|
|
token.address,
|
|
tokenFrom,
|
|
tokenTo,
|
|
tokenAmount,
|
|
new StringRevertError('TestTokenSpenderERC20Token/Revert').encode(),
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('_spendERC20Tokens() reverts if ERC20 token returns false', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(FALSE_RETURN_AMOUNT);
|
|
const tx = feature
|
|
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith(
|
|
new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
|
|
token.address,
|
|
tokenFrom,
|
|
tokenTo,
|
|
tokenAmount,
|
|
hexUtils.leftPad(0),
|
|
),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('getSpendableERC20BalanceOf()', () => {
|
|
it("returns the minimum of the owner's balance and allowance", async () => {
|
|
const balance = getRandomInteger(1, '1e18');
|
|
const allowance = getRandomInteger(1, '1e18');
|
|
const tokenOwner = randomAddress();
|
|
await token
|
|
.setBalanceAndAllowanceOf(tokenOwner, balance, allowanceTarget, allowance)
|
|
.awaitTransactionSuccessAsync();
|
|
const spendableBalance = await feature.getSpendableERC20BalanceOf(token.address, tokenOwner).callAsync();
|
|
expect(spendableBalance).to.bignumber.eq(BigNumber.min(balance, allowance));
|
|
});
|
|
});
|
|
});
|