aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-06-08 00:00:13 +0800
committerFabio Berger <me@fabioberger.com>2018-06-08 00:00:13 +0800
commitab5e021bda5cc8e39d8595580c09c3540a09aff5 (patch)
treee40c3be709d10e1a2463cb0807419c7b276f1548 /packages/contracts/src
parent0fc981400442e4c567ca363bdf0f4c03ba87473d (diff)
downloaddexon-0x-contracts-ab5e021bda5cc8e39d8595580c09c3540a09aff5.tar.gz
dexon-0x-contracts-ab5e021bda5cc8e39d8595580c09c3540a09aff5.tar.zst
dexon-0x-contracts-ab5e021bda5cc8e39d8595580c09c3540a09aff5.zip
POC: Generates an order from spec, get's the amount fillable
Diffstat (limited to 'packages/contracts/src')
-rw-r--r--packages/contracts/src/utils/erc20_wrapper.ts28
-rw-r--r--packages/contracts/src/utils/new_order_factory.ts (renamed from packages/contracts/src/utils/combinatorial_utils.ts)99
-rw-r--r--packages/contracts/src/utils/order_info_utils.ts44
-rw-r--r--packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts20
-rw-r--r--packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts32
-rw-r--r--packages/contracts/src/utils/types.ts5
6 files changed, 196 insertions, 32 deletions
diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts
index dceeceeea..efb245c89 100644
--- a/packages/contracts/src/utils/erc20_wrapper.ts
+++ b/packages/contracts/src/utils/erc20_wrapper.ts
@@ -25,8 +25,11 @@ export class ERC20Wrapper {
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
}
- public async deployDummyTokensAsync(): Promise<DummyERC20TokenContract[]> {
- for (let i = 0; i < constants.NUM_DUMMY_ERC20_TO_DEPLOY; i++) {
+ public async deployDummyTokensAsync(num?: number, decimals?: BigNumber): Promise<DummyERC20TokenContract[]> {
+ // TODO(fabio): Remove and refactor all tests
+ const finalNum = _.isUndefined(num) ? constants.NUM_DUMMY_ERC20_TO_DEPLOY : num;
+ const finalDecimals = _.isUndefined(decimals) ? constants.DUMMY_TOKEN_DECIMALS : decimals;
+ for (let i = 0; i < finalNum; i++) {
this._dummyTokenContracts.push(
await DummyERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.DummyERC20Token,
@@ -34,7 +37,7 @@ export class ERC20Wrapper {
txDefaults,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
+ finalDecimals,
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
),
);
@@ -73,6 +76,25 @@ export class ERC20Wrapper {
}
}
}
+ public async getBalanceAsync(owner: string, token: string): Promise<BigNumber> {
+ const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token);
+ if (_.isUndefined(tokenContractIfExists)) {
+ throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`);
+ }
+ const balance = new BigNumber(await tokenContractIfExists.balanceOf.callAsync(owner));
+ return balance;
+ }
+ public async getProxyAllowanceAsync(owner: string, token: string): Promise<BigNumber> {
+ this._validateProxyContractExistsOrThrow();
+ const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === token);
+ if (_.isUndefined(tokenContractIfExists)) {
+ throw new Error(`Token: ${token} was not deployed through ERC20Wrapper`);
+ }
+ const balance = new BigNumber(
+ await tokenContractIfExists.allowance.callAsync(owner, (this._proxyContract as ERC20ProxyContract).address),
+ );
+ return balance;
+ }
public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
this._validateDummyTokenContractsExistOrThrow();
const balancesByOwner: ERC20BalancesByOwner = {};
diff --git a/packages/contracts/src/utils/combinatorial_utils.ts b/packages/contracts/src/utils/new_order_factory.ts
index c7d48c86d..a4ded4230 100644
--- a/packages/contracts/src/utils/combinatorial_utils.ts
+++ b/packages/contracts/src/utils/new_order_factory.ts
@@ -2,10 +2,12 @@ import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-util
import { Order } from '@0xproject/types';
import { BigNumber, errorUtils } from '@0xproject/utils';
+import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token';
+
import { constants } from './constants';
import {
AssetDataScenario,
- ERC721Token,
+ ERC721TokenIdsByOwner,
ExpirationTimeSecondsScenario,
FeeRecipientAddressScenario,
OrderAmountScenario,
@@ -17,14 +19,39 @@ const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1000000);
const ONE_NFT_UNIT = new BigNumber(1);
const TEN_MINUTES_MS = 1000 * 60 * 10;
-export const combinatorialUtils = {
- generateOrder(
+/*
+ * TODO:
+ * - Write function that given an order, fillAmount, retrieves orderRelevantState and maps it to expected test outcome.
+ * - Write function that generates order permutations.
+ * - Write functions for other steps that must be permutated
+ */
+
+export class NewOrderFactory {
+ private _userAddresses: string[];
+ private _zrxAddress: string;
+ private _nonZrxERC20EighteenDecimalTokenAddresses: string[];
+ private _erc20FiveDecimalTokenAddresses: string[];
+ private _erc721Token: DummyERC721TokenContract;
+ private _erc721Balances: ERC721TokenIdsByOwner;
+ private _exchangeAddress: string;
+ constructor(
userAddresses: string[],
zrxAddress: string,
- nonZrxERC20EighteenDecimalTokenAddress: string,
- erc20FiveDecimalTokenAddress: string,
- erc721Token: ERC721Token,
+ nonZrxERC20EighteenDecimalTokenAddresses: string[],
+ erc20FiveDecimalTokenAddresses: string[],
+ erc721Token: DummyERC721TokenContract,
+ erc721Balances: ERC721TokenIdsByOwner,
exchangeAddress: string,
+ ) {
+ this._userAddresses = userAddresses;
+ this._zrxAddress = zrxAddress;
+ this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
+ this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
+ this._erc721Token = erc721Token;
+ this._erc721Balances = erc721Balances;
+ this._exchangeAddress = exchangeAddress;
+ }
+ public generateOrder(
feeRecipientScenario: FeeRecipientAddressScenario,
makerAssetAmountScenario: OrderAmountScenario,
takerAssetAmountScenario: OrderAmountScenario,
@@ -34,6 +61,10 @@ export const combinatorialUtils = {
makerAssetDataScenario: AssetDataScenario,
takerAssetDataScenario: AssetDataScenario,
): Order {
+ const makerAddress = this._userAddresses[1];
+ const takerAddress = this._userAddresses[2];
+ const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address];
+ const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address];
let feeRecipientAddress;
let makerAssetAmount;
let takerAssetAmount;
@@ -48,7 +79,7 @@ export const combinatorialUtils = {
feeRecipientAddress = constants.NULL_ADDRESS;
break;
case FeeRecipientAddressScenario.EthUserAddress:
- feeRecipientAddress = userAddresses[4];
+ feeRecipientAddress = this._userAddresses[4];
break;
default:
throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', feeRecipientScenario);
@@ -57,24 +88,34 @@ export const combinatorialUtils = {
const invalidAssetProxyIdHex = '0A';
switch (makerAssetDataScenario) {
case AssetDataScenario.ZRXFeeToken:
- makerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress);
+ makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress);
break;
case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress);
+ makerAssetData = assetProxyUtils.encodeERC20ProxyData(
+ this._nonZrxERC20EighteenDecimalTokenAddresses[0],
+ );
break;
case AssetDataScenario.ERC20FiveDecimals:
- makerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress);
+ makerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[0]);
break;
case AssetDataScenario.ERC20InvalidAssetProxyId: {
- const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress);
+ const validAssetData = assetProxyUtils.encodeERC20ProxyData(
+ this._nonZrxERC20EighteenDecimalTokenAddresses[0],
+ );
makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`;
break;
}
case AssetDataScenario.ERC721ValidAssetProxyId:
- makerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id);
+ makerAssetData = assetProxyUtils.encodeERC721ProxyData(
+ this._erc721Token.address,
+ erc721MakerAssetIds[0],
+ );
break;
case AssetDataScenario.ERC721InvalidAssetProxyId: {
- const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id);
+ const validAssetData = assetProxyUtils.encodeERC721ProxyData(
+ this._erc721Token.address,
+ erc721MakerAssetIds[0],
+ );
makerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`;
break;
}
@@ -84,24 +125,34 @@ export const combinatorialUtils = {
switch (takerAssetDataScenario) {
case AssetDataScenario.ZRXFeeToken:
- takerAssetData = assetProxyUtils.encodeERC20ProxyData(zrxAddress);
+ takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._zrxAddress);
break;
case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- takerAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress);
+ takerAssetData = assetProxyUtils.encodeERC20ProxyData(
+ this._nonZrxERC20EighteenDecimalTokenAddresses[1],
+ );
break;
case AssetDataScenario.ERC20FiveDecimals:
- takerAssetData = assetProxyUtils.encodeERC20ProxyData(erc20FiveDecimalTokenAddress);
+ takerAssetData = assetProxyUtils.encodeERC20ProxyData(this._erc20FiveDecimalTokenAddresses[1]);
break;
case AssetDataScenario.ERC20InvalidAssetProxyId: {
- const validAssetData = assetProxyUtils.encodeERC20ProxyData(nonZrxERC20EighteenDecimalTokenAddress);
+ const validAssetData = assetProxyUtils.encodeERC20ProxyData(
+ this._nonZrxERC20EighteenDecimalTokenAddresses[1],
+ );
takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`;
break;
}
case AssetDataScenario.ERC721ValidAssetProxyId:
- takerAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id);
+ takerAssetData = assetProxyUtils.encodeERC721ProxyData(
+ this._erc721Token.address,
+ erc721TakerAssetIds[0],
+ );
break;
case AssetDataScenario.ERC721InvalidAssetProxyId: {
- const validAssetData = assetProxyUtils.encodeERC721ProxyData(erc721Token.address, erc721Token.id);
+ const validAssetData = assetProxyUtils.encodeERC721ProxyData(
+ this._erc721Token.address,
+ erc721TakerAssetIds[0],
+ );
takerAssetData = `${validAssetData.slice(0, -2)}${invalidAssetProxyIdHex}`;
break;
}
@@ -194,8 +245,8 @@ export const combinatorialUtils = {
const order: Order = {
senderAddress: constants.NULL_ADDRESS,
- makerAddress: userAddresses[1],
- takerAddress: userAddresses[2],
+ makerAddress,
+ takerAddress,
makerFee,
takerFee,
makerAssetAmount,
@@ -203,11 +254,11 @@ export const combinatorialUtils = {
makerAssetData,
takerAssetData,
salt: generatePseudoRandomSalt(),
- exchangeAddress,
+ exchangeAddress: this._exchangeAddress,
feeRecipientAddress,
expirationTimeSeconds,
};
return order;
- },
-};
+ }
+}
diff --git a/packages/contracts/src/utils/order_info_utils.ts b/packages/contracts/src/utils/order_info_utils.ts
new file mode 100644
index 000000000..9df627da3
--- /dev/null
+++ b/packages/contracts/src/utils/order_info_utils.ts
@@ -0,0 +1,44 @@
+import { assetProxyUtils, OrderStateUtils } from '@0xproject/order-utils';
+import { SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+
+import { ExchangeContract } from '../contract_wrappers/generated/exchange';
+
+import { constants } from './constants';
+import { ERC20Wrapper } from './erc20_wrapper';
+import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './simple_erc20_balance_and_allowance_fetcher';
+import { SimpleOrderFilledCancelledFetcher } from './simple_filled_cancelled_fetcher';
+
+export class OrderInfoUtils {
+ private _orderStateUtils: OrderStateUtils;
+ private _erc20Wrapper: ERC20Wrapper;
+ constructor(exchangeContract: ExchangeContract, erc20Wrapper: ERC20Wrapper, zrxAddress: string) {
+ this._erc20Wrapper = erc20Wrapper;
+ const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(exchangeContract, zrxAddress);
+ const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher(erc20Wrapper);
+ this._orderStateUtils = new OrderStateUtils(
+ simpleERC20BalanceAndProxyAllowanceFetcher,
+ simpleOrderFilledCancelledFetcher,
+ );
+ }
+ public async getFillableTakerAssetAmountAsync(signedOrder: SignedOrder, takerAddress: string): Promise<BigNumber> {
+ const orderRelevantState = await this._orderStateUtils.getOrderRelevantStateAsync(signedOrder);
+ console.log('orderRelevantState', orderRelevantState);
+ if (takerAddress === constants.NULL_ADDRESS) {
+ return orderRelevantState.remainingFillableTakerAssetAmount;
+ }
+ const takerAssetData = assetProxyUtils.decodeERC20ProxyData(signedOrder.takerAssetData);
+ const takerBalance = await this._erc20Wrapper.getBalanceAsync(takerAddress, takerAssetData.tokenAddress);
+ const takerAllowance = await this._erc20Wrapper.getProxyAllowanceAsync(
+ takerAddress,
+ takerAssetData.tokenAddress,
+ );
+ // TODO: We also need to make sure taker has sufficient ZRX for fees...
+ const fillableTakerAssetAmount = BigNumber.min([
+ takerBalance,
+ takerAllowance,
+ orderRelevantState.remainingFillableTakerAssetAmount,
+ ]);
+ return fillableTakerAssetAmount;
+ }
+}
diff --git a/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts b/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts
new file mode 100644
index 000000000..6eed9227a
--- /dev/null
+++ b/packages/contracts/src/utils/simple_erc20_balance_and_allowance_fetcher.ts
@@ -0,0 +1,20 @@
+import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils';
+import { BigNumber } from '@0xproject/utils';
+
+import { ERC20Wrapper } from './erc20_wrapper';
+
+// TODO(fabio): Refactor this to also work for ERC721!
+export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
+ private _erc20TokenWrapper: ERC20Wrapper;
+ constructor(erc20TokenWrapper: ERC20Wrapper) {
+ this._erc20TokenWrapper = erc20TokenWrapper;
+ }
+ public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
+ const balance = await this._erc20TokenWrapper.getBalanceAsync(userAddress, tokenAddress);
+ return balance;
+ }
+ public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
+ const proxyAllowance = await this._erc20TokenWrapper.getProxyAllowanceAsync(userAddress, tokenAddress);
+ return proxyAllowance;
+ }
+}
diff --git a/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts b/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts
new file mode 100644
index 000000000..0a80637cc
--- /dev/null
+++ b/packages/contracts/src/utils/simple_filled_cancelled_fetcher.ts
@@ -0,0 +1,32 @@
+import { AbstractOrderFilledCancelledFetcher } from '@0xproject/order-utils';
+import { BigNumber } from '@0xproject/utils';
+import { BlockParamLiteral } from 'ethereum-types';
+
+import {
+ CancelContractEventArgs,
+ ExchangeContract,
+ FillContractEventArgs,
+} from '../contract_wrappers/generated/exchange';
+
+export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher {
+ private _exchangeContract: ExchangeContract;
+ private _zrxAddress: string;
+ constructor(exchange: ExchangeContract, zrxAddress: string) {
+ this._exchangeContract = exchange;
+ this._zrxAddress = zrxAddress;
+ }
+ public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
+ const filledTakerAmount = new BigNumber(await this._exchangeContract.filled.callAsync(orderHash));
+ return filledTakerAmount;
+ }
+ public async isOrderCancelledAsync(orderHash: string): Promise<boolean> {
+ const methodOpts = {
+ defaultBlock: BlockParamLiteral.Latest,
+ };
+ const isCancelled = await this._exchangeContract.cancelled.callAsync(orderHash);
+ return isCancelled;
+ }
+ public getZRXTokenAddress(): string {
+ return this._zrxAddress;
+ }
+}
diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts
index 94c7f627f..64f6400c5 100644
--- a/packages/contracts/src/utils/types.ts
+++ b/packages/contracts/src/utils/types.ts
@@ -148,11 +148,6 @@ export interface MatchOrder {
rightSignature: string;
}
-export interface ERC721Token {
- address: string;
- id: BigNumber;
-}
-
// Combinatorial testing types
export enum FeeRecipientAddressScenario {