Initial refactor of order-utils. Move many utils from contracts into this package.
This commit is contained in:
parent
10faa47495
commit
4874d55d03
1
.gitignore
vendored
1
.gitignore
vendored
@ -86,6 +86,7 @@ packages/contract-wrappers/src/contract_wrappers/generated/
|
|||||||
packages/metacoin/src/contract_wrappers
|
packages/metacoin/src/contract_wrappers
|
||||||
packages/fill-scenarios/src/generated_contract_wrappers/
|
packages/fill-scenarios/src/generated_contract_wrappers/
|
||||||
packages/order-watcher/src/generated_contract_wrappers/
|
packages/order-watcher/src/generated_contract_wrappers/
|
||||||
|
packages/order-utils/src/generated_contract_wrappers/
|
||||||
packages/migrations/src/v1/contract_wrappers
|
packages/migrations/src/v1/contract_wrappers
|
||||||
packages/migrations/src/v2/contract_wrappers
|
packages/migrations/src/v2/contract_wrappers
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ contract MixinSignatureValidator is
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Mapping of hash => signer => signed
|
// Mapping of hash => signer => signed
|
||||||
mapping(bytes32 => mapping(address => bool)) preSigned;
|
mapping(bytes32 => mapping(address => bool)) public preSigned;
|
||||||
|
|
||||||
/// @dev Approves a hash on-chain using any valid signature type.
|
/// @dev Approves a hash on-chain using any valid signature type.
|
||||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { generatePseudoRandomSalt } from '@0xproject/order-utils';
|
import { crypto, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||||
|
|
||||||
import { crypto } from './crypto';
|
|
||||||
|
|
||||||
export const addressUtils = {
|
export const addressUtils = {
|
||||||
generatePseudoRandomAddress(): string {
|
generatePseudoRandomAddress(): string {
|
||||||
|
@ -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 { BigNumber } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -9,7 +9,7 @@ import { constants } from './constants';
|
|||||||
import { formatters } from './formatters';
|
import { formatters } from './formatters';
|
||||||
import { logDecoder } from './log_decoder';
|
import { logDecoder } from './log_decoder';
|
||||||
import { orderUtils } from './order_utils';
|
import { orderUtils } from './order_utils';
|
||||||
import { AssetProxyId, OrderInfo, SignedTransaction } from './types';
|
import { OrderInfo, SignedTransaction } from './types';
|
||||||
|
|
||||||
export class ExchangeWrapper {
|
export class ExchangeWrapper {
|
||||||
private _exchange: ExchangeContract;
|
private _exchange: ExchangeContract;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
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 { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import ethUtil = require('ethereumjs-util');
|
import ethUtil = require('ethereumjs-util');
|
||||||
@ -14,17 +15,13 @@ import {
|
|||||||
ExchangeContract,
|
ExchangeContract,
|
||||||
FillContractEventArgs,
|
FillContractEventArgs,
|
||||||
} from '../contract_wrappers/generated/exchange';
|
} from '../contract_wrappers/generated/exchange';
|
||||||
import { assetProxyUtils } from '../utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../utils/chai_setup';
|
import { chaiSetup } from '../utils/chai_setup';
|
||||||
import { constants } from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
import { crypto } from '../utils/crypto';
|
|
||||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
||||||
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
||||||
import { OrderFactory } from '../utils/order_factory';
|
import { OrderFactory } from '../utils/order_factory';
|
||||||
import { orderUtils } from '../utils/order_utils';
|
|
||||||
import {
|
import {
|
||||||
AssetProxyId,
|
|
||||||
ContractName,
|
ContractName,
|
||||||
ERC20BalancesByOwner,
|
ERC20BalancesByOwner,
|
||||||
ERC721TokenIdsByOwner,
|
ERC721TokenIdsByOwner,
|
||||||
@ -122,7 +119,7 @@ export class MatchOrderTester {
|
|||||||
const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
|
const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
|
||||||
// Verify Left order preconditions
|
// Verify Left order preconditions
|
||||||
const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrderLeft),
|
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||||
);
|
);
|
||||||
const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft
|
const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft
|
||||||
? initialTakerAssetFilledAmountLeft
|
? initialTakerAssetFilledAmountLeft
|
||||||
@ -130,7 +127,7 @@ export class MatchOrderTester {
|
|||||||
expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft);
|
expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft);
|
||||||
// Verify Right order preconditions
|
// Verify Right order preconditions
|
||||||
const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrderRight),
|
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||||
);
|
);
|
||||||
const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight
|
const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight
|
||||||
? initialTakerAssetFilledAmountRight
|
? initialTakerAssetFilledAmountRight
|
||||||
@ -181,7 +178,7 @@ export class MatchOrderTester {
|
|||||||
orderTakerAssetFilledAmountRight: BigNumber,
|
orderTakerAssetFilledAmountRight: BigNumber,
|
||||||
): Promise<TransferAmounts> {
|
): Promise<TransferAmounts> {
|
||||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrderLeft),
|
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||||
);
|
);
|
||||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft);
|
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft);
|
||||||
const amountSoldByLeftMaker = amountBoughtByLeftMaker
|
const amountSoldByLeftMaker = amountBoughtByLeftMaker
|
||||||
@ -192,7 +189,7 @@ export class MatchOrderTester {
|
|||||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||||
const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker);
|
const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker);
|
||||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrderRight),
|
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||||
);
|
);
|
||||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight);
|
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight);
|
||||||
const amountSoldByRightMaker = amountBoughtByRightMaker
|
const amountSoldByRightMaker = amountBoughtByRightMaker
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
import { generatePseudoRandomSalt } from '@0xproject/order-utils';
|
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 { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
import { orderUtils } from './order_utils';
|
|
||||||
import { signingUtils } from './signing_utils';
|
import { signingUtils } from './signing_utils';
|
||||||
import { SignatureType } from './types';
|
|
||||||
|
|
||||||
export class OrderFactory {
|
export class OrderFactory {
|
||||||
private _defaultOrderParams: Partial<UnsignedOrder>;
|
private _defaultOrderParams: Partial<Order>;
|
||||||
private _privateKey: Buffer;
|
private _privateKey: Buffer;
|
||||||
constructor(privateKey: Buffer, defaultOrderParams: Partial<UnsignedOrder>) {
|
constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) {
|
||||||
this._defaultOrderParams = defaultOrderParams;
|
this._defaultOrderParams = defaultOrderParams;
|
||||||
this._privateKey = privateKey;
|
this._privateKey = privateKey;
|
||||||
}
|
}
|
||||||
public newSignedOrder(
|
public newSignedOrder(
|
||||||
customOrderParams: Partial<UnsignedOrder> = {},
|
customOrderParams: Partial<Order> = {},
|
||||||
signatureType: SignatureType = SignatureType.Ecrecover,
|
signatureType: SignatureType = SignatureType.Ecrecover,
|
||||||
): SignedOrder {
|
): SignedOrder {
|
||||||
const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000));
|
const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000));
|
||||||
@ -27,8 +26,8 @@ export class OrderFactory {
|
|||||||
takerAddress: constants.NULL_ADDRESS,
|
takerAddress: constants.NULL_ADDRESS,
|
||||||
...this._defaultOrderParams,
|
...this._defaultOrderParams,
|
||||||
...customOrderParams,
|
...customOrderParams,
|
||||||
} as any) as UnsignedOrder;
|
} as any) as Order;
|
||||||
const orderHashBuff = orderUtils.getOrderHashBuff(order);
|
const orderHashBuff = orderHashUtils.getOrderHashBuff(order);
|
||||||
const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
|
const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
|
||||||
const signedOrder = {
|
const signedOrder = {
|
||||||
...order,
|
...order,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Order, SignedOrder, UnsignedOrder } from '@0xproject/types';
|
import { Order, SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import ethUtil = require('ethereumjs-util');
|
import ethUtil = require('ethereumjs-util');
|
||||||
|
|
||||||
import { crypto } from './crypto';
|
|
||||||
import { CancelOrder, MatchOrder } from './types';
|
import { CancelOrder, MatchOrder } from './types';
|
||||||
|
|
||||||
export const orderUtils = {
|
export const orderUtils = {
|
||||||
@ -21,6 +20,9 @@ export const orderUtils = {
|
|||||||
};
|
};
|
||||||
return cancel;
|
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 {
|
getOrderStruct(signedOrder: SignedOrder): Order {
|
||||||
const orderStruct = {
|
const orderStruct = {
|
||||||
senderAddress: signedOrder.senderAddress,
|
senderAddress: signedOrder.senderAddress,
|
||||||
@ -35,74 +37,10 @@ export const orderUtils = {
|
|||||||
salt: signedOrder.salt,
|
salt: signedOrder.salt,
|
||||||
makerAssetData: signedOrder.makerAssetData,
|
makerAssetData: signedOrder.makerAssetData,
|
||||||
takerAssetData: signedOrder.takerAssetData,
|
takerAssetData: signedOrder.takerAssetData,
|
||||||
|
exchangeAddress: signedOrder.exchangeAddress,
|
||||||
};
|
};
|
||||||
return orderStruct;
|
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 {
|
createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder {
|
||||||
const fill = {
|
const fill = {
|
||||||
left: orderUtils.getOrderStruct(signedOrderLeft),
|
left: orderUtils.getOrderStruct(signedOrderLeft),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
|
import { SignatureType } from '@0xproject/types';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import { SignatureType } from './types';
|
|
||||||
|
|
||||||
export const signingUtils = {
|
export const signingUtils = {
|
||||||
signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer {
|
signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer {
|
||||||
if (signatureType === SignatureType.Ecrecover) {
|
if (signatureType === SignatureType.Ecrecover) {
|
||||||
|
@ -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 { BigNumber } from '@0xproject/utils';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import { crypto } from './crypto';
|
|
||||||
import { signingUtils } from './signing_utils';
|
import { signingUtils } from './signing_utils';
|
||||||
import { SignatureType, SignedTransaction } from './types';
|
import { SignedTransaction } from './types';
|
||||||
|
|
||||||
export class TransactionFactory {
|
export class TransactionFactory {
|
||||||
private _signer: string;
|
private _signer: string;
|
||||||
|
@ -43,12 +43,6 @@ export interface CancelOrdersBefore {
|
|||||||
salt: BigNumber;
|
salt: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AssetProxyId {
|
|
||||||
INVALID,
|
|
||||||
ERC20,
|
|
||||||
ERC721,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TransactionDataParams {
|
export interface TransactionDataParams {
|
||||||
name: string;
|
name: string;
|
||||||
abi: AbiDefinition[];
|
abi: AbiDefinition[];
|
||||||
@ -113,16 +107,6 @@ export enum ContractName {
|
|||||||
Authorizable = 'Authorizable',
|
Authorizable = 'Authorizable',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SignatureType {
|
|
||||||
Illegal,
|
|
||||||
Invalid,
|
|
||||||
Caller,
|
|
||||||
Ecrecover,
|
|
||||||
EIP712,
|
|
||||||
Trezor,
|
|
||||||
Contract,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SignedTransaction {
|
export interface SignedTransaction {
|
||||||
exchangeAddress: string;
|
exchangeAddress: string;
|
||||||
salt: BigNumber;
|
salt: BigNumber;
|
||||||
@ -158,23 +142,6 @@ export interface OrderInfo {
|
|||||||
orderTakerAssetFilledAmount: BigNumber;
|
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 {
|
export interface CancelOrder {
|
||||||
order: Order;
|
order: Order;
|
||||||
takerAssetCancelAmount: BigNumber;
|
takerAssetCancelAmount: BigNumber;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
|
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||||
|
import { AssetProxyId } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -8,12 +10,10 @@ import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/d
|
|||||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||||
import { AssetProxyId } from '../../src/utils/types';
|
|
||||||
import { provider, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
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 { BigNumber } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@ -17,16 +18,13 @@ import {
|
|||||||
FillContractEventArgs,
|
FillContractEventArgs,
|
||||||
} from '../../src/contract_wrappers/generated/exchange';
|
} from '../../src/contract_wrappers/generated/exchange';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { crypto } from '../../src/utils/crypto';
|
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { orderUtils } from '../../src/utils/order_utils';
|
import { ContractName, ERC20BalancesByOwner, ExchangeStatus } from '../../src/utils/types';
|
||||||
import { AssetProxyId, ContractName, ERC20BalancesByOwner, ExchangeStatus } from '../../src/utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -127,7 +125,6 @@ describe('Exchange core', () => {
|
|||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await blockchainLifecycle.revertAsync();
|
await blockchainLifecycle.revertAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fillOrder', () => {
|
describe('fillOrder', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
@ -141,7 +138,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
@ -151,7 +148,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountAfter1 = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountAfter1 = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountAfter1).to.be.bignumber.equal(fillTakerAssetAmount1);
|
expect(takerAssetFilledAmountAfter1).to.be.bignumber.equal(fillTakerAssetAmount1);
|
||||||
|
|
||||||
@ -161,7 +158,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountAfter2 = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountAfter2 = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountAfter2).to.be.bignumber.equal(takerAssetFilledAmountAfter1);
|
expect(takerAssetFilledAmountAfter2).to.be.bignumber.equal(takerAssetFilledAmountAfter1);
|
||||||
});
|
});
|
||||||
@ -173,7 +170,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
@ -181,7 +178,7 @@ describe('Exchange core', () => {
|
|||||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||||
|
|
||||||
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
||||||
|
|
||||||
@ -226,7 +223,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
@ -234,7 +231,7 @@ describe('Exchange core', () => {
|
|||||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||||
|
|
||||||
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
||||||
|
|
||||||
@ -279,7 +276,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
@ -287,7 +284,7 @@ describe('Exchange core', () => {
|
|||||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||||
|
|
||||||
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
expect(makerAmountBoughtAfter).to.be.bignumber.equal(takerAssetFillAmount);
|
||||||
|
|
||||||
@ -333,7 +330,7 @@ describe('Exchange core', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const takerAssetFilledAmountBefore = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
expect(takerAssetFilledAmountBefore).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
@ -341,7 +338,7 @@ describe('Exchange core', () => {
|
|||||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||||
|
|
||||||
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
const makerAmountBoughtAfter = await exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||||
orderUtils.getOrderHashHex(signedOrder),
|
orderHashUtils.getOrderHashHex(signedOrder),
|
||||||
);
|
);
|
||||||
const expectedMakerAmountBoughtAfter = takerAssetFillAmount.add(takerAssetFilledAmountBefore);
|
const expectedMakerAmountBoughtAfter = takerAssetFillAmount.add(takerAssetFilledAmountBefore);
|
||||||
expect(makerAmountBoughtAfter).to.be.bignumber.equal(expectedMakerAmountBoughtAfter);
|
expect(makerAmountBoughtAfter).to.be.bignumber.equal(expectedMakerAmountBoughtAfter);
|
||||||
@ -441,7 +438,7 @@ describe('Exchange core', () => {
|
|||||||
expect(expectedFilledTakerAssetAmount).to.be.bignumber.equal(logArgs.takerAssetFilledAmount);
|
expect(expectedFilledTakerAssetAmount).to.be.bignumber.equal(logArgs.takerAssetFilledAmount);
|
||||||
expect(expectedFeeMPaid).to.be.bignumber.equal(logArgs.makerFeePaid);
|
expect(expectedFeeMPaid).to.be.bignumber.equal(logArgs.makerFeePaid);
|
||||||
expect(expectedFeeTPaid).to.be.bignumber.equal(logArgs.takerFeePaid);
|
expect(expectedFeeTPaid).to.be.bignumber.equal(logArgs.takerFeePaid);
|
||||||
expect(orderUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
|
expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when taker is specified and order is claimed by other', async () => {
|
it('should throw when taker is specified and order is claimed by other', async () => {
|
||||||
@ -534,12 +531,6 @@ describe('Exchange core', () => {
|
|||||||
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||||
constants.REVERT,
|
constants.REVERT,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
|
||||||
await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
|
|
||||||
from: makerAddress,
|
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if taker allowances are too low to fill order', async () => {
|
it('should throw if taker allowances are too low to fill order', async () => {
|
||||||
@ -555,12 +546,6 @@ describe('Exchange core', () => {
|
|||||||
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||||
constants.REVERT,
|
constants.REVERT,
|
||||||
);
|
);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
|
||||||
await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
|
|
||||||
from: takerAddress,
|
|
||||||
}),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not change erc20Balances if an order is expired', async () => {
|
it('should not change erc20Balances if an order is expired', async () => {
|
||||||
@ -651,7 +636,7 @@ describe('Exchange core', () => {
|
|||||||
expect(signedOrder.feeRecipientAddress).to.be.equal(logArgs.feeRecipientAddress);
|
expect(signedOrder.feeRecipientAddress).to.be.equal(logArgs.feeRecipientAddress);
|
||||||
expect(signedOrder.makerAssetData).to.be.equal(logArgs.makerAssetData);
|
expect(signedOrder.makerAssetData).to.be.equal(logArgs.makerAssetData);
|
||||||
expect(signedOrder.takerAssetData).to.be.equal(logArgs.takerAssetData);
|
expect(signedOrder.takerAssetData).to.be.equal(logArgs.takerAssetData);
|
||||||
expect(orderUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
|
expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log an error if already cancelled', async () => {
|
it('should log an error if already cancelled', async () => {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
|
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||||
|
import { AssetProxyId } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
@ -8,12 +10,10 @@ import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c2
|
|||||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||||
import { TestAssetProxyDispatcherContract } from '../../src/contract_wrappers/generated/test_asset_proxy_dispatcher';
|
import { TestAssetProxyDispatcherContract } from '../../src/contract_wrappers/generated/test_asset_proxy_dispatcher';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||||
import { AssetProxyId } from '../../src/utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
|
import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils';
|
||||||
import { SignedOrder } from '@0xproject/types';
|
import { SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@ -7,11 +8,9 @@ import ethUtil = require('ethereumjs-util');
|
|||||||
import { TestLibsContract } from '../../src/contract_wrappers/generated/test_libs';
|
import { TestLibsContract } from '../../src/contract_wrappers/generated/test_libs';
|
||||||
import { addressUtils } from '../../src/utils/address_utils';
|
import { addressUtils } from '../../src/utils/address_utils';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { orderUtils } from '../../src/utils/order_utils';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -59,19 +58,19 @@ describe('Exchange libs', () => {
|
|||||||
describe('getOrderSchema', () => {
|
describe('getOrderSchema', () => {
|
||||||
it('should output the correct order schema hash', async () => {
|
it('should output the correct order schema hash', async () => {
|
||||||
const orderSchema = await libs.getOrderSchemaHash.callAsync();
|
const orderSchema = await libs.getOrderSchemaHash.callAsync();
|
||||||
expect(orderUtils.getOrderSchemaHex()).to.be.equal(orderSchema);
|
expect(orderHashUtils._getOrderSchemaHex()).to.be.equal(orderSchema);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('getDomainSeparatorSchema', () => {
|
describe('getDomainSeparatorSchema', () => {
|
||||||
it('should output the correct domain separator schema hash', async () => {
|
it('should output the correct domain separator schema hash', async () => {
|
||||||
const domainSeparatorSchema = await libs.getDomainSeparatorSchemaHash.callAsync();
|
const domainSeparatorSchema = await libs.getDomainSeparatorSchemaHash.callAsync();
|
||||||
expect(orderUtils.getDomainSeparatorSchemaHex()).to.be.equal(domainSeparatorSchema);
|
expect(orderHashUtils._getDomainSeparatorSchemaHex()).to.be.equal(domainSeparatorSchema);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('getOrderHash', () => {
|
describe('getOrderHash', () => {
|
||||||
it('should output the correct order hash', async () => {
|
it('should output the correct order hash', async () => {
|
||||||
const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder);
|
const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder);
|
||||||
expect(orderUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex);
|
expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import { LogWithDecodedArgs, SignedOrder } from '@0xproject/types';
|
import { assetProxyUtils, crypto } from '@0xproject/order-utils';
|
||||||
|
import { AssetProxyId, LogWithDecodedArgs, SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@ -17,17 +18,14 @@ import {
|
|||||||
FillContractEventArgs,
|
FillContractEventArgs,
|
||||||
} from '../../src/contract_wrappers/generated/exchange';
|
} from '../../src/contract_wrappers/generated/exchange';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { crypto } from '../../src/utils/crypto';
|
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||||
|
import { MatchOrderTester } from '../../src/utils/match_order_tester';
|
||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { orderUtils } from '../../src/utils/order_utils';
|
|
||||||
import {
|
import {
|
||||||
AssetProxyId,
|
|
||||||
ContractName,
|
ContractName,
|
||||||
ERC20BalancesByOwner,
|
ERC20BalancesByOwner,
|
||||||
ERC721TokenIdsByOwner,
|
ERC721TokenIdsByOwner,
|
||||||
@ -36,8 +34,6 @@ import {
|
|||||||
} from '../../src/utils/types';
|
} from '../../src/utils/types';
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
import { MatchOrderTester } from '../../src/utils/match_order_tester';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
|
import { orderHashUtils } from '@0xproject/order-utils';
|
||||||
|
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||||
import { SignedOrder } from '@0xproject/types';
|
import { SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@ -7,11 +9,9 @@ import ethUtil = require('ethereumjs-util');
|
|||||||
import { TestSignatureValidatorContract } from '../../src/contract_wrappers/generated/test_signature_validator';
|
import { TestSignatureValidatorContract } from '../../src/contract_wrappers/generated/test_signature_validator';
|
||||||
import { addressUtils } from '../../src/utils/address_utils';
|
import { addressUtils } from '../../src/utils/address_utils';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { orderUtils } from '../../src/utils/order_utils';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -65,7 +65,7 @@ describe('MixinSignatureValidator', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return true with a valid signature', async () => {
|
it('should return true with a valid signature', async () => {
|
||||||
const orderHashHex = orderUtils.getOrderHashHex(signedOrder);
|
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||||
orderHashHex,
|
orderHashHex,
|
||||||
signedOrder.makerAddress,
|
signedOrder.makerAddress,
|
||||||
@ -84,7 +84,7 @@ describe('MixinSignatureValidator', () => {
|
|||||||
]);
|
]);
|
||||||
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
|
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
|
||||||
signedOrder.signature = invalidSigHex;
|
signedOrder.signature = invalidSigHex;
|
||||||
const orderHashHex = orderUtils.getOrderHashHex(signedOrder);
|
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
|
||||||
orderHashHex,
|
orderHashHex,
|
||||||
signedOrder.makerAddress,
|
signedOrder.makerAddress,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import { Order, SignedOrder } from '@0xproject/types';
|
import { AssetProxyId, Order, SignatureType, SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
@ -9,7 +9,7 @@ import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/d
|
|||||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||||
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
@ -17,13 +17,7 @@ import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
|||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { orderUtils } from '../../src/utils/order_utils';
|
import { orderUtils } from '../../src/utils/order_utils';
|
||||||
import { TransactionFactory } from '../../src/utils/transaction_factory';
|
import { TransactionFactory } from '../../src/utils/transaction_factory';
|
||||||
import {
|
import { ERC20BalancesByOwner, ExchangeStatus, SignedTransaction } from '../../src/utils/types';
|
||||||
AssetProxyId,
|
|
||||||
ERC20BalancesByOwner,
|
|
||||||
ExchangeStatus,
|
|
||||||
SignatureType,
|
|
||||||
SignedTransaction,
|
|
||||||
} from '../../src/utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import { SignedOrder } from '@0xproject/types';
|
import { AssetProxyId, SignedOrder } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@ -14,14 +14,14 @@ import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c
|
|||||||
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
||||||
import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry';
|
import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry';
|
||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||||
import { OrderFactory } from '../../src/utils/order_factory';
|
import { OrderFactory } from '../../src/utils/order_factory';
|
||||||
import { AssetProxyId, ERC20BalancesByOwner } from '../../src/utils/types';
|
import { ERC20BalancesByOwner } from '../../src/utils/types';
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
|
import { AssetProxyId, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BN = require('bn.js');
|
import BN = require('bn.js');
|
||||||
@ -11,7 +11,6 @@ import { TestLibBytesContract } from '../../src/contract_wrappers/generated/test
|
|||||||
import { artifacts } from '../../src/utils/artifacts';
|
import { artifacts } from '../../src/utils/artifacts';
|
||||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||||
import { constants } from '../../src/utils/constants';
|
import { constants } from '../../src/utils/constants';
|
||||||
import { AssetProxyId } from '../../src/utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
@ -11,6 +11,7 @@ export const orderSchema = {
|
|||||||
makerAssetData: { $ref: '/Hex' },
|
makerAssetData: { $ref: '/Hex' },
|
||||||
takerAssetData: { $ref: '/Hex' },
|
takerAssetData: { $ref: '/Hex' },
|
||||||
salt: { $ref: '/Number' },
|
salt: { $ref: '/Number' },
|
||||||
|
exchangeAddress: { $ref: '/Address' },
|
||||||
feeRecipientAddress: { $ref: '/Address' },
|
feeRecipientAddress: { $ref: '/Address' },
|
||||||
expirationTimeSeconds: { $ref: '/Number' },
|
expirationTimeSeconds: { $ref: '/Number' },
|
||||||
},
|
},
|
||||||
@ -25,6 +26,7 @@ export const orderSchema = {
|
|||||||
'makerAssetData',
|
'makerAssetData',
|
||||||
'takerAssetData',
|
'takerAssetData',
|
||||||
'salt',
|
'salt',
|
||||||
|
'exchangeAddress',
|
||||||
'feeRecipientAddress',
|
'feeRecipientAddress',
|
||||||
'expirationTimeSeconds',
|
'expirationTimeSeconds',
|
||||||
],
|
],
|
||||||
|
@ -180,6 +180,7 @@ describe('Schema', () => {
|
|||||||
takerAssetData: NULL_ADDRESS,
|
takerAssetData: NULL_ADDRESS,
|
||||||
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
||||||
feeRecipientAddress: NULL_ADDRESS,
|
feeRecipientAddress: NULL_ADDRESS,
|
||||||
|
exchangeAddress: NULL_ADDRESS,
|
||||||
expirationTimeSeconds: '42',
|
expirationTimeSeconds: '42',
|
||||||
};
|
};
|
||||||
describe('#orderSchema', () => {
|
describe('#orderSchema', () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "artifacts/1.0.0",
|
"artifactsDir": "artifacts/2.0.0",
|
||||||
"contractsDir": "../contracts/src/contracts",
|
"contractsDir": "../contracts/src/contracts",
|
||||||
"contracts": [
|
"contracts": [
|
||||||
"Exchange_v1",
|
"Exchange_v1",
|
||||||
@ -10,7 +10,8 @@
|
|||||||
"MultiSigWallet",
|
"MultiSigWallet",
|
||||||
"MultiSigWalletWithTimeLock",
|
"MultiSigWalletWithTimeLock",
|
||||||
"MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
|
"MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
|
||||||
"TokenRegistry"
|
"TokenRegistry",
|
||||||
|
"ISigner"
|
||||||
],
|
],
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"outputSelection": {
|
"outputSelection": {
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"v1":
|
"v1":
|
||||||
"artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json",
|
"artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json",
|
||||||
"v2":
|
"v2":
|
||||||
"artifacts/2.0.0/@(DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|ZRXToken|WETH9).json"
|
"artifacts/2.0.0/@(DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|ZRXToken|WETH9|ISigner).json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -9,13 +9,16 @@
|
|||||||
"types": "lib/src/index.d.ts",
|
"types": "lib/src/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch": "tsc -w",
|
"watch": "tsc -w",
|
||||||
|
"prebuild": "run-s clean update_artifacts generate_contract_wrappers",
|
||||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||||
"test": "run-s clean build run_mocha",
|
"generate_contract_wrappers": "abi-gen --abis 'lib/src/artifacts/@(Exchange|ISigner).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers && prettier --write 'src/generated_contract_wrappers/**.ts'",
|
||||||
|
"update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/2.0.0/$i.json lib/src/artifacts; done;",
|
||||||
|
"test": "run-s build run_mocha",
|
||||||
"test:circleci": "yarn test:coverage",
|
"test:circleci": "yarn test:coverage",
|
||||||
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
|
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
|
||||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||||
"clean": "shx rm -rf lib scripts",
|
"clean": "shx rm -rf lib scripts lib/src/artifacts src/generated_contract_wrappers",
|
||||||
"lint": "tslint --project .",
|
"lint": "tslint --project .",
|
||||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
|
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
|
||||||
"docs:stage": "node scripts/stage_docs.js",
|
"docs:stage": "node scripts/stage_docs.js",
|
||||||
@ -23,6 +26,7 @@
|
|||||||
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json"
|
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
"contracts": "ISigner Exchange",
|
||||||
"postpublish": {
|
"postpublish": {
|
||||||
"docPublishConfigs": {
|
"docPublishConfigs": {
|
||||||
"extraFileIncludes": [
|
"extraFileIncludes": [
|
||||||
@ -63,8 +67,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xproject/assert": "^0.2.10",
|
"@0xproject/assert": "^0.2.10",
|
||||||
"@0xproject/json-schemas": "0.7.22",
|
"@0xproject/base-contract": "^0.3.2",
|
||||||
"@0xproject/types": "0.7.0",
|
"@0xproject/json-schemas": "0.7.24",
|
||||||
|
"@0xproject/sol-compiler": "^0.5.0",
|
||||||
|
"@0xproject/types": "^0.7.1",
|
||||||
"@0xproject/typescript-typings": "^0.3.2",
|
"@0xproject/typescript-typings": "^0.3.2",
|
||||||
"@0xproject/utils": "^0.6.2",
|
"@0xproject/utils": "^0.6.2",
|
||||||
"@0xproject/web3-wrapper": "^0.6.4",
|
"@0xproject/web3-wrapper": "^0.6.4",
|
||||||
@ -72,6 +78,7 @@
|
|||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
"ethereumjs-abi": "^0.6.4",
|
"ethereumjs-abi": "^0.6.4",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
|
"ethers": "^3.0.15",
|
||||||
"lodash": "^4.17.4"
|
"lodash": "^4.17.4"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
8
packages/order-utils/src/artifacts.ts
Normal file
8
packages/order-utils/src/artifacts.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Artifact } from '@0xproject/types';
|
||||||
|
|
||||||
|
import * as Exchange from './artifacts/Exchange.json';
|
||||||
|
import * as ISigner from './artifacts/ISigner.json';
|
||||||
|
export const artifacts = {
|
||||||
|
Exchange: (Exchange as any) as Artifact,
|
||||||
|
ISigner: (ISigner as any) as Artifact,
|
||||||
|
};
|
@ -8,8 +8,6 @@ import { BigNumber } from '@0xproject/utils';
|
|||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { isValidSignature } from './signature_utils';
|
|
||||||
|
|
||||||
export const assert = {
|
export const assert = {
|
||||||
...sharedAssert,
|
...sharedAssert,
|
||||||
async isSenderAddressAsync(
|
async isSenderAddressAsync(
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import { AssetProxyId, ERC20ProxyData, ERC721ProxyData, ProxyData } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BN = require('bn.js');
|
import BN = require('bn.js');
|
||||||
import ethUtil = require('ethereumjs-util');
|
import ethUtil = require('ethereumjs-util');
|
||||||
|
|
||||||
import { AssetProxyId, ERC20ProxyData, ERC721ProxyData, ProxyData } from './types';
|
const ERC20_PROXY_METADATA_BYTE_LENGTH = 21;
|
||||||
|
const ERC721_PROXY_METADATA_BYTE_LENGTH = 53;
|
||||||
|
|
||||||
export const assetProxyUtils = {
|
export const assetProxyUtils = {
|
||||||
encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer {
|
encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer {
|
||||||
@ -26,8 +28,10 @@ export const assetProxyUtils = {
|
|||||||
return address;
|
return address;
|
||||||
},
|
},
|
||||||
encodeUint256(value: BigNumber): Buffer {
|
encodeUint256(value: BigNumber): Buffer {
|
||||||
const formattedValue = new BN(value.toString(10));
|
const base = 10;
|
||||||
|
const formattedValue = new BN(value.toString(base));
|
||||||
const encodedValue = ethUtil.toBuffer(formattedValue);
|
const encodedValue = ethUtil.toBuffer(formattedValue);
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const paddedValue = ethUtil.setLengthLeft(encodedValue, 32);
|
const paddedValue = ethUtil.setLengthLeft(encodedValue, 32);
|
||||||
return paddedValue;
|
return paddedValue;
|
||||||
},
|
},
|
||||||
@ -45,7 +49,7 @@ export const assetProxyUtils = {
|
|||||||
},
|
},
|
||||||
decodeERC20ProxyData(proxyData: string): ERC20ProxyData {
|
decodeERC20ProxyData(proxyData: string): ERC20ProxyData {
|
||||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||||
if (encodedProxyMetadata.byteLength !== 21) {
|
if (encodedProxyMetadata.byteLength !== ERC20_PROXY_METADATA_BYTE_LENGTH) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${
|
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${
|
||||||
encodedProxyMetadata.byteLength
|
encodedProxyMetadata.byteLength
|
||||||
@ -61,7 +65,7 @@ export const assetProxyUtils = {
|
|||||||
}), but got ${assetProxyId}`,
|
}), but got ${assetProxyId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
|
const encodedTokenAddress = encodedProxyMetadata.slice(1, ERC20_PROXY_METADATA_BYTE_LENGTH);
|
||||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||||
const erc20ProxyData = {
|
const erc20ProxyData = {
|
||||||
assetProxyId,
|
assetProxyId,
|
||||||
@ -79,7 +83,7 @@ export const assetProxyUtils = {
|
|||||||
},
|
},
|
||||||
decodeERC721ProxyData(proxyData: string): ERC721ProxyData {
|
decodeERC721ProxyData(proxyData: string): ERC721ProxyData {
|
||||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||||
if (encodedProxyMetadata.byteLength !== 53) {
|
if (encodedProxyMetadata.byteLength !== ERC721_PROXY_METADATA_BYTE_LENGTH) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${
|
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${
|
||||||
encodedProxyMetadata.byteLength
|
encodedProxyMetadata.byteLength
|
||||||
@ -95,9 +99,10 @@ export const assetProxyUtils = {
|
|||||||
}), but got ${assetProxyId}`,
|
}), but got ${assetProxyId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
|
const addressOffset = 21;
|
||||||
|
const encodedTokenAddress = encodedProxyMetadata.slice(1, addressOffset);
|
||||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||||
const encodedTokenId = encodedProxyMetadata.slice(21, 53);
|
const encodedTokenId = encodedProxyMetadata.slice(addressOffset, ERC721_PROXY_METADATA_BYTE_LENGTH);
|
||||||
const tokenId = assetProxyUtils.decodeUint256(encodedTokenId);
|
const tokenId = assetProxyUtils.decodeUint256(encodedTokenId);
|
||||||
const erc721ProxyData = {
|
const erc721ProxyData = {
|
||||||
assetProxyId,
|
assetProxyId,
|
@ -26,7 +26,8 @@ export const crypto = {
|
|||||||
argTypes.push('uint8');
|
argTypes.push('uint8');
|
||||||
} else if (arg.isBigNumber) {
|
} else if (arg.isBigNumber) {
|
||||||
argTypes.push('uint256');
|
argTypes.push('uint256');
|
||||||
args[i] = new BN(arg.toString(10), 10);
|
const base = 10;
|
||||||
|
args[i] = new BN(arg.toString(base), base);
|
||||||
} else if (ethUtil.isValidAddress(arg)) {
|
} else if (ethUtil.isValidAddress(arg)) {
|
||||||
argTypes.push('address');
|
argTypes.push('address');
|
||||||
} else if (_.isString(arg)) {
|
} else if (_.isString(arg)) {
|
@ -1,23 +0,0 @@
|
|||||||
import { Order, OrderAddresses, OrderValues } from '@0xproject/types';
|
|
||||||
import { BigNumber } from '@0xproject/utils';
|
|
||||||
|
|
||||||
export const formatters = {
|
|
||||||
getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] {
|
|
||||||
const orderAddresses: OrderAddresses = [
|
|
||||||
order.maker,
|
|
||||||
order.taker,
|
|
||||||
order.makerTokenAddress,
|
|
||||||
order.takerTokenAddress,
|
|
||||||
order.feeRecipient,
|
|
||||||
];
|
|
||||||
const orderValues: OrderValues = [
|
|
||||||
order.makerTokenAmount,
|
|
||||||
order.takerTokenAmount,
|
|
||||||
order.makerFee,
|
|
||||||
order.takerFee,
|
|
||||||
order.expirationUnixTimestampSec,
|
|
||||||
order.salt,
|
|
||||||
];
|
|
||||||
return [orderAddresses, orderValues];
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,11 +1,12 @@
|
|||||||
export { getOrderHashHex, isValidOrderHash } from './order_hash';
|
export { orderHashUtils } from './order_hash';
|
||||||
export { isValidSignature, signOrderHashAsync } from './signature_utils';
|
export { isValidSignatureAsync, ecSignOrderHashAsync } from './signature_utils';
|
||||||
export { orderFactory } from './order_factory';
|
export { orderFactory } from './order_factory';
|
||||||
export { constants } from './constants';
|
export { constants } from './constants';
|
||||||
|
export { crypto } from './crypto';
|
||||||
export { generatePseudoRandomSalt } from './salt';
|
export { generatePseudoRandomSalt } from './salt';
|
||||||
export { OrderError } from './types';
|
export { OrderError } from './types';
|
||||||
export { formatters } from './formatters';
|
|
||||||
export { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
export { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
||||||
export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
||||||
export { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
export { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
||||||
export { OrderStateUtils } from './order_state_utils';
|
export { OrderStateUtils } from './order_state_utils';
|
||||||
|
export { assetProxyUtils } from './asset_proxy_utils';
|
||||||
|
@ -2,48 +2,56 @@ import { Provider, SignedOrder } from '@0xproject/types';
|
|||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { getOrderHashHex } from './order_hash';
|
import { orderHashUtils } from './order_hash';
|
||||||
import { generatePseudoRandomSalt } from './salt';
|
import { generatePseudoRandomSalt } from './salt';
|
||||||
import { signOrderHashAsync } from './signature_utils';
|
import { ecSignOrderHashAsync, getVRSHexString } from './signature_utils';
|
||||||
|
|
||||||
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
|
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
|
||||||
|
|
||||||
export const orderFactory = {
|
export const orderFactory = {
|
||||||
async createSignedOrderAsync(
|
async createSignedOrderAsync(
|
||||||
provider: Provider,
|
provider: Provider,
|
||||||
maker: string,
|
makerAddress: string,
|
||||||
taker: string,
|
takerAddress: string,
|
||||||
|
senderAddress: string,
|
||||||
makerFee: BigNumber,
|
makerFee: BigNumber,
|
||||||
takerFee: BigNumber,
|
takerFee: BigNumber,
|
||||||
makerTokenAmount: BigNumber,
|
makerAssetAmount: BigNumber,
|
||||||
makerTokenAddress: string,
|
makerAssetData: string,
|
||||||
takerTokenAmount: BigNumber,
|
takerAssetAmount: BigNumber,
|
||||||
takerTokenAddress: string,
|
takerAssetData: string,
|
||||||
exchangeContractAddress: string,
|
exchangeAddress: string,
|
||||||
feeRecipient: string,
|
feeRecipientAddress: string,
|
||||||
expirationUnixTimestampSecIfExists?: BigNumber,
|
expirationTimeSecondsIfExists?: BigNumber,
|
||||||
): Promise<SignedOrder> {
|
): Promise<SignedOrder> {
|
||||||
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
||||||
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists)
|
const expirationTimeSeconds = _.isUndefined(expirationTimeSecondsIfExists)
|
||||||
? defaultExpirationUnixTimestampSec
|
? defaultExpirationUnixTimestampSec
|
||||||
: expirationUnixTimestampSecIfExists;
|
: expirationTimeSecondsIfExists;
|
||||||
const order = {
|
const order = {
|
||||||
maker,
|
makerAddress,
|
||||||
taker,
|
takerAddress,
|
||||||
|
senderAddress,
|
||||||
makerFee,
|
makerFee,
|
||||||
takerFee,
|
takerFee,
|
||||||
makerTokenAmount,
|
makerAssetAmount,
|
||||||
takerTokenAmount,
|
takerAssetAmount,
|
||||||
makerTokenAddress,
|
makerAssetData,
|
||||||
takerTokenAddress,
|
takerAssetData,
|
||||||
salt: generatePseudoRandomSalt(),
|
salt: generatePseudoRandomSalt(),
|
||||||
exchangeContractAddress,
|
exchangeAddress,
|
||||||
feeRecipient,
|
feeRecipientAddress,
|
||||||
expirationUnixTimestampSec,
|
expirationTimeSeconds,
|
||||||
};
|
};
|
||||||
const orderHash = getOrderHashHex(order);
|
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||||
const ecSignature = await signOrderHashAsync(provider, orderHash, maker, SHOULD_ADD_PERSONAL_MESSAGE_PREFIX);
|
const ecSignature = await ecSignOrderHashAsync(
|
||||||
const signedOrder: SignedOrder = _.assign(order, { ecSignature });
|
provider,
|
||||||
|
orderHash,
|
||||||
|
makerAddress,
|
||||||
|
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
|
||||||
|
);
|
||||||
|
const signature = getVRSHexString(ecSignature);
|
||||||
|
const signedOrder: SignedOrder = _.assign(order, { signature });
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import { Order, SignedOrder, SolidityTypes } from '@0xproject/types';
|
import { Order, SignatureType, SignedOrder, SolidityTypes } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BN = require('bn.js');
|
import BN = require('bn.js');
|
||||||
import * as ethABI from 'ethereumjs-abi';
|
import * as ethABI from 'ethereumjs-abi';
|
||||||
@ -7,26 +7,32 @@ import * as ethUtil from 'ethereumjs-util';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { assert } from './assert';
|
import { assert } from './assert';
|
||||||
|
import { crypto } from './crypto';
|
||||||
|
|
||||||
const INVALID_TAKER_FORMAT = 'instance.taker is not of a type(s) string';
|
const INVALID_TAKER_FORMAT = 'instance.taker is not of a type(s) string';
|
||||||
|
|
||||||
/**
|
export const orderHashUtils = {
|
||||||
* Converts BigNumber instance to BN
|
/**
|
||||||
* The only reason we convert to BN is to remain compatible with `ethABI.soliditySHA3` that
|
* Checks if the supplied hex encoded order hash is valid.
|
||||||
* expects values of Solidity type `uint` to be passed as type `BN`.
|
* Note: Valid means it has the expected format, not that an order with the orderHash exists.
|
||||||
* We do not use BN anywhere else in the codebase.
|
* Use this method when processing orderHashes submitted as user input.
|
||||||
|
* @param orderHash Hex encoded orderHash.
|
||||||
|
* @return Whether the supplied orderHash has the expected format.
|
||||||
*/
|
*/
|
||||||
function bigNumberToBN(value: BigNumber): BN {
|
isValidOrderHash(orderHash: string): boolean {
|
||||||
const base = 10;
|
// Since this method can be called to check if any arbitrary string conforms to an orderHash's
|
||||||
return new BN(value.toString(), base);
|
// format, we only assert that we were indeed passed a string.
|
||||||
}
|
assert.isString('orderHash', orderHash);
|
||||||
|
const schemaValidator = new SchemaValidator();
|
||||||
/**
|
const isValid = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
|
||||||
|
return isValid;
|
||||||
|
},
|
||||||
|
/**
|
||||||
* Computes the orderHash for a supplied order.
|
* Computes the orderHash for a supplied order.
|
||||||
* @param order An object that conforms to the Order or SignedOrder interface definitions.
|
* @param order An object that conforms to the Order or SignedOrder interface definitions.
|
||||||
* @return The resulting orderHash from hashing the supplied order.
|
* @return The resulting orderHash from hashing the supplied order.
|
||||||
*/
|
*/
|
||||||
export function getOrderHashHex(order: Order | SignedOrder): string {
|
getOrderHashHex(order: SignedOrder | Order): string {
|
||||||
try {
|
try {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -37,54 +43,74 @@ export function getOrderHashHex(order: Order | SignedOrder): string {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const orderParts = [
|
|
||||||
{ value: order.exchangeContractAddress, type: SolidityTypes.Address },
|
|
||||||
{ value: order.maker, type: SolidityTypes.Address },
|
|
||||||
{ value: order.taker, type: SolidityTypes.Address },
|
|
||||||
{ value: order.makerTokenAddress, type: SolidityTypes.Address },
|
|
||||||
{ value: order.takerTokenAddress, type: SolidityTypes.Address },
|
|
||||||
{ value: order.feeRecipient, type: SolidityTypes.Address },
|
|
||||||
{
|
|
||||||
value: bigNumberToBN(order.makerTokenAmount),
|
|
||||||
type: SolidityTypes.Uint256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: bigNumberToBN(order.takerTokenAmount),
|
|
||||||
type: SolidityTypes.Uint256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: bigNumberToBN(order.makerFee),
|
|
||||||
type: SolidityTypes.Uint256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: bigNumberToBN(order.takerFee),
|
|
||||||
type: SolidityTypes.Uint256,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: bigNumberToBN(order.expirationUnixTimestampSec),
|
|
||||||
type: SolidityTypes.Uint256,
|
|
||||||
},
|
|
||||||
{ value: bigNumberToBN(order.salt), type: SolidityTypes.Uint256 },
|
|
||||||
];
|
|
||||||
const types = _.map(orderParts, o => o.type);
|
|
||||||
const values = _.map(orderParts, o => o.value);
|
|
||||||
const hashBuff = ethABI.soliditySHA3(types, values);
|
|
||||||
const hashHex = ethUtil.bufferToHex(hashBuff);
|
|
||||||
return hashHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const orderHashBuff = this.getOrderHashBuff(order);
|
||||||
* Checks if the supplied hex encoded order hash is valid.
|
const orderHashHex = `0x${orderHashBuff.toString('hex')}`;
|
||||||
* Note: Valid means it has the expected format, not that an order with the orderHash exists.
|
return orderHashHex;
|
||||||
* Use this method when processing orderHashes submitted as user input.
|
},
|
||||||
* @param orderHash Hex encoded orderHash.
|
/**
|
||||||
* @return Whether the supplied orderHash has the expected format.
|
* Computes the orderHash for a supplied order and returns it as a Buffer
|
||||||
|
* @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
|
||||||
*/
|
*/
|
||||||
export function isValidOrderHash(orderHash: string): boolean {
|
getOrderHashBuff(order: SignedOrder | Order): Buffer {
|
||||||
// Since this method can be called to check if any arbitrary string conforms to an orderHash's
|
const makerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.makerAssetData)]);
|
||||||
// format, we only assert that we were indeed passed a string.
|
const takerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.takerAssetData)]);
|
||||||
assert.isString('orderHash', orderHash);
|
|
||||||
const schemaValidator = new SchemaValidator();
|
const orderParamsHashBuff = crypto.solSHA3([
|
||||||
const isValid = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
|
order.makerAddress,
|
||||||
return isValid;
|
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 = this._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;
|
||||||
|
},
|
||||||
|
_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;
|
||||||
|
},
|
||||||
|
_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;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -11,7 +11,8 @@ import * as _ from 'lodash';
|
|||||||
|
|
||||||
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
||||||
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
||||||
import { getOrderHashHex } from './order_hash';
|
import { assetProxyUtils } from './asset_proxy_utils';
|
||||||
|
import { orderHashUtils } from './order_hash';
|
||||||
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
||||||
|
|
||||||
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
||||||
@ -23,7 +24,7 @@ export class OrderStateUtils {
|
|||||||
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
||||||
orderRelevantState.filledTakerTokenAmount,
|
orderRelevantState.filledTakerTokenAmount,
|
||||||
);
|
);
|
||||||
const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
const availableTakerTokenAmount = signedOrder.takerAssetAmount.minus(unavailableTakerTokenAmount);
|
||||||
if (availableTakerTokenAmount.eq(0)) {
|
if (availableTakerTokenAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
}
|
}
|
||||||
@ -42,9 +43,9 @@ export class OrderStateUtils {
|
|||||||
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
|
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerAssetAmount
|
||||||
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
||||||
.dividedBy(signedOrder.makerTokenAmount);
|
.dividedBy(signedOrder.makerAssetAmount);
|
||||||
if (
|
if (
|
||||||
orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
|
orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
|
||||||
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
|
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
|
||||||
@ -62,7 +63,7 @@ export class OrderStateUtils {
|
|||||||
}
|
}
|
||||||
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
||||||
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
||||||
const orderHash = getOrderHashHex(signedOrder);
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
try {
|
try {
|
||||||
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
|
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||||
const orderState: OrderStateValid = {
|
const orderState: OrderStateValid = {
|
||||||
@ -82,22 +83,22 @@ export class OrderStateUtils {
|
|||||||
}
|
}
|
||||||
public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
|
public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
|
||||||
const zrxTokenAddress = this._orderFilledCancelledFetcher.getZRXTokenAddress();
|
const zrxTokenAddress = this._orderFilledCancelledFetcher.getZRXTokenAddress();
|
||||||
const orderHash = getOrderHashHex(signedOrder);
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
const makerBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
const makerBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
||||||
signedOrder.makerTokenAddress,
|
signedOrder.makerAssetData,
|
||||||
signedOrder.maker,
|
signedOrder.makerAddress,
|
||||||
);
|
);
|
||||||
const makerProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
const makerProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
||||||
signedOrder.makerTokenAddress,
|
signedOrder.makerAssetData,
|
||||||
signedOrder.maker,
|
signedOrder.makerAddress,
|
||||||
);
|
);
|
||||||
const makerFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
const makerFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(
|
||||||
zrxTokenAddress,
|
zrxTokenAddress,
|
||||||
signedOrder.maker,
|
signedOrder.makerAddress,
|
||||||
);
|
);
|
||||||
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync(
|
||||||
zrxTokenAddress,
|
zrxTokenAddress,
|
||||||
signedOrder.maker,
|
signedOrder.makerAddress,
|
||||||
);
|
);
|
||||||
const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
|
const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash);
|
||||||
const cancelledTakerTokenAmount = await this._orderFilledCancelledFetcher.getCancelledTakerAmountAsync(
|
const cancelledTakerTokenAmount = await this._orderFilledCancelledFetcher.getCancelledTakerAmountAsync(
|
||||||
@ -106,8 +107,8 @@ export class OrderStateUtils {
|
|||||||
const unavailableTakerTokenAmount = await this._orderFilledCancelledFetcher.getUnavailableTakerAmountAsync(
|
const unavailableTakerTokenAmount = await this._orderFilledCancelledFetcher.getUnavailableTakerAmountAsync(
|
||||||
orderHash,
|
orderHash,
|
||||||
);
|
);
|
||||||
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
const totalMakerTokenAmount = signedOrder.makerAssetAmount;
|
||||||
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
const totalTakerTokenAmount = signedOrder.takerAssetAmount;
|
||||||
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const remainingMakerTokenAmount = remainingTakerTokenAmount
|
const remainingMakerTokenAmount = remainingTakerTokenAmount
|
||||||
.times(totalMakerTokenAmount)
|
.times(totalMakerTokenAmount)
|
||||||
@ -115,7 +116,8 @@ export class OrderStateUtils {
|
|||||||
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
||||||
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
||||||
|
|
||||||
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
|
const zrxAssetData = assetProxyUtils.encodeERC20ProxyData(zrxTokenAddress);
|
||||||
|
const isMakerTokenZRX = signedOrder.makerAssetData === zrxAssetData;
|
||||||
const remainingFillableCalculator = new RemainingFillableCalculator(
|
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||||
signedOrder,
|
signedOrder,
|
||||||
isMakerTokenZRX,
|
isMakerTokenZRX,
|
||||||
|
@ -23,7 +23,7 @@ export class RemainingFillableCalculator {
|
|||||||
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||||
this._remainingMakerFeeAmount = remainingMakerTokenAmount
|
this._remainingMakerFeeAmount = remainingMakerTokenAmount
|
||||||
.times(signedOrder.makerFee)
|
.times(signedOrder.makerFee)
|
||||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||||
}
|
}
|
||||||
public computeRemainingMakerFillable(): BigNumber {
|
public computeRemainingMakerFillable(): BigNumber {
|
||||||
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||||
@ -36,8 +36,8 @@ export class RemainingFillableCalculator {
|
|||||||
}
|
}
|
||||||
public computeRemainingTakerFillable(): BigNumber {
|
public computeRemainingTakerFillable(): BigNumber {
|
||||||
return this.computeRemainingMakerFillable()
|
return this.computeRemainingMakerFillable()
|
||||||
.times(this._signedOrder.takerTokenAmount)
|
.times(this._signedOrder.takerAssetAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
.dividedToIntegerBy(this._signedOrder.makerAssetAmount);
|
||||||
}
|
}
|
||||||
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||||
if (this._isMakerTokenZRX) {
|
if (this._isMakerTokenZRX) {
|
||||||
@ -59,7 +59,7 @@ export class RemainingFillableCalculator {
|
|||||||
}
|
}
|
||||||
private _calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
private _calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
||||||
// Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
|
// Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
|
||||||
const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedBy(this._signedOrder.makerFee);
|
const orderToFeeRatio = this._signedOrder.makerAssetAmount.dividedBy(this._signedOrder.makerFee);
|
||||||
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||||
// baseUnit of fee tokens.
|
// baseUnit of fee tokens.
|
||||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
||||||
@ -81,10 +81,10 @@ export class RemainingFillableCalculator {
|
|||||||
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
||||||
// This can result in a RoundingError being thrown by the Exchange Contract.
|
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerAssetAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerAssetAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableAmount = BigNumber.min(
|
const partiallyFillableAmount = BigNumber.min(
|
||||||
partiallyFillableMakerTokenAmount,
|
partiallyFillableMakerTokenAmount,
|
||||||
|
@ -1,28 +1,97 @@
|
|||||||
import { schemas } from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import { ECSignature, Provider } from '@0xproject/types';
|
import { ECSignature, Provider, SignatureType } from '@0xproject/types';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { artifacts } from './artifacts';
|
||||||
import { assert } from './assert';
|
import { assert } from './assert';
|
||||||
|
import { ExchangeContract } from './generated_contract_wrappers/exchange';
|
||||||
|
import { ISignerContract } from './generated_contract_wrappers/i_signer';
|
||||||
import { OrderError } from './types';
|
import { OrderError } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that the elliptic curve signature `signature` was generated
|
* Verifies that the provided signature is valid according to the 0x Protocol smart contracts
|
||||||
* by signing `data` with the private key corresponding to the `signerAddress` address.
|
|
||||||
* @param data The hex encoded data signed by the supplied signature.
|
* @param data The hex encoded data signed by the supplied signature.
|
||||||
* @param signature An object containing the elliptic curve signature parameters.
|
* @param signature An object containing the elliptic curve signature parameters.
|
||||||
* @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
|
* @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
|
||||||
* @return Whether the signature is valid for the supplied signerAddress and data.
|
* @return Whether the signature is valid for the supplied signerAddress and data.
|
||||||
*/
|
*/
|
||||||
export function isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
export async function isValidSignatureAsync(
|
||||||
|
provider: Provider,
|
||||||
|
data: string,
|
||||||
|
signature: string,
|
||||||
|
signerAddress: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const signatureTypeIndexIfExists = getSignatureTypeIndexIfExists(signature);
|
||||||
|
if (_.isUndefined(signatureTypeIndexIfExists)) {
|
||||||
|
throw new Error(`Unrecognized signatureType in signature: ${signature}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (signatureTypeIndexIfExists) {
|
||||||
|
case SignatureType.Illegal:
|
||||||
|
case SignatureType.Invalid:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Question: Does it make sense to handle this?
|
||||||
|
case SignatureType.Caller:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// TODO: Rename this type to `EthSign` b/c multiple of the signature
|
||||||
|
// types use ECRecover...
|
||||||
|
case SignatureType.Ecrecover: {
|
||||||
|
const ecSignature = parseECSignature(signature);
|
||||||
|
const dataBuff = ethUtil.toBuffer(data);
|
||||||
|
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
|
||||||
|
const msgHash = ethUtil.bufferToHex(msgHashBuff);
|
||||||
|
return isValidECSignature(msgHash, ecSignature, signerAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
case SignatureType.EIP712: {
|
||||||
|
const ecSignature = parseECSignature(signature);
|
||||||
|
return isValidECSignature(data, ecSignature, signerAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
case SignatureType.Trezor: {
|
||||||
|
const dataBuff = ethUtil.toBuffer(data);
|
||||||
|
const msgHashBuff = hashTrezorPersonalMessage(dataBuff);
|
||||||
|
const msgHash = ethUtil.bufferToHex(msgHashBuff);
|
||||||
|
const ecSignature = parseECSignature(signature);
|
||||||
|
return isValidECSignature(msgHash, ecSignature, signerAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rename Contract -> Wallet
|
||||||
|
case SignatureType.Contract: {
|
||||||
|
const signerContract = new ISignerContract(artifacts.ISigner.abi, signerAddress, provider);
|
||||||
|
const isValid = await signerContract.isValidSignature.callAsync(data, signature);
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SignatureType.PreSigned: {
|
||||||
|
const exchangeContract = new ExchangeContract(artifacts.Exchange.abi, signerAddress, provider);
|
||||||
|
const isValid = await exchangeContract.preSigned.callAsync(data, signerAddress);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVRSHexString(ecSignature: ECSignature): string {
|
||||||
|
const vrs = `0x${intToHex(ecSignature.v)}${ethUtil.stripHexPrefix(ecSignature.r)}${ethUtil.stripHexPrefix(
|
||||||
|
ecSignature.s,
|
||||||
|
)}`;
|
||||||
|
return vrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
||||||
assert.isHexString('data', data);
|
assert.isHexString('data', data);
|
||||||
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
|
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
|
||||||
assert.isETHAddressHex('signerAddress', signerAddress);
|
assert.isETHAddressHex('signerAddress', signerAddress);
|
||||||
const normalizedSignerAddress = signerAddress.toLowerCase();
|
const normalizedSignerAddress = signerAddress.toLowerCase();
|
||||||
|
|
||||||
const dataBuff = ethUtil.toBuffer(data);
|
const msgHashBuff = ethUtil.toBuffer(data);
|
||||||
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
|
|
||||||
try {
|
try {
|
||||||
const pubKey = ethUtil.ecrecover(
|
const pubKey = ethUtil.ecrecover(
|
||||||
msgHashBuff,
|
msgHashBuff,
|
||||||
@ -36,6 +105,7 @@ export function isValidSignature(data: string, signature: ECSignature, signerAdd
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs an orderHash and returns it's elliptic curve signature.
|
* Signs an orderHash and returns it's elliptic curve signature.
|
||||||
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6
|
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6
|
||||||
@ -48,7 +118,7 @@ export function isValidSignature(data: string, signature: ECSignature, signerAdd
|
|||||||
* before sending the request.
|
* before sending the request.
|
||||||
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
|
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
|
||||||
*/
|
*/
|
||||||
export async function signOrderHashAsync(
|
export async function ecSignOrderHashAsync(
|
||||||
provider: Provider,
|
provider: Provider,
|
||||||
orderHash: string,
|
orderHash: string,
|
||||||
signerAddress: string,
|
signerAddress: string,
|
||||||
@ -76,7 +146,7 @@ export async function signOrderHashAsync(
|
|||||||
const validVParamValues = [27, 28];
|
const validVParamValues = [27, 28];
|
||||||
const ecSignatureVRS = parseSignatureHexAsVRS(signature);
|
const ecSignatureVRS = parseSignatureHexAsVRS(signature);
|
||||||
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
||||||
const isValidVRSSignature = isValidSignature(orderHash, ecSignatureVRS, normalizedSignerAddress);
|
const isValidVRSSignature = isValidECSignature(orderHash, ecSignatureVRS, normalizedSignerAddress);
|
||||||
if (isValidVRSSignature) {
|
if (isValidVRSSignature) {
|
||||||
return ecSignatureVRS;
|
return ecSignatureVRS;
|
||||||
}
|
}
|
||||||
@ -84,7 +154,7 @@ export async function signOrderHashAsync(
|
|||||||
|
|
||||||
const ecSignatureRSV = parseSignatureHexAsRSV(signature);
|
const ecSignatureRSV = parseSignatureHexAsRSV(signature);
|
||||||
if (_.includes(validVParamValues, ecSignatureRSV.v)) {
|
if (_.includes(validVParamValues, ecSignatureRSV.v)) {
|
||||||
const isValidRSVSignature = isValidSignature(orderHash, ecSignatureRSV, normalizedSignerAddress);
|
const isValidRSVSignature = isValidECSignature(orderHash, ecSignatureRSV, normalizedSignerAddress);
|
||||||
if (isValidRSVSignature) {
|
if (isValidRSVSignature) {
|
||||||
return ecSignatureRSV;
|
return ecSignatureRSV;
|
||||||
}
|
}
|
||||||
@ -93,6 +163,39 @@ export async function signOrderHashAsync(
|
|||||||
throw new Error(OrderError.InvalidSignature);
|
throw new Error(OrderError.InvalidSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hashTrezorPersonalMessage(message: Buffer): Buffer {
|
||||||
|
const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.length));
|
||||||
|
return ethUtil.sha3(Buffer.concat([prefix, message]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseECSignature(signature: string): ECSignature {
|
||||||
|
const signatureTypeIndexIfExists = getSignatureTypeIndexIfExists(signature);
|
||||||
|
const ecSignatureTypes = [SignatureType.Ecrecover, SignatureType.EIP712, SignatureType.Trezor];
|
||||||
|
const isECSignatureType = _.includes(ecSignatureTypes, signatureTypeIndexIfExists);
|
||||||
|
if (!isECSignatureType) {
|
||||||
|
throw new Error(`Cannot parse non-ECSignature type: ${signatureTypeIndexIfExists}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
|
const vrsHex = `0x${signature.substr(4)}`;
|
||||||
|
const ecSignature = parseSignatureHexAsVRS(vrsHex);
|
||||||
|
|
||||||
|
return ecSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
function intToHex(i: number): string {
|
||||||
|
const hex = ethUtil.bufferToHex(ethUtil.toBuffer(i));
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSignatureTypeIndexIfExists(signature: string): number {
|
||||||
|
const unprefixedSignature = ethUtil.stripHexPrefix(signature);
|
||||||
|
const signatureTypeHex = unprefixedSignature.substr(0, 2);
|
||||||
|
const base = 16;
|
||||||
|
const signatureTypeInt = parseInt(signatureTypeHex, base);
|
||||||
|
return signatureTypeInt;
|
||||||
|
}
|
||||||
|
|
||||||
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
|
function parseSignatureHexAsVRS(signatureHex: string): ECSignature {
|
||||||
const signatureBuffer = ethUtil.toBuffer(signatureHex);
|
const signatureBuffer = ethUtil.toBuffer(signatureHex);
|
||||||
let v = signatureBuffer[0];
|
let v = signatureBuffer[0];
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { web3Factory } from '@0xproject/dev-utils';
|
import { web3Factory } from '@0xproject/dev-utils';
|
||||||
|
import { Order } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'make-promises-safe';
|
import 'make-promises-safe';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import { constants, getOrderHashHex } from '../src';
|
import { constants, orderHashUtils } from '../src';
|
||||||
|
|
||||||
import { chaiSetup } from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import { web3Wrapper } from './utils/web3_wrapper';
|
import { web3Wrapper } from './utils/web3_wrapper';
|
||||||
@ -14,24 +15,25 @@ const expect = chai.expect;
|
|||||||
|
|
||||||
describe('Order hashing', () => {
|
describe('Order hashing', () => {
|
||||||
describe('#getOrderHashHex', () => {
|
describe('#getOrderHashHex', () => {
|
||||||
const expectedOrderHash = '0x39da987067a3c9e5f1617694f1301326ba8c8b0498ebef5df4863bed394e3c83';
|
const expectedOrderHash = '0x367ad7730eb8b5feab8a9c9f47c6fcba77a2d4df125ee6a59cc26ac955710f7e';
|
||||||
const fakeExchangeContractAddress = '0xb69e673309512a9d726f87304c6984054f87a93b';
|
const fakeExchangeContractAddress = '0xb69e673309512a9d726f87304c6984054f87a93b';
|
||||||
const order = {
|
const order: Order = {
|
||||||
maker: constants.NULL_ADDRESS,
|
makerAddress: constants.NULL_ADDRESS,
|
||||||
taker: constants.NULL_ADDRESS,
|
takerAddress: constants.NULL_ADDRESS,
|
||||||
feeRecipient: constants.NULL_ADDRESS,
|
senderAddress: constants.NULL_ADDRESS,
|
||||||
makerTokenAddress: constants.NULL_ADDRESS,
|
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||||
takerTokenAddress: constants.NULL_ADDRESS,
|
makerAssetData: constants.NULL_ADDRESS,
|
||||||
exchangeContractAddress: fakeExchangeContractAddress,
|
takerAssetData: constants.NULL_ADDRESS,
|
||||||
|
exchangeAddress: fakeExchangeContractAddress,
|
||||||
salt: new BigNumber(0),
|
salt: new BigNumber(0),
|
||||||
makerFee: new BigNumber(0),
|
makerFee: new BigNumber(0),
|
||||||
takerFee: new BigNumber(0),
|
takerFee: new BigNumber(0),
|
||||||
makerTokenAmount: new BigNumber(0),
|
makerAssetAmount: new BigNumber(0),
|
||||||
takerTokenAmount: new BigNumber(0),
|
takerAssetAmount: new BigNumber(0),
|
||||||
expirationUnixTimestampSec: new BigNumber(0),
|
expirationTimeSeconds: new BigNumber(0),
|
||||||
};
|
};
|
||||||
it('calculates the order hash', async () => {
|
it('calculates the order hash', async () => {
|
||||||
const orderHash = getOrderHashHex(order);
|
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||||
expect(orderHash).to.be.equal(expectedOrderHash);
|
expect(orderHash).to.be.equal(expectedOrderHash);
|
||||||
});
|
});
|
||||||
it('throws a readable error message if taker format is invalid', async () => {
|
it('throws a readable error message if taker format is invalid', async () => {
|
||||||
@ -41,7 +43,7 @@ describe('Order hashing', () => {
|
|||||||
};
|
};
|
||||||
const expectedErrorMessage =
|
const expectedErrorMessage =
|
||||||
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||||
expect(() => getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
expect(() => orderHashUtils.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,8 +7,8 @@ import 'make-promises-safe';
|
|||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
|
|
||||||
import { generatePseudoRandomSalt, isValidOrderHash, isValidSignature, signOrderHashAsync } from '../src';
|
import { ecSignOrderHashAsync, generatePseudoRandomSalt, orderHashUtils } from '../src';
|
||||||
import * as signatureUtils from '../src/signature_utils';
|
import { isValidECSignature, isValidSignatureAsync } from '../src/signature_utils';
|
||||||
|
|
||||||
import { chaiSetup } from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||||
@ -20,7 +20,62 @@ const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
|
|||||||
|
|
||||||
describe('Signature utils', () => {
|
describe('Signature utils', () => {
|
||||||
describe('#isValidSignature', () => {
|
describe('#isValidSignature', () => {
|
||||||
// The Exchange smart contract `isValidSignature` method only validates orderHashes and assumes
|
let dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
|
||||||
|
const ethSignSignature =
|
||||||
|
'0x031B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254';
|
||||||
|
let address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
||||||
|
|
||||||
|
it("should return false if the data doesn't pertain to the signature & address", async () => {
|
||||||
|
expect(await isValidSignatureAsync(provider, '0x0', ethSignSignature, address)).to.be.false();
|
||||||
|
});
|
||||||
|
it("should return false if the address doesn't pertain to the signature & data", async () => {
|
||||||
|
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
||||||
|
expect(
|
||||||
|
await isValidSignatureAsync(provider, dataHex, ethSignSignature, validUnrelatedAddress),
|
||||||
|
).to.be.false();
|
||||||
|
});
|
||||||
|
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
|
||||||
|
const signatureArray = ethSignSignature.split('');
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
|
signatureArray[5] = 'C'; // V = 28, instead of 27
|
||||||
|
const wrongSignature = signatureArray.join('');
|
||||||
|
expect(await isValidSignatureAsync(provider, dataHex, wrongSignature, address)).to.be.false();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if signatureType is invalid', () => {
|
||||||
|
const signatureArray = ethSignSignature.split('');
|
||||||
|
signatureArray[3] = '9'; // SignatureType w/ index 9 doesn't exist
|
||||||
|
const signatureWithInvalidType = signatureArray.join('');
|
||||||
|
expect(isValidSignatureAsync(provider, dataHex, signatureWithInvalidType, address)).to.be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true for a valid Ecrecover (EthSign) signature', async () => {
|
||||||
|
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, ethSignSignature, address);
|
||||||
|
expect(isValidSignatureLocal).to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true for a valid EIP712 signature', async () => {
|
||||||
|
dataHex = '0xa1d7403bcbbcd75ec233cfd6584ff8dabed677d0e9bb32c2bea94e9dd8a109da';
|
||||||
|
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
|
||||||
|
const eip712Signature =
|
||||||
|
'0x041bdde07aac4bf12c12ddbb155919c43eba4146a2cfcf904a862950dbebe332554c6674975603eb5a4eaf8fd7f2e06350267e5b36cda9851a89f8bb49fe2fc9afe2';
|
||||||
|
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, eip712Signature, address);
|
||||||
|
expect(isValidSignatureLocal).to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true for a valid Trezor signature', async () => {
|
||||||
|
dataHex = '0xd0d994e31c88f33fd8a572552a70ed339de579e5ba49ee1d17cc978bbe1cdd21';
|
||||||
|
address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb';
|
||||||
|
const trezorSignature =
|
||||||
|
'0x051ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd99';
|
||||||
|
const isValidSignatureLocal = await isValidSignatureAsync(provider, dataHex, trezorSignature, address);
|
||||||
|
expect(isValidSignatureLocal).to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: remaining sigs
|
||||||
|
});
|
||||||
|
describe('#isValidECSignature', () => {
|
||||||
|
// The Exchange smart contract `isValidECSignature` method only validates orderHashes and assumes
|
||||||
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
|
// the length of the data is exactly 32 bytes. Thus for these tests, we use data of this size.
|
||||||
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
|
const dataHex = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
|
||||||
const signature = {
|
const signature = {
|
||||||
@ -30,18 +85,18 @@ describe('Signature utils', () => {
|
|||||||
};
|
};
|
||||||
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
||||||
it("should return false if the data doesn't pertain to the signature & address", async () => {
|
it("should return false if the data doesn't pertain to the signature & address", async () => {
|
||||||
expect(isValidSignature('0x0', signature, address)).to.be.false();
|
expect(isValidECSignature('0x0', signature, address)).to.be.false();
|
||||||
});
|
});
|
||||||
it("should return false if the address doesn't pertain to the signature & data", async () => {
|
it("should return false if the address doesn't pertain to the signature & data", async () => {
|
||||||
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
||||||
expect(isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
expect(isValidECSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
||||||
});
|
});
|
||||||
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
|
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
|
||||||
const wrongSignature = _.assign({}, signature, { v: 28 });
|
const wrongSignature = _.assign({}, signature, { v: 28 });
|
||||||
expect(isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
expect(isValidECSignature(dataHex, wrongSignature, address)).to.be.false();
|
||||||
});
|
});
|
||||||
it('should return true if the signature does pertain to the dataHex & address', async () => {
|
it('should return true if the signature does pertain to the dataHex & address', async () => {
|
||||||
const isValidSignatureLocal = isValidSignature(dataHex, signature, address);
|
const isValidSignatureLocal = isValidECSignature(dataHex, signature, address);
|
||||||
expect(isValidSignatureLocal).to.be.true();
|
expect(isValidSignatureLocal).to.be.true();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -60,20 +115,20 @@ describe('Signature utils', () => {
|
|||||||
});
|
});
|
||||||
describe('#isValidOrderHash', () => {
|
describe('#isValidOrderHash', () => {
|
||||||
it('returns false if the value is not a hex string', () => {
|
it('returns false if the value is not a hex string', () => {
|
||||||
const isValid = isValidOrderHash('not a hex');
|
const isValid = orderHashUtils.isValidOrderHash('not a hex');
|
||||||
expect(isValid).to.be.false();
|
expect(isValid).to.be.false();
|
||||||
});
|
});
|
||||||
it('returns false if the length is wrong', () => {
|
it('returns false if the length is wrong', () => {
|
||||||
const isValid = isValidOrderHash('0xdeadbeef');
|
const isValid = orderHashUtils.isValidOrderHash('0xdeadbeef');
|
||||||
expect(isValid).to.be.false();
|
expect(isValid).to.be.false();
|
||||||
});
|
});
|
||||||
it('returns true if order hash is correct', () => {
|
it('returns true if order hash is correct', () => {
|
||||||
const orderHashLength = 65;
|
const orderHashLength = 65;
|
||||||
const isValid = isValidOrderHash('0x' + Array(orderHashLength).join('0'));
|
const isValid = orderHashUtils.isValidOrderHash('0x' + Array(orderHashLength).join('0'));
|
||||||
expect(isValid).to.be.true();
|
expect(isValid).to.be.true();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#signOrderHashAsync', () => {
|
describe('#ecSignOrderHashAsync', () => {
|
||||||
let stubs: Sinon.SinonStub[] = [];
|
let stubs: Sinon.SinonStub[] = [];
|
||||||
let makerAddress: string;
|
let makerAddress: string;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -92,7 +147,7 @@ describe('Signature utils', () => {
|
|||||||
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
};
|
};
|
||||||
const ecSignature = await signOrderHashAsync(
|
const ecSignature = await ecSignOrderHashAsync(
|
||||||
provider,
|
provider,
|
||||||
orderHash,
|
orderHash,
|
||||||
makerAddress,
|
makerAddress,
|
||||||
@ -126,7 +181,7 @@ describe('Signature utils', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const ecSignature = await signOrderHashAsync(
|
const ecSignature = await ecSignOrderHashAsync(
|
||||||
fakeProvider,
|
fakeProvider,
|
||||||
orderHash,
|
orderHash,
|
||||||
makerAddress,
|
makerAddress,
|
||||||
@ -157,7 +212,7 @@ describe('Signature utils', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const ecSignature = await signOrderHashAsync(
|
const ecSignature = await ecSignOrderHashAsync(
|
||||||
fakeProvider,
|
fakeProvider,
|
||||||
orderHash,
|
orderHash,
|
||||||
makerAddress,
|
makerAddress,
|
||||||
|
@ -292,18 +292,15 @@ export interface Order {
|
|||||||
makerAssetData: string;
|
makerAssetData: string;
|
||||||
takerAssetData: string;
|
takerAssetData: string;
|
||||||
salt: BigNumber;
|
salt: BigNumber;
|
||||||
|
exchangeAddress: string;
|
||||||
feeRecipientAddress: string;
|
feeRecipientAddress: string;
|
||||||
expirationTimeSeconds: BigNumber;
|
expirationTimeSeconds: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SignedOrder extends UnsignedOrder {
|
export interface SignedOrder extends Order {
|
||||||
signature: string;
|
signature: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnsignedOrder extends Order {
|
|
||||||
exchangeAddress: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Elliptic Curve signature
|
* Elliptic Curve signature
|
||||||
*/
|
*/
|
||||||
@ -386,3 +383,46 @@ export interface Token {
|
|||||||
symbol: string;
|
symbol: string;
|
||||||
decimals: number;
|
decimals: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SignatureType {
|
||||||
|
Illegal,
|
||||||
|
Invalid,
|
||||||
|
Caller,
|
||||||
|
Ecrecover,
|
||||||
|
EIP712,
|
||||||
|
Trezor,
|
||||||
|
Contract,
|
||||||
|
PreSigned,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elliptic Curve signature
|
||||||
|
*/
|
||||||
|
export interface ECSignature {
|
||||||
|
v: number;
|
||||||
|
r: string;
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AssetProxyId {
|
||||||
|
INVALID,
|
||||||
|
ERC20,
|
||||||
|
ERC721,
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user