diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-07-12 03:53:22 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-07-12 07:15:08 +0800 |
commit | 8052625e76675fbe8c894e7a58fe8707ee14c5ad (patch) | |
tree | 9fc20b56c46fdd76525cdf5ef2e1a7c839ed03bc /src/contract_wrappers/exchange_wrapper.ts | |
parent | 2787bdc46b1670fb0444578b62ae85e6aa626264 (diff) | |
download | dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar.gz dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar.bz2 dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar.lz dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar.xz dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.tar.zst dexon-sol-tools-8052625e76675fbe8c894e7a58fe8707ee14c5ad.zip |
Migrate to using a single Exchange contract
Diffstat (limited to 'src/contract_wrappers/exchange_wrapper.ts')
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 108 |
1 files changed, 39 insertions, 69 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index c352c782b..50e0f5d3c 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -49,7 +49,7 @@ import {signedOrderSchema, orderSchema} from '../schemas/order_schemas'; import {constants} from '../utils/constants'; import {TokenWrapper} from './token_wrapper'; import {decorators} from '../utils/decorators'; -import {ExchangeArtifactsByName} from '../exchange_artifacts_by_name'; +import * as ExchangeArtifacts from '../artifacts/Exchange.json'; /** * This class includes all the functionality related to calling methods and subscribing to @@ -64,7 +64,7 @@ export class ExchangeWrapper extends ContractWrapper { [ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR, [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FILL_BALANCE_ALLOWANCE_ERROR, }; - private _exchangeContractByAddress: ExchangeContractByAddress; + private _exchangeContractIfExists?: ExchangeContract; private _exchangeLogEventEmitters: ContractEventEmitter[]; private _tokenWrapper: TokenWrapper; private static _getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] { @@ -89,7 +89,6 @@ export class ExchangeWrapper extends ContractWrapper { super(web3Wrapper); this._tokenWrapper = tokenWrapper; this._exchangeLogEventEmitters = []; - this._exchangeContractByAddress = {}; } /** * Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total @@ -97,14 +96,12 @@ export class ExchangeWrapper extends ContractWrapper { * subtracting the unavailable amount from the total order takerAmount. * @param orderHash The hex encoded orderHash for which you would like to retrieve the * unavailable takerAmount. - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. * @return The amount of the order (in taker tokens) that has either been filled or canceled. */ - public async getUnavailableTakerAmountAsync(orderHash: string, - exchangeContractAddress: string): Promise<BigNumber.BigNumber> { + public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> { assert.doesConformToSchema('orderHash', orderHash, orderHashSchema); - const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeContract = await this._getExchangeContractAsync(); let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.call(orderHash); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount); @@ -113,14 +110,12 @@ export class ExchangeWrapper extends ContractWrapper { /** * Retrieve the takerAmount of an order that has already been filled. * @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAmount. - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. * @return The amount of the order (in taker tokens) that has already been filled. */ - public async getFilledTakerAmountAsync(orderHash: string, - exchangeContractAddress: string): Promise<BigNumber.BigNumber> { + public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> { assert.doesConformToSchema('orderHash', orderHash, orderHashSchema); - const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeContract = await this._getExchangeContractAsync(); let fillAmountInBaseUnits = await exchangeContract.filled.call(orderHash); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits); @@ -130,14 +125,12 @@ export class ExchangeWrapper extends ContractWrapper { * Retrieve the takerAmount of an order that has been cancelled. * @param orderHash The hex encoded orderHash for which you would like to retrieve the * cancelled takerAmount. - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. * @return The amount of the order (in taker tokens) that has been cancelled. */ - public async getCanceledTakerAmountAsync(orderHash: string, - exchangeContractAddress: string): Promise<BigNumber.BigNumber> { + public async getCanceledTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> { assert.doesConformToSchema('orderHash', orderHash, orderHashSchema); - const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeContract = await this._getExchangeContractAsync(); let cancelledAmountInBaseUnits = await exchangeContract.cancelled.call(orderHash); // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits); @@ -169,7 +162,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const exchangeInstance = await this._getExchangeContractAsync(signedOrder.exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); await this._validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerTokenAmount, takerAddress); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); @@ -228,9 +221,6 @@ export class ExchangeWrapper extends ContractWrapper { const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); assert.hasAtMostOneUniqueValue(takerTokenAddresses, ExchangeContractErrs.MULTIPLE_TAKER_TOKENS_IN_FILL_UP_TO_DISALLOWED); - const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS); assert.isBigNumber('fillTakerTokenAmount', fillTakerTokenAmount); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); @@ -255,7 +245,7 @@ export class ExchangeWrapper extends ContractWrapper { orderAddressesValuesAndSignatureArray, ); - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]); + const exchangeInstance = await this._getExchangeContractAsync(); const gas = await exchangeInstance.fillOrdersUpTo.estimateGas( orderAddressesArray, orderValuesArray, @@ -310,12 +300,6 @@ export class ExchangeWrapper extends ContractWrapper { shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string): Promise<void> { assert.doesConformToSchema('orderFillRequests', orderFillRequests, orderFillRequestsSchema); - const exchangeContractAddresses = _.map( - orderFillRequests, - orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress, - ); - assert.hasAtMostOneUniqueValue(exchangeContractAddresses, - ExchangeContractErrs.BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); for (const orderFillRequest of orderFillRequests) { @@ -340,7 +324,7 @@ export class ExchangeWrapper extends ContractWrapper { orderAddressesValuesAmountsAndSignatureArray, ); - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]); + const exchangeInstance = await this._getExchangeContractAsync(); const gas = await exchangeInstance.batchFillOrders.estimateGas( orderAddressesArray, orderValuesArray, @@ -384,11 +368,10 @@ export class ExchangeWrapper extends ContractWrapper { assert.isBigNumber('fillTakerTokenAmount', fillTakerTokenAmount); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const exchangeInstance = await this._getExchangeContractAsync(signedOrder.exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); await this._validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerTokenAmount, takerAddress); - await this._validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder, exchangeInstance.address, - fillTakerTokenAmount); + await this._validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerTokenAmount); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder); @@ -438,10 +421,9 @@ export class ExchangeWrapper extends ContractWrapper { if (_.isEmpty(orderFillOrKillRequests)) { return; // no-op } - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]); + const exchangeInstance = await this._getExchangeContractAsync(); for (const request of orderFillOrKillRequests) { - await this._validateFillOrKillOrderAndThrowIfInvalidAsync(request.signedOrder, exchangeInstance.address, - request.fillTakerAmount); + await this._validateFillOrKillOrderAndThrowIfInvalidAsync(request.signedOrder, request.fillTakerAmount); } const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillOrKillRequests, request => { @@ -497,7 +479,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isBigNumber('takerTokenCancelAmount', cancelTakerTokenAmount); await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper); - const exchangeInstance = await this._getExchangeContractAsync(order.exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); await this._validateCancelOrderAndThrowIfInvalidAsync(order, cancelTakerTokenAmount); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order); @@ -551,7 +533,7 @@ export class ExchangeWrapper extends ContractWrapper { if (_.isEmpty(orderCancellationRequests)) { return; // no-op } - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]); + const exchangeInstance = await this._getExchangeContractAsync(); const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => { return [ ...ExchangeWrapper._getOrderAddressesAndValues(cancellationRequest.order), @@ -596,7 +578,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, subscriptionOptsSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, indexFilterValuesSchema); - const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeContract = await this._getExchangeContractAsync(); let createLogEvent: CreateContractEvent; switch (eventName) { case ExchangeEvents.LogFill: @@ -626,18 +608,24 @@ export class ExchangeWrapper extends ContractWrapper { await Promise.all(stopWatchingPromises); this._exchangeLogEventEmitters = []; } + /** + * Returns the Ethereum address of the Exchange contract being used. + */ + public async getContractAddressAsync(): Promise<string> { + const exchangeInstance = await this._getExchangeContractAsync(); + return exchangeInstance.address; + } private async _invalidateContractInstancesAsync(): Promise<void> { await this.stopWatchingAllEventsAsync(); - this._exchangeContractByAddress = {}; + delete this._exchangeContractIfExists; } private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature, - signerAddressHex: string, - exchangeContractAddress: string): Promise<boolean> { + signerAddressHex: string): Promise<boolean> { assert.isHexString('dataHex', dataHex); assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); const isValidSignature = await exchangeInstance.isValidSignature.call( signerAddressHex, @@ -649,7 +637,7 @@ export class ExchangeWrapper extends ContractWrapper { return isValidSignature; } private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> { - const exchangeInstance = await this._getExchangeContractAsync(order.exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order); const orderHashHex = await exchangeInstance.getOrderHash.call(orderAddresses, orderValues); return orderHashHex; @@ -673,7 +661,6 @@ export class ExchangeWrapper extends ContractWrapper { const wouldRoundingErrorOccur = await this._isRoundingErrorAsync( signedOrder.takerTokenAmount, fillTakerAmount, signedOrder.makerTokenAmount, - signedOrder.exchangeContractAddress, ); if (wouldRoundingErrorOccur) { throw new Error(ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR); @@ -685,7 +672,7 @@ export class ExchangeWrapper extends ContractWrapper { throw new Error(ExchangeContractErrs.ORDER_CANCEL_AMOUNT_ZERO); } const orderHash = utils.getOrderHashHex(order); - const unavailableAmount = await this.getUnavailableTakerAmountAsync(orderHash, order.exchangeContractAddress); + const unavailableAmount = await this.getUnavailableTakerAmountAsync(orderHash); if (order.takerTokenAmount.minus(unavailableAmount).eq(0)) { throw new Error(ExchangeContractErrs.ORDER_ALREADY_CANCELLED_OR_FILLED); } @@ -695,11 +682,10 @@ export class ExchangeWrapper extends ContractWrapper { } } private async _validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder: SignedOrder, - exchangeContractAddress: string, fillTakerAmount: BigNumber.BigNumber) { // Check that fillValue available >= fillTakerAmount const orderHashHex = utils.getOrderHashHex(signedOrder); - const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex, exchangeContractAddress); + const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex); const remainingTakerAmount = signedOrder.takerTokenAmount.minus(unavailableTakerAmount); if (remainingTakerAmount < fillTakerAmount) { throw new Error(ExchangeContractErrs.INSUFFICIENT_REMAINING_FILL_AMOUNT); @@ -776,40 +762,24 @@ export class ExchangeWrapper extends ContractWrapper { } private async _isRoundingErrorAsync(numerator: BigNumber.BigNumber, demoninator: BigNumber.BigNumber, - makerTokenAmount: BigNumber.BigNumber, - exchangeContractAddress: string): Promise<boolean> { + makerTokenAmount: BigNumber.BigNumber): Promise<boolean> { await assert.isUserAddressAvailableAsync(this._web3Wrapper); - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); const isRoundingError = await exchangeInstance.isRoundingError.call( demoninator, numerator, makerTokenAmount, ); return isRoundingError; } - private async _getExchangeContractAsync(exchangeContractAddress: string): Promise<ExchangeContract> { - if (!_.isUndefined(this._exchangeContractByAddress[exchangeContractAddress])) { - return this._exchangeContractByAddress[exchangeContractAddress]; + private async _getExchangeContractAsync(): Promise<ExchangeContract> { + if (!_.isUndefined(this._exchangeContractIfExists)) { + return this._exchangeContractIfExists; } - const ExchangeArtifacts = this._getExchangeArtifactsByAddressOrThrow(exchangeContractAddress); const contractInstance = await this._instantiateContractIfExistsAsync((ExchangeArtifacts as any)); - this._exchangeContractByAddress[exchangeContractAddress] = contractInstance as ExchangeContract; - return this._exchangeContractByAddress[exchangeContractAddress]; - } - private _getExchangeArtifactsByAddressOrThrow(exchangeContractAddress: string): ContractArtifact { - const exchangeArtifacts = _.values<ContractArtifact>(ExchangeArtifactsByName); - for (const exchangeArtifact of exchangeArtifacts) { - const networkSpecificExchangeArtifactValues = _.values(exchangeArtifact.networks); - const exchangeAddressesInArtifact = _.map( - networkSpecificExchangeArtifactValues, - networkSpecificExchangeArtifact => networkSpecificExchangeArtifact.address, - ); - if (_.includes(exchangeAddressesInArtifact, exchangeContractAddress)) { - return exchangeArtifact; - } - } - throw new Error(ZeroExError.EXCHANGE_CONTRACT_DOES_NOT_EXIST); + this._exchangeContractIfExists = contractInstance as ExchangeContract; + return this._exchangeContractIfExists; } private async _getZRXTokenAddressAsync(exchangeContractAddress: string): Promise<string> { - const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress); + const exchangeInstance = await this._getExchangeContractAsync(); const ZRXtokenAddress = await exchangeInstance.ZRX_TOKEN_CONTRACT.call(); return ZRXtokenAddress; } |