diff options
Diffstat (limited to 'packages/contract-wrappers/src/utils')
5 files changed, 24 insertions, 340 deletions
diff --git a/packages/contract-wrappers/src/utils/assert.ts b/packages/contract-wrappers/src/utils/assert.ts index 140979e7e..da6697b08 100644 --- a/packages/contract-wrappers/src/utils/assert.ts +++ b/packages/contract-wrappers/src/utils/assert.ts @@ -1,20 +1,28 @@ import { assert as sharedAssert } from '@0xproject/assert'; // We need those two unused imports because they're actually used by sharedAssert which gets injected here -// tslint:disable:no-unused-variable -import { Schema } from '@0xproject/json-schemas'; -import { ECSignature } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; +import { Schema } from '@0xproject/json-schemas'; // tslint:disable-line:no-unused-variable +import { isValidSignatureAsync } from '@0xproject/order-utils'; +import { ECSignature } from '@0xproject/types'; // tslint:disable-line:no-unused-variable +import { BigNumber } from '@0xproject/utils'; // tslint:disable-line:no-unused-variable import { Web3Wrapper } from '@0xproject/web3-wrapper'; -// tslint:enable:no-unused-variable - -import { isValidSignature } from '@0xproject/order-utils'; +import { Provider } from 'ethereum-types'; export const assert = { ...sharedAssert, - isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string): void { - const isValid = isValidSignature(orderHash, ecSignature, signerAddress); + async isValidSignatureAsync( + provider: Provider, + orderHash: string, + signature: string, + signerAddress: string, + ): Promise<void> { + const isValid = await isValidSignatureAsync(provider, orderHash, signature, signerAddress); this.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`); }, + isValidSubscriptionToken(variableName: string, subscriptionToken: string): void { + const uuidRegex = new RegExp('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$'); + const isValid = uuidRegex.test(subscriptionToken); + this.assert(isValid, `Expected ${variableName} to be a valid subscription token`); + }, async isSenderAddressAsync( variableName: string, senderAddressHex: string, diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts index 494575e7b..ccb4c6e11 100644 --- a/packages/contract-wrappers/src/utils/decorators.ts +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -30,8 +30,8 @@ const schemaErrorTransformer = (error: Error) => { */ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { const asyncErrorHandlingDecorator = ( - target: object, - key: string | symbol, + _target: object, + _key: string | symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>, ) => { const originalMethod = descriptor.value as AsyncMethod; @@ -57,8 +57,8 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { const syncErrorHandlingDecorator = ( - target: object, - key: string | symbol, + _target: object, + _key: string | symbol, descriptor: TypedPropertyDescriptor<SyncMethod>, ) => { const originalMethod = descriptor.value as SyncMethod; diff --git a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts b/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts deleted file mode 100644 index 527b8575d..000000000 --- a/packages/contract-wrappers/src/utils/exchange_transfer_simulator.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; - -import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store'; -import { TokenWrapper } from '../contract_wrappers/token_wrapper'; -import { TradeSide, TransferType } from '../types'; -import { constants } from '../utils/constants'; - -enum FailureReason { - Balance = 'balance', - ProxyAllowance = 'proxyAllowance', -} - -const ERR_MSG_MAPPING = { - [FailureReason.Balance]: { - [TradeSide.Maker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance, - }, - [TradeSide.Taker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance, - }, - }, - [FailureReason.ProxyAllowance]: { - [TradeSide.Maker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance, - }, - [TradeSide.Taker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance, - }, - }, -}; - -export class ExchangeTransferSimulator { - private _store: AbstractBalanceAndProxyAllowanceLazyStore; - private static _throwValidationError( - failureReason: FailureReason, - tradeSide: TradeSide, - transferType: TransferType, - ): never { - const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; - throw new Error(errMsg); - } - constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) { - this._store = store; - } - /** - * Simulates transferFrom call performed by a proxy - * @param tokenAddress Address of the token to be transferred - * @param from Owner of the transferred tokens - * @param to Recipient of the transferred tokens - * @param amountInBaseUnits The amount of tokens being transferred - * @param tradeSide Is Maker/Taker transferring - * @param transferType Is it a fee payment or a value transfer - */ - public async transferFromAsync( - tokenAddress: string, - from: string, - to: string, - amountInBaseUnits: BigNumber, - tradeSide: TradeSide, - transferType: TransferType, - ): Promise<void> { - // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/ - // allowances for the taker. We do however, want to increase the balance of the maker since the maker - // might be relying on those funds to fill subsequent orders or pay the order's fees. - if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) { - await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); - return; - } - const balance = await this._store.getBalanceAsync(tokenAddress, from); - const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from); - if (proxyAllowance.lessThan(amountInBaseUnits)) { - ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); - } - if (balance.lessThan(amountInBaseUnits)) { - ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType); - } - await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits); - await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); - await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); - } - private async _decreaseProxyAllowanceAsync( - tokenAddress: string, - userAddress: string, - amountInBaseUnits: BigNumber, - ): Promise<void> { - const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress); - if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); - } - } - private async _increaseBalanceAsync( - tokenAddress: string, - userAddress: string, - amountInBaseUnits: BigNumber, - ): Promise<void> { - 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<void> { - const balance = await this._store.getBalanceAsync(tokenAddress, userAddress); - this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); - } -} diff --git a/packages/contract-wrappers/src/utils/filter_utils.ts b/packages/contract-wrappers/src/utils/filter_utils.ts index 5256d010f..0e73987f7 100644 --- a/packages/contract-wrappers/src/utils/filter_utils.ts +++ b/packages/contract-wrappers/src/utils/filter_utils.ts @@ -1,14 +1,4 @@ -// tslint:disable:no-unused-variable -import { - ConstructorAbi, - ContractAbi, - EventAbi, - FallbackAbi, - FilterObject, - LogEntry, - MethodAbi, -} from '@0xproject/types'; -// tslint:enable:no-unused-variable +import { ConstructorAbi, ContractAbi, EventAbi, FallbackAbi, FilterObject, LogEntry, MethodAbi } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; @@ -30,7 +20,7 @@ export const filterUtils = { blockRange?: BlockRange, ): FilterObject { const eventAbi = _.find(abi, { name: eventName }) as EventAbi; - const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName); + const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi); const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature)); const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues); const topics = [topicForEventSignature, ...topicsForIndexedArgs]; @@ -46,7 +36,7 @@ export const filterUtils = { } return filter; }, - getEventSignatureFromAbiByName(eventAbi: EventAbi, eventName: ContractEvents): string { + getEventSignatureFromAbiByName(eventAbi: EventAbi): string { const types = _.map(eventAbi.inputs, 'type'); const signature = `${eventAbi.name}(${types.join(',')})`; return signature; diff --git a/packages/contract-wrappers/src/utils/order_validation_utils.ts b/packages/contract-wrappers/src/utils/order_validation_utils.ts deleted file mode 100644 index c6ef26275..000000000 --- a/packages/contract-wrappers/src/utils/order_validation_utils.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { getOrderHashHex, isValidSignature, OrderError } from '@0xproject/order-utils'; -import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; - -import { ExchangeContract } from '../contract_wrappers/generated/exchange'; -import { TradeSide, TransferType } from '../types'; -import { constants } from '../utils/constants'; -import { utils } from '../utils/utils'; - -import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; - -export class OrderValidationUtils { - private _exchangeContract: ExchangeContract; - public static validateCancelOrderThrowIfInvalid( - order: Order, - cancelTakerTokenAmount: BigNumber, - unavailableTakerTokenAmount: BigNumber, - ): void { - if (cancelTakerTokenAmount.eq(0)) { - throw new Error(ExchangeContractErrs.OrderCancelAmountZero); - } - if (order.takerTokenAmount.eq(unavailableTakerTokenAmount)) { - throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); - } - const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); - if (order.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { - throw new Error(ExchangeContractErrs.OrderCancelExpired); - } - } - public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - senderAddress: string, - zrxTokenAddress: string, - ): Promise<void> { - const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerTokenAmount, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerTokenAddress, - signedOrder.maker, - senderAddress, - fillMakerTokenAmount, - TradeSide.Maker, - TransferType.Trade, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.takerTokenAddress, - senderAddress, - signedOrder.maker, - fillTakerTokenAmount, - TradeSide.Taker, - TransferType.Trade, - ); - const makerFeeAmount = OrderValidationUtils._getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerFee, - ); - await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, - signedOrder.maker, - signedOrder.feeRecipient, - makerFeeAmount, - TradeSide.Maker, - TransferType.Fee, - ); - const takerFeeAmount = OrderValidationUtils._getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.takerFee, - ); - await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, - senderAddress, - signedOrder.feeRecipient, - takerFeeAmount, - TradeSide.Taker, - TransferType.Fee, - ); - } - private static _validateRemainingFillAmountNotZeroOrThrow( - takerTokenAmount: BigNumber, - unavailableTakerTokenAmount: BigNumber, - ): void { - if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { - throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); - } - } - private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber): void { - const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); - if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { - throw new Error(ExchangeContractErrs.OrderFillExpired); - } - } - private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - const fillMakerTokenAmount = numerator - .mul(target) - .div(denominator) - .round(0); - return fillMakerTokenAmount; - } - constructor(exchangeContract: ExchangeContract) { - this._exchangeContract = exchangeContract; - } - public async validateOrderFillableOrThrowAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - zrxTokenAddress: string, - expectedFillTakerTokenAmount?: BigNumber, - ): Promise<void> { - const orderHash = getOrderHashHex(signedOrder); - const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync( - orderHash, - ); - OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( - signedOrder.takerTokenAmount, - unavailableTakerTokenAmount, - ); - OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); - let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); - if (!_.isUndefined(expectedFillTakerTokenAmount)) { - fillTakerTokenAmount = expectedFillTakerTokenAmount; - } - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator, - signedOrder, - fillTakerTokenAmount, - signedOrder.taker, - zrxTokenAddress, - ); - } - public async validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string, - zrxTokenAddress: string, - ): Promise<BigNumber> { - if (fillTakerTokenAmount.eq(0)) { - throw new Error(ExchangeContractErrs.OrderFillAmountZero); - } - const orderHash = getOrderHashHex(signedOrder); - if (!isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) { - throw new Error(OrderError.InvalidSignature); - } - const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync( - orderHash, - ); - OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow( - signedOrder.takerTokenAmount, - unavailableTakerTokenAmount, - ); - if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) { - throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); - } - OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); - const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); - const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) - ? remainingTakerTokenAmount - : fillTakerTokenAmount; - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator, - signedOrder, - filledTakerTokenAmount, - takerAddress, - zrxTokenAddress, - ); - - const wouldRoundingErrorOccur = await this._exchangeContract.isRoundingError.callAsync( - filledTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerTokenAmount, - ); - if (wouldRoundingErrorOccur) { - throw new Error(ExchangeContractErrs.OrderFillRoundingError); - } - return filledTakerTokenAmount; - } - public async validateFillOrKillOrderThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string, - zrxTokenAddress: string, - ): Promise<void> { - const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator, - signedOrder, - fillTakerTokenAmount, - takerAddress, - zrxTokenAddress, - ); - if (filledTakerTokenAmount !== fillTakerTokenAmount) { - throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); - } - } -} |