aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils')
-rw-r--r--packages/order-utils/package.json30
-rw-r--r--packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts17
-rw-r--r--packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts15
-rw-r--r--packages/order-utils/src/eip712_utils.ts44
-rw-r--r--packages/order-utils/src/exchange_transfer_simulator.ts9
-rw-r--r--packages/order-utils/src/index.ts51
-rw-r--r--packages/order-utils/src/monorepo_scripts/postpublish.ts8
-rw-r--r--packages/order-utils/src/monorepo_scripts/stage_docs.ts8
-rw-r--r--packages/order-utils/src/order_factory.ts9
-rw-r--r--packages/order-utils/src/order_hash.ts8
-rw-r--r--packages/order-utils/src/order_state_utils.ts53
-rw-r--r--packages/order-utils/src/order_validation_utils.ts54
-rw-r--r--packages/order-utils/src/signature_utils.ts626
-rw-r--r--packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts43
-rw-r--r--packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts45
-rw-r--r--packages/order-utils/test/order_hash_test.ts4
-rw-r--r--packages/order-utils/test/signature_utils_test.ts82
17 files changed, 681 insertions, 425 deletions
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index fa8f3563e..bcfb0611f 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -9,38 +9,29 @@
"types": "lib/src/index.d.ts",
"scripts": {
"watch_without_deps": "yarn pre_build && tsc -w",
- "build": "run-s pre_build transpile copy_monorepo_scripts",
- "pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 generate_contract_wrappers",
+ "build": "run-s pre_build transpile",
+ "pre_build": "run-s update_artifacts_v2_beta update_artifacts_v2 copy_artifacts generate_contract_wrappers",
"transpile": "tsc",
- "copy_monorepo_scripts": "copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
- "generate_contract_wrappers": "abi-gen --abis 'lib/src/artifacts/@(Exchange|IWallet|IValidator|DummyERC20Token|ERC20Proxy|ERC20Token).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
- "update_artifacts_v2_beta": "for i in ${npm_package_config_contracts_v2_beta}; do copyfiles -u 4 ../migrations/artifacts/2.0.0-beta-testnet/$i.json lib/src/artifacts; done;",
- "update_artifacts_v2": "for i in ${npm_package_config_contracts_v2}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json lib/src/artifacts; done;",
+ "generate_contract_wrappers": "abi-gen --abis './src/artifacts/@(Exchange|IWallet|IValidator|DummyERC20Token|ERC20Proxy|ERC20Token).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
+ "update_artifacts_v2_beta": "for i in ${npm_package_config_contracts_v2_beta}; do copyfiles -u 4 ../migrations/artifacts/2.0.0-beta-testnet/$i.json src/artifacts; done;",
+ "update_artifacts_v2": "for i in ${npm_package_config_contracts_v2}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json src/artifacts; done;",
+ "copy_artifacts": "copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --bail --exit",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "clean": "shx rm -rf lib scripts lib/src/artifacts src/generated_contract_wrappers",
+ "clean": "shx rm -rf lib lib/src/artifacts src/generated_contract_wrappers",
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
- "manual:postpublish": "yarn build; node ./scripts/postpublish.js",
- "docs:stage": "node scripts/stage_docs.js",
- "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
- "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json"
+ "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"contracts_v2_beta": "IWallet IValidator Exchange ERC20Proxy ERC20Token",
"contracts_v2": "DummyERC20Token",
"postpublish": {
- "docPublishConfigs": {
- "extraFileIncludes": [
- "../types/src/index.ts",
- "../ethereum-types/src/index.ts"
- ],
- "s3BucketPath": "s3://doc-jsons/order-utils/",
- "s3StagingBucketPath": "s3://staging-doc-jsons/order-utils/"
- }
+ "assets": [],
+ "shouldPublishDocs": true
}
},
"license": "Apache-2.0",
@@ -54,7 +45,6 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
"devDependencies": {
"@0xproject/dev-utils": "^1.0.4",
- "@0xproject/monorepo-scripts": "^1.0.5",
"@0xproject/tslint-config": "^1.0.5",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
diff --git a/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts b/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts
index b2760d98e..7cb859ca7 100644
--- a/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts
+++ b/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts
@@ -1,6 +1,23 @@
import { BigNumber } from '@0xproject/utils';
+/**l
+ * An abstract class to be implemented in order to use OrderStateUtils. The class that
+ * implements this interface must be capable of fetching the balance and proxyAllowance
+ * for an Ethereum address and assetData
+ */
export abstract class AbstractBalanceAndProxyAllowanceFetcher {
+ /**
+ * Get balance of assetData for userAddress
+ * @param assetData AssetData for which to fetch the balance
+ * @param userAddress Ethereum address for which to fetch the balance
+ * @return Balance amount in base units
+ */
public abstract async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
+ /**
+ * Get the 0x asset proxy allowance of assetData for userAddress
+ * @param assetData AssetData for which to fetch the allowance
+ * @param userAddress Ethereum address for which to fetch the allowance
+ * @return Allowance amount in base units
+ */
public abstract async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber>;
}
diff --git a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
index 865ea4e43..d2b01c359 100644
--- a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
+++ b/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts
@@ -1,7 +1,22 @@
import { BigNumber } from '@0xproject/utils';
+/**l
+ * An abstract class to be implemented in order to use OrderStateUtils. The class that
+ * implements this interface must be capable of fetching the amount filled of an order
+ * and whether it's been cancelled.
+ */
export abstract class AbstractOrderFilledCancelledFetcher {
+ /**
+ * Get the amount of the order's takerToken amount already filled
+ * @param orderHash OrderHash of order we are interested in
+ * @return FilledTakerAmount
+ */
public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>;
+ /**
+ * Whether an order is cancelled
+ * @param orderHash OrderHash of order we are interested in
+ * @return Whether or not the order is cancelled
+ */
public abstract async isOrderCancelledAsync(orderHash: string): Promise<boolean>;
public abstract getZRXAssetData(): string;
}
diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts
index 2594e6d6d..b303c93dc 100644
--- a/packages/order-utils/src/eip712_utils.ts
+++ b/packages/order-utils/src/eip712_utils.ts
@@ -18,14 +18,14 @@ const EIP712_DOMAIN_SCHEMA: EIP712Schema = {
],
};
-export const EIP712Utils = {
+export const eip712Utils = {
/**
* Compiles the EIP712Schema and returns the hash of the schema.
* @param schema The EIP712 schema.
* @return The hash of the compiled schema
*/
compileSchema(schema: EIP712Schema): Buffer {
- const eip712Schema = EIP712Utils._encodeType(schema);
+ const eip712Schema = eip712Utils._encodeType(schema);
const eip712SchemaHashBuffer = crypto.solSHA3([eip712Schema]);
return eip712SchemaHashBuffer;
},
@@ -36,25 +36,47 @@ export const EIP712Utils = {
* @return The hash of an EIP712 message with domain separator prefixed
*/
createEIP712Message(hashStruct: Buffer, contractAddress: string): Buffer {
- const domainSeparatorHashBuffer = EIP712Utils._getDomainSeparatorHashBuffer(contractAddress);
+ const domainSeparatorHashBuffer = eip712Utils._getDomainSeparatorHashBuffer(contractAddress);
const messageBuff = crypto.solSHA3([EIP191_PREFIX, domainSeparatorHashBuffer, hashStruct]);
return messageBuff;
},
+ /**
+ * Pad an address to 32 bytes
+ * @param address Address to pad
+ * @return padded address
+ */
pad32Address(address: string): Buffer {
const addressBuffer = ethUtil.toBuffer(address);
- const addressPadded = EIP712Utils.pad32Buffer(addressBuffer);
+ const addressPadded = eip712Utils.pad32Buffer(addressBuffer);
return addressPadded;
},
+ /**
+ * Pad an buffer to 32 bytes
+ * @param buffer Address to pad
+ * @return padded buffer
+ */
pad32Buffer(buffer: Buffer): Buffer {
const bufferPadded = ethUtil.setLengthLeft(buffer, EIP712_VALUE_LENGTH);
return bufferPadded;
},
+ /**
+ * Hash together a EIP712 schema with the corresponding data
+ * @param schema EIP712-compliant schema
+ * @param data Data the complies to the schema
+ * @return A buffer containing the SHA256 hash of the schema and encoded data
+ */
+ structHash(schema: EIP712Schema, data: { [key: string]: any }): Buffer {
+ const encodedData = eip712Utils._encodeData(schema, data);
+ const schemaHash = eip712Utils.compileSchema(schema);
+ const hashBuffer = crypto.solSHA3([schemaHash, ...encodedData]);
+ return hashBuffer;
+ },
_getDomainSeparatorSchemaBuffer(): Buffer {
- return EIP712Utils.compileSchema(EIP712_DOMAIN_SCHEMA);
+ return eip712Utils.compileSchema(EIP712_DOMAIN_SCHEMA);
},
_getDomainSeparatorHashBuffer(exchangeAddress: string): Buffer {
- const domainSeparatorSchemaBuffer = EIP712Utils._getDomainSeparatorSchemaBuffer();
- const encodedData = EIP712Utils._encodeData(EIP712_DOMAIN_SCHEMA, {
+ const domainSeparatorSchemaBuffer = eip712Utils._getDomainSeparatorSchemaBuffer();
+ const encodedData = eip712Utils._encodeData(EIP712_DOMAIN_SCHEMA, {
name: EIP712_DOMAIN_NAME,
version: EIP712_DOMAIN_VERSION,
verifyingContract: exchangeAddress,
@@ -77,17 +99,11 @@ export const EIP712Utils = {
} else if (parameter.type === EIP712Types.Uint256) {
encodedValues.push(value);
} else if (parameter.type === EIP712Types.Address) {
- encodedValues.push(EIP712Utils.pad32Address(value));
+ encodedValues.push(eip712Utils.pad32Address(value));
} else {
throw new Error(`Unable to encode ${parameter.type}`);
}
}
return encodedValues;
},
- structHash(schema: EIP712Schema, data: { [key: string]: any }): Buffer {
- const encodedData = EIP712Utils._encodeData(schema, data);
- const schemaHash = EIP712Utils.compileSchema(schema);
- const hashBuffer = crypto.solSHA3([schemaHash, ...encodedData]);
- return hashBuffer;
- },
};
diff --git a/packages/order-utils/src/exchange_transfer_simulator.ts b/packages/order-utils/src/exchange_transfer_simulator.ts
index c3a4f9c2a..81c849c64 100644
--- a/packages/order-utils/src/exchange_transfer_simulator.ts
+++ b/packages/order-utils/src/exchange_transfer_simulator.ts
@@ -33,6 +33,10 @@ const ERR_MSG_MAPPING = {
},
};
+/**
+ * An exchange transfer simulator which simulates asset transfers exactly how the
+ * 0x exchange contract would do them.
+ */
export class ExchangeTransferSimulator {
private readonly _store: AbstractBalanceAndProxyAllowanceLazyStore;
private static _throwValidationError(
@@ -43,6 +47,11 @@ export class ExchangeTransferSimulator {
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
throw new Error(errMsg);
}
+ /**
+ * Instantiate a ExchangeTransferSimulator
+ * @param store A class that implements AbstractBalanceAndProxyAllowanceLazyStore
+ * @return an instance of ExchangeTransferSimulator
+ */
constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
this._store = store;
}
diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts
index 681fbc904..638126af6 100644
--- a/packages/order-utils/src/index.ts
+++ b/packages/order-utils/src/index.ts
@@ -1,27 +1,36 @@
export { orderHashUtils } from './order_hash';
-export {
- isValidSignatureAsync,
- isValidPresignedSignatureAsync,
- isValidWalletSignatureAsync,
- isValidValidatorSignatureAsync,
- isValidECSignature,
- ecSignOrderHashAsync,
- addSignedMessagePrefix,
- parseECSignature,
-} from './signature_utils';
-export { orderFactory } from './order_factory';
-export { constants } from './constants';
-export { crypto } from './crypto';
+export { signatureUtils } from './signature_utils';
export { generatePseudoRandomSalt } from './salt';
-export { CreateOrderOpts, OrderError, EIP712Parameter, EIP712Schema, EIP712Types } from './types';
+export { assetDataUtils } from './asset_data_utils';
+export { eip712Utils } from './eip712_utils';
+export { marketUtils } from './market_utils';
+
+export { OrderStateUtils } from './order_state_utils';
export { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
-export { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store';
-export { OrderFilledCancelledLazyStore } from './store/order_filled_cancelled_lazy_store';
-export { RemainingFillableCalculator } from './remaining_fillable_calculator';
-export { OrderStateUtils } from './order_state_utils';
-export { assetDataUtils } from './asset_data_utils';
-export { EIP712Utils } from './eip712_utils';
+
export { OrderValidationUtils } from './order_validation_utils';
export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
-export { marketUtils } from './market_utils';
+export { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store';
+export { OrderFilledCancelledLazyStore } from './store/order_filled_cancelled_lazy_store';
+
+export { Provider } from 'ethereum-types';
+export {
+ SignedOrder,
+ Order,
+ OrderRelevantState,
+ OrderState,
+ ECSignature,
+ ERC20AssetData,
+ ERC721AssetData,
+ AssetProxyId,
+} from '@0xproject/types';
+export {
+ CreateOrderOpts,
+ OrderError,
+ EIP712Parameter,
+ EIP712Schema,
+ EIP712Types,
+ TradeSide,
+ TransferType,
+} from './types';
diff --git a/packages/order-utils/src/monorepo_scripts/postpublish.ts b/packages/order-utils/src/monorepo_scripts/postpublish.ts
deleted file mode 100644
index dcb99d0f7..000000000
--- a/packages/order-utils/src/monorepo_scripts/postpublish.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { postpublishUtils } from '@0xproject/monorepo-scripts';
-
-import * as packageJSON from '../package.json';
-import * as tsConfigJSON from '../tsconfig.json';
-
-const cwd = `${__dirname}/..`;
-// tslint:disable-next-line:no-floating-promises
-postpublishUtils.runAsync(packageJSON, tsConfigJSON, cwd);
diff --git a/packages/order-utils/src/monorepo_scripts/stage_docs.ts b/packages/order-utils/src/monorepo_scripts/stage_docs.ts
deleted file mode 100644
index e732ac8eb..000000000
--- a/packages/order-utils/src/monorepo_scripts/stage_docs.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { postpublishUtils } from '@0xproject/monorepo-scripts';
-
-import * as packageJSON from '../package.json';
-import * as tsConfigJSON from '../tsconfig.json';
-
-const cwd = `${__dirname}/..`;
-// tslint:disable-next-line:no-floating-promises
-postpublishUtils.publishDocsToStagingAsync(packageJSON, tsConfigJSON, cwd);
diff --git a/packages/order-utils/src/order_factory.ts b/packages/order-utils/src/order_factory.ts
index 4a6f3924b..46a69ae4d 100644
--- a/packages/order-utils/src/order_factory.ts
+++ b/packages/order-utils/src/order_factory.ts
@@ -6,7 +6,7 @@ import * as _ from 'lodash';
import { constants } from './constants';
import { orderHashUtils } from './order_hash';
import { generatePseudoRandomSalt } from './salt';
-import { ecSignOrderHashAsync } from './signature_utils';
+import { signatureUtils } from './signature_utils';
import { CreateOrderOpts } from './types';
export const orderFactory = {
@@ -58,7 +58,12 @@ export const orderFactory = {
createOrderOpts,
);
const orderHash = orderHashUtils.getOrderHashHex(order);
- const signature = await ecSignOrderHashAsync(provider, orderHash, makerAddress, SignerType.Default);
+ const signature = await signatureUtils.ecSignOrderHashAsync(
+ provider,
+ orderHash,
+ makerAddress,
+ SignerType.Default,
+ );
const signedOrder: SignedOrder = _.assign(order, { signature });
return signedOrder;
},
diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts
index 54c500653..8e98f8767 100644
--- a/packages/order-utils/src/order_hash.ts
+++ b/packages/order-utils/src/order_hash.ts
@@ -3,7 +3,7 @@ import { Order, SignedOrder } from '@0xproject/types';
import * as _ from 'lodash';
import { assert } from './assert';
-import { EIP712Utils } from './eip712_utils';
+import { eip712Utils } from './eip712_utils';
import { EIP712Schema, EIP712Types } from './types';
const INVALID_TAKER_FORMAT = 'instance.takerAddress is not of a type(s) string';
@@ -69,11 +69,11 @@ export const orderHashUtils = {
* @return The resulting orderHash from hashing the supplied order as a Buffer
*/
getOrderHashBuffer(order: SignedOrder | Order): Buffer {
- const orderParamsHashBuff = EIP712Utils.structHash(EIP712_ORDER_SCHEMA, order);
- const orderHashBuff = EIP712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress);
+ const orderParamsHashBuff = eip712Utils.structHash(EIP712_ORDER_SCHEMA, order);
+ const orderHashBuff = eip712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress);
return orderHashBuff;
},
_getOrderSchemaBuffer(): Buffer {
- return EIP712Utils.compileSchema(EIP712_ORDER_SCHEMA);
+ return eip712Utils.compileSchema(EIP712_ORDER_SCHEMA);
},
};
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts
index 189bf4180..cb08c5ae2 100644
--- a/packages/order-utils/src/order_state_utils.ts
+++ b/packages/order-utils/src/order_state_utils.ts
@@ -91,6 +91,14 @@ export class OrderStateUtils {
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
}
}
+ /**
+ * Instantiate OrderStateUtils
+ * @param balanceAndProxyAllowanceFetcher A class that is capable of fetching balances
+ * and proxyAllowances for Ethereum addresses. It must implement AbstractBalanceAndProxyAllowanceFetcher
+ * @param orderFilledCancelledFetcher A class that is capable of fetching whether an order
+ * is cancelled and how much of it has been filled. It must implement AbstractOrderFilledCancelledFetcher
+ * @return Instance of OrderStateUtils
+ */
constructor(
balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher,
orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher,
@@ -98,6 +106,14 @@ export class OrderStateUtils {
this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher;
this._orderFilledCancelledFetcher = orderFilledCancelledFetcher;
}
+ /**
+ * Get the orderState for an "open" order (i.e where takerAddress=NULL_ADDRESS)
+ * This method will only check the maker's balance/allowance to calculate the
+ * OrderState.
+ * @param signedOrder The order of interest
+ * @return State relevant to the signedOrder, as well as whether the signedOrder is "valid".
+ * Validity is defined as a non-zero amount of the order can still be filled.
+ */
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
@@ -127,6 +143,11 @@ export class OrderStateUtils {
return orderState;
}
}
+ /**
+ * Get state relevant to an order (i.e makerBalance, makerAllowance, filledTakerAssetAmount, etc...
+ * @param signedOrder Order of interest
+ * @return An instance of OrderRelevantState
+ */
public async getOpenOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
const isMaker = true;
const sidedOrderRelevantState = await this._getSidedOrderRelevantStateAsync(
@@ -149,6 +170,12 @@ export class OrderStateUtils {
};
return orderRelevantState;
}
+ /**
+ * Get the max amount of the supplied order's takerAmount that could still be filled
+ * @param signedOrder Order of interest
+ * @param takerAddress Hypothetical taker of the order
+ * @return fillableTakerAssetAmount
+ */
public async getMaxFillableTakerAssetAmountAsync(
signedOrder: SignedOrder,
takerAddress: string,
@@ -181,32 +208,6 @@ export class OrderStateUtils {
return fillableTakerAssetAmount;
}
- public async getMaxFillableTakerAssetAmountForFailingOrderAsync(
- signedOrder: SignedOrder,
- takerAddress: string,
- ): Promise<BigNumber> {
- // Get min of taker balance & allowance
- const takerAssetBalanceOfTaker = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
- signedOrder.takerAssetData,
- takerAddress,
- );
- const takerAssetAllowanceOfTaker = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
- signedOrder.takerAssetData,
- takerAddress,
- );
- const minTakerAssetAmount = BigNumber.min([takerAssetBalanceOfTaker, takerAssetAllowanceOfTaker]);
-
- // get remainingFillAmount
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const filledTakerAssetAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
- const remainingFillTakerAssetAmount = signedOrder.takerAssetAmount.minus(filledTakerAssetAmount);
-
- if (minTakerAssetAmount.gte(remainingFillTakerAssetAmount)) {
- return remainingFillTakerAssetAmount;
- } else {
- return minTakerAssetAmount;
- }
- }
private async _getSidedOrderRelevantStateAsync(
isMakerSide: boolean,
signedOrder: SignedOrder,
diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts
index 67d747081..972e6f6d6 100644
--- a/packages/order-utils/src/order_validation_utils.ts
+++ b/packages/order-utils/src/order_validation_utils.ts
@@ -9,11 +9,21 @@ import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_f
import { constants } from './constants';
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
import { orderHashUtils } from './order_hash';
-import { isValidSignatureAsync } from './signature_utils';
+import { signatureUtils } from './signature_utils';
import { utils } from './utils';
+/**
+ * A utility class for validating orders
+ */
export class OrderValidationUtils {
private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher;
+ /**
+ * A Typescript implementation mirroring the implementation of isRoundingError in the
+ * Exchange smart contract
+ * @param numerator Numerator value. When used to check an order, pass in `takerAssetFilledAmount`
+ * @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount`
+ * @param target Target value. When used to check an order, pass in `order.makerAssetAmount`
+ */
public static isRoundingError(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
// Solidity's mulmod() in JS
// Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions
@@ -31,6 +41,15 @@ export class OrderValidationUtils {
const isError = errPercentageTimes1000000.gt(1000);
return isError;
}
+ /**
+ * Validate that the maker & taker have sufficient balances/allowances
+ * to fill the supplied order to the fillTakerAssetAmount amount
+ * @param exchangeTradeEmulator ExchangeTradeEmulator to use
+ * @param signedOrder SignedOrder to test
+ * @param fillTakerAssetAmount Amount of takerAsset to fill the signedOrder
+ * @param senderAddress Sender of the fillOrder tx
+ * @param zrxAssetData AssetData for the ZRX token
+ */
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator,
signedOrder: SignedOrder,
@@ -104,9 +123,22 @@ export class OrderValidationUtils {
throw new Error(RevertReason.OrderUnfillable);
}
}
+ /**
+ * Instantiate OrderValidationUtils
+ * @param orderFilledCancelledFetcher A module that implements the AbstractOrderFilledCancelledFetcher
+ * @return An instance of OrderValidationUtils
+ */
constructor(orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher) {
this._orderFilledCancelledFetcher = orderFilledCancelledFetcher;
}
+ /**
+ * Validate if the supplied order is fillable, and throw if it isn't
+ * @param exchangeTradeEmulator ExchangeTradeEmulator instance
+ * @param signedOrder SignedOrder of interest
+ * @param zrxAssetData ZRX assetData
+ * @param expectedFillTakerTokenAmount If supplied, this call will make sure this amount is fillable.
+ * If it isn't supplied, we check if the order is fillable for a non-zero amount
+ */
public async validateOrderFillableOrThrowAsync(
exchangeTradeEmulator: ExchangeTransferSimulator,
signedOrder: SignedOrder,
@@ -132,6 +164,15 @@ export class OrderValidationUtils {
zrxAssetData,
);
}
+ /**
+ * Validate a call to FillOrder and throw if it wouldn't succeed
+ * @param exchangeTradeEmulator ExchangeTradeEmulator to use
+ * @param provider Web3 provider to use for JSON RPC requests
+ * @param signedOrder SignedOrder of interest
+ * @param fillTakerAssetAmount Amount we'd like to fill the order for
+ * @param takerAddress The taker of the order
+ * @param zrxAssetData ZRX asset data
+ */
public async validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator,
provider: Provider,
@@ -147,7 +188,7 @@ export class OrderValidationUtils {
throw new Error(RevertReason.InvalidTakerAmount);
}
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const isValid = await isValidSignatureAsync(
+ const isValid = await signatureUtils.isValidSignatureAsync(
provider,
orderHash,
signedOrder.signature,
@@ -187,6 +228,15 @@ export class OrderValidationUtils {
}
return filledTakerTokenAmount;
}
+ /**
+ * Validate a call to fillOrKillOrder and throw if it would fail
+ * @param exchangeTradeEmulator ExchangeTradeEmulator to use
+ * @param provider Web3 provider to use for JSON RPC requests
+ * @param signedOrder SignedOrder of interest
+ * @param fillTakerAssetAmount Amount we'd like to fill the order for
+ * @param takerAddress The taker of the order
+ * @param zrxAssetData ZRX asset data
+ */
public async validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator,
provider: Provider,
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts
index 870aef2ed..d466bb00d 100644
--- a/packages/order-utils/src/signature_utils.ts
+++ b/packages/order-utils/src/signature_utils.ts
@@ -13,329 +13,353 @@ import { IWalletContract } from './generated_contract_wrappers/i_wallet';
import { OrderError } from './types';
import { utils } from './utils';
-/**
- * Verifies that the provided signature is valid according to the 0x Protocol smart contracts
- * @param data The hex encoded data signed by the supplied signature.
- * @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType].
- * E.g [vrs][SignatureType.EIP712]
- * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
- * @return Whether the signature is valid for the supplied signerAddress and data.
- */
-export async function isValidSignatureAsync(
- provider: Provider,
- data: string,
- signature: string,
- signerAddress: string,
-): Promise<boolean> {
- assert.isWeb3Provider('provider', provider);
- assert.isHexString('data', data);
- assert.isHexString('signature', signature);
- assert.isETHAddressHex('signerAddress', signerAddress);
- const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature);
- if (_.isUndefined(signatureTypeIndexIfExists)) {
- throw new Error(`Unrecognized signatureType in signature: ${signature}`);
- }
-
- switch (signatureTypeIndexIfExists) {
- case SignatureType.Illegal:
- case SignatureType.Invalid:
- return false;
-
- case SignatureType.EIP712: {
- const ecSignature = parseECSignature(signature);
- return isValidECSignature(data, ecSignature, signerAddress);
+export const signatureUtils = {
+ /**
+ * Verifies that the provided signature is valid according to the 0x Protocol smart contracts
+ * @param data The hex encoded data signed by the supplied signature.
+ * @param signature A hex encoded 0x Protocol signature made up of: [TypeSpecificData][SignatureType].
+ * E.g [vrs][SignatureType.EIP712]
+ * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
+ * @return Whether the signature is valid for the supplied signerAddress and data.
+ */
+ async isValidSignatureAsync(
+ provider: Provider,
+ data: string,
+ signature: string,
+ signerAddress: string,
+ ): Promise<boolean> {
+ assert.isWeb3Provider('provider', provider);
+ assert.isHexString('data', data);
+ assert.isHexString('signature', signature);
+ assert.isETHAddressHex('signerAddress', signerAddress);
+ const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature);
+ if (_.isUndefined(signatureTypeIndexIfExists)) {
+ throw new Error(`Unrecognized signatureType in signature: ${signature}`);
}
- case SignatureType.EthSign: {
- const ecSignature = parseECSignature(signature);
- const prefixedMessageHex = addSignedMessagePrefix(data, SignerType.Default);
- return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
- }
+ switch (signatureTypeIndexIfExists) {
+ case SignatureType.Illegal:
+ case SignatureType.Invalid:
+ return false;
- case SignatureType.Caller:
- // HACK: We currently do not "validate" the caller signature type.
- // It can only be validated during Exchange contract execution.
- throw new Error('Caller signature type cannot be validated off-chain');
+ case SignatureType.EIP712: {
+ const ecSignature = signatureUtils.parseECSignature(signature);
+ return signatureUtils.isValidECSignature(data, ecSignature, signerAddress);
+ }
- case SignatureType.Wallet: {
- const isValid = await isValidWalletSignatureAsync(provider, data, signature, signerAddress);
- return isValid;
- }
+ case SignatureType.EthSign: {
+ const ecSignature = signatureUtils.parseECSignature(signature);
+ const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.EthSign);
+ return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
+ }
- case SignatureType.Validator: {
- const isValid = await isValidValidatorSignatureAsync(provider, data, signature, signerAddress);
- return isValid;
- }
+ case SignatureType.Caller:
+ // HACK: We currently do not "validate" the caller signature type.
+ // It can only be validated during Exchange contract execution.
+ throw new Error('Caller signature type cannot be validated off-chain');
- case SignatureType.PreSigned: {
- return isValidPresignedSignatureAsync(provider, data, signerAddress);
- }
+ case SignatureType.Wallet: {
+ const isValid = await signatureUtils.isValidWalletSignatureAsync(
+ provider,
+ data,
+ signature,
+ signerAddress,
+ );
+ return isValid;
+ }
- case SignatureType.Trezor: {
- const prefixedMessageHex = addSignedMessagePrefix(data, SignerType.Trezor);
- const ecSignature = parseECSignature(signature);
- return isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
- }
+ case SignatureType.Validator: {
+ const isValid = await signatureUtils.isValidValidatorSignatureAsync(
+ provider,
+ data,
+ signature,
+ signerAddress,
+ );
+ return isValid;
+ }
- default:
- throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`);
- }
-}
+ case SignatureType.PreSigned: {
+ return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress);
+ }
-/**
- * Verifies that the provided presigned signature is valid according to the 0x Protocol smart contracts
- * @param data The hex encoded data signed by the supplied signature.
- * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned]
- * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
- * @return Whether the data was preSigned by the supplied signerAddress.
- */
-export async function isValidPresignedSignatureAsync(
- provider: Provider,
- data: string,
- signerAddress: string,
-): Promise<boolean> {
- assert.isWeb3Provider('provider', provider);
- assert.isHexString('data', data);
- assert.isETHAddressHex('signerAddress', signerAddress);
- const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
- const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
- return isValid;
-}
-
-/**
- * Verifies that the provided wallet signature is valid according to the 0x Protocol smart contracts
- * @param data The hex encoded data signed by the supplied signature.
- * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned]
- * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
- * @return Whether the data was preSigned by the supplied signerAddress.
- */
-export async function isValidWalletSignatureAsync(
- provider: Provider,
- data: string,
- signature: string,
- signerAddress: string,
-): Promise<boolean> {
- assert.isWeb3Provider('provider', provider);
- assert.isHexString('data', data);
- assert.isHexString('signature', signature);
- assert.isETHAddressHex('signerAddress', signerAddress);
- // tslint:disable-next-line:custom-no-magic-numbers
- const signatureWithoutType = signature.slice(-2);
- const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider);
- const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType);
- return isValid;
-}
-
-/**
- * Verifies that the provided validator signature is valid according to the 0x Protocol smart contracts
- * @param data The hex encoded data signed by the supplied signature.
- * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned]
- * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
- * @return Whether the data was preSigned by the supplied signerAddress.
- */
-export async function isValidValidatorSignatureAsync(
- provider: Provider,
- data: string,
- signature: string,
- signerAddress: string,
-): Promise<boolean> {
- assert.isWeb3Provider('provider', provider);
- assert.isHexString('data', data);
- assert.isHexString('signature', signature);
- assert.isETHAddressHex('signerAddress', signerAddress);
- const validatorSignature = parseValidatorSignature(signature);
- const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
- const isValidatorApproved = await exchangeContract.allowedValidators.callAsync(
- signerAddress,
- validatorSignature.validatorAddress,
- );
- if (!isValidatorApproved) {
- throw new Error(`Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`);
- }
+ case SignatureType.Trezor: {
+ const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Trezor);
+ const ecSignature = signatureUtils.parseECSignature(signature);
+ return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress);
+ }
- const validatorContract = new IValidatorContract(artifacts.IValidator.compilerOutput.abi, signerAddress, provider);
- const isValid = await validatorContract.isValidSignature.callAsync(
- data,
- signerAddress,
- validatorSignature.signature,
- );
- return isValid;
-}
-
-/**
- * Checks if the supplied elliptic curve signature corresponds to signing `data` with
- * the private key corresponding to `signerAddress`
- * @param data The hex encoded data signed by the supplied signature.
- * @param signature An object containing the elliptic curve signature parameters.
- * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
- * @return Whether the ECSignature is valid.
- */
-export function isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
- assert.isHexString('data', data);
- assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
- assert.isETHAddressHex('signerAddress', signerAddress);
-
- const msgHashBuff = ethUtil.toBuffer(data);
- try {
- const pubKey = ethUtil.ecrecover(
- msgHashBuff,
- signature.v,
- ethUtil.toBuffer(signature.r),
- ethUtil.toBuffer(signature.s),
+ default:
+ throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`);
+ }
+ },
+ /**
+ * Verifies that the provided presigned signature is valid according to the 0x Protocol smart contracts
+ * @param provider Web3 provider to use for all JSON RPC requests
+ * @param data The hex encoded data signed by the supplied signature
+ * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
+ * @return Whether the data was preSigned by the supplied signerAddress
+ */
+ async isValidPresignedSignatureAsync(provider: Provider, data: string, signerAddress: string): Promise<boolean> {
+ assert.isWeb3Provider('provider', provider);
+ assert.isHexString('data', data);
+ assert.isETHAddressHex('signerAddress', signerAddress);
+ const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
+ const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
+ return isValid;
+ },
+ /**
+ * Verifies that the provided wallet signature is valid according to the 0x Protocol smart contracts
+ * @param provider Web3 provider to use for all JSON RPC requests
+ * @param data The hex encoded data signed by the supplied signature.
+ * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned]
+ * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
+ * @return Whether the data was preSigned by the supplied signerAddress.
+ */
+ async isValidWalletSignatureAsync(
+ provider: Provider,
+ data: string,
+ signature: string,
+ signerAddress: string,
+ ): Promise<boolean> {
+ assert.isWeb3Provider('provider', provider);
+ assert.isHexString('data', data);
+ assert.isHexString('signature', signature);
+ assert.isETHAddressHex('signerAddress', signerAddress);
+ // tslint:disable-next-line:custom-no-magic-numbers
+ const signatureWithoutType = signature.slice(-2);
+ const walletContract = new IWalletContract(artifacts.IWallet.compilerOutput.abi, signerAddress, provider);
+ const isValid = await walletContract.isValidSignature.callAsync(data, signatureWithoutType);
+ return isValid;
+ },
+ /**
+ * Verifies that the provided validator signature is valid according to the 0x Protocol smart contracts
+ * @param provider Web3 provider to use for all JSON RPC requests
+ * @param data The hex encoded data signed by the supplied signature.
+ * @param signature A hex encoded presigned 0x Protocol signature made up of: [SignatureType.Presigned]
+ * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
+ * @return Whether the data was preSigned by the supplied signerAddress.
+ */
+ async isValidValidatorSignatureAsync(
+ provider: Provider,
+ data: string,
+ signature: string,
+ signerAddress: string,
+ ): Promise<boolean> {
+ assert.isWeb3Provider('provider', provider);
+ assert.isHexString('data', data);
+ assert.isHexString('signature', signature);
+ assert.isETHAddressHex('signerAddress', signerAddress);
+ const validatorSignature = parseValidatorSignature(signature);
+ const exchangeContract = new ExchangeContract(artifacts.Exchange.compilerOutput.abi, signerAddress, provider);
+ const isValidatorApproved = await exchangeContract.allowedValidators.callAsync(
+ signerAddress,
+ validatorSignature.validatorAddress,
);
- const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
- return retrievedAddress === signerAddress;
- } catch (err) {
- return false;
- }
-}
-
-/**
- * Signs an orderHash and returns it's elliptic curve signature and signature type.
- * This method currently supports TestRPC, Geth and Parity above and below V1.6.6
- * @param orderHash Hex encoded orderHash to sign.
- * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
- * must be available via the Provider supplied to 0x.js.
- * @param signerType Different signers add/require different prefixes to be prepended to the message being signed.
- * Since we cannot know ahead of time which signer you are using, you must supply a SignerType.
- * @return A hex encoded string containing the Elliptic curve signature generated by signing the orderHash and the Signature Type.
- */
-export async function ecSignOrderHashAsync(
- provider: Provider,
- orderHash: string,
- signerAddress: string,
- signerType: SignerType,
-): Promise<string> {
- assert.isWeb3Provider('provider', provider);
- assert.isHexString('orderHash', orderHash);
- assert.isETHAddressHex('signerAddress', signerAddress);
- const web3Wrapper = new Web3Wrapper(provider);
- await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
- const normalizedSignerAddress = signerAddress.toLowerCase();
+ if (!isValidatorApproved) {
+ throw new Error(
+ `Validator ${validatorSignature.validatorAddress} was not pre-approved by ${signerAddress}.`,
+ );
+ }
- let msgHashHex = orderHash;
- const prefixedMsgHashHex = addSignedMessagePrefix(orderHash, signerType);
- // Metamask incorrectly implements eth_sign and does not prefix the message as per the spec
- // Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e
- if (signerType === SignerType.Metamask) {
- msgHashHex = prefixedMsgHashHex;
- }
- const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHashHex);
+ const validatorContract = new IValidatorContract(
+ artifacts.IValidator.compilerOutput.abi,
+ signerAddress,
+ provider,
+ );
+ const isValid = await validatorContract.isValidSignature.callAsync(
+ data,
+ signerAddress,
+ validatorSignature.signature,
+ );
+ return isValid;
+ },
+ /**
+ * Checks if the supplied elliptic curve signature corresponds to signing `data` with
+ * the private key corresponding to `signerAddress`
+ * @param data The hex encoded data signed by the supplied signature.
+ * @param signature An object containing the elliptic curve signature parameters.
+ * @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
+ * @return Whether the ECSignature is valid.
+ */
+ isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
+ assert.isHexString('data', data);
+ assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
+ assert.isETHAddressHex('signerAddress', signerAddress);
- // HACK: There is no consensus on whether the signatureHex string should be formatted as
- // v + r + s OR r + s + v, and different clients (even different versions of the same client)
- // return the signature params in different orders. In order to support all client implementations,
- // we parse the signature in both ways, and evaluate if either one is a valid signature.
- // r + s + v is the most prevalent format from eth_sign, so we attempt this first.
- // tslint:disable-next-line:custom-no-magic-numbers
- const validVParamValues = [27, 28];
- const ecSignatureRSV = parseSignatureHexAsRSV(signature);
- if (_.includes(validVParamValues, ecSignatureRSV.v)) {
- const isValidRSVSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureRSV, normalizedSignerAddress);
- if (isValidRSVSignature) {
- const convertedSignatureHex = convertECSignatureToSignatureHex(ecSignatureRSV, signerType);
- return convertedSignatureHex;
+ const msgHashBuff = ethUtil.toBuffer(data);
+ try {
+ const pubKey = ethUtil.ecrecover(
+ msgHashBuff,
+ signature.v,
+ ethUtil.toBuffer(signature.r),
+ ethUtil.toBuffer(signature.s),
+ );
+ const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
+ return retrievedAddress === signerAddress;
+ } catch (err) {
+ return false;
}
- }
- const ecSignatureVRS = parseSignatureHexAsVRS(signature);
- if (_.includes(validVParamValues, ecSignatureVRS.v)) {
- const isValidVRSSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureVRS, normalizedSignerAddress);
- if (isValidVRSSignature) {
- const convertedSignatureHex = convertECSignatureToSignatureHex(ecSignatureVRS, signerType);
- return convertedSignatureHex;
+ },
+ /**
+ * Signs an orderHash and returns it's elliptic curve signature and signature type.
+ * This method currently supports TestRPC, Geth and Parity above and below V1.6.6
+ * @param orderHash Hex encoded orderHash to sign.
+ * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
+ * must be available via the Provider supplied to 0x.js.
+ * @param signerType Different signers add/require different prefixes to be prepended to the message being signed.
+ * Since we cannot know ahead of time which signer you are using, you must supply a SignerType.
+ * @return A hex encoded string containing the Elliptic curve signature generated by signing the orderHash and the Signature Type.
+ */
+ async ecSignOrderHashAsync(
+ provider: Provider,
+ orderHash: string,
+ signerAddress: string,
+ signerType: SignerType,
+ ): Promise<string> {
+ assert.isWeb3Provider('provider', provider);
+ assert.isHexString('orderHash', orderHash);
+ assert.isETHAddressHex('signerAddress', signerAddress);
+ const web3Wrapper = new Web3Wrapper(provider);
+ await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
+ const normalizedSignerAddress = signerAddress.toLowerCase();
+
+ let msgHashHex = orderHash;
+ const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(orderHash, signerType);
+ // Metamask incorrectly implements eth_sign and does not prefix the message as per the spec
+ // Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e
+ if (signerType === SignerType.Metamask) {
+ msgHashHex = prefixedMsgHashHex;
}
- }
+ const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHashHex);
- throw new Error(OrderError.InvalidSignature);
-}
-/**
- * Combines ECSignature with V,R,S and the relevant signature type for use in 0x protocol
- * @param ecSignature The ECSignature of the signed data
- * @param signerType The SignerType of the signed data
- * @return Hex encoded string of signature (v,r,s) with Signature Type
- */
-export function convertECSignatureToSignatureHex(ecSignature: ECSignature, signerType: SignerType): string {
- const signatureBuffer = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ethUtil.toBuffer(ecSignature.r),
- ethUtil.toBuffer(ecSignature.s),
- ]);
- const signatureHex = `0x${signatureBuffer.toString('hex')}`;
- let signatureType;
- switch (signerType) {
- case SignerType.Metamask:
- case SignerType.Ledger:
- case SignerType.Default: {
- signatureType = SignatureType.EthSign;
- break;
+ // HACK: There is no consensus on whether the signatureHex string should be formatted as
+ // v + r + s OR r + s + v, and different clients (even different versions of the same client)
+ // return the signature params in different orders. In order to support all client implementations,
+ // we parse the signature in both ways, and evaluate if either one is a valid signature.
+ // r + s + v is the most prevalent format from eth_sign, so we attempt this first.
+ // tslint:disable-next-line:custom-no-magic-numbers
+ const validVParamValues = [27, 28];
+ const ecSignatureRSV = parseSignatureHexAsRSV(signature);
+ if (_.includes(validVParamValues, ecSignatureRSV.v)) {
+ const isValidRSVSignature = signatureUtils.isValidECSignature(
+ prefixedMsgHashHex,
+ ecSignatureRSV,
+ normalizedSignerAddress,
+ );
+ if (isValidRSVSignature) {
+ const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(
+ ecSignatureRSV,
+ signerType,
+ );
+ return convertedSignatureHex;
+ }
}
- case SignerType.Trezor: {
- signatureType = SignatureType.Trezor;
- break;
+ const ecSignatureVRS = parseSignatureHexAsVRS(signature);
+ if (_.includes(validVParamValues, ecSignatureVRS.v)) {
+ const isValidVRSSignature = signatureUtils.isValidECSignature(
+ prefixedMsgHashHex,
+ ecSignatureVRS,
+ normalizedSignerAddress,
+ );
+ if (isValidVRSSignature) {
+ const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(
+ ecSignatureVRS,
+ signerType,
+ );
+ return convertedSignatureHex;
+ }
}
- default:
- throw new Error(`Unrecognized SignerType: ${signerType}`);
- }
- const signatureWithType = convertToSignatureWithType(signatureHex, signatureType);
- return signatureWithType;
-}
-/**
- * Combines the signature proof and the Signature Type.
- * @param signature The hex encoded signature proof
- * @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc.
- * @return Hex encoded string of signature proof with Signature Type
- */
-export function convertToSignatureWithType(signature: string, signatureType: SignatureType): string {
- const signatureBuffer = Buffer.concat([ethUtil.toBuffer(signature), ethUtil.toBuffer(signatureType)]);
- const signatureHex = `0x${signatureBuffer.toString('hex')}`;
- return signatureHex;
-}
-/**
- * Adds the relevant prefix to the message being signed.
- * @param message Message to sign
- * @param signerType The type of message prefix to add for a given SignerType. Different signers expect
- * specific message prefixes.
- * @return Prefixed message
- */
-export function addSignedMessagePrefix(message: string, signerType: SignerType = SignerType.Default): string {
- assert.isString('message', message);
- assert.doesBelongToStringEnum('signerType', signerType, SignerType);
- switch (signerType) {
- case SignerType.Metamask:
- case SignerType.Ledger:
- case SignerType.Default: {
- const msgBuff = ethUtil.toBuffer(message);
- const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff);
- const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
- return prefixedMsgHex;
+
+ throw new Error(OrderError.InvalidSignature);
+ },
+ /**
+ * Combines ECSignature with V,R,S and the relevant signature type for use in 0x protocol
+ * @param ecSignature The ECSignature of the signed data
+ * @param signerType The SignerType of the signed data
+ * @return Hex encoded string of signature (v,r,s) with Signature Type
+ */
+ convertECSignatureToSignatureHex(ecSignature: ECSignature, signerType: SignerType): string {
+ const signatureBuffer = Buffer.concat([
+ ethUtil.toBuffer(ecSignature.v),
+ ethUtil.toBuffer(ecSignature.r),
+ ethUtil.toBuffer(ecSignature.s),
+ ]);
+ const signatureHex = `0x${signatureBuffer.toString('hex')}`;
+ let signatureType;
+ switch (signerType) {
+ case SignerType.Metamask:
+ case SignerType.Ledger:
+ case SignerType.Default: {
+ signatureType = SignatureType.EthSign;
+ break;
+ }
+ case SignerType.Trezor: {
+ signatureType = SignatureType.Trezor;
+ break;
+ }
+ default:
+ throw new Error(`Unrecognized SignerType: ${signerType}`);
}
- case SignerType.Trezor: {
- const msgBuff = ethUtil.toBuffer(message);
- const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff);
- const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
- return prefixedMsgHex;
+ const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, signatureType);
+ return signatureWithType;
+ },
+ /**
+ * Combines the signature proof and the Signature Type.
+ * @param signature The hex encoded signature proof
+ * @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc.
+ * @return Hex encoded string of signature proof with Signature Type
+ */
+ convertToSignatureWithType(signature: string, signatureType: SignatureType): string {
+ const signatureBuffer = Buffer.concat([ethUtil.toBuffer(signature), ethUtil.toBuffer(signatureType)]);
+ const signatureHex = `0x${signatureBuffer.toString('hex')}`;
+ return signatureHex;
+ },
+ /**
+ * Adds the relevant prefix to the message being signed.
+ * @param message Message to sign
+ * @param signerType The type of message prefix to add for a given SignerType. Different signers expect
+ * specific message prefixes.
+ * @return Prefixed message
+ */
+ addSignedMessagePrefix(message: string, signerType: SignerType = SignerType.Default): string {
+ assert.isString('message', message);
+ assert.doesBelongToStringEnum('signerType', signerType, SignerType);
+ switch (signerType) {
+ case SignerType.Metamask:
+ case SignerType.Ledger:
+ case SignerType.Default: {
+ const msgBuff = ethUtil.toBuffer(message);
+ const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff);
+ const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
+ return prefixedMsgHex;
+ }
+ case SignerType.Trezor: {
+ const msgBuff = ethUtil.toBuffer(message);
+ const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff);
+ const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff);
+ return prefixedMsgHex;
+ }
+ default:
+ throw new Error(`Unrecognized SignerType: ${signerType}`);
}
- default:
- throw new Error(`Unrecognized SignerType: ${signerType}`);
- }
-}
-
-/**
- * Parse a 0x protocol hex-encoded signature string into it's ECSignature components
- * @param signature A hex encoded ecSignature 0x Protocol signature
- * @return An ECSignature object with r,s,v parameters
- */
-export function parseECSignature(signature: string): ECSignature {
- assert.isHexString('signature', signature);
- const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
- assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
+ },
+ /**
+ * Parse a 0x protocol hex-encoded signature string into it's ECSignature components
+ * @param signature A hex encoded ecSignature 0x Protocol signature
+ * @return An ECSignature object with r,s,v parameters
+ */
+ parseECSignature(signature: string): ECSignature {
+ assert.isHexString('signature', signature);
+ const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor];
+ assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes);
- // tslint:disable-next-line:custom-no-magic-numbers
- const vrsHex = signature.slice(0, -2);
- const ecSignature = parseSignatureHexAsVRS(vrsHex);
+ // tslint:disable-next-line:custom-no-magic-numbers
+ const vrsHex = signature.slice(0, -2);
+ const ecSignature = parseSignatureHexAsVRS(vrsHex);
- return ecSignature;
-}
+ return ecSignature;
+ },
+};
function hashTrezorPersonalMessage(message: Buffer): Buffer {
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength));
diff --git a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
index 5a2c1d7ff..8a65178b0 100644
--- a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
+++ b/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts
@@ -21,11 +21,21 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
[userAddress: string]: BigNumber;
};
};
+ /**
+ * Instantiates a BalanceAndProxyAllowanceLazyStore
+ * @param balanceAndProxyAllowanceFetcher Class the implements the AbstractBalanceAndProxyAllowanceFetcher
+ * @return Instance of BalanceAndProxyAllowanceLazyStore
+ */
constructor(balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher) {
this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher;
this._balance = {};
this._proxyAllowance = {};
}
+ /**
+ * Get a users balance of an asset
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
if (_.isUndefined(this._balance[assetData]) || _.isUndefined(this._balance[assetData][userAddress])) {
const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, userAddress);
@@ -34,12 +44,22 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
const cachedBalance = this._balance[assetData][userAddress];
return cachedBalance;
}
+ /**
+ * Set the balance of an asset for a user
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public setBalance(assetData: string, userAddress: string, balance: BigNumber): void {
if (_.isUndefined(this._balance[assetData])) {
this._balance[assetData] = {};
}
this._balance[assetData][userAddress] = balance;
}
+ /**
+ * Clear the balance of an asset for a user
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public deleteBalance(assetData: string, userAddress: string): void {
if (!_.isUndefined(this._balance[assetData])) {
delete this._balance[assetData][userAddress];
@@ -48,6 +68,11 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
}
}
}
+ /**
+ * Get the 0x asset proxy allowance
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
if (
_.isUndefined(this._proxyAllowance[assetData]) ||
@@ -62,12 +87,22 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
const cachedProxyAllowance = this._proxyAllowance[assetData][userAddress];
return cachedProxyAllowance;
}
+ /**
+ * Set the 0x asset proxy allowance
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void {
if (_.isUndefined(this._proxyAllowance[assetData])) {
this._proxyAllowance[assetData] = {};
}
this._proxyAllowance[assetData][userAddress] = proxyAllowance;
}
+ /**
+ * Clear the 0x asset proxy allowance
+ * @param assetData AssetData of interest
+ * @param userAddress Ethereum address of interest
+ */
public deleteProxyAllowance(assetData: string, userAddress: string): void {
if (!_.isUndefined(this._proxyAllowance[assetData])) {
delete this._proxyAllowance[assetData][userAddress];
@@ -76,6 +111,11 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
}
}
}
+ /**
+ * Clear all ERC721 0x proxy allowances a user has on all items of a specific ERC721 contract
+ * @param tokenAddress ERc721 token address
+ * @param userAddress Owner Ethereum address
+ */
public deleteAllERC721ProxyAllowance(tokenAddress: string, userAddress: string): void {
for (const assetData in this._proxyAllowance) {
if (this._proxyAllowance.hasOwnProperty(assetData)) {
@@ -90,6 +130,9 @@ export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProx
}
}
}
+ /**
+ * Delete all balances & allowances
+ */
public deleteAll(): void {
this._balance = {};
this._proxyAllowance = {};
diff --git a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts b/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
index 336c6d0ba..6155c2064 100644
--- a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
+++ b/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts
@@ -15,11 +15,21 @@ export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancell
private _isCancelled: {
[orderHash: string]: boolean;
};
+ /**
+ * Instantiate a OrderFilledCancelledLazyStore
+ * @param orderFilledCancelledFetcher Class instance that implements the AbstractOrderFilledCancelledFetcher
+ * @returns An instance of OrderFilledCancelledLazyStore
+ */
constructor(orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher) {
this._orderFilledCancelledFetcher = orderFilledCancelledFetcher;
this._filledTakerAmount = {};
this._isCancelled = {};
}
+ /**
+ * Get the filledTakerAssetAmount of an order
+ * @param orderHash OrderHash from order of interest
+ * @return filledTakerAssetAmount
+ */
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
if (_.isUndefined(this._filledTakerAmount[orderHash])) {
const filledTakerAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
@@ -28,12 +38,26 @@ export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancell
const cachedFilledTakerAmount = this._filledTakerAmount[orderHash];
return cachedFilledTakerAmount;
}
+ /**
+ * Set the filledTakerAssetAmount of an order
+ * @param orderHash OrderHash from order of interest
+ * @param filledTakerAmount Desired filledTakerAssetAmount
+ */
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
this._filledTakerAmount[orderHash] = filledTakerAmount;
}
+ /**
+ * Clear the filledTakerAssetAmount of an order
+ * @param orderHash OrderHash from order of interest
+ */
public deleteFilledTakerAmount(orderHash: string): void {
delete this._filledTakerAmount[orderHash];
}
+ /**
+ * Check if an order has been cancelled
+ * @param orderHash OrderHash from order of interest
+ * @return Whether the order has been cancelled
+ */
public async getIsCancelledAsync(orderHash: string): Promise<boolean> {
if (_.isUndefined(this._isCancelled[orderHash])) {
const isCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
@@ -42,22 +66,43 @@ export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancell
const cachedIsCancelled = this._isCancelled[orderHash]; // tslint:disable-line:boolean-naming
return cachedIsCancelled;
}
+ /**
+ * Set whether an order has been cancelled or not
+ * @param orderHash OrderHash from order of interest
+ * @param isCancelled Whether this order should be cancelled or not
+ */
public setIsCancelled(orderHash: string, isCancelled: boolean): void {
this._isCancelled[orderHash] = isCancelled;
}
+ /**
+ * Clear whether the order has been cancelled if already set
+ * @param orderHash OrderHash from order of interest
+ */
public deleteIsCancelled(orderHash: string): void {
delete this._isCancelled[orderHash];
}
+ /**
+ * Clear all filled/cancelled state
+ */
public deleteAll(): void {
this.deleteAllFilled();
this.deleteAllIsCancelled();
}
+ /**
+ * Clear all cancelled state
+ */
public deleteAllIsCancelled(): void {
this._isCancelled = {};
}
+ /**
+ * Clear all filled state
+ */
public deleteAllFilled(): void {
this._filledTakerAmount = {};
}
+ /**
+ * Get the ZRX assetData
+ */
public getZRXAssetData(): string {
const zrxAssetData = this._orderFilledCancelledFetcher.getZRXAssetData();
return zrxAssetData;
diff --git a/packages/order-utils/test/order_hash_test.ts b/packages/order-utils/test/order_hash_test.ts
index 0a6be83d0..3fdbbad21 100644
--- a/packages/order-utils/test/order_hash_test.ts
+++ b/packages/order-utils/test/order_hash_test.ts
@@ -3,7 +3,9 @@ import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
import 'mocha';
-import { constants, orderHashUtils } from '../src';
+import { orderHashUtils } from '../src';
+
+import { constants } from '../src/constants';
import { chaiSetup } from './utils/chai_setup';
diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts
index a25d2afd6..06ff86515 100644
--- a/packages/order-utils/test/signature_utils_test.ts
+++ b/packages/order-utils/test/signature_utils_test.ts
@@ -6,8 +6,8 @@ import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
-import { ecSignOrderHashAsync, generatePseudoRandomSalt } from '../src';
-import { convertECSignatureToSignatureHex, isValidECSignature, isValidSignatureAsync } from '../src/signature_utils';
+import { signatureUtils, generatePseudoRandomSalt } from '../src';
+import { convertECSignatureToSignatureHex, isValidSignatureAsync } from '../src/signature_utils';
import { chaiSetup } from './utils/chai_setup';
import { provider, web3Wrapper } from './utils/web3_wrapper';
@@ -24,12 +24,14 @@ describe('Signature utils', () => {
it("should return false if the data doesn't pertain to the signature & address", async () => {
const bytes32Zeros = '0x0000000000000000000000000000000000000000000000000000000000000000';
- expect(await isValidSignatureAsync(provider, bytes32Zeros, ethSignSignature, address)).to.be.false();
+ expect(
+ await signatureUtils.isValidSignatureAsync(provider, bytes32Zeros, ethSignSignature, address),
+ ).to.be.false();
});
it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
expect(
- await isValidSignatureAsync(provider, dataHex, ethSignSignature, validUnrelatedAddress),
+ await signatureUtils.isValidSignatureAsync(provider, dataHex, ethSignSignature, validUnrelatedAddress),
).to.be.false();
});
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
@@ -37,18 +39,27 @@ describe('Signature utils', () => {
// tslint:disable-next-line:custom-no-magic-numbers
signatureArray[5] = 'C'; // V = 28, instead of 27
const wrongSignature = signatureArray.join('');
- expect(await isValidSignatureAsync(provider, dataHex, wrongSignature, address)).to.be.false();
+ expect(
+ await signatureUtils.isValidSignatureAsync(provider, dataHex, wrongSignature, address),
+ ).to.be.false();
});
it('should throw if signatureType is invalid', () => {
const signatureArray = ethSignSignature.split('');
signatureArray[3] = '9'; // SignatureType w/ index 9 doesn't exist
const signatureWithInvalidType = signatureArray.join('');
- expect(isValidSignatureAsync(provider, dataHex, signatureWithInvalidType, address)).to.be.rejected();
+ expect(
+ signatureUtils.isValidSignatureAsync(provider, dataHex, signatureWithInvalidType, address),
+ ).to.be.rejected();
});
it('should return true for a valid Ecrecover (EthSign) signature', async () => {
- const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, ethSignSignature, address);
+ const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
+ provider,
+ dataHex,
+ ethSignSignature,
+ address,
+ );
expect(isValidSignatureLocal).to.be.true();
});
@@ -57,7 +68,12 @@ describe('Signature utils', () => {
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
const eip712Signature =
'0x1bdde07aac4bf12c12ddbb155919c43eba4146a2cfcf904a862950dbebe332554c6674975603eb5a4eaf8fd7f2e06350267e5b36cda9851a89f8bb49fe2fc9afe202';
- const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, eip712Signature, address);
+ const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
+ provider,
+ dataHex,
+ eip712Signature,
+ address,
+ );
expect(isValidSignatureLocal).to.be.true();
});
@@ -66,7 +82,12 @@ describe('Signature utils', () => {
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
const trezorSignature =
'0x1ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd9908';
- const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, trezorSignature, address);
+ const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync(
+ provider,
+ dataHex,
+ trezorSignature,
+ address,
+ );
expect(isValidSignatureLocal).to.be.true();
});
});
@@ -80,18 +101,18 @@ describe('Signature utils', () => {
const address = '0x0e5cb767cce09a7f3ca594df118aa519be5e2b5a';
it("should return false if the data doesn't pertain to the signature & address", async () => {
- expect(isValidECSignature('0x0', signature, address)).to.be.false();
+ expect(signatureUtils.isValidECSignature('0x0', signature, address)).to.be.false();
});
it("should return false if the address doesn't pertain to the signature & data", async () => {
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
- expect(isValidECSignature(data, signature, validUnrelatedAddress)).to.be.false();
+ expect(signatureUtils.isValidECSignature(data, signature, validUnrelatedAddress)).to.be.false();
});
it("should return false if the signature doesn't pertain to the data & address", async () => {
const wrongSignature = _.assign({}, signature, { v: 28 });
- expect(isValidECSignature(data, wrongSignature, address)).to.be.false();
+ expect(signatureUtils.isValidECSignature(data, wrongSignature, address)).to.be.false();
});
it('should return true if the signature does pertain to the data & address', async () => {
- const isValidSignatureLocal = isValidECSignature(data, signature, address);
+ const isValidSignatureLocal = signatureUtils.isValidECSignature(data, signature, address);
expect(isValidSignatureLocal).to.be.true();
});
});
@@ -124,7 +145,12 @@ describe('Signature utils', () => {
const orderHash = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const expectedSignature =
'0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403';
- const ecSignature = await ecSignOrderHashAsync(provider, orderHash, makerAddress, SignerType.Default);
+ const ecSignature = await signatureUtils.ecSignOrderHashAsync(
+ provider,
+ orderHash,
+ makerAddress,
+ SignerType.Default,
+ );
expect(ecSignature).to.equal(expectedSignature);
});
it('should return the correct Signature for signatureHex concatenated as R + S + V', async () => {
@@ -150,7 +176,12 @@ describe('Signature utils', () => {
}
},
};
- const ecSignature = await ecSignOrderHashAsync(fakeProvider, orderHash, makerAddress, SignerType.Default);
+ const ecSignature = await signatureUtils.ecSignOrderHashAsync(
+ fakeProvider,
+ orderHash,
+ makerAddress,
+ SignerType.Default,
+ );
expect(ecSignature).to.equal(expectedSignature);
});
it('should return the correct Signature for signatureHex concatenated as V + R + S', async () => {
@@ -173,7 +204,12 @@ describe('Signature utils', () => {
},
};
- const ecSignature = await ecSignOrderHashAsync(fakeProvider, orderHash, makerAddress, SignerType.Default);
+ const ecSignature = await signatureUtils.ecSignOrderHashAsync(
+ fakeProvider,
+ orderHash,
+ makerAddress,
+ SignerType.Default,
+ );
expect(ecSignature).to.equal(expectedSignature);
});
// Note this is due to a bug in Metamask where it does not prefix before signing, this is a known issue and is to be fixed in the future
@@ -202,12 +238,22 @@ describe('Signature utils', () => {
},
};
- const ecSignature = await ecSignOrderHashAsync(fakeProvider, orderHash, makerAddress, SignerType.Metamask);
+ const ecSignature = await signatureUtils.ecSignOrderHashAsync(
+ fakeProvider,
+ orderHash,
+ makerAddress,
+ SignerType.Metamask,
+ );
expect(ecSignature).to.equal(expectedSignature);
});
it('should return a valid signature', async () => {
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
- const ecSignature = await ecSignOrderHashAsync(provider, orderHash, makerAddress, SignerType.Default);
+ const ecSignature = await signatureUtils.ecSignOrderHashAsync(
+ provider,
+ orderHash,
+ makerAddress,
+ SignerType.Default,
+ );
const isValidSignature = await isValidSignatureAsync(provider, orderHash, ecSignature, makerAddress);
expect(isValidSignature).to.be.true();