diff options
author | Jacob Evans <jacob@dekz.net> | 2018-10-05 09:45:53 +0800 |
---|---|---|
committer | Jacob Evans <jacob@dekz.net> | 2018-10-05 15:12:17 +0800 |
commit | 75d274f330dc0c18577e764ca77ffb36d5a3f27e (patch) | |
tree | 9a70714a89783dfe58ffa002d39f3967de957bdc /packages/order-utils/src | |
parent | 6e462b7dba61611a5347c9aa181d4ae69294d7af (diff) | |
download | dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar.gz dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar.bz2 dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar.lz dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar.xz dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.tar.zst dexon-sol-tools-75d274f330dc0c18577e764ca77ffb36d5a3f27e.zip |
Return SignedOrder from signing utils.
Create a helper back in EIP712Utils for code cleanup.
Moved constants in order-utils into the constants object
Diffstat (limited to 'packages/order-utils/src')
-rw-r--r-- | packages/order-utils/src/constants.ts | 47 | ||||
-rw-r--r-- | packages/order-utils/src/eip712_utils.ts | 75 | ||||
-rw-r--r-- | packages/order-utils/src/index.ts | 9 | ||||
-rw-r--r-- | packages/order-utils/src/order_hash.ts | 43 | ||||
-rw-r--r-- | packages/order-utils/src/signature_utils.ts | 64 |
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); |