From db2917b01caa49d74c9ebcae2d36e9c3946b94d8 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 22 Nov 2017 15:43:17 -0600 Subject: Enable some new linter rules and fix the issues --- .../src/contract_wrappers/exchange_wrapper.ts | 8 +- .../contract_wrappers/token_registry_wrapper.ts | 30 ++-- .../0x.js/src/order_watcher/order_state_watcher.ts | 2 +- .../stores/balance_proxy_allowance_lazy_store.ts | 8 +- .../stores/order_filled_cancelled_lazy_store.ts | 4 +- .../src/subproviders/empty_wallet_subprovider.ts | 2 + packages/0x.js/src/utils/abi_decoder.ts | 20 +-- .../0x.js/src/utils/exchange_transfer_simulator.ts | 14 +- packages/0x.js/src/utils/order_state_utils.ts | 68 ++++----- packages/0x.js/src/utils/order_validation_utils.ts | 155 +++++++++++---------- packages/0x.js/test/order_validation_test.ts | 10 +- packages/tslint-config/tslint.json | 47 +++++-- 12 files changed, 201 insertions(+), 167 deletions(-) (limited to 'packages') diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 97ea54362..b35219b24 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -559,7 +559,7 @@ export class ExchangeWrapper extends ContractWrapper { if (shouldValidate) { const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); - this._orderValidationUtils.validateCancelOrderThrowIfInvalid( + OrderValidationUtils.validateCancelOrderThrowIfInvalid( order, cancelTakerTokenAmount, unavailableTakerTokenAmount); } @@ -613,7 +613,7 @@ export class ExchangeWrapper extends ContractWrapper { for (const orderCancellationRequest of orderCancellationRequests) { const orderHash = utils.getOrderHashHex(orderCancellationRequest.order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); - this._orderValidationUtils.validateCancelOrderThrowIfInvalid( + OrderValidationUtils.validateCancelOrderThrowIfInvalid( orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount, unavailableTakerTokenAmount, ); @@ -767,7 +767,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount); const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); - this._orderValidationUtils.validateCancelOrderThrowIfInvalid( + OrderValidationUtils.validateCancelOrderThrowIfInvalid( order, cancelTakerTokenAmount, unavailableTakerTokenAmount); } /** @@ -884,4 +884,4 @@ export class ExchangeWrapper extends ContractWrapper { const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase(); return tokenTransferProxyAddressLowerCase; } -} +} // tslint:disable:max-file-line-count diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts index 60fe7f33a..468e58350 100644 --- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts @@ -14,6 +14,18 @@ import {ContractWrapper} from './contract_wrapper'; export class TokenRegistryWrapper extends ContractWrapper { private _tokenRegistryContractIfExists?: TokenRegistryContract; private _contractAddressIfExists?: string; + private static _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined { + if (metadata[0] === constants.NULL_ADDRESS) { + return undefined; + } + const token = { + address: metadata[0], + name: metadata[1], + symbol: metadata[2], + decimals: metadata[3].toNumber(), + }; + return token; + } constructor(web3Wrapper: Web3Wrapper, contractAddressIfExists?: string) { super(web3Wrapper); this._contractAddressIfExists = contractAddressIfExists; @@ -51,7 +63,7 @@ export class TokenRegistryWrapper extends ContractWrapper { const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address); - const token = this._createTokenFromMetadata(metadata); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise { @@ -76,14 +88,14 @@ export class TokenRegistryWrapper extends ContractWrapper { assert.isString('symbol', symbol); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol); - const token = this._createTokenFromMetadata(metadata); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } public async getTokenByNameIfExistsAsync(name: string): Promise { assert.isString('name', name); const tokenRegistryContract = await this._getTokenRegistryContractAsync(); const metadata = await tokenRegistryContract.getTokenByName.callAsync(name); - const token = this._createTokenFromMetadata(metadata); + const token = TokenRegistryWrapper._createTokenFromMetadata(metadata); return token; } /** @@ -103,18 +115,6 @@ export class TokenRegistryWrapper extends ContractWrapper { return this._contractAddressIfExists; } } - private _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined { - if (metadata[0] === constants.NULL_ADDRESS) { - return undefined; - } - const token = { - address: metadata[0], - name: metadata[1], - symbol: metadata[2], - decimals: metadata[3].toNumber(), - }; - return token; - } private _invalidateContractInstance(): void { delete this._tokenRegistryContractIfExists; } diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts index 4d57935a1..919a58df7 100644 --- a/packages/0x.js/src/order_watcher/order_state_watcher.ts +++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts @@ -38,7 +38,7 @@ import {ExpirationWatcher} from './expiration_watcher'; interface DependentOrderHashes { [makerAddress: string]: { - [makerToken: string]: Set, + [makerToken: string]: Set; }; } diff --git a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts index 293f75db9..afc40b86d 100644 --- a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts +++ b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts @@ -12,13 +12,13 @@ export class BalanceAndProxyAllowanceLazyStore { private token: TokenWrapper; private balance: { [tokenAddress: string]: { - [userAddress: string]: BigNumber, - }, + [userAddress: string]: BigNumber; + }; }; private proxyAllowance: { [tokenAddress: string]: { - [userAddress: string]: BigNumber, - }, + [userAddress: string]: BigNumber; + }; }; constructor(token: TokenWrapper) { this.token = token; diff --git a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts index 59c1bb7a7..28b32f9e2 100644 --- a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts +++ b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts @@ -11,10 +11,10 @@ import {BlockParamLiteral} from '../types'; export class OrderFilledCancelledLazyStore { private exchange: ExchangeWrapper; private filledTakerAmount: { - [orderHash: string]: BigNumber, + [orderHash: string]: BigNumber; }; private cancelledTakerAmount: { - [orderHash: string]: BigNumber, + [orderHash: string]: BigNumber; }; constructor(exchange: ExchangeWrapper) { this.exchange = exchange; diff --git a/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts b/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts index 2f260217c..d707d5652 100644 --- a/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts +++ b/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts @@ -6,6 +6,7 @@ import {JSONRPCPayload} from '../types'; * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js */ export class EmptyWalletSubProvider { + // tslint:disable-next-line:prefer-function-over-method public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) { switch (payload.method) { case 'eth_accounts': @@ -18,6 +19,7 @@ export class EmptyWalletSubProvider { } } // Required to implement this method despite not needing it for this subprovider + // tslint:disable-next-line:prefer-function-over-method public setEngine(engine: any) { // noop } diff --git a/packages/0x.js/src/utils/abi_decoder.ts b/packages/0x.js/src/utils/abi_decoder.ts index f027026da..f26b057f0 100644 --- a/packages/0x.js/src/utils/abi_decoder.ts +++ b/packages/0x.js/src/utils/abi_decoder.ts @@ -8,6 +8,15 @@ import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, export class AbiDecoder { private savedABIs: Web3.AbiDefinition[] = []; private methodIds: {[signatureHash: string]: Web3.EventAbi} = {}; + private static padZeros(address: string) { + let formatted = address; + if (_.startsWith(formatted, '0x')) { + formatted = formatted.slice(2); + } + + formatted = _.padStart(formatted, 40, '0'); + return `0x${formatted}`; + } constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } @@ -32,7 +41,7 @@ export class AbiDecoder { // Indexed parameters are stored in topics. Non-indexed ones in decodedData let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++]; if (param.type === SolidityTypes.Address) { - value = this.padZeros(new BigNumber(value).toString(16)); + value = AbiDecoder.padZeros(new BigNumber(value).toString(16)); } else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint8 || param.type === SolidityTypes.Uint) { @@ -57,13 +66,4 @@ export class AbiDecoder { }); this.savedABIs = this.savedABIs.concat(abiArray); } - private padZeros(address: string) { - let formatted = address; - if (_.startsWith(formatted, '0x')) { - formatted = formatted.slice(2); - } - - formatted = _.padStart(formatted, 40, '0'); - return `0x${formatted}`; - } } diff --git a/packages/0x.js/src/utils/exchange_transfer_simulator.ts b/packages/0x.js/src/utils/exchange_transfer_simulator.ts index c3a2d1585..00a0efd3f 100644 --- a/packages/0x.js/src/utils/exchange_transfer_simulator.ts +++ b/packages/0x.js/src/utils/exchange_transfer_simulator.ts @@ -36,6 +36,11 @@ const ERR_MSG_MAPPING = { export class ExchangeTransferSimulator { private store: BalanceAndProxyAllowanceLazyStore; private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber; + private static throwValidationError(failureReason: FailureReason, tradeSide: TradeSide, + transferType: TransferType): never { + const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; + throw new Error(errMsg); + } constructor(token: TokenWrapper) { this.store = new BalanceAndProxyAllowanceLazyStore(token); this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; @@ -55,10 +60,10 @@ export class ExchangeTransferSimulator { 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); + ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType); } if (balance.lessThan(amountInBaseUnits)) { - this.throwValidationError(FailureReason.Balance, tradeSide, transferType); + ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType); } await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits); await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits); @@ -81,9 +86,4 @@ export class ExchangeTransferSimulator { const balance = await this.store.getBalanceAsync(tokenAddress, userAddress); this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits)); } - private throwValidationError(failureReason: FailureReason, tradeSide: TradeSide, - transferType: TransferType): never { - const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; - throw new Error(errMsg); - } } diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts index 6654b9ae1..7dee89914 100644 --- a/packages/0x.js/src/utils/order_state_utils.ts +++ b/packages/0x.js/src/utils/order_state_utils.ts @@ -25,6 +25,39 @@ const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001; export class OrderStateUtils { private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; + private static validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { + const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.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); + } + } + const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount + .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) + .dividedBy(signedOrder.makerTokenAmount); + if (orderRelevantState.remainingFillableTakerTokenAmount + .lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) { + throw new Error(ExchangeContractErrs.OrderFillRoundingError); + } + // TODO Add linear function solver when maker token is ZRX #badass + // Return the max amount that's fillable + } constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) { this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; @@ -34,7 +67,7 @@ export class OrderStateUtils { const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder); const orderHash = ZeroEx.getOrderHashHex(signedOrder); try { - this.validateIfOrderIsValid(signedOrder, orderRelevantState); + OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState); const orderState: OrderStateValid = { isValid: true, orderHash, @@ -103,37 +136,4 @@ export class OrderStateUtils { }; return orderRelevantState; } - private validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { - const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.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); - } - } - const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount - .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) - .dividedBy(signedOrder.makerTokenAmount); - if (orderRelevantState.remainingFillableTakerTokenAmount - .lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) { - throw new Error(ExchangeContractErrs.OrderFillRoundingError); - } - // TODO Add linear function solver when maker token is ZRX #badass - // Return the max amount that's fillable - } } diff --git a/packages/0x.js/src/utils/order_validation_utils.ts b/packages/0x.js/src/utils/order_validation_utils.ts index 06cfca7bd..d514483e0 100644 --- a/packages/0x.js/src/utils/order_validation_utils.ts +++ b/packages/0x.js/src/utils/order_validation_utils.ts @@ -13,6 +13,77 @@ import {ExchangeTransferSimulator} from './exchange_transfer_simulator'; export class OrderValidationUtils { private tokenWrapper: TokenWrapper; private exchangeWrapper: ExchangeWrapper; + 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 { + 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, + ) { + if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { + throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); + } + } + private static validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) { + 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(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) { this.tokenWrapper = tokenWrapper; this.exchangeWrapper = exchangeWrapper; @@ -22,15 +93,15 @@ export class OrderValidationUtils { expectedFillTakerTokenAmount?: BigNumber): Promise { const orderHash = utils.getOrderHashHex(signedOrder); const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); - this.validateRemainingFillAmountNotZeroOrThrow( + OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow( signedOrder.takerTokenAmount, unavailableTakerTokenAmount, ); - this.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); if (!_.isUndefined(expectedFillTakerTokenAmount)) { fillTakerTokenAmount = expectedFillTakerTokenAmount; } - const fillMakerTokenAmount = this.getPartialAmount( + const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount, @@ -39,7 +110,7 @@ export class OrderValidationUtils { signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount, TradeSide.Maker, TransferType.Trade, ); - const makerFeeAmount = this.getPartialAmount( + const makerFeeAmount = OrderValidationUtils.getPartialAmount( fillTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerFee, @@ -61,18 +132,18 @@ export class OrderValidationUtils { throw new Error(ZeroExError.InvalidSignature); } const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash); - this.validateRemainingFillAmountNotZeroOrThrow( + OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow( signedOrder.takerTokenAmount, unavailableTakerTokenAmount, ); if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) { throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker); } - this.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); + OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec); const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount); const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ? remainingTakerTokenAmount : fillTakerTokenAmount; - await this.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress, ); @@ -94,74 +165,4 @@ export class OrderValidationUtils { throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount); } } - public 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 async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string): Promise { - const fillMakerTokenAmount = this.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 = this.getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerFee, - ); - await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker, - TransferType.Fee, - ); - const takerFeeAmount = this.getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.takerFee, - ); - await exchangeTradeEmulator.transferFromAsync( - zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker, - TransferType.Fee, - ); - } - private validateRemainingFillAmountNotZeroOrThrow( - takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber, - ) { - if (takerTokenAmount.eq(unavailableTakerTokenAmount)) { - throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); - } - } - private validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) { - const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); - if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) { - throw new Error(ExchangeContractErrs.OrderFillExpired); - } - } - private getPartialAmount(numerator: BigNumber, denominator: BigNumber, - target: BigNumber): BigNumber { - const fillMakerTokenAmount = numerator - .mul(target) - .div(denominator) - .round(0); - return fillMakerTokenAmount; - } } diff --git a/packages/0x.js/test/order_validation_test.ts b/packages/0x.js/test/order_validation_test.ts index 811cd48c4..3282ebb3e 100644 --- a/packages/0x.js/test/order_validation_test.ts +++ b/packages/0x.js/test/order_validation_test.ts @@ -114,7 +114,7 @@ describe('OrderValidation', () => { makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); // 27 <--> 28 - signedOrder.ecSignature.v = 27 + (28 - signedOrder.ecSignature.v); + signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27; return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( signedOrder, fillableAmount, takerAddress, )).to.be.rejectedWith(ZeroExError.InvalidSignature); @@ -230,7 +230,7 @@ describe('OrderValidation', () => { makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress, fillableAmount, feeRecipient, ); - await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); @@ -266,7 +266,7 @@ describe('OrderValidation', () => { makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient, ); - await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); @@ -301,7 +301,7 @@ describe('OrderValidation', () => { const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount, ); - await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress, ); expect(transferFromAsync.callCount).to.be.equal(4); @@ -316,7 +316,7 @@ describe('OrderValidation', () => { fillableAmount, ZeroEx.NULL_ADDRESS, ); const fillTakerTokenAmount = fillableAmount.div(2).round(0); - await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress, ); const makerPartialFee = makerFee.div(2); diff --git a/packages/tslint-config/tslint.json b/packages/tslint-config/tslint.json index 4c2c7adf4..11b0e4d2e 100644 --- a/packages/tslint-config/tslint.json +++ b/packages/tslint-config/tslint.json @@ -4,21 +4,24 @@ "tslint-react" ], "rules": { + "adjacent-overload-signatures": true, "arrow-parens": [true, "ban-single-arg-parens"], "arrow-return-shorthand": true, "await-promise": true, - "ordered-imports": [ - true, - { - "grouped-imports": true - } - ], - "quotemark": [true, "single", "avoid-escape", "jsx-double"], + "binary-expression-operand-order": true, "callable-types": true, + "class-name": true, + "curly": true, + "eofline": true, + "encoding": true, + "import-spacing": true, + "indent": [true, "spaces", 4], "interface-name": false, "interface-over-type-literal": true, - "object-literal-sort-keys": false, + "linebreak-style": [true, "LF"], "max-classes-per-file": false, + "max-classes-per-file": [true, 1], + "max-file-line-count": [true, 500], "max-line-length": [true, 120], "member-access": true, "member-ordering": [true, @@ -26,19 +29,47 @@ "static-before-instance", "variables-before-functions" ], + "newline-before-return": false, + "new-parens": true, "no-angle-bracket-type-assertion": true, + "no-boolean-literal-compare": true, "no-default-export": true, "no-empty-interface": false, "no-floating-promises": true, "no-non-null-assertion": true, "no-parameter-reassignment": true, + "no-redundant-jsdoc": true, "no-return-await": true, "no-string-throw": true, "no-submodule-imports": false, "no-unnecessary-type-assertion": true, "no-implicit-dependencies": [true, "dev"], + "number-literal-format": true, + "object-literal-sort-keys": false, + "ordered-imports": [ + true, + { + "grouped-imports": true + } + ], "prefer-const": true, + "prefer-for-of": true, + "prefer-function-over-method": true, "promise-function-async": true, + "quotemark": [true, "single", "avoid-escape", "jsx-double"], + "semicolon": [true, "always"], + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never", + "method": "never", + "constructor": "never", + "asyncArrow": "always" + } + ], + "space-within-parens": false, + "type-literal-delimiter": true, "variable-name": [true, "ban-keywords", "allow-pascal-case" -- cgit v1.2.3