aboutsummaryrefslogtreecommitdiffstats
path: root/src/contract_wrappers/exchange_wrapper.ts
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2017-07-12 03:53:22 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2017-07-12 07:15:08 +0800
commit8052625e76675fbe8c894e7a58fe8707ee14c5ad (patch)
tree9fc20b56c46fdd76525cdf5ef2e1a7c839ed03bc /src/contract_wrappers/exchange_wrapper.ts
parent2787bdc46b1670fb0444578b62ae85e6aa626264 (diff)
downloaddexon-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.ts108
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;
}