@0x/order-utils
: Add getOrderHash()
, getExchangeTransactionHash()
, getExchangeProxyTransactionHash()
This commit is contained in:
parent
aced474dc5
commit
829a353b14
@ -5,6 +5,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Add ERC20 Transformer utils and export useful constants.",
|
"note": "Add ERC20 Transformer utils and export useful constants.",
|
||||||
"pr": 2604
|
"pr": 2604
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `getOrderHash()`, `getExchangeTransactionHash()`, `getExchangeProxyTransactionHash()`",
|
||||||
|
"pr": 2610
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^3.0.8",
|
"@0x/assert": "^3.0.8",
|
||||||
|
"@0x/contract-addresses": "^4.10.0",
|
||||||
"@0x/contract-wrappers": "^13.7.0",
|
"@0x/contract-wrappers": "^13.7.0",
|
||||||
"@0x/json-schemas": "^5.0.8",
|
"@0x/json-schemas": "^5.0.8",
|
||||||
"@0x/utils": "^5.5.0",
|
"@0x/utils": "^5.5.0",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||||
import { BigNumber, NULL_ADDRESS, NULL_BYTES } from '@0x/utils';
|
import { BigNumber, NULL_ADDRESS, NULL_BYTES } from '@0x/utils';
|
||||||
import { MethodAbi } from 'ethereum-types';
|
import { MethodAbi } from 'ethereum-types';
|
||||||
|
|
||||||
@ -150,6 +151,27 @@ export const constants = {
|
|||||||
{ name: 'transactionSignature', type: 'bytes' },
|
{ name: 'transactionSignature', type: 'bytes' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
MAINNET_EXCHANGE_PROXY_DOMAIN: {
|
||||||
|
name: 'ZeroEx',
|
||||||
|
version: '1.0.0',
|
||||||
|
chainId: 1,
|
||||||
|
verifyingContract: getContractAddressesForChainOrThrow(1).exchangeProxy,
|
||||||
|
},
|
||||||
|
EXCHANGE_PROXY_MTX_SCEHMA: {
|
||||||
|
name: 'MetaTransactionData',
|
||||||
|
parameters: [
|
||||||
|
{ name: 'signer', type: 'address' },
|
||||||
|
{ name: 'sender', type: 'address' },
|
||||||
|
{ name: 'minGasPrice', type: 'uint256' },
|
||||||
|
{ name: 'maxGasPrice', type: 'uint256' },
|
||||||
|
{ name: 'expirationTime', type: 'uint256' },
|
||||||
|
{ name: 'salt', type: 'uint256' },
|
||||||
|
{ name: 'callData', type: 'bytes' },
|
||||||
|
{ name: 'value', type: 'uint256' },
|
||||||
|
{ name: 'feeToken', type: 'address' },
|
||||||
|
{ name: 'feeAmount', type: 'uint256' },
|
||||||
|
],
|
||||||
|
},
|
||||||
ERC20_METHOD_ABI,
|
ERC20_METHOD_ABI,
|
||||||
ERC721_METHOD_ABI,
|
ERC721_METHOD_ABI,
|
||||||
MULTI_ASSET_METHOD_ABI,
|
MULTI_ASSET_METHOD_ABI,
|
||||||
|
@ -5,11 +5,12 @@ import {
|
|||||||
EIP712Object,
|
EIP712Object,
|
||||||
EIP712TypedData,
|
EIP712TypedData,
|
||||||
EIP712Types,
|
EIP712Types,
|
||||||
|
ExchangeProxyMetaTransaction,
|
||||||
Order,
|
Order,
|
||||||
SignedZeroExTransaction,
|
SignedZeroExTransaction,
|
||||||
ZeroExTransaction,
|
ZeroExTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
import { hexUtils, signTypedDataUtils } from '@0x/utils';
|
import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
@ -131,4 +132,18 @@ export const eip712Utils = {
|
|||||||
);
|
);
|
||||||
return typedData;
|
return typedData;
|
||||||
},
|
},
|
||||||
|
createExchangeProxyMetaTransactionTypedData(mtx: ExchangeProxyMetaTransaction): EIP712TypedData {
|
||||||
|
return eip712Utils.createTypedData(
|
||||||
|
constants.EXCHANGE_PROXY_MTX_SCEHMA.name,
|
||||||
|
{
|
||||||
|
MetaTransactionData: constants.EXCHANGE_PROXY_MTX_SCEHMA.parameters,
|
||||||
|
},
|
||||||
|
_.mapValues(
|
||||||
|
_.omit(mtx, 'domain'),
|
||||||
|
// tslint:disable-next-line: custom-no-magic-numbers
|
||||||
|
v => (BigNumber.isBigNumber(v) ? v.toString(10) : v),
|
||||||
|
) as EIP712Object,
|
||||||
|
_domain,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
29
packages/order-utils/src/hash_utils.ts
Normal file
29
packages/order-utils/src/hash_utils.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ExchangeProxyMetaTransaction, Order, ZeroExTransaction } from '@0x/types';
|
||||||
|
import { hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||||
|
|
||||||
|
import { eip712Utils } from './eip712_utils';
|
||||||
|
import { orderHashUtils } from './order_hash_utils';
|
||||||
|
import { transactionHashUtils } from './transaction_hash_utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the EIP712 hash of an order.
|
||||||
|
*/
|
||||||
|
export function getOrderHash(order: Order): string {
|
||||||
|
return orderHashUtils.getOrderHash(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the EIP712 hash of an Exchange meta-transaction.
|
||||||
|
*/
|
||||||
|
export function getExchangeMetaTransactionHash(tx: ZeroExTransaction): string {
|
||||||
|
return transactionHashUtils.getTransactionHash(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the EIP712 hash of an Exchange Proxy meta-transaction.
|
||||||
|
*/
|
||||||
|
export function getExchangeProxyMetaTransactionHash(mtx: ExchangeProxyMetaTransaction): string {
|
||||||
|
return hexUtils.toHex(
|
||||||
|
signTypedDataUtils.generateTypedDataHash(eip712Utils.createExchangeProxyMetaTransactionTypedData(mtx)),
|
||||||
|
);
|
||||||
|
}
|
@ -49,6 +49,8 @@ export {
|
|||||||
ZeroExTransaction,
|
ZeroExTransaction,
|
||||||
SignedZeroExTransaction,
|
SignedZeroExTransaction,
|
||||||
ValidatorSignature,
|
ValidatorSignature,
|
||||||
|
ExchangeProxyMetaTransaction,
|
||||||
|
SignedExchangeProxyMetaTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -77,6 +79,8 @@ export {
|
|||||||
decodeAffiliateFeeTransformerData,
|
decodeAffiliateFeeTransformerData,
|
||||||
} from './transformer_data_encoders';
|
} from './transformer_data_encoders';
|
||||||
|
|
||||||
|
export { getOrderHash, getExchangeMetaTransactionHash, getExchangeProxyMetaTransactionHash } from './hash_utils';
|
||||||
|
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
export const NULL_ADDRESS = constants.NULL_ADDRESS;
|
export const NULL_ADDRESS = constants.NULL_ADDRESS;
|
||||||
export const NULL_BYTES = constants.NULL_BYTES;
|
export const NULL_BYTES = constants.NULL_BYTES;
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import { schemas } from '@0x/json-schemas';
|
import { schemas } from '@0x/json-schemas';
|
||||||
import {
|
import {
|
||||||
ECSignature,
|
ECSignature,
|
||||||
|
ExchangeProxyMetaTransaction,
|
||||||
Order,
|
Order,
|
||||||
SignatureType,
|
SignatureType,
|
||||||
|
SignedExchangeProxyMetaTransaction,
|
||||||
SignedOrder,
|
SignedOrder,
|
||||||
SignedZeroExTransaction,
|
SignedZeroExTransaction,
|
||||||
ValidatorSignature,
|
ValidatorSignature,
|
||||||
ZeroExTransaction,
|
ZeroExTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
import { providerUtils } from '@0x/utils';
|
import { hexUtils, providerUtils } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { SupportedProvider } from 'ethereum-types';
|
import { SupportedProvider } from 'ethereum-types';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
@ -16,6 +18,7 @@ import * as _ from 'lodash';
|
|||||||
|
|
||||||
import { assert } from './assert';
|
import { assert } from './assert';
|
||||||
import { eip712Utils } from './eip712_utils';
|
import { eip712Utils } from './eip712_utils';
|
||||||
|
import { getExchangeProxyMetaTransactionHash } from './hash_utils';
|
||||||
import { orderHashUtils } from './order_hash_utils';
|
import { orderHashUtils } from './order_hash_utils';
|
||||||
import { transactionHashUtils } from './transaction_hash_utils';
|
import { transactionHashUtils } from './transaction_hash_utils';
|
||||||
import { TypedDataError } from './types';
|
import { TypedDataError } from './types';
|
||||||
@ -187,6 +190,96 @@ export const signatureUtils = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Signs an Exchange Proxy meta-transaction and returns a SignedExchangeProxyMetaTransaction.
|
||||||
|
* First `eth_signTypedData` is requested then a fallback to `eth_sign` if not
|
||||||
|
* available on the supplied provider.
|
||||||
|
* @param supportedProvider Web3 provider to use for all JSON RPC requests
|
||||||
|
* @param transaction The ExchangeProxyMetaTransaction to sign.
|
||||||
|
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
|
||||||
|
* must be available via the supplied Provider.
|
||||||
|
* @return A SignedExchangeProxyMetaTransaction containing the order and
|
||||||
|
* elliptic curve signature with Signature Type.
|
||||||
|
*/
|
||||||
|
async ecSignExchangeProxyMetaTransactionAsync(
|
||||||
|
supportedProvider: SupportedProvider,
|
||||||
|
transaction: ExchangeProxyMetaTransaction,
|
||||||
|
signerAddress: string,
|
||||||
|
): Promise<SignedExchangeProxyMetaTransaction> {
|
||||||
|
assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]);
|
||||||
|
try {
|
||||||
|
const signedTransaction = await signatureUtils.ecSignTypedDataExchangeProxyMetaTransactionAsync(
|
||||||
|
supportedProvider,
|
||||||
|
transaction,
|
||||||
|
signerAddress,
|
||||||
|
);
|
||||||
|
return signedTransaction;
|
||||||
|
} catch (err) {
|
||||||
|
// HACK: We are unable to handle specific errors thrown since provider is not an object
|
||||||
|
// under our control. It could be Metamask Web3, Ethers, or any general RPC provider.
|
||||||
|
// We check for a user denying the signature request in a way that supports Metamask and
|
||||||
|
// Coinbase Wallet. Unfortunately for signers with a different error message,
|
||||||
|
// they will receive two signature requests.
|
||||||
|
if (err.message.includes('User denied message signature')) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
const transactionHash = getExchangeProxyMetaTransactionHash(transaction);
|
||||||
|
const signatureHex = await signatureUtils.ecSignHashAsync(
|
||||||
|
supportedProvider,
|
||||||
|
transactionHash,
|
||||||
|
signerAddress,
|
||||||
|
);
|
||||||
|
const signedTransaction = {
|
||||||
|
...transaction,
|
||||||
|
signature: signatureHex,
|
||||||
|
};
|
||||||
|
return signedTransaction;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Signs an Exchange Proxy meta-transaction using `eth_signTypedData` and
|
||||||
|
* returns a SignedZeroExTransaction.
|
||||||
|
* @param supportedProvider Web3 provider to use for all JSON RPC requests
|
||||||
|
* @param transaction The Exchange Proxy transaction to sign.
|
||||||
|
* @param signerAddress The hex encoded Ethereum address you wish
|
||||||
|
* to sign it with. This address must be available via the supplied Provider.
|
||||||
|
* @return A SignedExchangeProxyMetaTransaction containing the
|
||||||
|
* ExchangeProxyMetaTransaction and elliptic curve signature with Signature Type.
|
||||||
|
*/
|
||||||
|
async ecSignTypedDataExchangeProxyMetaTransactionAsync(
|
||||||
|
supportedProvider: SupportedProvider,
|
||||||
|
transaction: ExchangeProxyMetaTransaction,
|
||||||
|
signerAddress: string,
|
||||||
|
): Promise<SignedExchangeProxyMetaTransaction> {
|
||||||
|
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||||
|
assert.isETHAddressHex('signerAddress', signerAddress);
|
||||||
|
assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]);
|
||||||
|
const web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper);
|
||||||
|
const normalizedSignerAddress = signerAddress.toLowerCase();
|
||||||
|
const typedData = eip712Utils.createExchangeProxyMetaTransactionTypedData(transaction);
|
||||||
|
try {
|
||||||
|
const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData);
|
||||||
|
const ecSignatureRSV = parseSignatureHexAsRSV(signature);
|
||||||
|
const signatureHex = hexUtils.concat(
|
||||||
|
ecSignatureRSV.v,
|
||||||
|
ecSignatureRSV.r,
|
||||||
|
ecSignatureRSV.s,
|
||||||
|
SignatureType.EIP712,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...transaction,
|
||||||
|
signature: signatureHex,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
// Detect if Metamask to transition users to the MetamaskSubprovider
|
||||||
|
if ((provider as any).isMetaMask) {
|
||||||
|
throw new Error(TypedDataError.InvalidMetamaskSigner);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Signs a hash using `eth_sign` and returns its elliptic curve signature and signature type.
|
* Signs a hash using `eth_sign` and returns its elliptic curve signature and signature type.
|
||||||
* @param supportedProvider Web3 provider to use for all JSON RPC requests
|
* @param supportedProvider Web3 provider to use for all JSON RPC requests
|
||||||
@ -245,12 +338,7 @@ export const signatureUtils = {
|
|||||||
* @return Hex encoded string of signature (v,r,s) with Signature Type
|
* @return Hex encoded string of signature (v,r,s) with Signature Type
|
||||||
*/
|
*/
|
||||||
convertECSignatureToSignatureHex(ecSignature: ECSignature): string {
|
convertECSignatureToSignatureHex(ecSignature: ECSignature): string {
|
||||||
const signatureBuffer = Buffer.concat([
|
const signatureHex = hexUtils.concat(ecSignature.v, ecSignature.r, ecSignature.s);
|
||||||
ethUtil.toBuffer(ecSignature.v),
|
|
||||||
ethUtil.toBuffer(ecSignature.r),
|
|
||||||
ethUtil.toBuffer(ecSignature.s),
|
|
||||||
]);
|
|
||||||
const signatureHex = `0x${signatureBuffer.toString('hex')}`;
|
|
||||||
const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, SignatureType.EthSign);
|
const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, SignatureType.EthSign);
|
||||||
return signatureWithType;
|
return signatureWithType;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user