aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/test
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-06-12 06:23:48 +0800
committerFabio Berger <me@fabioberger.com>2018-06-12 06:23:48 +0800
commit7e78f5941ad9cb2fd5225899f79823c7376894c0 (patch)
tree13fadf90f821e9fead1373a2e567e6d86fe27e0f /packages/order-utils/test
parent20f93185975d16c77492f05eb86dd89695539cd9 (diff)
parentbc0ae6be318a15bf8670a6da9a59d9bdb12cadae (diff)
downloaddexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar.gz
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar.bz2
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar.lz
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar.xz
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.tar.zst
dexon-sol-tools-7e78f5941ad9cb2fd5225899f79823c7376894c0.zip
Merge branch 'v2-prototype' into feature/combinatorial-testing
* v2-prototype: (68 commits) Stop exporting ArtifactWriter Fix no-unused-variable tslint rule to include parameters and fix issues Fix linter exclude rule Validate all signature types rather then only ECSignatures Store the instantiated OrderValidationUtils Remove global hooks from tests and deploy contracts from within the specific tests Add EmitStatement to ASTVisitor Fix tslint issues Add back artifacts file Fix a bug in SolCompilerArtifacts adapter config overriding Move OrderValidationUtils (+ tests) and ExchangeTransferSimulator to order-utils export parseECSignature method Export ArtifactWriter from migrations package Remove unused artifact file Pass in generated contract wrapper to orderValidationUtils at instantiation Refactor orderValidationUtils to use the generated contract wrapper instead of the higher-level one Refactor ExchangeTransferSimulator public interface to accet an AbstractBalanceAndProxyAllowanceLazyStore so that this module could be re-used in different contexts. Increase timeout for contract migrations Remove some copy-paste code Await transactions in migrations ...
Diffstat (limited to 'packages/order-utils/test')
-rw-r--r--packages/order-utils/test/exchange_transfer_simulator_test.ts177
-rw-r--r--packages/order-utils/test/order_validation_utils_test.ts70
-rw-r--r--packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts26
3 files changed, 273 insertions, 0 deletions
diff --git a/packages/order-utils/test/exchange_transfer_simulator_test.ts b/packages/order-utils/test/exchange_transfer_simulator_test.ts
new file mode 100644
index 000000000..eeae42698
--- /dev/null
+++ b/packages/order-utils/test/exchange_transfer_simulator_test.ts
@@ -0,0 +1,177 @@
+import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
+import { ExchangeContractErrs } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import 'make-promises-safe';
+
+import { artifacts } from '../src/artifacts';
+import { constants } from '../src/constants';
+import { ExchangeTransferSimulator } from '../src/exchange_transfer_simulator';
+import { DummyERC20TokenContract } from '../src/generated_contract_wrappers/dummy_e_r_c20_token';
+import { ERC20ProxyContract } from '../src/generated_contract_wrappers/e_r_c20_proxy';
+import { ERC20TokenContract } from '../src/generated_contract_wrappers/e_r_c20_token';
+import { BalanceAndProxyAllowanceLazyStore } from '../src/store/balance_and_proxy_allowance_lazy_store';
+import { TradeSide, TransferType } from '../src/types';
+
+import { chaiSetup } from './utils/chai_setup';
+import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './utils/simple_erc20_balance_and_proxy_allowance_fetcher';
+import { provider, web3Wrapper } from './utils/web3_wrapper';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+
+describe('ExchangeTransferSimulator', async () => {
+ const transferAmount = new BigNumber(5);
+ let userAddresses: string[];
+ let dummyERC20Token: DummyERC20TokenContract;
+ let coinbase: string;
+ let sender: string;
+ let recipient: string;
+ let exampleTokenAddress: string;
+ let exchangeTransferSimulator: ExchangeTransferSimulator;
+ let txHash: string;
+ let erc20ProxyAddress: string;
+ before(async function(): Promise<void> {
+ const mochaTestTimeoutMs = 20000;
+ this.timeout(mochaTestTimeoutMs);
+
+ userAddresses = await web3Wrapper.getAvailableAddressesAsync();
+ [coinbase, sender, recipient] = userAddresses;
+
+ const txDefaults = {
+ gas: devConstants.GAS_LIMIT,
+ from: devConstants.TESTRPC_FIRST_ADDRESS,
+ };
+
+ const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
+ artifacts.ERC20Proxy,
+ provider,
+ txDefaults,
+ );
+ erc20ProxyAddress = erc20Proxy.address;
+
+ const totalSupply = new BigNumber(100000000000000000000);
+ const name = 'Test';
+ const symbol = 'TST';
+ const decimals = new BigNumber(18);
+ // tslint:disable-next-line:no-unused-variable
+ dummyERC20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
+ artifacts.DummyERC20Token,
+ provider,
+ txDefaults,
+ name,
+ symbol,
+ decimals,
+ totalSupply,
+ );
+
+ exampleTokenAddress = dummyERC20Token.address;
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('#transferFromAsync', function(): void {
+ // HACK: For some reason these tests need a slightly longer timeout
+ const mochaTestTimeoutMs = 3000;
+ this.timeout(mochaTestTimeoutMs);
+
+ beforeEach(() => {
+ const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher(
+ (dummyERC20Token as any) as ERC20TokenContract,
+ erc20ProxyAddress,
+ );
+ const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
+ simpleERC20BalanceAndProxyAllowanceFetcher,
+ );
+ exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
+ });
+ it("throws if the user doesn't have enough allowance", async () => {
+ return expect(
+ exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress,
+ sender,
+ recipient,
+ transferAmount,
+ TradeSide.Taker,
+ TransferType.Trade,
+ ),
+ ).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
+ });
+ it("throws if the user doesn't have enough balance", async () => {
+ txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, {
+ from: sender,
+ });
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ return expect(
+ exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress,
+ sender,
+ recipient,
+ transferAmount,
+ TradeSide.Maker,
+ TransferType.Trade,
+ ),
+ ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
+ });
+ it('updates balances and proxyAllowance after transfer', async () => {
+ txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, {
+ from: coinbase,
+ });
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+
+ txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, {
+ from: sender,
+ });
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+
+ await exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress,
+ sender,
+ recipient,
+ transferAmount,
+ TradeSide.Taker,
+ TransferType.Trade,
+ );
+ const store = (exchangeTransferSimulator as any)._store;
+ const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
+ const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
+ const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
+ expect(senderBalance).to.be.bignumber.equal(0);
+ expect(recipientBalance).to.be.bignumber.equal(transferAmount);
+ expect(senderProxyAllowance).to.be.bignumber.equal(0);
+ });
+ it("doesn't update proxyAllowance after transfer if unlimited", async () => {
+ txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, {
+ from: coinbase,
+ });
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ txHash = await dummyERC20Token.approve.sendTransactionAsync(
+ erc20ProxyAddress,
+ constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
+ {
+ from: sender,
+ },
+ );
+ await web3Wrapper.awaitTransactionSuccessAsync(txHash);
+ await exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress,
+ sender,
+ recipient,
+ transferAmount,
+ TradeSide.Taker,
+ TransferType.Trade,
+ );
+ const store = (exchangeTransferSimulator as any)._store;
+ const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
+ const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
+ const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
+ expect(senderBalance).to.be.bignumber.equal(0);
+ expect(recipientBalance).to.be.bignumber.equal(transferAmount);
+ expect(senderProxyAllowance).to.be.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
+ });
+ });
+});
diff --git a/packages/order-utils/test/order_validation_utils_test.ts b/packages/order-utils/test/order_validation_utils_test.ts
new file mode 100644
index 000000000..d3ff867d7
--- /dev/null
+++ b/packages/order-utils/test/order_validation_utils_test.ts
@@ -0,0 +1,70 @@
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import 'mocha';
+
+import { OrderValidationUtils } from '../src/order_validation_utils';
+
+import { chaiSetup } from './utils/chai_setup';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('OrderValidationUtils', () => {
+ describe('#isRoundingError', () => {
+ it('should return false if there is a rounding error of 0.1%', async () => {
+ const numerator = new BigNumber(20);
+ const denominator = new BigNumber(999);
+ const target = new BigNumber(50);
+ // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.false();
+ });
+
+ it('should return false if there is a rounding of 0.09%', async () => {
+ const numerator = new BigNumber(20);
+ const denominator = new BigNumber(9991);
+ const target = new BigNumber(500);
+ // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.false();
+ });
+
+ it('should return true if there is a rounding error of 0.11%', async () => {
+ const numerator = new BigNumber(20);
+ const denominator = new BigNumber(9989);
+ const target = new BigNumber(500);
+ // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.true();
+ });
+
+ it('should return true if there is a rounding error > 0.1%', async () => {
+ const numerator = new BigNumber(3);
+ const denominator = new BigNumber(7);
+ const target = new BigNumber(10);
+ // rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.true();
+ });
+
+ it('should return false when there is no rounding error', async () => {
+ const numerator = new BigNumber(1);
+ const denominator = new BigNumber(2);
+ const target = new BigNumber(10);
+
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.false();
+ });
+
+ it('should return false when there is rounding error <= 0.1%', async () => {
+ // randomly generated numbers
+ const numerator = new BigNumber(76564);
+ const denominator = new BigNumber(676373677);
+ const target = new BigNumber(105762562);
+ // rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
+ // (76564*105762562/676373677) = 0.0007%
+ const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
+ expect(isRoundingError).to.be.false();
+ });
+ });
+});
diff --git a/packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts b/packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts
new file mode 100644
index 000000000..d41eaca40
--- /dev/null
+++ b/packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts
@@ -0,0 +1,26 @@
+import { BigNumber } from '@0xproject/utils';
+
+import { AbstractBalanceAndProxyAllowanceFetcher } from '../../src/abstract/abstract_balance_and_proxy_allowance_fetcher';
+
+import { ERC20TokenContract } from '../../src/generated_contract_wrappers/e_r_c20_token';
+
+export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
+ private _erc20TokenContract: ERC20TokenContract;
+ private _erc20ProxyAddress: string;
+ constructor(erc20TokenWrapper: ERC20TokenContract, erc20ProxyAddress: string) {
+ this._erc20TokenContract = erc20TokenWrapper;
+ this._erc20ProxyAddress = erc20ProxyAddress;
+ }
+ public async getBalanceAsync(_assetData: string, userAddress: string): Promise<BigNumber> {
+ // HACK: We cheat and don't pass in the assetData since it's always the same token used
+ // in our tests.
+ const balance = await this._erc20TokenContract.balanceOf.callAsync(userAddress);
+ return balance;
+ }
+ public async getProxyAllowanceAsync(_assetData: string, userAddress: string): Promise<BigNumber> {
+ // HACK: We cheat and don't pass in the assetData since it's always the same token used
+ // in our tests.
+ const proxyAllowance = await this._erc20TokenContract.allowance.callAsync(userAddress, this._erc20ProxyAddress);
+ return proxyAllowance;
+ }
+}