From a896904ae7c453f51b1f46de2be3a28416db72d1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 30 Oct 2017 18:38:10 +0200 Subject: Add naive order state watcher implementation Revalidate all orders upon event received and emit order states even if not changed --- src/utils/order_state_utils.ts | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/utils/order_state_utils.ts (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts new file mode 100644 index 000000000..2a5becf9a --- /dev/null +++ b/src/utils/order_state_utils.ts @@ -0,0 +1,99 @@ +import * as _ from 'lodash'; +import BigNumber from 'bignumber.js'; +import { + ExchangeContractErrs, + SignedOrder, + OrderRelevantState, + MethodOpts, + OrderState, + OrderStateValid, + OrderStateInvalid, +} from '../types'; +import {ZeroEx} from '../0x'; +import {TokenWrapper} from '../contract_wrappers/token_wrapper'; +import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; +import {utils} from '../utils/utils'; +import {constants} from '../utils/constants'; + +export class OrderStateUtils { + private tokenWrapper: TokenWrapper; + private exchangeWrapper: ExchangeWrapper; + constructor(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) { + this.tokenWrapper = tokenWrapper; + this.exchangeWrapper = exchangeWrapper; + } + public async getOrderStateAsync(signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise { + const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder, methodOpts); + const orderHash = ZeroEx.getOrderHashHex(signedOrder); + try { + this.validateIfOrderIsValid(signedOrder, orderRelevantState); + const orderState: OrderStateValid = { + isValid: true, + orderHash, + orderRelevantState, + }; + return orderState; + } catch (err) { + const orderState: OrderStateInvalid = { + isValid: false, + orderHash, + error: err.message, + }; + return orderState; + } + } + public async getOrderRelevantStateAsync( + signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise { + const zrxTokenAddress = await this.exchangeWrapper.getZRXTokenAddressAsync(); + const orderHash = ZeroEx.getOrderHashHex(signedOrder); + const makerBalance = await this.tokenWrapper.getBalanceAsync( + signedOrder.makerTokenAddress, signedOrder.maker, methodOpts, + ); + const makerProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync( + signedOrder.makerTokenAddress, signedOrder.maker, methodOpts, + ); + const makerFeeBalance = await this.tokenWrapper.getBalanceAsync( + zrxTokenAddress, signedOrder.maker, methodOpts, + ); + const makerFeeProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync( + zrxTokenAddress, signedOrder.maker, methodOpts, + ); + const filledTakerTokenAmount = await this.exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); + const canceledTakerTokenAmount = await this.exchangeWrapper.getCanceledTakerAmountAsync(orderHash, methodOpts); + const orderRelevantState = { + makerBalance, + makerProxyAllowance, + makerFeeBalance, + makerFeeProxyAllowance, + filledTakerTokenAmount, + canceledTakerTokenAmount, + }; + return orderRelevantState; + } + private validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { + const unavailableTakerTokenAmount = orderRelevantState.canceledTakerTokenAmount.add( + orderRelevantState.filledTakerTokenAmount, + ); + const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); + if (availableTakerTokenAmount.eq(0)) { + throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); + } + + if (orderRelevantState.makerBalance.eq(0)) { + throw new Error(ExchangeContractErrs.InsufficientMakerBalance); + } + if (orderRelevantState.makerProxyAllowance.eq(0)) { + throw new Error(ExchangeContractErrs.InsufficientMakerAllowance); + } + if (!signedOrder.makerFee.eq(0)) { + if (orderRelevantState.makerFeeBalance.eq(0)) { + throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance); + } + if (orderRelevantState.makerFeeProxyAllowance.eq(0)) { + throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance); + } + } + // TODO Add linear function solver when maker token is ZRX #badass + // Return the max amount that's fillable + } +} -- cgit v1.2.3 From ee3115550e26b276c35b33fed085f46a08ca05d5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 8 Nov 2017 18:59:59 -0500 Subject: Add todo comments --- src/utils/abi_decoder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 247ba0e5b..840ad9be0 100644 --- a/src/utils/abi_decoder.ts +++ b/src/utils/abi_decoder.ts @@ -10,7 +10,7 @@ export class AbiDecoder { constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } - // This method can only decode logs from the 0x smart contracts + // This method can only decode logs from the 0x & ERC20 smart contracts public tryToDecodeLogOrNoop( log: Web3.LogEntry): LogWithDecodedArgs|RawLog { const methodId = log.topics[0]; -- cgit v1.2.3 From c96c681758a9bb62b4444ce21747c3781e9dc742 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 9 Nov 2017 10:09:20 -0500 Subject: Add assert.isValidBaseUnitAmount that checks for decimals in amounts that should be in baseUnits. This can sometimes alert developers whenever they accidentally pass in unitAmounts. --- src/utils/assert.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/utils') diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 286105345..48aed6ad3 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -11,6 +11,12 @@ export const assert = { const isBigNumber = _.isObject(value) && (value as any).isBigNumber; this.assert(isBigNumber, this.typeAssertionMessage(variableName, 'BigNumber', value)); }, + isValidBaseUnitAmount(variableName: string, value: BigNumber) { + const hasDecimals = value.decimalPlaces() !== 0; + this.assert( + !hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, + ); + }, isUndefined(value: any, variableName?: string): void { this.assert(_.isUndefined(value), this.typeAssertionMessage(variableName, 'undefined', value)); }, -- cgit v1.2.3 From 6aa91d89e0fd02601f7e4df86e8499edc00316ce Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 9 Nov 2017 16:30:32 -0500 Subject: Remove redundant assertions --- src/utils/assert.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src/utils') diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 48aed6ad3..667b41b7b 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -12,6 +12,7 @@ export const assert = { this.assert(isBigNumber, this.typeAssertionMessage(variableName, 'BigNumber', value)); }, isValidBaseUnitAmount(variableName: string, value: BigNumber) { + assert.isBigNumber(variableName, value); const hasDecimals = value.decimalPlaces() !== 0; this.assert( !hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, -- cgit v1.2.3 From 62861d1e1315a14e955b30a45db05e7907b0d22d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 9 Nov 2017 17:18:03 -0500 Subject: Move isValidSignature implementation into signatureUtils --- src/utils/signature_utils.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/utils') diff --git a/src/utils/signature_utils.ts b/src/utils/signature_utils.ts index b312b5554..d066f8bf0 100644 --- a/src/utils/signature_utils.ts +++ b/src/utils/signature_utils.ts @@ -2,6 +2,21 @@ import * as ethUtil from 'ethereumjs-util'; import {ECSignature} from '../types'; export const signatureUtils = { + isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean { + const dataBuff = ethUtil.toBuffer(data); + const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); + try { + const pubKey = ethUtil.ecrecover( + msgHashBuff, + signature.v, + ethUtil.toBuffer(signature.r), + ethUtil.toBuffer(signature.s)); + const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return retrievedAddress === signerAddress; + } catch (err) { + return false; + } + }, parseSignatureHexAsVRS(signatureHex: string): ECSignature { const signatureBuffer = ethUtil.toBuffer(signatureHex); let v = signatureBuffer[0]; -- cgit v1.2.3 From 02cc3f911624d31d581d4637d17ad2fa6fd95bc6 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 9 Nov 2017 17:18:30 -0500 Subject: Create assert.isValidSignature method and use it in `addOrder` --- src/utils/assert.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 667b41b7b..e5c9439f3 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -1,8 +1,10 @@ import * as _ from 'lodash'; -import BigNumber from 'bignumber.js'; import * as Web3 from 'web3'; -import {Web3Wrapper} from '../web3_wrapper'; +import BigNumber from 'bignumber.js'; import {SchemaValidator, Schema} from '0x-json-schemas'; +import {Web3Wrapper} from '../web3_wrapper'; +import {signatureUtils} from '../utils/signature_utils'; +import {ECSignature} from '../types'; const HEX_REGEX = /^0x[0-9A-F]*$/i; @@ -18,6 +20,10 @@ export const assert = { !hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, ); }, + isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) { + const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress); + this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`); + }, isUndefined(value: any, variableName?: string): void { this.assert(_.isUndefined(value), this.typeAssertionMessage(variableName, 'undefined', value)); }, -- cgit v1.2.3 From 3e2a614eb9a4f1219e2f11ea29c8a7cd59dd74dd Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Sun, 12 Nov 2017 11:28:01 -0500 Subject: Calculate the remaining order amount in maker units --- src/utils/order_state_utils.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index 2a5becf9a..ff5c1880d 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -60,6 +60,21 @@ export class OrderStateUtils { ); const filledTakerTokenAmount = await this.exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); const canceledTakerTokenAmount = await this.exchangeWrapper.getCanceledTakerAmountAsync(orderHash, methodOpts); + const unavailableTakerTokenAmount = + await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash, methodOpts); + const totalMakerTokenAmount = signedOrder.makerTokenAmount; + const totalTakerTokenAmount = signedOrder.takerTokenAmount; + const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); + // 200 in order, 100 unavailable = 100 remaning, 0.5 remaning proportion + const remainingTakerProportion = remainingTakerTokenAmount.dividedBy(totalTakerTokenAmount); + const remainingMakerTokenAmount = remainingTakerProportion.times(totalMakerTokenAmount); + // min allowance, balance in account of maker + const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); + // min ^, remaining order maker token amount + const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount); + // TODO + // edge case when maker token is ZRX + // rounding issues, check if its fillabae const orderRelevantState = { makerBalance, makerProxyAllowance, @@ -67,6 +82,7 @@ export class OrderStateUtils { makerFeeProxyAllowance, filledTakerTokenAmount, canceledTakerTokenAmount, + remainingFillableMakerTokenAmount, }; return orderRelevantState; } -- cgit v1.2.3 From fdb3fa6801e07972f53a05c312c2ee933809f823 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Sun, 12 Nov 2017 17:24:31 -0500 Subject: Added specs for allowance and balance changes --- src/utils/order_state_utils.ts | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index ff5c1880d..fde7a7e02 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -72,9 +72,7 @@ export class OrderStateUtils { const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); // min ^, remaining order maker token amount const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount); - // TODO // edge case when maker token is ZRX - // rounding issues, check if its fillabae const orderRelevantState = { makerBalance, makerProxyAllowance, -- cgit v1.2.3 From 5e77e8809abd96136fb11ebdc84a2aefa32d4cea Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Sun, 12 Nov 2017 17:30:57 -0500 Subject: Update comment --- src/utils/order_state_utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index fde7a7e02..4f57de9fe 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -65,7 +65,7 @@ export class OrderStateUtils { const totalMakerTokenAmount = signedOrder.makerTokenAmount; const totalTakerTokenAmount = signedOrder.takerTokenAmount; const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); - // 200 in order, 100 unavailable = 100 remaning, 0.5 remaning proportion + // 200 in order, 100 unavailable = 100 remaning, 0.5 remaining in taker proportion const remainingTakerProportion = remainingTakerTokenAmount.dividedBy(totalTakerTokenAmount); const remainingMakerTokenAmount = remainingTakerProportion.times(totalMakerTokenAmount); // min allowance, balance in account of maker -- cgit v1.2.3 From 42e3ab91a794f61d65008d969b3d48080b5035d7 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Sun, 12 Nov 2017 19:17:27 -0500 Subject: Perform the division after multiplication to reduce compounding the rounding errors --- src/utils/order_state_utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index 4f57de9fe..7c10a5480 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -66,13 +66,13 @@ export class OrderStateUtils { const totalTakerTokenAmount = signedOrder.takerTokenAmount; const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); // 200 in order, 100 unavailable = 100 remaning, 0.5 remaining in taker proportion - const remainingTakerProportion = remainingTakerTokenAmount.dividedBy(totalTakerTokenAmount); - const remainingMakerTokenAmount = remainingTakerProportion.times(totalMakerTokenAmount); + const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount) + .dividedToIntegerBy(totalTakerTokenAmount); // min allowance, balance in account of maker const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); // min ^, remaining order maker token amount const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount); - // edge case when maker token is ZRX + // TODO: Handle edge case where maker token is ZRX with fee const orderRelevantState = { makerBalance, makerProxyAllowance, -- cgit v1.2.3 From 32246fd26bc71b09818491d513a380a8bd85fdec Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Sun, 12 Nov 2017 19:37:03 -0500 Subject: remove comments --- src/utils/order_state_utils.ts | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index 7c10a5480..36a4b68d6 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -65,12 +65,9 @@ export class OrderStateUtils { const totalMakerTokenAmount = signedOrder.makerTokenAmount; const totalTakerTokenAmount = signedOrder.takerTokenAmount; const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); - // 200 in order, 100 unavailable = 100 remaning, 0.5 remaining in taker proportion const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount) .dividedToIntegerBy(totalTakerTokenAmount); - // min allowance, balance in account of maker const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); - // min ^, remaining order maker token amount const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount); // TODO: Handle edge case where maker token is ZRX with fee const orderRelevantState = { -- cgit v1.2.3 From ddbcf5f4706a9d75cd5fd4af508f3c07a78f2886 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 10 Nov 2017 11:11:32 -0500 Subject: Refactor out BalanceAndProxyAllowanceLazyStore --- src/utils/exchange_transfer_simulator.ts | 55 ++------------------------------ 1 file changed, 2 insertions(+), 53 deletions(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index 89b23c8ab..6812759fc 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import BigNumber from 'bignumber.js'; import {ExchangeContractErrs, TradeSide, TransferType} from '../types'; -import {TokenWrapper} from '../contract_wrappers/token_wrapper'; +import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; enum FailureReason { Balance = 'balance', @@ -31,57 +31,6 @@ const ERR_MSG_MAPPING = { }, }; -/** - * Copy on read store for balances/proxyAllowances of tokens/accounts touched in trades - */ -export class BalanceAndProxyAllowanceLazyStore { - protected _token: TokenWrapper; - private _balance: { - [tokenAddress: string]: { - [userAddress: string]: BigNumber, - }, - }; - private _proxyAllowance: { - [tokenAddress: string]: { - [userAddress: string]: BigNumber, - }, - }; - constructor(token: TokenWrapper) { - this._token = token; - this._balance = {}; - this._proxyAllowance = {}; - } - protected async getBalanceAsync(tokenAddress: string, userAddress: string): Promise { - if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) { - const balance = await this._token.getBalanceAsync(tokenAddress, userAddress); - this.setBalance(tokenAddress, userAddress, balance); - } - const cachedBalance = this._balance[tokenAddress][userAddress]; - return cachedBalance; - } - protected setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void { - if (_.isUndefined(this._balance[tokenAddress])) { - this._balance[tokenAddress] = {}; - } - this._balance[tokenAddress][userAddress] = balance; - } - protected async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise { - if (_.isUndefined(this._proxyAllowance[tokenAddress]) || - _.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) { - const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress); - this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance); - } - const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress]; - return cachedProxyAllowance; - } - protected setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void { - if (_.isUndefined(this._proxyAllowance[tokenAddress])) { - this._proxyAllowance[tokenAddress] = {}; - } - this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance; - } -} - export class ExchangeTransferSimulator extends BalanceAndProxyAllowanceLazyStore { /** * Simulates transferFrom call performed by a proxy @@ -110,7 +59,7 @@ export class ExchangeTransferSimulator extends BalanceAndProxyAllowanceLazyStore private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string, amountInBaseUnits: BigNumber): Promise { const proxyAllowance = await this.getProxyAllowanceAsync(tokenAddress, userAddress); - if (!proxyAllowance.eq(this._token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + if (!proxyAllowance.eq(this.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); } } -- cgit v1.2.3 From 742660591f66b1bccd194803a1bf1e43a60a3b31 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 10 Nov 2017 11:15:08 -0500 Subject: Make a store an instance variable of exchange transfer simulator and stop inheriting it --- src/utils/exchange_transfer_simulator.ts | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index 6812759fc..ecdec0be0 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -1,6 +1,7 @@ import * as _ from 'lodash'; import BigNumber from 'bignumber.js'; import {ExchangeContractErrs, TradeSide, TransferType} from '../types'; +import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; enum FailureReason { @@ -31,7 +32,13 @@ const ERR_MSG_MAPPING = { }, }; -export class ExchangeTransferSimulator extends BalanceAndProxyAllowanceLazyStore { +export class ExchangeTransferSimulator { + private store: BalanceAndProxyAllowanceLazyStore; + private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; + constructor(token: TokenWrapper) { + this.store = new BalanceAndProxyAllowanceLazyStore(token); + this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + } /** * Simulates transferFrom call performed by a proxy * @param tokenAddress Address of the token to be transferred @@ -44,8 +51,8 @@ export class ExchangeTransferSimulator extends BalanceAndProxyAllowanceLazyStore public async transferFromAsync(tokenAddress: string, from: string, to: string, amountInBaseUnits: BigNumber, tradeSide: TradeSide, transferType: TransferType): Promise { - const balance = await this.getBalanceAsync(tokenAddress, from); - const proxyAllowance = await this.getProxyAllowanceAsync(tokenAddress, from); + const balance = await this.store.getBalanceAsync(tokenAddress, from); + const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from); if (proxyAllowance.lessThan(amountInBaseUnits)) { this.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); } @@ -58,20 +65,20 @@ export class ExchangeTransferSimulator extends BalanceAndProxyAllowanceLazyStore } private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string, amountInBaseUnits: BigNumber): Promise { - const proxyAllowance = await this.getProxyAllowanceAsync(tokenAddress, userAddress); - if (!proxyAllowance.eq(this.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); + const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, userAddress); + if (!proxyAllowance.eq(this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { + this.store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); } } private async increaseBalanceAsync(tokenAddress: string, userAddress: string, amountInBaseUnits: BigNumber): Promise { - const balance = await this.getBalanceAsync(tokenAddress, userAddress); - this.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); + const balance = await this.store.getBalanceAsync(tokenAddress, userAddress); + this.store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits)); } private async decreaseBalanceAsync(tokenAddress: string, userAddress: string, amountInBaseUnits: BigNumber): Promise { - const balance = await this.getBalanceAsync(tokenAddress, userAddress); - this.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); + const balance = await this.store.getBalanceAsync(tokenAddress, userAddress); + this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); } private throwValidationError(failureReason: FailureReason, tradeSide: TradeSide, transferType: TransferType): Promise { -- cgit v1.2.3 From 6edae865168dc86a5a3b39558158d22a4ff3bd99 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 10 Nov 2017 12:12:30 -0500 Subject: Make store configurable by blockParam --- src/utils/exchange_transfer_simulator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index ecdec0be0..56bd48f17 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash'; import BigNumber from 'bignumber.js'; -import {ExchangeContractErrs, TradeSide, TransferType} from '../types'; +import {ExchangeContractErrs, TradeSide, TransferType, BlockParamLiteral} from '../types'; import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; @@ -36,7 +36,7 @@ export class ExchangeTransferSimulator { private store: BalanceAndProxyAllowanceLazyStore; private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; constructor(token: TokenWrapper) { - this.store = new BalanceAndProxyAllowanceLazyStore(token); + this.store = new BalanceAndProxyAllowanceLazyStore(token, BlockParamLiteral.Latest); this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; } /** -- cgit v1.2.3 From ffcc4877638262b29c8a88535e9535da07428396 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 10 Nov 2017 15:05:24 -0500 Subject: Create fake blockStore for exchange transfer simulator --- src/utils/exchange_transfer_simulator.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index 56bd48f17..cd46397ed 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'; import {ExchangeContractErrs, TradeSide, TransferType, BlockParamLiteral} from '../types'; import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; +import {BlockStore} from '../stores/block_store'; enum FailureReason { Balance = 'balance', @@ -36,7 +37,9 @@ export class ExchangeTransferSimulator { private store: BalanceAndProxyAllowanceLazyStore; private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; constructor(token: TokenWrapper) { - this.store = new BalanceAndProxyAllowanceLazyStore(token, BlockParamLiteral.Latest); + const blockStore = new BlockStore(); + const latestBlockConfirmationNumber = 1; + this.store = new BalanceAndProxyAllowanceLazyStore(token, blockStore, latestBlockConfirmationNumber); this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; } /** -- cgit v1.2.3 From e72ba39c41a86cd17a3115426ad579efbfe11ddc Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 10 Nov 2017 15:07:05 -0500 Subject: Make orderStateUtils operate on stores --- src/utils/order_state_utils.ts | 53 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'src/utils') diff --git a/src/utils/order_state_utils.ts b/src/utils/order_state_utils.ts index 36a4b68d6..f82601cae 100644 --- a/src/utils/order_state_utils.ts +++ b/src/utils/order_state_utils.ts @@ -1,4 +1,5 @@ import * as _ from 'lodash'; +import * as Web3 from 'web3'; import BigNumber from 'bignumber.js'; import { ExchangeContractErrs, @@ -14,16 +15,19 @@ import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; import {utils} from '../utils/utils'; import {constants} from '../utils/constants'; +import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store'; +import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; export class OrderStateUtils { - private tokenWrapper: TokenWrapper; - private exchangeWrapper: ExchangeWrapper; - constructor(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) { - this.tokenWrapper = tokenWrapper; - this.exchangeWrapper = exchangeWrapper; + private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; + private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; + constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, + orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) { + this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; + this.orderFilledCancelledLazyStore = orderFilledCancelledLazyStore; } - public async getOrderStateAsync(signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise { - const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder, methodOpts); + public async getOrderStateAsync(signedOrder: SignedOrder): Promise { + const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder); try { this.validateIfOrderIsValid(signedOrder, orderRelevantState); @@ -42,26 +46,31 @@ export class OrderStateUtils { return orderState; } } - public async getOrderRelevantStateAsync( - signedOrder: SignedOrder, methodOpts?: MethodOpts): Promise { - const zrxTokenAddress = await this.exchangeWrapper.getZRXTokenAddressAsync(); + public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise { + // HACK: We access the private property here but otherwise the interface will be less nice. + // If we pass it from the instantiator - there is no opportunity to get it there + // because JS doesn't support async constructors. + // Moreover - it's cached under the hood so it's equivalent to an async constructor. + const exchange = (this.orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper; + const zrxTokenAddress = await exchange.getZRXTokenAddressAsync(); const orderHash = ZeroEx.getOrderHashHex(signedOrder); - const makerBalance = await this.tokenWrapper.getBalanceAsync( - signedOrder.makerTokenAddress, signedOrder.maker, methodOpts, + const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync( + signedOrder.makerTokenAddress, signedOrder.maker, ); - const makerProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync( - signedOrder.makerTokenAddress, signedOrder.maker, methodOpts, + const makerProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + signedOrder.makerTokenAddress, signedOrder.maker, ); - const makerFeeBalance = await this.tokenWrapper.getBalanceAsync( - zrxTokenAddress, signedOrder.maker, methodOpts, + const makerFeeBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync( + zrxTokenAddress, signedOrder.maker, ); - const makerFeeProxyAllowance = await this.tokenWrapper.getProxyAllowanceAsync( - zrxTokenAddress, signedOrder.maker, methodOpts, + const makerFeeProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + zrxTokenAddress, signedOrder.maker, ); - const filledTakerTokenAmount = await this.exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); - const canceledTakerTokenAmount = await this.exchangeWrapper.getCanceledTakerAmountAsync(orderHash, methodOpts); - const unavailableTakerTokenAmount = - await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash, methodOpts); + const filledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash); + const canceledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getCancelledTakerAmountAsync( + orderHash, + ); + const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash); const totalMakerTokenAmount = signedOrder.makerTokenAmount; const totalTakerTokenAmount = signedOrder.takerTokenAmount; const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); -- cgit v1.2.3 From a9ae555b88cc36ff2cbd92fdd37a339702860c01 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Sun, 12 Nov 2017 13:06:25 -0500 Subject: Store number of confirmations in a blockStore --- src/utils/exchange_transfer_simulator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index cd46397ed..475dcf953 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -37,9 +37,9 @@ export class ExchangeTransferSimulator { private store: BalanceAndProxyAllowanceLazyStore; private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; constructor(token: TokenWrapper) { - const blockStore = new BlockStore(); const latestBlockConfirmationNumber = 1; - this.store = new BalanceAndProxyAllowanceLazyStore(token, blockStore, latestBlockConfirmationNumber); + const blockStore = new BlockStore(latestBlockConfirmationNumber); + this.store = new BalanceAndProxyAllowanceLazyStore(token, blockStore); this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; } /** -- cgit v1.2.3 From 84c965d459b948eb03cb8a70a66663bd7b35f463 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Sun, 12 Nov 2017 18:10:47 -0500 Subject: Remove blockStore and default to numConfirmations === 0 --- src/utils/exchange_transfer_simulator.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/utils') diff --git a/src/utils/exchange_transfer_simulator.ts b/src/utils/exchange_transfer_simulator.ts index 475dcf953..308ef06db 100644 --- a/src/utils/exchange_transfer_simulator.ts +++ b/src/utils/exchange_transfer_simulator.ts @@ -3,7 +3,6 @@ import BigNumber from 'bignumber.js'; import {ExchangeContractErrs, TradeSide, TransferType, BlockParamLiteral} from '../types'; import {TokenWrapper} from '../contract_wrappers/token_wrapper'; import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; -import {BlockStore} from '../stores/block_store'; enum FailureReason { Balance = 'balance', @@ -37,9 +36,7 @@ export class ExchangeTransferSimulator { private store: BalanceAndProxyAllowanceLazyStore; private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; constructor(token: TokenWrapper) { - const latestBlockConfirmationNumber = 1; - const blockStore = new BlockStore(latestBlockConfirmationNumber); - this.store = new BalanceAndProxyAllowanceLazyStore(token, blockStore); + this.store = new BalanceAndProxyAllowanceLazyStore(token); this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; } /** -- cgit v1.2.3