aboutsummaryrefslogtreecommitdiffstats
path: root/src/contract_wrappers/exchange_wrapper.ts
diff options
context:
space:
mode:
authorLeonid <logvinov.leon@gmail.com>2017-07-04 03:28:34 +0800
committerGitHub <noreply@github.com>2017-07-04 03:28:34 +0800
commitd4cef89587ef8ea0f7fbab1146c4524e8f588eac (patch)
tree93dcf602b5a738bad03c121384707fcf19518310 /src/contract_wrappers/exchange_wrapper.ts
parentd506a1f98562dd11ecff5e936a93fce6d14e48a9 (diff)
parent8204409c6d6bf773aa8ebb38006a3975ed43a684 (diff)
downloaddexon-0x-contracts-d4cef89587ef8ea0f7fbab1146c4524e8f588eac.tar.gz
dexon-0x-contracts-d4cef89587ef8ea0f7fbab1146c4524e8f588eac.tar.zst
dexon-0x-contracts-d4cef89587ef8ea0f7fbab1146c4524e8f588eac.zip
Merge pull request #82 from 0xProject/add-exchange-address-to-order-struct
Allow multiple Exchange contracts and multiple artifacts
Diffstat (limited to 'src/contract_wrappers/exchange_wrapper.ts')
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts206
1 files changed, 145 insertions, 61 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index 5d514e5ec..f596cb429 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -7,6 +7,7 @@ import {
ExchangeContract,
ExchangeContractErrCodes,
ExchangeContractErrs,
+ ZeroExError,
OrderValues,
OrderAddresses,
Order,
@@ -25,11 +26,14 @@ import {
LogErrorContractEventArgs,
LogFillContractEventArgs,
LogCancelContractEventArgs,
+ ExchangeContractByAddress,
+ ContractArtifact,
} from '../types';
import {assert} from '../utils/assert';
import {utils} from '../utils/utils';
import {ContractWrapper} from './contract_wrapper';
-import * as ExchangeArtifacts from '../artifacts/Exchange.json';
+import {ProxyWrapper} from './proxy_wrapper';
+import {ExchangeArtifactsByName} from '../exchange_artifacts_by_name';
import {ecSignatureSchema} from '../schemas/ec_signature_schema';
import {signedOrdersSchema} from '../schemas/signed_orders_schema';
import {orderFillRequestsSchema} from '../schemas/order_fill_requests_schema';
@@ -53,9 +57,10 @@ 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 _exchangeContractIfExists?: ExchangeContract;
+ private _exchangeContractByAddress: ExchangeContractByAddress;
private _exchangeLogEventEmitters: ContractEventEmitter[];
private _tokenWrapper: TokenWrapper;
+ private _proxyWrapper: ProxyWrapper;
private static _getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] {
const orderAddresses: OrderAddresses = [
order.maker,
@@ -74,27 +79,31 @@ export class ExchangeWrapper extends ContractWrapper {
];
return [orderAddresses, orderValues];
}
- constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper) {
+ constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper, proxyWrapper: ProxyWrapper) {
super(web3Wrapper);
this._tokenWrapper = tokenWrapper;
+ this._proxyWrapper = proxyWrapper;
this._exchangeLogEventEmitters = [];
+ this._exchangeContractByAddress = {};
}
- public async invalidateContractInstanceAsync(): Promise<void> {
+ public async invalidateContractInstancesAsync(): Promise<void> {
await this.stopWatchingAllEventsAsync();
- delete this._exchangeContractIfExists;
+ this._exchangeContractByAddress = {};
}
/**
* Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
* amount that has been filled or cancelled. The remaining takerAmount can be calculated by
* 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 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 use.
* @return The amount of the order (in taker tokens) that has either been filled or canceled.
*/
- public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> {
+ public async getUnavailableTakerAmountAsync(orderHash: string,
+ exchangeContractAddress: string): Promise<BigNumber.BigNumber> {
assert.isValidOrderHash('orderHash', orderHash);
- const exchangeContract = await this._getExchangeContractAsync();
+ const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress);
let unavailableAmountInBaseUnits = await exchangeContract.getUnavailableValueT.call(orderHash);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
unavailableAmountInBaseUnits = new BigNumber(unavailableAmountInBaseUnits);
@@ -103,12 +112,14 @@ 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 use.
* @return The amount of the order (in taker tokens) that has already been filled.
*/
- public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> {
+ public async getFilledTakerAmountAsync(orderHash: string,
+ exchangeContractAddress: string): Promise<BigNumber.BigNumber> {
assert.isValidOrderHash('orderHash', orderHash);
- const exchangeContract = await this._getExchangeContractAsync();
+ const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress);
let fillAmountInBaseUnits = await exchangeContract.filled.call(orderHash);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
@@ -118,12 +129,14 @@ 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 use.
* @return The amount of the order (in taker tokens) that has been cancelled.
*/
- public async getCanceledTakerAmountAsync(orderHash: string): Promise<BigNumber.BigNumber> {
+ public async getCanceledTakerAmountAsync(orderHash: string,
+ exchangeContractAddress: string): Promise<BigNumber.BigNumber> {
assert.isValidOrderHash('orderHash', orderHash);
- const exchangeContract = await this._getExchangeContractAsync();
+ const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress);
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.call(orderHash);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
@@ -152,7 +165,7 @@ export class ExchangeWrapper extends ContractWrapper {
assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(signedOrder.exchangeContractAddress);
await this._validateFillOrderAndThrowIfInvalidAsync(signedOrder, takerTokenFillAmount, takerAddress);
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
@@ -205,12 +218,15 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], takerTokenFillAmount: BigNumber.BigNumber,
shouldCheckTransfer: boolean, takerAddress: string): Promise<BigNumber.BigNumber> {
+ assert.doesConformToSchema('signedOrders', signedOrders, signedOrdersSchema);
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
- ExchangeContractErrs.MULTIPLE_TAKER_TOKENS_IN_FILL_UP_TO_DISALLOWED);
+ 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('takerTokenFillAmount', takerTokenFillAmount);
assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer);
- assert.doesConformToSchema('signedOrders', signedOrders, signedOrdersSchema);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
for (const signedOrder of signedOrders) {
await this._validateFillOrderAndThrowIfInvalidAsync(
@@ -233,7 +249,7 @@ export class ExchangeWrapper extends ContractWrapper {
orderAddressesValuesAndSignatureArray,
);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]);
const gas = await exchangeInstance.fillUpTo.estimateGas(
orderAddressesArray,
orderValuesArray,
@@ -282,9 +298,15 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[],
shouldCheckTransfer: 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('shouldCheckTransfer', shouldCheckTransfer);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- assert.doesConformToSchema('orderFillRequests', orderFillRequests, orderFillRequestsSchema);
for (const orderFillRequest of orderFillRequests) {
await this._validateFillOrderAndThrowIfInvalidAsync(
orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, takerAddress);
@@ -307,7 +329,7 @@ export class ExchangeWrapper extends ContractWrapper {
orderAddressesValuesAmountsAndSignatureArray,
);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]);
const gas = await exchangeInstance.batchFill.estimateGas(
orderAddressesArray,
orderValuesArray,
@@ -351,7 +373,7 @@ export class ExchangeWrapper extends ContractWrapper {
assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(signedOrder.exchangeContractAddress);
await this._validateFillOrderAndThrowIfInvalidAsync(signedOrder, takerTokenFillAmount, takerAddress);
await this._validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder, exchangeInstance.address,
@@ -394,9 +416,18 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async batchFillOrKillAsync(orderFillOrKillRequests: OrderFillOrKillRequest[],
takerAddress: string): Promise<void> {
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
assert.doesConformToSchema('orderFillOrKillRequests', orderFillOrKillRequests, orderFillOrKillRequestsSchema);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeContractAddresses = _.map(
+ orderFillOrKillRequests,
+ orderFillOrKillRequest => orderFillOrKillRequest.signedOrder.exchangeContractAddress,
+ );
+ assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
+ ExchangeContractErrs.BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS);
+ await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
+ if (_.isEmpty(orderFillOrKillRequests)) {
+ return; // no-op
+ }
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]);
for (const request of orderFillOrKillRequests) {
await this._validateFillOrKillOrderAndThrowIfInvalidAsync(request.signedOrder, exchangeInstance.address,
request.fillTakerAmount);
@@ -455,7 +486,7 @@ export class ExchangeWrapper extends ContractWrapper {
assert.isBigNumber('takerTokenCancelAmount', takerTokenCancelAmount);
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(order.exchangeContractAddress);
await this._validateCancelOrderAndThrowIfInvalidAsync(order, takerTokenCancelAmount);
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
@@ -489,12 +520,18 @@ export class ExchangeWrapper extends ContractWrapper {
*/
@decorators.contractCallErrorHandler
public async batchCancelOrderAsync(orderCancellationRequests: OrderCancellationRequest[]): Promise<void> {
+ assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
+ orderCancellationRequestsSchema);
+ const exchangeContractAddresses = _.map(
+ orderCancellationRequests,
+ orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
+ );
+ assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
+ ExchangeContractErrs.BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS);
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH_DISALLOWED);
const maker = makers[0];
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
- assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
- orderCancellationRequestsSchema);
for (const cancellationRequest of orderCancellationRequests) {
await this._validateCancelOrderAndThrowIfInvalidAsync(
cancellationRequest.order, cancellationRequest.takerTokenCancelAmount,
@@ -503,7 +540,7 @@ export class ExchangeWrapper extends ContractWrapper {
if (_.isEmpty(orderCancellationRequests)) {
return; // no-op
}
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddresses[0]);
const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => {
return [
...ExchangeWrapper._getOrderAddressesAndValues(cancellationRequest.order),
@@ -534,16 +571,17 @@ export class ExchangeWrapper extends ContractWrapper {
}
/**
* Subscribe to an event type emitted by the Exchange smart contract
- * @param eventName The exchange contract event you would like to subscribe to.
- * @param subscriptionOpts Subscriptions options that let you configure the subscription.
- * @param indexFilterValues An object where the keys are indexed args returned by the event and
- * the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
+ * @param eventName The exchange contract event you would like to subscribe to.
+ * @param subscriptionOpts Subscriptions options that let you configure the subscription.
+ * @param indexFilterValues An object where the keys are indexed args returned by the event and
+ * the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
+ * @param exchangeContractAddress The hex encoded address of the Exchange contract to use.
* @return ContractEventEmitter object
*/
public async subscribeAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues):
+ indexFilterValues: IndexedFilterValues, exchangeContractAddress: string):
Promise<ContractEventEmitter> {
- const exchangeContract = await this._getExchangeContractAsync();
+ const exchangeContract = await this._getExchangeContractAsync(exchangeContractAddress);
let createLogEvent: CreateContractEvent;
switch (eventName) {
case ExchangeEvents.LogFill:
@@ -565,13 +603,41 @@ export class ExchangeWrapper extends ContractWrapper {
return eventEmitter;
}
/**
- * Returns the ethereum address of the current exchange contract
+ * Returns the ethereum addresses of all available exchange contracts
+ * on the network that the provided web3 instance is connected to
+ * @return The ethereum addresses of all available exchange contracts.
+ */
+ public async getAvailableContractAddressesAsync(): Promise<string[]> {
+ const networkId = await this._web3Wrapper.getNetworkIdIfExistsAsync();
+ if (_.isUndefined(networkId)) {
+ return [];
+ } else {
+ const exchangeArtifacts = _.values(ExchangeArtifactsByName);
+ const networkSpecificExchangeArtifacts = _.compact(_.map(
+ exchangeArtifacts, exchangeArtifact => exchangeArtifact.networks[networkId]));
+ const exchangeAddresses = _.map(
+ networkSpecificExchangeArtifacts,
+ networkSpecificExchangeArtifact => networkSpecificExchangeArtifact.address,
+ );
+ return exchangeAddresses;
+ }
+ }
+ /**
+ * Returns the ethereum addresses of all available exchange contracts
* on the network that the provided web3 instance is connected to
- * @return The ethereum address of the current exchange contract.
+ * that are currently authorized on the Proxy contract
+ * @return The ethereum addresses of all available and authorized exchange contract.
*/
- public async getContractAddressAsync(): Promise<string> {
- const exchangeContract = await this._getExchangeContractAsync();
- return exchangeContract.address;
+ public async getProxyAuthorizedContractAddressesAsync(): Promise<string[]> {
+ const exchangeContractAddresses = await this.getAvailableContractAddressesAsync();
+ const proxyAuthorizedExchangeContractAddresses = [];
+ for (const exchangeContractAddress of exchangeContractAddresses) {
+ const isAuthorized = await this._isExchangeContractAddressProxyAuthorizedAsync(exchangeContractAddress);
+ if (isAuthorized) {
+ proxyAuthorizedExchangeContractAddresses.push(exchangeContractAddress);
+ }
+ }
+ return proxyAuthorizedExchangeContractAddresses;
}
/**
* Stops watching for all exchange events
@@ -582,6 +648,10 @@ export class ExchangeWrapper extends ContractWrapper {
await Promise.all(stopWatchingPromises);
this._exchangeLogEventEmitters = [];
}
+ private async _isExchangeContractAddressProxyAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
+ const isAuthorized = await this._proxyWrapper.isAuthorizedAsync(exchangeContractAddress);
+ return isAuthorized;
+ }
private _wrapEventEmitter(event: ContractEventObj): ContractEventEmitter {
const zeroExEvent = {
watch: event.watch.bind(event),
@@ -592,12 +662,13 @@ export class ExchangeWrapper extends ContractWrapper {
return zeroExEvent;
}
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature,
- signerAddressHex: string): Promise<boolean> {
+ signerAddressHex: string,
+ exchangeContractAddress: string): Promise<boolean> {
assert.isHexString('dataHex', dataHex);
assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress);
const isValidSignature = await exchangeInstance.isValidSignature.call(
signerAddressHex,
@@ -608,13 +679,8 @@ export class ExchangeWrapper extends ContractWrapper {
);
return isValidSignature;
}
- private async _getOrderHashHexAsync(order: Order|SignedOrder): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const orderHashHex = utils.getOrderHashHex(order, exchangeInstance.address);
- return orderHashHex;
- }
private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(order.exchangeContractAddress);
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
const orderHashHex = await exchangeInstance.getOrderHash.call(orderAddresses, orderValues);
return orderHashHex;
@@ -632,12 +698,13 @@ export class ExchangeWrapper extends ContractWrapper {
if (signedOrder.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
throw new Error(ExchangeContractErrs.ORDER_FILL_EXPIRED);
}
- const zrxTokenAddress = await this._getZRXTokenAddressAsync();
+ const zrxTokenAddress = await this._getZRXTokenAddressAsync(signedOrder.exchangeContractAddress);
await this._validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync(signedOrder, fillTakerAmount,
senderAddress, zrxTokenAddress);
const wouldRoundingErrorOccur = await this._isRoundingErrorAsync(
signedOrder.takerTokenAmount, fillTakerAmount, signedOrder.makerTokenAmount,
+ signedOrder.exchangeContractAddress,
);
if (wouldRoundingErrorOccur) {
throw new Error(ExchangeContractErrs.ORDER_FILL_ROUNDING_ERROR);
@@ -648,8 +715,8 @@ export class ExchangeWrapper extends ContractWrapper {
if (takerTokenCancelAmount.eq(0)) {
throw new Error(ExchangeContractErrs.ORDER_CANCEL_AMOUNT_ZERO);
}
- const orderHash = await this._getOrderHashHexAsync(order);
- const unavailableAmount = await this.getUnavailableTakerAmountAsync(orderHash);
+ const orderHash = utils.getOrderHashHex(order);
+ const unavailableAmount = await this.getUnavailableTakerAmountAsync(orderHash, order.exchangeContractAddress);
if (order.takerTokenAmount.minus(unavailableAmount).eq(0)) {
throw new Error(ExchangeContractErrs.ORDER_ALREADY_CANCELLED_OR_FILLED);
}
@@ -659,11 +726,11 @@ export class ExchangeWrapper extends ContractWrapper {
}
}
private async _validateFillOrKillOrderAndThrowIfInvalidAsync(signedOrder: SignedOrder,
- exchangeAddress: string,
+ exchangeContractAddress: string,
fillTakerAmount: BigNumber.BigNumber) {
// Check that fillValue available >= fillTakerAmount
- const orderHashHex = utils.getOrderHashHex(signedOrder, exchangeAddress);
- const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex);
+ const orderHashHex = utils.getOrderHashHex(signedOrder);
+ const unavailableTakerAmount = await this.getUnavailableTakerAmountAsync(orderHashHex, exchangeContractAddress);
const remainingTakerAmount = signedOrder.takerTokenAmount.minus(unavailableTakerAmount);
if (remainingTakerAmount < fillTakerAmount) {
throw new Error(ExchangeContractErrs.INSUFFICIENT_REMAINING_FILL_AMOUNT);
@@ -740,24 +807,41 @@ export class ExchangeWrapper extends ContractWrapper {
}
private async _isRoundingErrorAsync(takerTokenAmount: BigNumber.BigNumber,
fillTakerAmount: BigNumber.BigNumber,
- makerTokenAmount: BigNumber.BigNumber): Promise<boolean> {
+ makerTokenAmount: BigNumber.BigNumber,
+ exchangeContractAddress: string): Promise<boolean> {
await assert.isUserAddressAvailableAsync(this._web3Wrapper);
- const exchangeInstance = await this._getExchangeContractAsync();
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress);
const isRoundingError = await exchangeInstance.isRoundingError.call(
takerTokenAmount, fillTakerAmount, makerTokenAmount,
);
return isRoundingError;
}
- private async _getExchangeContractAsync(): Promise<ExchangeContract> {
- if (!_.isUndefined(this._exchangeContractIfExists)) {
- return this._exchangeContractIfExists;
+ private async _getExchangeContractAsync(exchangeContractAddress: string): Promise<ExchangeContract> {
+ if (!_.isUndefined(this._exchangeContractByAddress[exchangeContractAddress])) {
+ return this._exchangeContractByAddress[exchangeContractAddress];
}
+ const ExchangeArtifacts = this._getExchangeArtifactsByAddressOrThrow(exchangeContractAddress);
const contractInstance = await this._instantiateContractIfExistsAsync((ExchangeArtifacts as any));
- this._exchangeContractIfExists = contractInstance as ExchangeContract;
- return this._exchangeContractIfExists;
+ 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);
}
- private async _getZRXTokenAddressAsync(): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- return exchangeInstance.ZRX.call();
+ private async _getZRXTokenAddressAsync(exchangeContractAddress: string): Promise<string> {
+ const exchangeInstance = await this._getExchangeContractAsync(exchangeContractAddress);
+ const ZRXtokenAddress = await exchangeInstance.ZRX.call();
+ return ZRXtokenAddress;
}
}