aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--circle.yml2
-rw-r--r--package.json2
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts91
-rw-r--r--src/types.ts33
-rw-r--r--src/web3_wrapper.ts7
-rw-r--r--test/utils/blockchain_lifecycle.ts2
6 files changed, 127 insertions, 10 deletions
diff --git a/circle.yml b/circle.yml
index 448524aa1..4919516f2 100644
--- a/circle.yml
+++ b/circle.yml
@@ -4,7 +4,7 @@ machine:
test:
override:
- - node node_modules/ethereumjs-testrpc/bin/testrpc -m "concert load couple harbor equip island argue ramp clarify fence smart topic":
+ - npm run testrpc:
background: true
- git clone git@github.com:0xProject/contracts.git ../contracts
- cd ../contracts; git checkout 38c2b4c; npm install && npm run migrate
diff --git a/package.json b/package.json
index 75a55b899..59e33a7dd 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"scripts": {
"prebuild": "npm run clean",
"build": "run-p build:*:prod",
- "lint": "tslint src/**/*.ts",
+ "lint": "tslint src/**/*.ts test/**/*.ts",
"test": "run-s clean test:commonjs",
"test:umd": "run-s substitute_umd_bundle run_mocha; npm run clean",
"test:coverage": "nyc npm run test --all",
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index f0f153c2b..c129eb367 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -1,12 +1,28 @@
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
-import {ECSignature, ZeroExError, ExchangeContract} from '../types';
+import {
+ ECSignature,
+ ExchangeContract,
+ ExchangeContractErrs,
+ OrderValues,
+ OrderAddresses,
+} 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 {ContractResponse} from '../types';
+import {constants} from '../utils/constants';
export class ExchangeWrapper extends ContractWrapper {
+ private exchangeContractErrToMsg = {
+ [ExchangeContractErrs.ERROR_FILL_EXPIRED]: 'The order you attempted to fill is expired',
+ [ExchangeContractErrs.ERROR_CANCEL_EXPIRED]: 'The order you attempted to cancel is expired',
+ [ExchangeContractErrs.ERROR_FILL_NO_VALUE]: 'This order has already been filled or cancelled',
+ [ExchangeContractErrs.ERROR_CANCEL_NO_VALUE]: 'This order has already been filled or cancelled',
+ [ExchangeContractErrs.ERROR_FILL_TRUNCATION]: 'The rounding error was too large when filling this order',
+ [ExchangeContractErrs.ERROR_FILL_BALANCE_ALLOWANCE]: 'Maker or taker has insufficient balance or allowance',
+ };
constructor(web3Wrapper: Web3Wrapper) {
super(web3Wrapper);
}
@@ -16,11 +32,8 @@ 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 contractInstance = await this.instantiateContractIfExistsAsync((ExchangeArtifacts as any));
- const exchangeInstance = contractInstance as ExchangeContract;
+ const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
+ const exchangeInstance = await this.getExchangeInstanceOrThrowAsync();
const isValidSignature = await exchangeInstance.isValidSignature.call(
signerAddressHex,
@@ -29,9 +42,73 @@ export class ExchangeWrapper extends ContractWrapper {
ecSignature.r,
ecSignature.s,
{
- from: senderAddressIfExists,
+ from: senderAddress,
},
);
return isValidSignature;
}
+ public async fillOrderAsync(maker: string, taker: string, makerTokenAddress: string,
+ takerTokenAddress: string, makerTokenAmount: BigNumber.BigNumber,
+ takerTokenAmount: BigNumber.BigNumber, makerFee: BigNumber.BigNumber,
+ takerFee: BigNumber.BigNumber, expirationUnixTimestampSec: BigNumber.BigNumber,
+ feeRecipient: string, fillAmount: BigNumber.BigNumber,
+ ecSignature: ECSignature, salt: BigNumber.BigNumber) {
+ assert.isBigNumber('salt', salt);
+ assert.isBigNumber('makerFee', makerFee);
+ assert.isBigNumber('takerFee', takerFee);
+ assert.isBigNumber('fillAmount', fillAmount);
+ assert.isBigNumber('makerTokenAmount', makerTokenAmount);
+ assert.isBigNumber('takerTokenAmount', takerTokenAmount);
+ assert.isBigNumber('expirationUnixTimestampSec', expirationUnixTimestampSec);
+ assert.isETHAddressHex('maker', maker);
+ assert.isETHAddressHex('taker', taker);
+ assert.isETHAddressHex('feeRecipient', feeRecipient);
+ assert.isETHAddressHex('makerTokenAddress', makerTokenAddress);
+ assert.isETHAddressHex('takerTokenAddress', takerTokenAddress);
+ assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema);
+
+ const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync();
+ const exchangeInstance = await this.getExchangeInstanceOrThrowAsync();
+
+ taker = taker === '' ? constants.NULL_ADDRESS : taker;
+ const shouldCheckTransfer = true;
+ const orderAddresses: OrderAddresses = [
+ maker,
+ taker,
+ makerTokenAddress,
+ takerTokenAddress,
+ feeRecipient,
+ ];
+ const orderValues: OrderValues = [
+ makerTokenAmount,
+ takerTokenAmount,
+ makerFee,
+ takerFee,
+ expirationUnixTimestampSec,
+ salt,
+ ];
+ const response: ContractResponse = await exchangeInstance.fill(
+ orderAddresses,
+ orderValues,
+ fillAmount,
+ shouldCheckTransfer,
+ ecSignature.v,
+ ecSignature.r,
+ ecSignature.s,
+ {
+ from: senderAddress,
+ },
+ );
+ const errEvent = _.find(response.logs, {event: 'LogError'});
+ if (!_.isUndefined(errEvent)) {
+ const errCode = errEvent.args.errorId.toNumber();
+ const humanReadableErrMessage = this.exchangeContractErrToMsg[errCode];
+ throw new Error(humanReadableErrMessage);
+ }
+ return response;
+ }
+ private async getExchangeInstanceOrThrowAsync(): Promise<ExchangeContract> {
+ const contractInstance = await this.instantiateContractIfExistsAsync((ExchangeArtifacts as any));
+ return contractInstance as ExchangeContract;
+ }
}
diff --git a/src/types.ts b/src/types.ts
index 3bed01547..0c661915e 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -26,8 +26,23 @@ export interface ECSignature {
s: string;
}
+export type OrderAddresses = [string, string, string, string, string];
+
+export type OrderValues = [
+ BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber,
+ BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber
+];
+
+export interface TxData {
+ from: string;
+}
+
export interface ExchangeContract {
isValidSignature: any;
+ fill: (
+ orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber,
+ shouldCheckTransfer: boolean, v: number, r: string, s: string, txData: TxData,
+ ) => ContractResponse;
}
export const SolidityTypes = strEnum([
@@ -35,3 +50,21 @@ export const SolidityTypes = strEnum([
'uint256',
]);
export type SolidityTypes = keyof typeof SolidityTypes;
+
+export enum ExchangeContractErrs {
+ ERROR_FILL_EXPIRED, // Order has already expired
+ ERROR_FILL_NO_VALUE, // Order has already been fully filled or cancelled
+ ERROR_FILL_TRUNCATION, // Rounding error too large
+ ERROR_FILL_BALANCE_ALLOWANCE, // Insufficient balance or allowance for token transfer
+ ERROR_CANCEL_EXPIRED, // Order has already expired
+ ERROR_CANCEL_NO_VALUE, // Order has already been fully filled or cancelled
+};
+
+export interface ContractResponse {
+ logs: ContractEvent[];
+}
+
+export interface ContractEvent {
+ event: string;
+ args: any;
+}
diff --git a/src/web3_wrapper.ts b/src/web3_wrapper.ts
index 97d04db8c..1ed1c0b29 100644
--- a/src/web3_wrapper.ts
+++ b/src/web3_wrapper.ts
@@ -2,6 +2,8 @@ import * as _ from 'lodash';
import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
+import {ZeroExError} from "./types";
+import {assert} from "./utils/assert";
export class Web3Wrapper {
private web3: Web3;
@@ -20,6 +22,11 @@ export class Web3Wrapper {
const firstAccount = await this.getFirstAddressIfExistsAsync();
return firstAccount;
}
+ public async getSenderAddressOrThrowAsync(): Promise<string> {
+ const senderAddressIfExists = await this.getSenderAddressIfExistsAsync();
+ assert.assert(!_.isUndefined(senderAddressIfExists), ZeroExError.USER_HAS_NO_ASSOCIATED_ADDRESSES);
+ return senderAddressIfExists as string;
+ }
public async getFirstAddressIfExistsAsync(): Promise<string|undefined> {
const addresses = await promisify(this.web3.eth.getAccounts)();
if (_.isEmpty(addresses)) {
diff --git a/test/utils/blockchain_lifecycle.ts b/test/utils/blockchain_lifecycle.ts
index 68e169ac0..50eb57b95 100644
--- a/test/utils/blockchain_lifecycle.ts
+++ b/test/utils/blockchain_lifecycle.ts
@@ -17,4 +17,4 @@ export class BlockchainLifecycle {
throw new Error(`Snapshot with id #${this.snapshotId} failed to revert`);
}
}
-};
+}