Return SignedOrder from signing utils.
Create a helper back in EIP712Utils for code cleanup. Moved constants in order-utils into the constants object
This commit is contained in:
@@ -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' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
75
packages/order-utils/src/eip712_utils.ts
Normal file
75
packages/order-utils/src/eip712_utils.ts
Normal file
@@ -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;
|
||||
},
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user