diff options
Diffstat (limited to 'packages/order-utils')
-rw-r--r-- | packages/order-utils/src/eip712_utils.ts | 6 | ||||
-rw-r--r-- | packages/order-utils/src/order_hash.ts | 2 | ||||
-rw-r--r-- | packages/order-utils/src/signature_utils.ts | 50 | ||||
-rw-r--r-- | packages/order-utils/test/signature_utils_test.ts | 55 |
4 files changed, 98 insertions, 15 deletions
diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts index b303c93dc..01f1e930e 100644 --- a/packages/order-utils/src/eip712_utils.ts +++ b/packages/order-utils/src/eip712_utils.ts @@ -5,11 +5,11 @@ import { crypto } from './crypto'; import { EIP712Schema, EIP712Types } from './types'; const EIP191_PREFIX = '\x19\x01'; -const EIP712_DOMAIN_NAME = '0x Protocol'; -const EIP712_DOMAIN_VERSION = '2'; const EIP712_VALUE_LENGTH = 32; +export const EIP712_DOMAIN_NAME = '0x Protocol'; +export const EIP712_DOMAIN_VERSION = '2'; -const EIP712_DOMAIN_SCHEMA: EIP712Schema = { +export const EIP712_DOMAIN_SCHEMA: EIP712Schema = { name: 'EIP712Domain', parameters: [ { name: 'name', type: EIP712Types.String }, diff --git a/packages/order-utils/src/order_hash.ts b/packages/order-utils/src/order_hash.ts index 8e98f8767..151c1f801 100644 --- a/packages/order-utils/src/order_hash.ts +++ b/packages/order-utils/src/order_hash.ts @@ -8,7 +8,7 @@ import { EIP712Schema, EIP712Types } from './types'; const INVALID_TAKER_FORMAT = 'instance.takerAddress is not of a type(s) string'; -const EIP712_ORDER_SCHEMA: EIP712Schema = { +export const EIP712_ORDER_SCHEMA: EIP712Schema = { name: 'Order', parameters: [ { name: 'makerAddress', type: EIP712Types.Address }, diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 3b656d3fc..05c673ae2 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, SignatureType, SignerType, ValidatorSignature } from '@0xproject/types'; +import { ECSignature, Order, SignatureType, SignerType, ValidatorSignature } from '@0xproject/types'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; @@ -7,9 +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 './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 } from './order_hash'; import { OrderError } from './types'; import { utils } from './utils'; @@ -192,6 +194,52 @@ export const signatureUtils = { } }, /** + * Signs an order using `eth_signTypedData` and returns it's elliptic curve signature and signature type. + * This method currently supports Ganache. + * @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. + */ + async ecSignOrderAsync(provider: Provider, order: Order, signerAddress: string): Promise<string> { + assert.isWeb3Provider('provider', provider); + assert.isETHAddressHex('signerAddress', signerAddress); + const web3Wrapper = new Web3Wrapper(provider); + await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); + const normalizedSignerAddress = signerAddress.toLowerCase(); + 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: { + ...order, + salt: order.salt.toString(), + makerFee: order.makerFee.toString(), + takerFee: order.takerFee.toString(), + makerAssetAmount: order.makerAssetAmount.toString(), + takerAssetAmount: order.takerAssetAmount.toString(), + expirationTimeSeconds: order.expirationTimeSeconds.toString(), + }, + primaryType: 'Order', + }; + const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData); + const ecSignatureRSV = parseSignatureHexAsRSV(signature); + const signatureBuffer = Buffer.concat([ + ethUtil.toBuffer(ecSignatureRSV.v), + ethUtil.toBuffer(ecSignatureRSV.r), + ethUtil.toBuffer(ecSignatureRSV.s), + ethUtil.toBuffer(SignatureType.EIP712), + ]); + const signatureHex = `0x${signatureBuffer.toString('hex')}`; + return signatureHex; + }, + /** * 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. diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 2ca1109a1..40ce16165 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -1,12 +1,13 @@ -import { SignerType } from '@0xproject/types'; +import { Order, SignatureType, SignerType } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import { JSONRPCErrorCallback, JSONRPCRequestPayload } from 'ethereum-types'; +import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import 'mocha'; -import * as Sinon from 'sinon'; -import { generatePseudoRandomSalt } from '../src'; +import { generatePseudoRandomSalt, orderHashUtils } from '../src'; +import { constants } from '../src/constants'; import { signatureUtils } from '../src/signature_utils'; import { chaiSetup } from './utils/chai_setup'; @@ -115,19 +116,53 @@ describe('Signature utils', () => { expect(salt.lessThan(twoPow256)).to.be.true(); }); }); - describe('#ecSignOrderHashAsync', () => { - let stubs: Sinon.SinonStub[] = []; + describe('#ecSignOrderAsync', () => { let makerAddress: string; + const fakeExchangeContractAddress = '0x1dc4c1cefef38a777b15aa20260a54e584b16c48'; + let order: Order; before(async () => { const availableAddreses = await web3Wrapper.getAvailableAddressesAsync(); makerAddress = availableAddreses[0]; + order = { + makerAddress, + takerAddress: constants.NULL_ADDRESS, + senderAddress: constants.NULL_ADDRESS, + feeRecipientAddress: constants.NULL_ADDRESS, + makerAssetData: constants.NULL_ADDRESS, + takerAssetData: constants.NULL_ADDRESS, + exchangeAddress: fakeExchangeContractAddress, + salt: new BigNumber(0), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + makerAssetAmount: new BigNumber(0), + takerAssetAmount: new BigNumber(0), + expirationTimeSeconds: new BigNumber(0), + }; }); - afterEach(() => { - // clean up any stubs after the test has completed - _.each(stubs, s => s.restore()); - stubs = []; + it('should result in the same signature as signing order hash without prefix', async () => { + const orderHashHex = orderHashUtils.getOrderHashHex(order); + const sig = ethUtil.ecsign( + ethUtil.toBuffer(orderHashHex), + Buffer.from('F2F48EE19680706196E2E339E5DA3491186E0C4C5030670656B0E0164837257D', 'hex'), + ); + const signatureBuffer = Buffer.concat([ + ethUtil.toBuffer(sig.v), + ethUtil.toBuffer(sig.r), + ethUtil.toBuffer(sig.s), + ethUtil.toBuffer(SignatureType.EIP712), + ]); + const signatureHex = `0x${signatureBuffer.toString('hex')}`; + const eip712Signature = await signatureUtils.ecSignOrderAsync(provider, order, makerAddress); + expect(signatureHex).to.eq(eip712Signature); + }); + }); + describe('#ecSignOrderHashAsync', () => { + let makerAddress: string; + before(async () => { + const availableAddreses = await web3Wrapper.getAvailableAddressesAsync(); + makerAddress = availableAddreses[0]; }); - it('Should return the correct Signature', async () => { + it('should return the correct Signature', async () => { const orderHash = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0'; const expectedSignature = '0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403'; |