aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/src')
-rw-r--r--packages/order-utils/src/constants.ts47
-rw-r--r--packages/order-utils/src/eip712_utils.ts75
-rw-r--r--packages/order-utils/src/index.ts9
-rw-r--r--packages/order-utils/src/order_hash.ts43
-rw-r--r--packages/order-utils/src/signature_utils.ts64
5 files changed, 154 insertions, 84 deletions
diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts
index 5403606c3..7de20a696 100644
--- a/packages/order-utils/src/constants.ts
+++ b/packages/order-utils/src/constants.ts
@@ -13,16 +13,39 @@ export const constants = {
BASE_16: 16,
INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite
ZERO_AMOUNT: new BigNumber(0),
-};
-
-export const EIP712_DOMAIN_NAME = '0x Protocol';
-export const EIP712_DOMAIN_VERSION = '2';
-
-export const EIP712_DOMAIN_SCHEMA = {
- name: 'EIP712Domain',
- parameters: [
- { name: 'name', type: 'string' },
- { name: 'version', type: 'string' },
- { name: 'verifyingContract', type: 'address' },
- ],
+ EIP712_DOMAIN_NAME: '0x Protocol',
+ EIP712_DOMAIN_VERSION: '2',
+ EIP712_DOMAIN_SCHEMA: {
+ name: 'EIP712Domain',
+ parameters: [
+ { name: 'name', type: 'string' },
+ { name: 'version', type: 'string' },
+ { name: 'verifyingContract', type: 'address' },
+ ],
+ },
+ EIP712_ORDER_SCHEMA: {
+ name: 'Order',
+ parameters: [
+ { name: 'makerAddress', type: 'address' },
+ { name: 'takerAddress', type: 'address' },
+ { name: 'feeRecipientAddress', type: 'address' },
+ { name: 'senderAddress', type: 'address' },
+ { name: 'makerAssetAmount', type: 'uint256' },
+ { name: 'takerAssetAmount', type: 'uint256' },
+ { name: 'makerFee', type: 'uint256' },
+ { name: 'takerFee', type: 'uint256' },
+ { name: 'expirationTimeSeconds', type: 'uint256' },
+ { name: 'salt', type: 'uint256' },
+ { name: 'makerAssetData', type: 'bytes' },
+ { name: 'takerAssetData', type: 'bytes' },
+ ],
+ },
+ EIP712_ZEROEX_TRANSACTION_SCHEMA: {
+ name: 'ZeroExTransaction',
+ parameters: [
+ { name: 'salt', type: 'uint256' },
+ { name: 'signerAddress', type: 'address' },
+ { name: 'data', type: 'bytes' },
+ ],
+ },
};
diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts
new file mode 100644
index 000000000..43b421de7
--- /dev/null
+++ b/packages/order-utils/src/eip712_utils.ts
@@ -0,0 +1,75 @@
+import { EIP712Object, EIP712TypedData, EIP712Types, Order, ZeroExTransaction } from '@0xproject/types';
+import * as _ from 'lodash';
+
+import { constants } from './constants';
+
+export const eip712Utils = {
+ /**
+ * Creates a EIP712TypedData object specific to the 0x protocol for use with signTypedData.
+ * @param primaryType The primary type found in message
+ * @param types The additional types for the data in message
+ * @param message The contents of the message
+ * @param exchangeAddress The address of the exchange contract
+ * @return A typed data object
+ */
+ createTypedData: (
+ primaryType: string,
+ types: EIP712Types,
+ message: EIP712Object,
+ exchangeAddress: string,
+ ): EIP712TypedData => {
+ const typedData = {
+ types: {
+ EIP712Domain: constants.EIP712_DOMAIN_SCHEMA.parameters,
+ ...types,
+ },
+ domain: {
+ name: constants.EIP712_DOMAIN_NAME,
+ version: constants.EIP712_DOMAIN_VERSION,
+ verifyingContract: exchangeAddress,
+ },
+ message,
+ primaryType,
+ };
+ return typedData;
+ },
+ /**
+ * Creates an Order EIP712TypedData object for use with signTypedData.
+ * @param Order the order
+ * @return A typed data object
+ */
+ createOrderTypedData: (order: Order): EIP712TypedData => {
+ const normalizedOrder = _.mapValues(order, value => {
+ return !_.isString(value) ? value.toString() : value;
+ });
+ const typedData = eip712Utils.createTypedData(
+ constants.EIP712_ORDER_SCHEMA.name,
+ { Order: constants.EIP712_ORDER_SCHEMA.parameters },
+ normalizedOrder,
+ order.exchangeAddress,
+ );
+ return typedData;
+ },
+ /**
+ * Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and
+ * 0x Exchange executeTransaction.
+ * @param ZeroExTransaction the 0x transaction
+ * @param exchangeAddress The address of the exchange contract
+ * @return A typed data object
+ */
+ createZeroExTransactionTypedData: (
+ zeroExTransaction: ZeroExTransaction,
+ exchangeAddress: string,
+ ): EIP712TypedData => {
+ const normalizedTransaction = _.mapValues(zeroExTransaction, value => {
+ return !_.isString(value) ? value.toString() : value;
+ });
+ const typedData = eip712Utils.createTypedData(
+ constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.name,
+ { ZeroExTransaction: constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.parameters },
+ normalizedTransaction,
+ exchangeAddress,
+ );
+ return typedData;
+ },
+};
diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts
index 89a843d8f..2e05fdf2b 100644
--- a/packages/order-utils/src/index.ts
+++ b/packages/order-utils/src/index.ts
@@ -18,7 +18,8 @@ export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
export { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store';
export { OrderFilledCancelledLazyStore } from './store/order_filled_cancelled_lazy_store';
-export { EIP712_DOMAIN_NAME, EIP712_DOMAIN_SCHEMA, EIP712_DOMAIN_VERSION } from './constants';
+export { constants } from './constants';
+export { eip712Utils } from './eip712_utils';
export { Provider, JSONRPCRequestPayload, JSONRPCErrorCallback, JSONRPCResponsePayload } from 'ethereum-types';
export {
@@ -34,6 +35,12 @@ export {
OrderStateValid,
OrderStateInvalid,
ExchangeContractErrs,
+ EIP712Parameter,
+ EIP712TypedData,
+ EIP712Types,
+ EIP712Object,
+ EIP712ObjectValue,
+ ZeroExTransaction,
} from '@0xproject/types';
export {
OrderError,
diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts
index 37b9da811..a6dd6688c 100644
--- a/packages/order-utils/src/order_hash.ts
+++ b/packages/order-utils/src/order_hash.ts
@@ -4,28 +4,10 @@ import { signTypedDataUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import { assert } from './assert';
-import { EIP712_DOMAIN_NAME, EIP712_DOMAIN_SCHEMA, EIP712_DOMAIN_VERSION } from './constants';
+import { eip712Utils } from './eip712_utils';
const INVALID_TAKER_FORMAT = 'instance.takerAddress is not of a type(s) string';
-export const EIP712_ORDER_SCHEMA = {
- name: 'Order',
- parameters: [
- { name: 'makerAddress', type: 'address' },
- { name: 'takerAddress', type: 'address' },
- { name: 'feeRecipientAddress', type: 'address' },
- { name: 'senderAddress', type: 'address' },
- { name: 'makerAssetAmount', type: 'uint256' },
- { name: 'takerAssetAmount', type: 'uint256' },
- { name: 'makerFee', type: 'uint256' },
- { name: 'takerFee', type: 'uint256' },
- { name: 'expirationTimeSeconds', type: 'uint256' },
- { name: 'salt', type: 'uint256' },
- { name: 'makerAssetData', type: 'bytes' },
- { name: 'takerAssetData', type: 'bytes' },
- ],
-};
-
export const orderHashUtils = {
/**
* Checks if the supplied hex encoded order hash is valid.
@@ -45,7 +27,7 @@ export const orderHashUtils = {
/**
* Computes the orderHash for a supplied order.
* @param order An object that conforms to the Order or SignedOrder interface definitions.
- * @return The resulting orderHash from hashing the supplied order.
+ * @return Hex encoded string orderHash from hashing the supplied order.
*/
getOrderHashHex(order: SignedOrder | Order): string {
try {
@@ -64,27 +46,12 @@ export const orderHashUtils = {
return orderHashHex;
},
/**
- * Computes the orderHash for a supplied order and returns it as a Buffer
+ * Computes the orderHash for a supplied order
* @param order An object that conforms to the Order or SignedOrder interface definitions.
- * @return The resulting orderHash from hashing the supplied order as a Buffer
+ * @return A Buffer containing the resulting orderHash from hashing the supplied order
*/
getOrderHashBuffer(order: SignedOrder | Order): Buffer {
- const normalizedOrder = _.mapValues(order, value => {
- return _.isObject(value) ? value.toString() : value;
- });
- const typedData = {
- types: {
- EIP712Domain: EIP712_DOMAIN_SCHEMA.parameters,
- Order: EIP712_ORDER_SCHEMA.parameters,
- },
- domain: {
- name: EIP712_DOMAIN_NAME,
- version: EIP712_DOMAIN_VERSION,
- verifyingContract: order.exchangeAddress,
- },
- message: normalizedOrder,
- primaryType: EIP712_ORDER_SCHEMA.name,
- };
+ const typedData = eip712Utils.createOrderTypedData(order);
const orderHashBuff = signTypedDataUtils.signTypedDataHash(typedData);
return orderHashBuff;
},
diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts
index 2d7fcfc9e..8c92b87dd 100644
--- a/packages/order-utils/src/signature_utils.ts
+++ b/packages/order-utils/src/signature_utils.ts
@@ -1,5 +1,5 @@
import { schemas } from '@0xproject/json-schemas';
-import { ECSignature, Order, SignatureType, ValidatorSignature } from '@0xproject/types';
+import { ECSignature, Order, SignatureType, SignedOrder, ValidatorSignature } from '@0xproject/types';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { Provider } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
@@ -7,11 +7,11 @@ import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { assert } from './assert';
-import { EIP712_DOMAIN_NAME, EIP712_DOMAIN_SCHEMA, EIP712_DOMAIN_VERSION } from './constants';
+import { eip712Utils } from './eip712_utils';
import { ExchangeContract } from './generated_contract_wrappers/exchange';
import { IValidatorContract } from './generated_contract_wrappers/i_validator';
import { IWalletContract } from './generated_contract_wrappers/i_wallet';
-import { EIP712_ORDER_SCHEMA, orderHashUtils } from './order_hash';
+import { orderHashUtils } from './order_hash';
import { OrderError } from './types';
import { utils } from './utils';
@@ -195,53 +195,45 @@ export const signatureUtils = {
},
/**
* Signs an order and returns its elliptic curve signature and signature type. First `eth_signTypedData` is requested
- * then a fallback to `eth_sign` if not available on this provider.
+ * then a fallback to `eth_sign` if not available on the supplied provider.
* @param order The Order 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.
- * @return A hex encoded string containing the Elliptic curve signature generated by signing the orderHash and the Signature Type.
+ * must be available via the supplied Provider.
+ * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type.
*/
- async ecSignOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<string> {
+ async ecSignOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<SignedOrder> {
try {
- const signatureHex = signatureUtils.ecSignTypedDataOrderAsync(provider, order, signerAddress);
- return signatureHex;
+ const signedOrder = signatureUtils.ecSignTypedDataOrderAsync(provider, order, signerAddress);
+ return signedOrder;
} catch (err) {
// Fallback to using EthSign when ethSignTypedData is not supported
const orderHash = orderHashUtils.getOrderHashHex(order);
const signatureHex = await signatureUtils.ecSignHashAsync(provider, orderHash, signerAddress);
- return signatureHex;
+ const signedOrder = {
+ ...order,
+ signature: signatureHex,
+ };
+ return signedOrder;
}
},
/**
* Signs an order using `eth_signTypedData` and returns its elliptic curve signature and signature type.
* @param order The Order 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.
- * @return A hex encoded string containing the Elliptic curve signature generated by signing the order with `eth_signTypedData`
- * and the Signature Type.
+ * must be available via the supplied Provider.
+ * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type.
*/
- async ecSignTypedDataOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<string> {
+ async ecSignTypedDataOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<SignedOrder> {
assert.isWeb3Provider('provider', provider);
assert.isETHAddressHex('signerAddress', signerAddress);
const web3Wrapper = new Web3Wrapper(provider);
await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
+ // Detect if Metamask to transition users to the MetamaskSubprovider
+ if ((provider as any).isMetaMask) {
+ throw new Error('Unsupported Provider, please use MetamaskSubprovider.');
+ }
const normalizedSignerAddress = signerAddress.toLowerCase();
- const normalizedOrder = _.mapValues(order, value => {
- return _.isObject(value) ? value.toString() : value;
- });
- const typedData = {
- types: {
- EIP712Domain: EIP712_DOMAIN_SCHEMA.parameters,
- Order: EIP712_ORDER_SCHEMA.parameters,
- },
- domain: {
- name: EIP712_DOMAIN_NAME,
- version: EIP712_DOMAIN_VERSION,
- verifyingContract: order.exchangeAddress,
- },
- message: normalizedOrder,
- primaryType: 'Order',
- };
+ const typedData = eip712Utils.createOrderTypedData(order);
const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData);
const ecSignatureRSV = parseSignatureHexAsRSV(signature);
const signatureBuffer = Buffer.concat([
@@ -251,14 +243,16 @@ export const signatureUtils = {
ethUtil.toBuffer(SignatureType.EIP712),
]);
const signatureHex = `0x${signatureBuffer.toString('hex')}`;
- return signatureHex;
+ return {
+ ...order,
+ signature: signatureHex,
+ };
},
/**
* Signs a hash and returns its elliptic curve signature and signature type.
- * This method currently supports TestRPC, Geth and Parity above and below V1.6.6
* @param msgHash Hex encoded message 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.
+ * must be available via the supplied Provider.
* @return A hex encoded string containing the Elliptic curve signature generated by signing the msgHash and the Signature Type.
*/
async ecSignHashAsync(provider: Provider, msgHash: string, signerAddress: string): Promise<string> {
@@ -268,6 +262,10 @@ export const signatureUtils = {
const web3Wrapper = new Web3Wrapper(provider);
await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
const normalizedSignerAddress = signerAddress.toLowerCase();
+ // Detect if Metamask to transition users to the MetamaskSubprovider
+ if ((provider as any).isMetaMask) {
+ throw new Error('Unsupported Provider, please use MetamaskSubprovider.');
+ }
const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHash);
const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(msgHash);