aboutsummaryrefslogtreecommitdiffstats
path: root/src/contract_wrappers
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2017-06-02 00:14:17 +0800
committerFabio Berger <me@fabioberger.com>2017-06-02 00:14:17 +0800
commitacb8a6c55ee2c97db5d738621929feea759465b3 (patch)
tree57cfa925d645cb11bb1731381be56d0f66f8f0f1 /src/contract_wrappers
parentecf92a4ad786a324d4c8ce9dba926f377766a144 (diff)
parent389c18e98e2b5663b1732d7c34f9b21afef66e44 (diff)
downloaddexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar.gz
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar.bz2
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar.lz
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar.xz
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.tar.zst
dexon-sol-tools-acb8a6c55ee2c97db5d738621929feea759465b3.zip
Merge branch 'fillOrderAsync' into unavailableFilledCancelled
# Conflicts: # src/contract_wrappers/exchange_wrapper.ts # src/types.ts # src/utils/assert.ts
Diffstat (limited to 'src/contract_wrappers')
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts113
1 files changed, 106 insertions, 7 deletions
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index 74303cf82..7fcf91cbf 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -1,13 +1,35 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import {Web3Wrapper} from '../web3_wrapper';
-import {ECSignature, ZeroExError, ExchangeContract} from '../types';
+import {
+ ECSignature,
+ ExchangeContract,
+ ExchangeContractErrCodes,
+ ExchangeContractErrs,
+ FillOrderValidationErrs,
+ OrderValues,
+ OrderAddresses,
+ SignedOrder,
+ ContractEvent,
+} from '../types';
import {assert} from '../utils/assert';
import {ContractWrapper} from './contract_wrapper';
import * as ExchangeArtifacts from '../artifacts/Exchange.json';
import {ecSignatureSchema} from '../schemas/ec_signature_schema';
+import {signedOrderSchema} from '../schemas/order_schemas';
+import {SchemaValidator} from '../utils/schema_validator';
+import {ContractResponse} from '../types';
+import {constants} from '../utils/constants';
export class ExchangeWrapper extends ContractWrapper {
+ private exchangeContractErrCodesToMsg = {
+ [ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.ORDER_EXPIRED,
+ [ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.ORDER_EXPIRED,
+ [ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO,
+ [ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.ORDER_REMAINING_FILL_AMOUNT_ZERO,
+ [ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.ORDER_ROUNDING_ERROR,
+ [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.ORDER_BALANCE_ALLOWANCE_ERROR,
+ };
private exchangeContractIfExists?: ExchangeContract;
constructor(web3Wrapper: Web3Wrapper) {
super(web3Wrapper);
@@ -21,19 +43,17 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
- const senderAddressIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync();
- assert.assert(!_.isUndefined(senderAddressIfExists), ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
+ const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
+ const exchangeInstance = await this.getExchangeContractAsync();
- const exchangeContract = await this.getExchangeContractAsync();
-
- const isValidSignature = await exchangeContract.isValidSignature.call(
+ const isValidSignature = await exchangeInstance.isValidSignature.call(
signerAddressHex,
dataHex,
ecSignature.v,
ecSignature.r,
ecSignature.s,
{
- from: senderAddressIfExists,
+ from: senderAddress,
},
);
return isValidSignature;
@@ -70,6 +90,85 @@ export class ExchangeWrapper extends ContractWrapper {
const cancelledAmountInBaseUnits = await exchangeContract.cancelled.call(orderHashHex);
return cancelledAmountInBaseUnits;
}
+ /**
+ * Fills a signed order with a fillAmount denominated in baseUnits of the taker token. The caller can
+ * decide whether they want the call to throw if the balance/allowance checks fail by setting
+ * shouldCheckTransfer to false. If set to true, the call will fail without throwing, preserving gas costs.
+ */
+ public async fillOrderAsync(signedOrder: SignedOrder, fillTakerAmountInBaseUnits: BigNumber.BigNumber,
+ shouldCheckTransfer: boolean): Promise<void> {
+ assert.doesConformToSchema('signedOrder',
+ SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object),
+ signedOrderSchema);
+ assert.isBigNumber('fillTakerAmountInBaseUnits', fillTakerAmountInBaseUnits);
+ assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer);
+
+ const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
+ const exchangeInstance = await this.getExchangeContractAsync();
+
+ this.validateFillOrder(signedOrder, fillTakerAmountInBaseUnits, senderAddress);
+
+ const orderAddresses: OrderAddresses = [
+ signedOrder.maker,
+ signedOrder.taker,
+ signedOrder.makerTokenAddress,
+ signedOrder.takerTokenAddress,
+ signedOrder.feeRecipient,
+ ];
+ const orderValues: OrderValues = [
+ signedOrder.makerTokenAmount,
+ signedOrder.takerTokenAmount,
+ signedOrder.makerFee,
+ signedOrder.takerFee,
+ signedOrder.expirationUnixTimestampSec,
+ signedOrder.salt,
+ ];
+ const gas = await exchangeInstance.fill.estimateGas(
+ orderAddresses,
+ orderValues,
+ fillTakerAmountInBaseUnits,
+ shouldCheckTransfer,
+ signedOrder.ecSignature.v,
+ signedOrder.ecSignature.r,
+ signedOrder.ecSignature.s,
+ {
+ from: senderAddress,
+ },
+ );
+ const response: ContractResponse = await exchangeInstance.fill(
+ orderAddresses,
+ orderValues,
+ fillTakerAmountInBaseUnits,
+ shouldCheckTransfer,
+ signedOrder.ecSignature.v,
+ signedOrder.ecSignature.r,
+ signedOrder.ecSignature.s,
+ {
+ from: senderAddress,
+ gas,
+ },
+ );
+ this.throwErrorLogsAsErrors(response.logs);
+ }
+ private validateFillOrder(signedOrder: SignedOrder, fillAmount: BigNumber.BigNumber, senderAddress: string) {
+ if (fillAmount.eq(0)) {
+ throw new Error(FillOrderValidationErrs.FILL_AMOUNT_IS_ZERO);
+ }
+ if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== senderAddress) {
+ throw new Error(FillOrderValidationErrs.NOT_A_TAKER);
+ }
+ if (signedOrder.expirationUnixTimestampSec.lessThan(Date.now() / 1000)) {
+ throw new Error(FillOrderValidationErrs.EXPIRED);
+ }
+ }
+ private throwErrorLogsAsErrors(logs: ContractEvent[]): void {
+ const errEvent = _.find(logs, {event: 'LogError'});
+ if (!_.isUndefined(errEvent)) {
+ const errCode = errEvent.args.errorId.toNumber();
+ const errMessage = this.exchangeContractErrCodesToMsg[errCode];
+ throw new Error(errMessage);
+ }
+ }
private async getExchangeContractAsync(): Promise<ExchangeContract> {
if (!_.isUndefined(this.exchangeContractIfExists)) {
return this.exchangeContractIfExists;