* FQT: Pack Protocol/source name into source ID (#162) * `@0x/contracts-zero-ex`: Encode protocol ID and source name in bridge source ID `@0x/asset-swapper`: Use new bridge source ID encoding. * fix linter issues * contracts cleanup (#164) * `@0x/contracts-zero-ex`: Add PancakeSwapFeature * `@0x/contracts-zero-ex`: Remove tokenspender/allowance target/greedy tokens stuff.' `@0x/contract-addresses`: Add BSC addresses. Remove exchangeProxyAllowanceTarget. `@0x/migrations`: Remove exchangeProxyAllowanceTarget. * Update contracts/zero-ex/contracts/src/features/IPancakeSwapFeature.sol Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> * `@0x/contracts-zero-ex`: Add sushiswap support to PancakeSwap * `@0x/contract-artifacts`: Regenerate artifacts `@0x/contract-wrappers`: Regenerate wrappers * `@0x/contract-addresses`: Add BSC addresses Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> * feat: Better chain support (#163) * feat: Better chain support * feat: better chain support refactor deployment constants (#166) * proliferate the chainId * Refactor sampler to remove DeploymentConstants dependency and fixed addresses * Rework WETH out, replacing with address(0) * wat * hack DeploymentConstants for now * proliferate the chainId * Refactor sampler to remove DeploymentConstants dependency and fixed addresses * remove duped network addresses * Rework the bridge source encoder * Use the constants NATIVE_FEE_TOKEN in EP consumer * `@0x/contract-addresses`: Fix WBNB address (#170) Co-authored-by: Lawrence Forman <lawrence@0xproject.com> * multichain enable cakez vip (#171) * feat: Better chain support * feat: better chain support refactor deployment constants (#166) * proliferate the chainId * Refactor sampler to remove DeploymentConstants dependency and fixed addresses * Rework WETH out, replacing with address(0) * wat * hack DeploymentConstants for now * proliferate the chainId * Refactor sampler to remove DeploymentConstants dependency and fixed addresses * remove duped network addresses * `asset-swapper`: enable pancake VIP route generation Co-authored-by: Jacob Evans <jacob@dekz.net> Co-authored-by: Lawrence Forman <me@merklejerk.com> * `@0x/contracts-zero-ex`: Fix `PancakeSwapFeature` sushi values (#172) * `@0x/contracts-zero-ex`: Fix `PancakeSwapFeature` sushi values * `@0x/contracts-zero-ex`: I am a bad protocologist Co-authored-by: Lawrence Forman <me@merklejerk.com> * feat: BSC Nerve + Dodo + Nerve + Ellipsis (#181) * feat: BSC Nerve + DODO v1 * CHANGELOGs * Remove extra balance fetch * Add Belt * Added Ellipsis * Update FQT address * `@0x/contracts-zero-ex`: Delete TokenSpenderFeature and get stuff compiling * `@0x/asset-swapper`: fix compilation * prettier * `@0x/asset-swapper`: Truncate LiquidityProvider source ID name * Update packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts Co-authored-by: Jacob Evans <jacob@dekz.net> * Update packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts Co-authored-by: Jacob Evans <jacob@dekz.net> * `@0x/contracts-zero-ex`: Fix BakerySwap on PackageSwapFeature (#190) * address review comments Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> Co-authored-by: Jacob Evans <jacob@dekz.net> Co-authored-by: Lawrence Forman <me@merklejerk.com>
175 lines
6.9 KiB
TypeScript
175 lines
6.9 KiB
TypeScript
import {
|
|
blockchainTests,
|
|
expect,
|
|
getRandomInteger,
|
|
randomAddress,
|
|
verifyEventsFromLogs,
|
|
} from '@0x/contracts-test-utils';
|
|
import { BigNumber, hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
|
|
|
|
import { artifacts } from './artifacts';
|
|
import {
|
|
TestFixinTokenSpenderContract,
|
|
TestTokenSpenderERC20TokenContract,
|
|
TestTokenSpenderERC20TokenEvents,
|
|
} from './wrappers';
|
|
|
|
blockchainTests.resets('FixinTokenSpender', env => {
|
|
let tokenSpender: TestFixinTokenSpenderContract;
|
|
let token: TestTokenSpenderERC20TokenContract;
|
|
let greedyToken: TestTokenSpenderERC20TokenContract;
|
|
|
|
before(async () => {
|
|
token = await TestTokenSpenderERC20TokenContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestTokenSpenderERC20Token,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
greedyToken = await TestTokenSpenderERC20TokenContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestTokenSpenderERC20Token,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
await greedyToken.setGreedyRevert(true).awaitTransactionSuccessAsync();
|
|
|
|
tokenSpender = await TestFixinTokenSpenderContract.deployFrom0xArtifactAsync(
|
|
artifacts.TestFixinTokenSpender,
|
|
env.provider,
|
|
env.txDefaults,
|
|
artifacts,
|
|
);
|
|
});
|
|
|
|
describe('transferERC20Tokens()', () => {
|
|
const EMPTY_RETURN_AMOUNT = 1337;
|
|
const FALSE_RETURN_AMOUNT = 1338;
|
|
const REVERT_RETURN_AMOUNT = 1339;
|
|
const EXTRA_RETURN_TRUE_AMOUNT = 1341;
|
|
const EXTRA_RETURN_FALSE_AMOUNT = 1342;
|
|
|
|
it('transferERC20Tokens() successfully calls compliant ERC20 token', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(123456);
|
|
const receipt = await tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
verifyEventsFromLogs(
|
|
receipt.logs,
|
|
[
|
|
{
|
|
sender: tokenSpender.address,
|
|
from: tokenFrom,
|
|
to: tokenTo,
|
|
amount: tokenAmount,
|
|
},
|
|
],
|
|
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
|
|
);
|
|
});
|
|
|
|
it('transferERC20Tokens() successfully calls non-compliant ERC20 token', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(EMPTY_RETURN_AMOUNT);
|
|
const receipt = await tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
verifyEventsFromLogs(
|
|
receipt.logs,
|
|
[
|
|
{
|
|
sender: tokenSpender.address,
|
|
from: tokenFrom,
|
|
to: tokenTo,
|
|
amount: tokenAmount,
|
|
},
|
|
],
|
|
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
|
|
);
|
|
});
|
|
|
|
it('transferERC20Tokens() reverts if ERC20 token reverts', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(REVERT_RETURN_AMOUNT);
|
|
const tx = tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
const expectedError = new StringRevertError('TestTokenSpenderERC20Token/Revert');
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
|
|
it('transferERC20Tokens() reverts if ERC20 token returns false', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(FALSE_RETURN_AMOUNT);
|
|
const tx = tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
|
|
});
|
|
|
|
it('transferERC20Tokens() allows extra data after true', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(EXTRA_RETURN_TRUE_AMOUNT);
|
|
|
|
const receipt = await tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
verifyEventsFromLogs(
|
|
receipt.logs,
|
|
[
|
|
{
|
|
sender: tokenSpender.address,
|
|
from: tokenFrom,
|
|
to: tokenTo,
|
|
amount: tokenAmount,
|
|
},
|
|
],
|
|
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
|
|
);
|
|
});
|
|
|
|
it("transferERC20Tokens() reverts when there's extra data after false", async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(EXTRA_RETURN_FALSE_AMOUNT);
|
|
|
|
const tx = tokenSpender
|
|
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(EXTRA_RETURN_FALSE_AMOUNT, 64)));
|
|
});
|
|
|
|
it('transferERC20Tokens() cannot call self', async () => {
|
|
const tokenFrom = randomAddress();
|
|
const tokenTo = randomAddress();
|
|
const tokenAmount = new BigNumber(123456);
|
|
|
|
const tx = tokenSpender
|
|
.transferERC20Tokens(tokenSpender.address, tokenFrom, tokenTo, tokenAmount)
|
|
.awaitTransactionSuccessAsync();
|
|
return expect(tx).to.revertWith('FixinTokenSpender/CANNOT_INVOKE_SELF');
|
|
});
|
|
});
|
|
|
|
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, tokenSpender.address, allowance)
|
|
.awaitTransactionSuccessAsync();
|
|
const spendableBalance = await tokenSpender
|
|
.getSpendableERC20BalanceOf(token.address, tokenOwner)
|
|
.callAsync();
|
|
expect(spendableBalance).to.bignumber.eq(BigNumber.min(balance, allowance));
|
|
});
|
|
});
|
|
});
|