diff options
author | Fabio Berger <me@fabioberger.com> | 2018-05-30 07:58:30 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-05-30 07:58:30 +0800 |
commit | 4874d55d03918b47967024777194d88a5f2bc1fc (patch) | |
tree | 4a53834e9424a8b33aa7d0edaf13de11f2e807a3 /packages/contracts/src/utils | |
parent | 10faa474950a902af943b3c51f3703491afa6520 (diff) | |
download | dexon-0x-contracts-4874d55d03918b47967024777194d88a5f2bc1fc.tar.gz dexon-0x-contracts-4874d55d03918b47967024777194d88a5f2bc1fc.tar.zst dexon-0x-contracts-4874d55d03918b47967024777194d88a5f2bc1fc.zip |
Initial refactor of order-utils. Move many utils from contracts into this package.
Diffstat (limited to 'packages/contracts/src/utils')
-rw-r--r-- | packages/contracts/src/utils/address_utils.ts | 4 | ||||
-rw-r--r-- | packages/contracts/src/utils/asset_proxy_utils.ts | 144 | ||||
-rw-r--r-- | packages/contracts/src/utils/crypto.ts | 45 | ||||
-rw-r--r-- | packages/contracts/src/utils/exchange_wrapper.ts | 4 | ||||
-rw-r--r-- | packages/contracts/src/utils/match_order_tester.ts | 15 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_factory.ts | 15 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_utils.ts | 72 | ||||
-rw-r--r-- | packages/contracts/src/utils/signing_utils.ts | 3 | ||||
-rw-r--r-- | packages/contracts/src/utils/transaction_factory.ts | 6 | ||||
-rw-r--r-- | packages/contracts/src/utils/types.ts | 33 |
10 files changed, 25 insertions, 316 deletions
diff --git a/packages/contracts/src/utils/address_utils.ts b/packages/contracts/src/utils/address_utils.ts index dc63459f9..a9fb6921a 100644 --- a/packages/contracts/src/utils/address_utils.ts +++ b/packages/contracts/src/utils/address_utils.ts @@ -1,6 +1,4 @@ -import { generatePseudoRandomSalt } from '@0xproject/order-utils'; - -import { crypto } from './crypto'; +import { crypto, generatePseudoRandomSalt } from '@0xproject/order-utils'; export const addressUtils = { generatePseudoRandomAddress(): string { diff --git a/packages/contracts/src/utils/asset_proxy_utils.ts b/packages/contracts/src/utils/asset_proxy_utils.ts deleted file mode 100644 index c042da5d0..000000000 --- a/packages/contracts/src/utils/asset_proxy_utils.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { BigNumber } from '@0xproject/utils'; -import BN = require('bn.js'); -import ethUtil = require('ethereumjs-util'); - -import { AssetProxyId, ERC20ProxyData, ERC721ProxyData, ProxyData } from './types'; - -export const assetProxyUtils = { - encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer { - return ethUtil.toBuffer(assetProxyId); - }, - decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId { - return ethUtil.bufferToInt(encodedAssetProxyId); - }, - encodeAddress(address: string): Buffer { - if (!ethUtil.isValidAddress(address)) { - throw new Error(`Invalid Address: ${address}`); - } - const encodedAddress = ethUtil.toBuffer(address); - return encodedAddress; - }, - decodeAddress(encodedAddress: Buffer): string { - const address = ethUtil.bufferToHex(encodedAddress); - if (!ethUtil.isValidAddress(address)) { - throw new Error(`Invalid Address: ${address}`); - } - return address; - }, - encodeUint256(value: BigNumber): Buffer { - const formattedValue = new BN(value.toString(10)); - const encodedValue = ethUtil.toBuffer(formattedValue); - const paddedValue = ethUtil.setLengthLeft(encodedValue, 32); - return paddedValue; - }, - decodeUint256(encodedValue: Buffer): BigNumber { - const formattedValue = ethUtil.bufferToHex(encodedValue); - const value = new BigNumber(formattedValue, 16); - return value; - }, - encodeERC20ProxyData(tokenAddress: string): string { - const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC20); - const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress); - const encodedMetadata = Buffer.concat([encodedAssetProxyId, encodedAddress]); - const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata); - return encodedMetadataHex; - }, - decodeERC20ProxyData(proxyData: string): ERC20ProxyData { - const encodedProxyMetadata = ethUtil.toBuffer(proxyData); - if (encodedProxyMetadata.byteLength !== 21) { - throw new Error( - `Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${ - encodedProxyMetadata.byteLength - }`, - ); - } - const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1); - const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId); - if (assetProxyId !== AssetProxyId.ERC20) { - throw new Error( - `Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${ - AssetProxyId.ERC20 - }), but got ${assetProxyId}`, - ); - } - const encodedTokenAddress = encodedProxyMetadata.slice(1, 21); - const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress); - const erc20ProxyData = { - assetProxyId, - tokenAddress, - }; - return erc20ProxyData; - }, - encodeERC721ProxyData(tokenAddress: string, tokenId: BigNumber): string { - const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC721); - const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress); - const encodedTokenId = assetProxyUtils.encodeUint256(tokenId); - const encodedMetadata = Buffer.concat([encodedAssetProxyId, encodedAddress, encodedTokenId]); - const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata); - return encodedMetadataHex; - }, - decodeERC721ProxyData(proxyData: string): ERC721ProxyData { - const encodedProxyMetadata = ethUtil.toBuffer(proxyData); - if (encodedProxyMetadata.byteLength !== 53) { - throw new Error( - `Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${ - encodedProxyMetadata.byteLength - }`, - ); - } - const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1); - const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId); - if (assetProxyId !== AssetProxyId.ERC721) { - throw new Error( - `Could not decode ERC721 Proxy Data. Expected Asset Proxy Id to be ERC721 (${ - AssetProxyId.ERC721 - }), but got ${assetProxyId}`, - ); - } - const encodedTokenAddress = encodedProxyMetadata.slice(1, 21); - const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress); - const encodedTokenId = encodedProxyMetadata.slice(21, 53); - const tokenId = assetProxyUtils.decodeUint256(encodedTokenId); - const erc721ProxyData = { - assetProxyId, - tokenAddress, - tokenId, - }; - return erc721ProxyData; - }, - decodeProxyDataId(proxyData: string): AssetProxyId { - const encodedProxyMetadata = ethUtil.toBuffer(proxyData); - if (encodedProxyMetadata.byteLength < 1) { - throw new Error( - `Could not decode Proxy Data. Expected length of encoded data to be at least 1. Got ${ - encodedProxyMetadata.byteLength - }`, - ); - } - const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1); - const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId); - return assetProxyId; - }, - decodeProxyData(proxyData: string): ProxyData { - const assetProxyId = assetProxyUtils.decodeProxyDataId(proxyData); - switch (assetProxyId) { - case AssetProxyId.ERC20: - const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(proxyData); - const generalizedERC20ProxyData = { - assetProxyId, - tokenAddress: erc20ProxyData.tokenAddress, - }; - return generalizedERC20ProxyData; - case AssetProxyId.ERC721: - const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(proxyData); - const generaliedERC721ProxyData = { - assetProxyId, - tokenAddress: erc721ProxyData.tokenAddress, - data: erc721ProxyData.tokenId, - }; - return generaliedERC721ProxyData; - default: - throw new Error(`Unrecognized asset proxy id: ${assetProxyId}`); - } - }, -}; diff --git a/packages/contracts/src/utils/crypto.ts b/packages/contracts/src/utils/crypto.ts deleted file mode 100644 index 80c5f30a5..000000000 --- a/packages/contracts/src/utils/crypto.ts +++ /dev/null @@ -1,45 +0,0 @@ -import BN = require('bn.js'); -import ABI = require('ethereumjs-abi'); -import ethUtil = require('ethereumjs-util'); -import * as _ from 'lodash'; - -export const crypto = { - /** - * We convert types from JS to Solidity as follows: - * BigNumber -> uint256 - * number -> uint8 - * string -> string - * boolean -> bool - * valid Ethereum address -> address - */ - solSHA3(args: any[]): Buffer { - return crypto._solHash(args, ABI.soliditySHA3); - }, - solSHA256(args: any[]): Buffer { - return crypto._solHash(args, ABI.soliditySHA256); - }, - _solHash(args: any[], hashFunction: (types: string[], values: any[]) => Buffer): Buffer { - const argTypes: string[] = []; - _.each(args, (arg, i) => { - const isNumber = _.isFinite(arg); - if (isNumber) { - argTypes.push('uint8'); - } else if (arg.isBigNumber) { - argTypes.push('uint256'); - args[i] = new BN(arg.toString(10), 10); - } else if (ethUtil.isValidAddress(arg)) { - argTypes.push('address'); - } else if (_.isString(arg)) { - argTypes.push('string'); - } else if (_.isBuffer(arg)) { - argTypes.push('bytes'); - } else if (_.isBoolean(arg)) { - argTypes.push('bool'); - } else { - throw new Error(`Unable to guess arg type: ${arg}`); - } - }); - const hash = hashFunction(argTypes, args); - return hash; - }, -}; diff --git a/packages/contracts/src/utils/exchange_wrapper.ts b/packages/contracts/src/utils/exchange_wrapper.ts index 0446f35d1..f7bd207a4 100644 --- a/packages/contracts/src/utils/exchange_wrapper.ts +++ b/packages/contracts/src/utils/exchange_wrapper.ts @@ -1,4 +1,4 @@ -import { Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; +import { AssetProxyId, Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; @@ -9,7 +9,7 @@ import { constants } from './constants'; import { formatters } from './formatters'; import { logDecoder } from './log_decoder'; import { orderUtils } from './order_utils'; -import { AssetProxyId, OrderInfo, SignedTransaction } from './types'; +import { OrderInfo, SignedTransaction } from './types'; export class ExchangeWrapper { private _exchange: ExchangeContract; diff --git a/packages/contracts/src/utils/match_order_tester.ts b/packages/contracts/src/utils/match_order_tester.ts index 87399b9f6..85348b14d 100644 --- a/packages/contracts/src/utils/match_order_tester.ts +++ b/packages/contracts/src/utils/match_order_tester.ts @@ -1,5 +1,6 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { LogWithDecodedArgs, SignedOrder } from '@0xproject/types'; +import { assetProxyUtils, crypto, orderHashUtils } from '@0xproject/order-utils'; +import { AssetProxyId, LogWithDecodedArgs, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import ethUtil = require('ethereumjs-util'); @@ -14,17 +15,13 @@ import { ExchangeContract, FillContractEventArgs, } from '../contract_wrappers/generated/exchange'; -import { assetProxyUtils } from '../utils/asset_proxy_utils'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; -import { crypto } from '../utils/crypto'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; import { OrderFactory } from '../utils/order_factory'; -import { orderUtils } from '../utils/order_utils'; import { - AssetProxyId, ContractName, ERC20BalancesByOwner, ERC721TokenIdsByOwner, @@ -122,7 +119,7 @@ export class MatchOrderTester { const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress; // Verify Left order preconditions const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderUtils.getOrderHashHex(signedOrderLeft), + orderHashUtils.getOrderHashHex(signedOrderLeft), ); const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft ? initialTakerAssetFilledAmountLeft @@ -130,7 +127,7 @@ export class MatchOrderTester { expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); // Verify Right order preconditions const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderUtils.getOrderHashHex(signedOrderRight), + orderHashUtils.getOrderHashHex(signedOrderRight), ); const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight ? initialTakerAssetFilledAmountRight @@ -181,7 +178,7 @@ export class MatchOrderTester { orderTakerAssetFilledAmountRight: BigNumber, ): Promise<TransferAmounts> { let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderUtils.getOrderHashHex(signedOrderLeft), + orderHashUtils.getOrderHashHex(signedOrderLeft), ); amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft); const amountSoldByLeftMaker = amountBoughtByLeftMaker @@ -192,7 +189,7 @@ export class MatchOrderTester { .dividedToIntegerBy(signedOrderRight.makerAssetAmount); const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker); let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderUtils.getOrderHashHex(signedOrderRight), + orderHashUtils.getOrderHashHex(signedOrderRight), ); amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); const amountSoldByRightMaker = amountBoughtByRightMaker diff --git a/packages/contracts/src/utils/order_factory.ts b/packages/contracts/src/utils/order_factory.ts index f704c26ec..59fc663f4 100644 --- a/packages/contracts/src/utils/order_factory.ts +++ b/packages/contracts/src/utils/order_factory.ts @@ -1,22 +1,21 @@ import { generatePseudoRandomSalt } from '@0xproject/order-utils'; -import { SignedOrder, UnsignedOrder } from '@0xproject/types'; +import { orderHashUtils } from '@0xproject/order-utils'; +import { Order, SignatureType, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { constants } from './constants'; -import { orderUtils } from './order_utils'; import { signingUtils } from './signing_utils'; -import { SignatureType } from './types'; export class OrderFactory { - private _defaultOrderParams: Partial<UnsignedOrder>; + private _defaultOrderParams: Partial<Order>; private _privateKey: Buffer; - constructor(privateKey: Buffer, defaultOrderParams: Partial<UnsignedOrder>) { + constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) { this._defaultOrderParams = defaultOrderParams; this._privateKey = privateKey; } public newSignedOrder( - customOrderParams: Partial<UnsignedOrder> = {}, + customOrderParams: Partial<Order> = {}, signatureType: SignatureType = SignatureType.Ecrecover, ): SignedOrder { const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000)); @@ -27,8 +26,8 @@ export class OrderFactory { takerAddress: constants.NULL_ADDRESS, ...this._defaultOrderParams, ...customOrderParams, - } as any) as UnsignedOrder; - const orderHashBuff = orderUtils.getOrderHashBuff(order); + } as any) as Order; + const orderHashBuff = orderHashUtils.getOrderHashBuff(order); const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType); const signedOrder = { ...order, diff --git a/packages/contracts/src/utils/order_utils.ts b/packages/contracts/src/utils/order_utils.ts index 6d1aaa06b..dd7a04cb6 100644 --- a/packages/contracts/src/utils/order_utils.ts +++ b/packages/contracts/src/utils/order_utils.ts @@ -1,8 +1,7 @@ -import { Order, SignedOrder, UnsignedOrder } from '@0xproject/types'; +import { Order, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import ethUtil = require('ethereumjs-util'); -import { crypto } from './crypto'; import { CancelOrder, MatchOrder } from './types'; export const orderUtils = { @@ -21,6 +20,9 @@ export const orderUtils = { }; return cancel; }, + // TODO: This seems redundant... it currently returns a deep copy w/o signature. + // Question: Should we still have a separate OrderStruct type that simply doesn't + // include the exchangeAddress? Seems like we need to for batch ops... getOrderStruct(signedOrder: SignedOrder): Order { const orderStruct = { senderAddress: signedOrder.senderAddress, @@ -35,74 +37,10 @@ export const orderUtils = { salt: signedOrder.salt, makerAssetData: signedOrder.makerAssetData, takerAssetData: signedOrder.takerAssetData, + exchangeAddress: signedOrder.exchangeAddress, }; return orderStruct; }, - getDomainSeparatorSchemaHex(): string { - const domainSeparatorSchemaHashBuff = crypto.solSHA3(['DomainSeparator(address contract)']); - const schemaHashHex = `0x${domainSeparatorSchemaHashBuff.toString('hex')}`; - return schemaHashHex; - }, - getDomainSeparatorHashHex(exchangeAddress: string): string { - const domainSeparatorHashBuff = crypto.solSHA3([exchangeAddress]); - const domainSeparatorHashHex = `0x${domainSeparatorHashBuff.toString('hex')}`; - return domainSeparatorHashHex; - }, - getOrderSchemaHex(): string { - const orderSchemaHashBuff = crypto.solSHA3([ - 'Order(', - 'address makerAddress,', - 'address takerAddress,', - 'address feeRecipientAddress,', - 'address senderAddress,', - 'uint256 makerAssetAmount,', - 'uint256 takerAssetAmount,', - 'uint256 makerFee,', - 'uint256 takerFee,', - 'uint256 expirationTimeSeconds,', - 'uint256 salt,', - 'bytes makerAssetData,', - 'bytes takerAssetData,', - ')', - ]); - const schemaHashHex = `0x${orderSchemaHashBuff.toString('hex')}`; - return schemaHashHex; - }, - getOrderHashBuff(order: SignedOrder | UnsignedOrder): Buffer { - const makerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.makerAssetData)]); - const takerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.takerAssetData)]); - - const orderParamsHashBuff = crypto.solSHA3([ - order.makerAddress, - order.takerAddress, - order.feeRecipientAddress, - order.senderAddress, - order.makerAssetAmount, - order.takerAssetAmount, - order.makerFee, - order.takerFee, - order.expirationTimeSeconds, - order.salt, - makerAssetDataHash, - takerAssetDataHash, - ]); - const orderParamsHashHex = `0x${orderParamsHashBuff.toString('hex')}`; - const orderSchemaHashHex = orderUtils.getOrderSchemaHex(); - const domainSeparatorHashHex = this.getDomainSeparatorHashHex(order.exchangeAddress); - const domainSeparatorSchemaHex = this.getDomainSeparatorSchemaHex(); - const orderHashBuff = crypto.solSHA3([ - new BigNumber(domainSeparatorSchemaHex), - new BigNumber(domainSeparatorHashHex), - new BigNumber(orderSchemaHashHex), - new BigNumber(orderParamsHashHex), - ]); - return orderHashBuff; - }, - getOrderHashHex(order: SignedOrder | UnsignedOrder): string { - const orderHashBuff = orderUtils.getOrderHashBuff(order); - const orderHashHex = `0x${orderHashBuff.toString('hex')}`; - return orderHashHex; - }, createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder { const fill = { left: orderUtils.getOrderStruct(signedOrderLeft), diff --git a/packages/contracts/src/utils/signing_utils.ts b/packages/contracts/src/utils/signing_utils.ts index 61ab1f138..41d63832e 100644 --- a/packages/contracts/src/utils/signing_utils.ts +++ b/packages/contracts/src/utils/signing_utils.ts @@ -1,7 +1,6 @@ +import { SignatureType } from '@0xproject/types'; import * as ethUtil from 'ethereumjs-util'; -import { SignatureType } from './types'; - export const signingUtils = { signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer { if (signatureType === SignatureType.Ecrecover) { diff --git a/packages/contracts/src/utils/transaction_factory.ts b/packages/contracts/src/utils/transaction_factory.ts index 941bff96d..41907132a 100644 --- a/packages/contracts/src/utils/transaction_factory.ts +++ b/packages/contracts/src/utils/transaction_factory.ts @@ -1,10 +1,10 @@ -import { generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { crypto, generatePseudoRandomSalt } from '@0xproject/order-utils'; +import { SignatureType } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as ethUtil from 'ethereumjs-util'; -import { crypto } from './crypto'; import { signingUtils } from './signing_utils'; -import { SignatureType, SignedTransaction } from './types'; +import { SignedTransaction } from './types'; export class TransactionFactory { private _signer: string; diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 90f90ec27..e4401bd92 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -43,12 +43,6 @@ export interface CancelOrdersBefore { salt: BigNumber; } -export enum AssetProxyId { - INVALID, - ERC20, - ERC721, -} - export interface TransactionDataParams { name: string; abi: AbiDefinition[]; @@ -113,16 +107,6 @@ export enum ContractName { Authorizable = 'Authorizable', } -export enum SignatureType { - Illegal, - Invalid, - Caller, - Ecrecover, - EIP712, - Trezor, - Contract, -} - export interface SignedTransaction { exchangeAddress: string; salt: BigNumber; @@ -158,23 +142,6 @@ export interface OrderInfo { orderTakerAssetFilledAmount: BigNumber; } -export interface ERC20ProxyData { - assetProxyId: AssetProxyId; - tokenAddress: string; -} - -export interface ERC721ProxyData { - assetProxyId: AssetProxyId; - tokenAddress: string; - tokenId: BigNumber; -} - -export interface ProxyData { - assetProxyId: AssetProxyId; - tokenAddress?: string; - data?: any; -} - export interface CancelOrder { order: Order; takerAssetCancelAmount: BigNumber; |