Merge pull request #379 from 0xProject/portal_json

Make portal order JSON compatible with 0x.js
This commit is contained in:
Leonid
2018-02-09 09:27:08 +01:00
committed by GitHub
19 changed files with 189 additions and 291 deletions

View File

@@ -2,6 +2,7 @@ import {
BlockParam, BlockParam,
BlockRange, BlockRange,
DecodedLogEvent, DecodedLogEvent,
ECSignature,
ExchangeContractEventArgs, ExchangeContractEventArgs,
ExchangeEvents, ExchangeEvents,
IndexedFilterValues, IndexedFilterValues,
@@ -35,10 +36,10 @@ import {
BlockchainErrs, BlockchainErrs,
ContractInstance, ContractInstance,
EtherscanLinkSuffixes, EtherscanLinkSuffixes,
Order as PortalOrder,
ProviderType, ProviderType,
Side, Side,
SideToAssetToken, SideToAssetToken,
SignatureData,
Token, Token,
TokenByAddress, TokenByAddress,
} from 'ts/types'; } from 'ts/types';
@@ -288,39 +289,24 @@ export class Blockchain {
}), }),
); );
} }
public portalOrderToSignedOrder( public portalOrderToZeroExOrder(portalOrder: PortalOrder): SignedOrder {
maker: string,
taker: string,
makerTokenAddress: string,
takerTokenAddress: string,
makerTokenAmount: BigNumber,
takerTokenAmount: BigNumber,
makerFee: BigNumber,
takerFee: BigNumber,
expirationUnixTimestampSec: BigNumber,
feeRecipient: string,
signatureData: SignatureData,
salt: BigNumber,
): SignedOrder {
const ecSignature = signatureData;
const exchangeContractAddress = this.getExchangeContractAddressIfExists(); const exchangeContractAddress = this.getExchangeContractAddressIfExists();
const takerOrNullAddress = _.isEmpty(taker) ? constants.NULL_ADDRESS : taker; const zeroExSignedOrder = {
const signedOrder = {
ecSignature,
exchangeContractAddress, exchangeContractAddress,
expirationUnixTimestampSec, maker: portalOrder.signedOrder.maker,
feeRecipient, taker: portalOrder.signedOrder.taker,
maker, makerTokenAddress: portalOrder.signedOrder.makerTokenAddress,
makerFee, takerTokenAddress: portalOrder.signedOrder.takerTokenAddress,
makerTokenAddress, makerTokenAmount: new BigNumber(portalOrder.signedOrder.makerTokenAmount),
makerTokenAmount, takerTokenAmount: new BigNumber(portalOrder.signedOrder.takerTokenAmount),
salt, makerFee: new BigNumber(portalOrder.signedOrder.makerFee),
taker: takerOrNullAddress, takerFee: new BigNumber(portalOrder.signedOrder.takerFee),
takerFee, expirationUnixTimestampSec: new BigNumber(portalOrder.signedOrder.expirationUnixTimestampSec),
takerTokenAddress, feeRecipient: portalOrder.signedOrder.feeRecipient,
takerTokenAmount, ecSignature: portalOrder.signedOrder.ecSignature,
salt: new BigNumber(portalOrder.signedOrder.salt),
}; };
return signedOrder; return zeroExSignedOrder;
} }
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> { public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
@@ -413,7 +399,7 @@ export class Blockchain {
return newTokenBalancePromise; return newTokenBalancePromise;
} }
public async signOrderHashAsync(orderHash: string): Promise<SignatureData> { public async signOrderHashAsync(orderHash: string): Promise<ECSignature> {
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
const makerAddress = this._userAddress; const makerAddress = this._userAddress;
// If makerAddress is undefined, this means they have a web3 instance injected into their browser // If makerAddress is undefined, this means they have a web3 instance injected into their browser
@@ -436,11 +422,8 @@ export class Blockchain {
makerAddress, makerAddress,
shouldAddPersonalMessagePrefix, shouldAddPersonalMessagePrefix,
); );
const signatureData = _.extend({}, ecSignature, { this._dispatcher.updateECSignature(ecSignature);
hash: orderHash, return ecSignature;
});
this._dispatcher.updateSignatureData(signatureData);
return signatureData;
} }
public async mintTestTokensAsync(token: Token) { public async mintTestTokensAsync(token: Token) {
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);

View File

@@ -18,8 +18,8 @@ import { EthereumAddress } from 'ts/components/ui/ethereum_address';
import { Identicon } from 'ts/components/ui/identicon'; import { Identicon } from 'ts/components/ui/identicon';
import { VisualOrder } from 'ts/components/visual_order'; import { VisualOrder } from 'ts/components/visual_order';
import { Dispatcher } from 'ts/redux/dispatcher'; import { Dispatcher } from 'ts/redux/dispatcher';
import { orderSchema } from 'ts/schemas/order_schema'; import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { SchemaValidator } from 'ts/schemas/validator'; import { validator } from 'ts/schemas/validator';
import { AlertTypes, BlockchainErrs, Order, Token, TokenByAddress, WebsitePaths } from 'ts/types'; import { AlertTypes, BlockchainErrs, Order, Token, TokenByAddress, WebsitePaths } from 'ts/types';
import { colors } from 'ts/utils/colors'; import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
@@ -59,7 +59,6 @@ interface FillOrderState {
} }
export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
private _validator: SchemaValidator;
private _isUnmounted: boolean; private _isUnmounted: boolean;
constructor(props: FillOrderProps) { constructor(props: FillOrderProps) {
super(props); super(props);
@@ -82,7 +81,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
isConfirmingTokenTracking: false, isConfirmingTokenTracking: false,
tokensToTrack: [], tokensToTrack: [],
}; };
this._validator = new SchemaValidator();
} }
public componentWillMount() { public componentWillMount() {
if (!_.isEmpty(this.state.orderJSON)) { if (!_.isEmpty(this.state.orderJSON)) {
@@ -109,7 +107,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
<FillOrderJSON <FillOrderJSON
blockchain={this.props.blockchain} blockchain={this.props.blockchain}
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
networkId={this.props.networkId}
orderJSON={this.state.orderJSON} orderJSON={this.state.orderJSON}
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
/> />
@@ -136,7 +133,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
<FillOrderJSON <FillOrderJSON
blockchain={this.props.blockchain} blockchain={this.props.blockchain}
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
networkId={this.props.networkId}
orderJSON={this.state.orderJSON} orderJSON={this.state.orderJSON}
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
/> />
@@ -182,16 +178,16 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
); );
} }
private _renderVisualOrder() { private _renderVisualOrder() {
const takerTokenAddress = this.state.parsedOrder.taker.token.address; const takerTokenAddress = this.state.parsedOrder.signedOrder.takerTokenAddress;
const takerToken = this.props.tokenByAddress[takerTokenAddress]; const takerToken = this.props.tokenByAddress[takerTokenAddress];
const orderTakerAmount = new BigNumber(this.state.parsedOrder.taker.amount); const orderTakerAmount = new BigNumber(this.state.parsedOrder.signedOrder.takerTokenAmount);
const orderMakerAmount = new BigNumber(this.state.parsedOrder.maker.amount); const orderMakerAmount = new BigNumber(this.state.parsedOrder.signedOrder.makerTokenAmount);
const takerAssetToken = { const takerAssetToken = {
amount: orderTakerAmount.minus(this.state.unavailableTakerAmount), amount: orderTakerAmount.minus(this.state.unavailableTakerAmount),
symbol: takerToken.symbol, symbol: takerToken.symbol,
}; };
const fillToken = this.props.tokenByAddress[takerToken.address]; const fillToken = this.props.tokenByAddress[takerTokenAddress];
const makerTokenAddress = this.state.parsedOrder.maker.token.address; const makerTokenAddress = this.state.parsedOrder.signedOrder.makerTokenAddress;
const makerToken = this.props.tokenByAddress[makerTokenAddress]; const makerToken = this.props.tokenByAddress[makerTokenAddress];
const makerAssetToken = { const makerAssetToken = {
amount: orderMakerAmount.times(takerAssetToken.amount).div(orderTakerAmount), amount: orderMakerAmount.times(takerAssetToken.amount).div(orderTakerAmount),
@@ -201,10 +197,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
amount: this.props.orderFillAmount, amount: this.props.orderFillAmount,
symbol: takerToken.symbol, symbol: takerToken.symbol,
}; };
const orderTaker = !_.isEmpty(this.state.parsedOrder.taker.address) const parsedOrderExpiration = new BigNumber(this.state.parsedOrder.signedOrder.expirationUnixTimestampSec);
? this.state.parsedOrder.taker.address
: this.props.userAddress;
const parsedOrderExpiration = new BigNumber(this.state.parsedOrder.expiration);
const exchangeRate = orderMakerAmount.div(orderTakerAmount); const exchangeRate = orderMakerAmount.div(orderTakerAmount);
let orderReceiveAmount = 0; let orderReceiveAmount = 0;
@@ -213,7 +206,8 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals);
} }
const isUserMaker = const isUserMaker =
!_.isUndefined(this.state.parsedOrder) && this.state.parsedOrder.maker.address === this.props.userAddress; !_.isUndefined(this.state.parsedOrder) &&
this.state.parsedOrder.signedOrder.maker === this.props.userAddress;
const expiryDate = utils.convertToReadableDateTimeFromUnixTimestamp(parsedOrderExpiration); const expiryDate = utils.convertToReadableDateTimeFromUnixTimestamp(parsedOrderExpiration);
return ( return (
<div className="pt3 pb1"> <div className="pt3 pb1">
@@ -224,11 +218,11 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
Maker: Maker:
</div> </div>
<div className="col col-2 pr1"> <div className="col col-2 pr1">
<Identicon address={this.state.parsedOrder.maker.address} diameter={23} /> <Identicon address={this.state.parsedOrder.signedOrder.maker} diameter={23} />
</div> </div>
<div className="col col-6"> <div className="col col-6">
<EthereumAddress <EthereumAddress
address={this.state.parsedOrder.maker.address} address={this.state.parsedOrder.signedOrder.maker}
networkId={this.props.networkId} networkId={this.props.networkId}
/> />
</div> </div>
@@ -237,8 +231,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
<div className="lg-px4 md-px4 sm-px0"> <div className="lg-px4 md-px4 sm-px0">
<div className="lg-px4 md-px4 sm-px1 pt1"> <div className="lg-px4 md-px4 sm-px1 pt1">
<VisualOrder <VisualOrder
orderTakerAddress={orderTaker}
orderMakerAddress={this.state.parsedOrder.maker.address}
makerAssetToken={makerAssetToken} makerAssetToken={makerAssetToken}
takerAssetToken={takerAssetToken} takerAssetToken={takerAssetToken}
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
@@ -361,15 +353,16 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
return; return;
} }
const makerTokenIfExists = this.props.tokenByAddress[this.state.parsedOrder.maker.token.address]; const makerTokenIfExists = this.props.tokenByAddress[this.state.parsedOrder.signedOrder.makerTokenAddress];
const takerTokenIfExists = this.props.tokenByAddress[this.state.parsedOrder.taker.token.address]; const takerTokenIfExists = this.props.tokenByAddress[this.state.parsedOrder.signedOrder.takerTokenAddress];
const tokensToTrack = []; const tokensToTrack: Token[] = [];
const isUnseenMakerToken = _.isUndefined(makerTokenIfExists); const isUnseenMakerToken = _.isUndefined(makerTokenIfExists);
const isMakerTokenTracked = !_.isUndefined(makerTokenIfExists) && makerTokenIfExists.isTracked; const isMakerTokenTracked = !_.isUndefined(makerTokenIfExists) && makerTokenIfExists.isTracked;
if (isUnseenMakerToken) { if (isUnseenMakerToken) {
tokensToTrack.push({ tokensToTrack.push({
...this.state.parsedOrder.maker.token, ...this.state.parsedOrder.metadata.makerToken,
address: this.state.parsedOrder.signedOrder.makerTokenAddress,
iconUrl: undefined, iconUrl: undefined,
isTracked: false, isTracked: false,
isRegistered: false, isRegistered: false,
@@ -381,7 +374,8 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
const isTakerTokenTracked = !_.isUndefined(takerTokenIfExists) && takerTokenIfExists.isTracked; const isTakerTokenTracked = !_.isUndefined(takerTokenIfExists) && takerTokenIfExists.isTracked;
if (isUnseenTakerToken) { if (isUnseenTakerToken) {
tokensToTrack.push({ tokensToTrack.push({
...this.state.parsedOrder.taker.token, ...this.state.parsedOrder.metadata.takerToken,
address: this.state.parsedOrder.signedOrder.takerTokenAddress,
iconUrl: undefined, iconUrl: undefined,
isTracked: false, isTracked: false,
isRegistered: false, isRegistered: false,
@@ -403,9 +397,10 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
private async _validateFillOrderFireAndForgetAsync(orderJSON: string) { private async _validateFillOrderFireAndForgetAsync(orderJSON: string) {
let orderJSONErrMsg = ''; let orderJSONErrMsg = '';
let parsedOrder: Order; let parsedOrder: Order;
let orderHash: string;
try { try {
const order = JSON.parse(orderJSON); const order = JSON.parse(orderJSON);
const validationResult = this._validator.validate(order, orderSchema); const validationResult = validator.validate(order, portalOrderSchema);
if (validationResult.errors.length > 0) { if (validationResult.errors.length > 0) {
orderJSONErrMsg = 'Submitted order JSON is not a valid order'; orderJSONErrMsg = 'Submitted order JSON is not a valid order';
utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`); utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`);
@@ -413,41 +408,36 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
} }
parsedOrder = order; parsedOrder = order;
const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists(); const makerAmount = new BigNumber(parsedOrder.signedOrder.makerTokenAmount);
const makerAmount = new BigNumber(parsedOrder.maker.amount); const takerAmount = new BigNumber(parsedOrder.signedOrder.takerTokenAmount);
const takerAmount = new BigNumber(parsedOrder.taker.amount); const expiration = new BigNumber(parsedOrder.signedOrder.expirationUnixTimestampSec);
const expiration = new BigNumber(parsedOrder.expiration); const salt = new BigNumber(parsedOrder.signedOrder.salt);
const salt = new BigNumber(parsedOrder.salt); const parsedMakerFee = new BigNumber(parsedOrder.signedOrder.makerFee);
const parsedMakerFee = new BigNumber(parsedOrder.maker.feeAmount); const parsedTakerFee = new BigNumber(parsedOrder.signedOrder.takerFee);
const parsedTakerFee = new BigNumber(parsedOrder.taker.feeAmount);
const zeroExOrder: ZeroExOrder = { const zeroExOrder: ZeroExOrder = {
exchangeContractAddress: parsedOrder.exchangeContract, exchangeContractAddress: parsedOrder.signedOrder.exchangeContractAddress,
expirationUnixTimestampSec: expiration, expirationUnixTimestampSec: expiration,
feeRecipient: parsedOrder.feeRecipient, feeRecipient: parsedOrder.signedOrder.feeRecipient,
maker: parsedOrder.maker.address, maker: parsedOrder.signedOrder.maker,
makerFee: parsedMakerFee, makerFee: parsedMakerFee,
makerTokenAddress: parsedOrder.maker.token.address, makerTokenAddress: parsedOrder.signedOrder.makerTokenAddress,
makerTokenAmount: makerAmount, makerTokenAmount: makerAmount,
salt, salt,
taker: _.isEmpty(parsedOrder.taker.address) ? constants.NULL_ADDRESS : parsedOrder.taker.address, taker: _.isEmpty(parsedOrder.signedOrder.taker)
? constants.NULL_ADDRESS
: parsedOrder.signedOrder.taker,
takerFee: parsedTakerFee, takerFee: parsedTakerFee,
takerTokenAddress: parsedOrder.taker.token.address, takerTokenAddress: parsedOrder.signedOrder.takerTokenAddress,
takerTokenAmount: takerAmount, takerTokenAmount: takerAmount,
}; };
const orderHash = ZeroEx.getOrderHashHex(zeroExOrder); orderHash = ZeroEx.getOrderHashHex(zeroExOrder);
const signature = parsedOrder.signature; const exchangeContractAddr = this.props.blockchain.getExchangeContractAddressIfExists();
const isValidSignature = ZeroEx.isValidSignature(signature.hash, signature, parsedOrder.maker.address); const signature = parsedOrder.signedOrder.ecSignature;
if (this.props.networkId !== parsedOrder.networkId) { const isValidSignature = ZeroEx.isValidSignature(orderHash, signature, parsedOrder.signedOrder.maker);
orderJSONErrMsg = `This order was made on another Ethereum network if (exchangeContractAddr !== parsedOrder.signedOrder.exchangeContractAddress) {
(id: ${parsedOrder.networkId}). Connect to this network to fill.`; orderJSONErrMsg = 'This order was made on another network or using a deprecated Exchange contract';
parsedOrder = undefined;
} else if (exchangeContractAddr !== parsedOrder.exchangeContract) {
orderJSONErrMsg = 'This order was made using a deprecated 0x Exchange contract.';
parsedOrder = undefined;
} else if (orderHash !== signature.hash) {
orderJSONErrMsg = 'Order hash does not match supplied plaintext values';
parsedOrder = undefined; parsedOrder = undefined;
} else if (!isValidSignature) { } else if (!isValidSignature) {
orderJSONErrMsg = 'Order signature is invalid'; orderJSONErrMsg = 'Order signature is invalid';
@@ -478,13 +468,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
// Clear cache entry if user updates orderJSON to invalid entry // Clear cache entry if user updates orderJSON to invalid entry
this.props.dispatcher.updateUserSuppliedOrderCache(undefined); this.props.dispatcher.updateUserSuppliedOrderCache(undefined);
} else { } else {
const orderHash = parsedOrder.signature.hash;
unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash);
const isMakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync( const isMakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync(
parsedOrder.maker.token.address, parsedOrder.signedOrder.makerTokenAddress,
); );
const isTakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync( const isTakerTokenAddressInRegistry = await this.props.blockchain.isAddressInTokenRegistryAsync(
parsedOrder.taker.token.address, parsedOrder.signedOrder.takerTokenAddress,
); );
this.setState({ this.setState({
isMakerTokenAddressInRegistry, isMakerTokenAddressInRegistry,
@@ -529,20 +518,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
globalErrMsg = 'You must specify a fill amount'; globalErrMsg = 'You must specify a fill amount';
} }
const signedOrder = this.props.blockchain.portalOrderToSignedOrder( const signedOrder = this.props.blockchain.portalOrderToZeroExOrder(parsedOrder);
parsedOrder.maker.address,
parsedOrder.taker.address,
parsedOrder.maker.token.address,
parsedOrder.taker.token.address,
new BigNumber(parsedOrder.maker.amount),
new BigNumber(parsedOrder.taker.amount),
new BigNumber(parsedOrder.maker.feeAmount),
new BigNumber(parsedOrder.taker.feeAmount),
new BigNumber(this.state.parsedOrder.expiration),
parsedOrder.feeRecipient,
parsedOrder.signature,
new BigNumber(parsedOrder.salt),
);
if (_.isEmpty(globalErrMsg)) { if (_.isEmpty(globalErrMsg)) {
try { try {
await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( await this.props.blockchain.validateFillOrderThrowIfInvalidAsync(
@@ -551,7 +527,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
this.props.userAddress, this.props.userAddress,
); );
} catch (err) { } catch (err) {
globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.taker.address); globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.signedOrder.taker);
} }
} }
if (!_.isEmpty(globalErrMsg)) { if (!_.isEmpty(globalErrMsg)) {
@@ -562,7 +538,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
return; return;
} }
const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId]; const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${parsedOrder.taker.token.symbol}-${networkName}`; const eventLabel = `${parsedOrder.metadata.takerToken.symbol}-${networkName}`;
try { try {
const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync( const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync(
signedOrder, signedOrder,
@@ -572,7 +548,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
category: 'Portal', category: 'Portal',
action: 'Fill Order Success', action: 'Fill Order Success',
label: eventLabel, label: eventLabel,
value: parsedOrder.taker.amount, value: parsedOrder.signedOrder.takerTokenAmount,
}); });
// After fill completes, let's force fetch the token balances // After fill completes, let's force fetch the token balances
this.props.dispatcher.forceTokenStateRefetch(); this.props.dispatcher.forceTokenStateRefetch();
@@ -591,7 +567,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
category: 'Portal', category: 'Portal',
action: 'Fill Order Failure', action: 'Fill Order Failure',
label: eventLabel, label: eventLabel,
value: parsedOrder.taker.amount, value: parsedOrder.signedOrder.takerTokenAmount,
}); });
const errMsg = `${err}`; const errMsg = `${err}`;
if (utils.didUserDenyWeb3Request(errMsg)) { if (utils.didUserDenyWeb3Request(errMsg)) {
@@ -618,7 +594,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
}); });
const parsedOrder = this.state.parsedOrder; const parsedOrder = this.state.parsedOrder;
const orderHash = parsedOrder.signature.hash;
const takerAddress = this.props.userAddress; const takerAddress = this.props.userAddress;
if (_.isUndefined(takerAddress)) { if (_.isUndefined(takerAddress)) {
@@ -630,28 +605,16 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
} }
let globalErrMsg = ''; let globalErrMsg = '';
const takerTokenAmount = new BigNumber(parsedOrder.taker.amount); const takerTokenAmount = new BigNumber(parsedOrder.signedOrder.takerTokenAmount);
const signedOrder = this.props.blockchain.portalOrderToSignedOrder( const signedOrder = this.props.blockchain.portalOrderToZeroExOrder(parsedOrder);
parsedOrder.maker.address, const orderHash = ZeroEx.getOrderHashHex(signedOrder);
parsedOrder.taker.address,
parsedOrder.maker.token.address,
parsedOrder.taker.token.address,
new BigNumber(parsedOrder.maker.amount),
takerTokenAmount,
new BigNumber(parsedOrder.maker.feeAmount),
new BigNumber(parsedOrder.taker.feeAmount),
new BigNumber(this.state.parsedOrder.expiration),
parsedOrder.feeRecipient,
parsedOrder.signature,
new BigNumber(parsedOrder.salt),
);
const unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); const unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash);
const availableTakerTokenAmount = takerTokenAmount.minus(unavailableTakerAmount); const availableTakerTokenAmount = takerTokenAmount.minus(unavailableTakerAmount);
try { try {
await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync(signedOrder, availableTakerTokenAmount); await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync(signedOrder, availableTakerTokenAmount);
} catch (err) { } catch (err) {
globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.taker.address); globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.signedOrder.taker);
} }
if (!_.isEmpty(globalErrMsg)) { if (!_.isEmpty(globalErrMsg)) {
this.setState({ this.setState({
@@ -661,7 +624,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
return; return;
} }
const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId]; const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${parsedOrder.maker.token.symbol}-${networkName}`; const eventLabel = `${parsedOrder.metadata.makerToken.symbol}-${networkName}`;
try { try {
await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount); await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount);
this.setState({ this.setState({
@@ -674,7 +637,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
category: 'Portal', category: 'Portal',
action: 'Cancel Order Success', action: 'Cancel Order Success',
label: eventLabel, label: eventLabel,
value: parsedOrder.maker.amount, value: parsedOrder.signedOrder.makerTokenAmount,
}); });
return; return;
} catch (err) { } catch (err) {
@@ -689,7 +652,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
category: 'Portal', category: 'Portal',
action: 'Cancel Order Failure', action: 'Cancel Order Failure',
label: eventLabel, label: eventLabel,
value: parsedOrder.maker.amount, value: parsedOrder.signedOrder.makerTokenAmount,
}); });
globalErrMsg = 'Failed to cancel order, please refresh and try again'; globalErrMsg = 'Failed to cancel order, please refresh and try again';
utils.consoleLog(`${err}`); utils.consoleLog(`${err}`);

View File

@@ -12,7 +12,6 @@ import { utils } from 'ts/utils/utils';
interface FillOrderJSONProps { interface FillOrderJSONProps {
blockchain: Blockchain; blockchain: Blockchain;
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
networkId: number;
orderJSON: string; orderJSON: string;
onFillOrderJSONChanged: (event: any) => void; onFillOrderJSONChanged: (event: any) => void;
} }
@@ -34,8 +33,7 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder
}, },
}; };
const hintOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec(); const hintOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
const hintSignatureData = { const hintECSignature = {
hash: '0xf965a9978a0381ab58f5a2408ad967c...',
r: '0xf01103f759e2289a28593eaf22e5820032...', r: '0xf01103f759e2289a28593eaf22e5820032...',
s: '937862111edcba395f8a9e0cc1b2c5e12320...', s: '937862111edcba395f8a9e0cc1b2c5e12320...',
v: 27, v: 27,
@@ -43,7 +41,6 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder
const hintSalt = ZeroEx.generatePseudoRandomSalt(); const hintSalt = ZeroEx.generatePseudoRandomSalt();
const feeRecipient = constants.NULL_ADDRESS; const feeRecipient = constants.NULL_ADDRESS;
const hintOrder = utils.generateOrder( const hintOrder = utils.generateOrder(
this.props.networkId,
exchangeContract, exchangeContract,
hintSideToAssetToken, hintSideToAssetToken,
hintOrderExpiryTimestamp, hintOrderExpiryTimestamp,
@@ -52,7 +49,7 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder
constants.MAKER_FEE, constants.MAKER_FEE,
constants.TAKER_FEE, constants.TAKER_FEE,
feeRecipient, feeRecipient,
hintSignatureData, hintECSignature,
this.props.tokenByAddress, this.props.tokenByAddress,
hintSalt, hintSalt,
); );

View File

@@ -1,4 +1,4 @@
import { Order, ZeroEx } from '0x.js'; import { ECSignature, Order, ZeroEx } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import Dialog from 'material-ui/Dialog'; import Dialog from 'material-ui/Dialog';
@@ -17,18 +17,9 @@ import { HelpTooltip } from 'ts/components/ui/help_tooltip';
import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
import { SwapIcon } from 'ts/components/ui/swap_icon'; import { SwapIcon } from 'ts/components/ui/swap_icon';
import { Dispatcher } from 'ts/redux/dispatcher'; import { Dispatcher } from 'ts/redux/dispatcher';
import { orderSchema } from 'ts/schemas/order_schema'; import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { SchemaValidator } from 'ts/schemas/validator'; import { validator } from 'ts/schemas/validator';
import { import { AlertTypes, BlockchainErrs, HashData, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
AlertTypes,
BlockchainErrs,
HashData,
Side,
SideToAssetToken,
SignatureData,
Token,
TokenByAddress,
} from 'ts/types';
import { colors } from 'ts/utils/colors'; import { colors } from 'ts/utils/colors';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter'; import { errorReporter } from 'ts/utils/error_reporter';
@@ -49,7 +40,7 @@ interface GenerateOrderFormProps {
orderExpiryTimestamp: BigNumber; orderExpiryTimestamp: BigNumber;
networkId: number; networkId: number;
userAddress: string; userAddress: string;
orderSignatureData: SignatureData; orderECSignature: ECSignature;
orderTakerAddress: string; orderTakerAddress: string;
orderSalt: BigNumber; orderSalt: BigNumber;
sideToAssetToken: SideToAssetToken; sideToAssetToken: SideToAssetToken;
@@ -64,7 +55,6 @@ interface GenerateOrderFormState {
} }
export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> { export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
private _validator: SchemaValidator;
constructor(props: GenerateOrderFormProps) { constructor(props: GenerateOrderFormProps) {
super(props); super(props);
this.state = { this.state = {
@@ -72,7 +62,6 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
shouldShowIncompleteErrs: false, shouldShowIncompleteErrs: false,
signingState: SigningState.UNSIGNED, signingState: SigningState.UNSIGNED,
}; };
this._validator = new SchemaValidator();
} }
public componentDidMount() { public componentDidMount() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
@@ -88,6 +77,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
allowed to fill this order. If no taker is<br> \ allowed to fill this order. If no taker is<br> \
specified, anyone is able to fill it.'; specified, anyone is able to fill it.';
const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists(); const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists();
const initialTakerAddress =
this.props.orderTakerAddress === ZeroEx.NULL_ADDRESS ? '' : this.props.orderTakerAddress;
return ( return (
<div className="clearfix mb2 lg-px4 md-px4 sm-px2"> <div className="clearfix mb2 lg-px4 md-px4 sm-px2">
<h3>Generate an order</h3> <h3>Generate an order</h3>
@@ -168,7 +159,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
<div className="pt1 flex mx-auto"> <div className="pt1 flex mx-auto">
<IdenticonAddressInput <IdenticonAddressInput
label="Taker" label="Taker"
initialAddress={this.props.orderTakerAddress} initialAddress={initialTakerAddress}
updateOrderAddress={this._updateOrderAddress.bind(this)} updateOrderAddress={this._updateOrderAddress.bind(this)}
/> />
<div className="pt3"> <div className="pt3">
@@ -209,14 +200,13 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
<OrderJSON <OrderJSON
exchangeContractIfExists={exchangeContractIfExists} exchangeContractIfExists={exchangeContractIfExists}
orderExpiryTimestamp={this.props.orderExpiryTimestamp} orderExpiryTimestamp={this.props.orderExpiryTimestamp}
orderSignatureData={this.props.orderSignatureData} orderECSignature={this.props.orderECSignature}
orderTakerAddress={this.props.orderTakerAddress} orderTakerAddress={this.props.orderTakerAddress}
orderMakerAddress={this.props.userAddress} orderMakerAddress={this.props.userAddress}
orderSalt={this.props.orderSalt} orderSalt={this.props.orderSalt}
orderMakerFee={this.props.hashData.makerFee} orderMakerFee={this.props.hashData.makerFee}
orderTakerFee={this.props.hashData.takerFee} orderTakerFee={this.props.hashData.takerFee}
orderFeeRecipient={this.props.hashData.feeRecipientAddress} orderFeeRecipient={this.props.hashData.feeRecipientAddress}
networkId={this.props.networkId}
sideToAssetToken={this.props.sideToAssetToken} sideToAssetToken={this.props.sideToAssetToken}
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
/> />
@@ -327,9 +317,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
let globalErrMsg = ''; let globalErrMsg = '';
try { try {
const signatureData = await this.props.blockchain.signOrderHashAsync(orderHash); const ecSignature = await this.props.blockchain.signOrderHashAsync(orderHash);
const order = utils.generateOrder( const order = utils.generateOrder(
this.props.networkId,
exchangeContractAddr, exchangeContractAddr,
this.props.sideToAssetToken, this.props.sideToAssetToken,
hashData.orderExpiryTimestamp, hashData.orderExpiryTimestamp,
@@ -338,11 +327,11 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
hashData.makerFee, hashData.makerFee,
hashData.takerFee, hashData.takerFee,
hashData.feeRecipientAddress, hashData.feeRecipientAddress,
signatureData, ecSignature,
this.props.tokenByAddress, this.props.tokenByAddress,
hashData.orderSalt, hashData.orderSalt,
); );
const validationResult = this._validator.validate(order, orderSchema); const validationResult = validator.validate(order, portalOrderSchema);
if (validationResult.errors.length > 0) { if (validationResult.errors.length > 0) {
globalErrMsg = 'Order signing failed. Please refresh and try again'; globalErrMsg = 'Order signing failed. Please refresh and try again';
utils.consoleLog(`Unexpected error occured: Order validation failed: utils.consoleLog(`Unexpected error occured: Order validation failed:
@@ -367,7 +356,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
} }
private _updateOrderAddress(address?: string): void { private _updateOrderAddress(address?: string): void {
if (!_.isUndefined(address)) { if (!_.isUndefined(address)) {
this.props.dispatcher.updateOrderTakerAddress(address); const normalizedAddress = _.isEmpty(address) ? ZeroEx.NULL_ADDRESS : address;
this.props.dispatcher.updateOrderTakerAddress(normalizedAddress);
} }
} }
} }

View File

@@ -1,10 +1,11 @@
import { ECSignature } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import Paper from 'material-ui/Paper'; import Paper from 'material-ui/Paper';
import TextField from 'material-ui/TextField'; import TextField from 'material-ui/TextField';
import * as React from 'react'; import * as React from 'react';
import { CopyIcon } from 'ts/components/ui/copy_icon'; import { CopyIcon } from 'ts/components/ui/copy_icon';
import { SideToAssetToken, SignatureData, TokenByAddress, WebsitePaths } from 'ts/types'; import { SideToAssetToken, TokenByAddress, WebsitePaths } from 'ts/types';
import { configs } from 'ts/utils/configs'; import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter'; import { errorReporter } from 'ts/utils/error_reporter';
@@ -13,14 +14,13 @@ import { utils } from 'ts/utils/utils';
interface OrderJSONProps { interface OrderJSONProps {
exchangeContractIfExists: string; exchangeContractIfExists: string;
orderExpiryTimestamp: BigNumber; orderExpiryTimestamp: BigNumber;
orderSignatureData: SignatureData; orderECSignature: ECSignature;
orderTakerAddress: string; orderTakerAddress: string;
orderMakerAddress: string; orderMakerAddress: string;
orderSalt: BigNumber; orderSalt: BigNumber;
orderMakerFee: BigNumber; orderMakerFee: BigNumber;
orderTakerFee: BigNumber; orderTakerFee: BigNumber;
orderFeeRecipient: string; orderFeeRecipient: string;
networkId: number;
sideToAssetToken: SideToAssetToken; sideToAssetToken: SideToAssetToken;
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
} }
@@ -40,7 +40,6 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
} }
public render() { public render() {
const order = utils.generateOrder( const order = utils.generateOrder(
this.props.networkId,
this.props.exchangeContractIfExists, this.props.exchangeContractIfExists,
this.props.sideToAssetToken, this.props.sideToAssetToken,
this.props.orderExpiryTimestamp, this.props.orderExpiryTimestamp,
@@ -49,7 +48,7 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
this.props.orderMakerFee, this.props.orderMakerFee,
this.props.orderTakerFee, this.props.orderTakerFee,
this.props.orderFeeRecipient, this.props.orderFeeRecipient,
this.props.orderSignatureData, this.props.orderECSignature,
this.props.tokenByAddress, this.props.tokenByAddress,
this.props.orderSalt, this.props.orderSalt,
); );
@@ -162,7 +161,6 @@ You can see and fill it here: ${this.state.shareLink}`);
} }
private _getOrderUrl() { private _getOrderUrl() {
const order = utils.generateOrder( const order = utils.generateOrder(
this.props.networkId,
this.props.exchangeContractIfExists, this.props.exchangeContractIfExists,
this.props.sideToAssetToken, this.props.sideToAssetToken,
this.props.orderExpiryTimestamp, this.props.orderExpiryTimestamp,
@@ -171,7 +169,7 @@ You can see and fill it here: ${this.state.shareLink}`);
this.props.orderMakerFee, this.props.orderMakerFee,
this.props.orderTakerFee, this.props.orderTakerFee,
this.props.orderFeeRecipient, this.props.orderFeeRecipient,
this.props.orderSignatureData, this.props.orderECSignature,
this.props.tokenByAddress, this.props.tokenByAddress,
this.props.orderSalt, this.props.orderSalt,
); );

View File

@@ -21,8 +21,8 @@ import { FlashMessage } from 'ts/components/ui/flash_message';
import { GenerateOrderForm } from 'ts/containers/generate_order_form'; import { GenerateOrderForm } from 'ts/containers/generate_order_form';
import { localStorage } from 'ts/local_storage/local_storage'; import { localStorage } from 'ts/local_storage/local_storage';
import { Dispatcher } from 'ts/redux/dispatcher'; import { Dispatcher } from 'ts/redux/dispatcher';
import { orderSchema } from 'ts/schemas/order_schema'; import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { SchemaValidator } from 'ts/schemas/validator'; import { validator } from 'ts/schemas/validator';
import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, WebsitePaths } from 'ts/types'; import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, WebsitePaths } from 'ts/types';
import { colors } from 'ts/utils/colors'; import { colors } from 'ts/utils/colors';
import { configs } from 'ts/utils/configs'; import { configs } from 'ts/utils/configs';
@@ -367,9 +367,8 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
return undefined; return undefined;
} }
const validator = new SchemaValidator();
const order = JSON.parse(decodeURIComponent(orderPair[1])); const order = JSON.parse(decodeURIComponent(orderPair[1]));
const validationResult = validator.validate(order, orderSchema); const validationResult = validator.validate(order, portalOrderSchema);
if (validationResult.errors.length > 0) { if (validationResult.errors.length > 0) {
utils.consoleLog(`Invalid shared order: ${validationResult.errors}`); utils.consoleLog(`Invalid shared order: ${validationResult.errors}`);
return undefined; return undefined;

View File

@@ -8,8 +8,6 @@ import { utils } from 'ts/utils/utils';
const PRECISION = 5; const PRECISION = 5;
interface VisualOrderProps { interface VisualOrderProps {
orderTakerAddress: string;
orderMakerAddress: string;
makerAssetToken: AssetToken; makerAssetToken: AssetToken;
takerAssetToken: AssetToken; takerAssetToken: AssetToken;
makerToken: Token; makerToken: Token;

View File

@@ -1,3 +1,4 @@
import { ECSignature } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as React from 'react'; import * as React from 'react';
@@ -6,7 +7,7 @@ import { Blockchain } from 'ts/blockchain';
import { GenerateOrderForm as GenerateOrderFormComponent } from 'ts/components/generate_order/generate_order_form'; import { GenerateOrderForm as GenerateOrderFormComponent } from 'ts/components/generate_order/generate_order_form';
import { Dispatcher } from 'ts/redux/dispatcher'; import { Dispatcher } from 'ts/redux/dispatcher';
import { State } from 'ts/redux/reducer'; import { State } from 'ts/redux/reducer';
import { BlockchainErrs, HashData, SideToAssetToken, SignatureData, TokenByAddress } from 'ts/types'; import { BlockchainErrs, HashData, SideToAssetToken, TokenByAddress } from 'ts/types';
interface GenerateOrderFormProps { interface GenerateOrderFormProps {
blockchain: Blockchain; blockchain: Blockchain;
@@ -18,7 +19,7 @@ interface ConnectedState {
blockchainErr: BlockchainErrs; blockchainErr: BlockchainErrs;
blockchainIsLoaded: boolean; blockchainIsLoaded: boolean;
orderExpiryTimestamp: BigNumber; orderExpiryTimestamp: BigNumber;
orderSignatureData: SignatureData; orderECSignature: ECSignature;
userAddress: string; userAddress: string;
orderTakerAddress: string; orderTakerAddress: string;
orderSalt: BigNumber; orderSalt: BigNumber;
@@ -32,7 +33,7 @@ const mapStateToProps = (state: State, ownProps: GenerateOrderFormProps): Connec
blockchainErr: state.blockchainErr, blockchainErr: state.blockchainErr,
blockchainIsLoaded: state.blockchainIsLoaded, blockchainIsLoaded: state.blockchainIsLoaded,
orderExpiryTimestamp: state.orderExpiryTimestamp, orderExpiryTimestamp: state.orderExpiryTimestamp,
orderSignatureData: state.orderSignatureData, orderECSignature: state.orderECSignature,
orderTakerAddress: state.orderTakerAddress, orderTakerAddress: state.orderTakerAddress,
orderSalt: state.orderSalt, orderSalt: state.orderSalt,
networkId: state.networkId, networkId: state.networkId,

View File

@@ -1,3 +1,4 @@
import { ECSignature } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import { State } from 'ts/redux/reducer'; import { State } from 'ts/redux/reducer';
@@ -10,7 +11,6 @@ import {
ScreenWidths, ScreenWidths,
Side, Side,
SideToAssetToken, SideToAssetToken,
SignatureData,
Token, Token,
TokenByAddress, TokenByAddress,
} from 'ts/types'; } from 'ts/types';
@@ -148,10 +148,10 @@ export class Dispatcher {
type: ActionTypes.ForceTokenStateRefetch, type: ActionTypes.ForceTokenStateRefetch,
}); });
} }
public updateSignatureData(signatureData: SignatureData) { public updateECSignature(ecSignature: ECSignature) {
this._dispatch({ this._dispatch({
data: signatureData, data: ecSignature,
type: ActionTypes.UpdateOrderSignatureData, type: ActionTypes.UpdateOrderECSignature,
}); });
} }
public updateUserEtherBalance(balance: BigNumber) { public updateUserEtherBalance(balance: BigNumber) {

View File

@@ -1,4 +1,4 @@
import { ZeroEx } from '0x.js'; import { ECSignature, ZeroEx } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as moment from 'moment'; import * as moment from 'moment';
@@ -11,7 +11,6 @@ import {
ScreenWidths, ScreenWidths,
Side, Side,
SideToAssetToken, SideToAssetToken,
SignatureData,
TokenByAddress, TokenByAddress,
} from 'ts/types'; } from 'ts/types';
import { utils } from 'ts/utils/utils'; import { utils } from 'ts/utils/utils';
@@ -29,7 +28,7 @@ export interface State {
orderExpiryTimestamp: BigNumber; orderExpiryTimestamp: BigNumber;
orderFillAmount: BigNumber; orderFillAmount: BigNumber;
orderTakerAddress: string; orderTakerAddress: string;
orderSignatureData: SignatureData; orderECSignature: ECSignature;
orderSalt: BigNumber; orderSalt: BigNumber;
nodeVersion: string; nodeVersion: string;
screenWidth: ScreenWidths; screenWidth: ScreenWidths;
@@ -59,13 +58,12 @@ const INITIAL_STATE: State = {
networkId: undefined, networkId: undefined,
orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(), orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(),
orderFillAmount: undefined, orderFillAmount: undefined,
orderSignatureData: { orderECSignature: {
hash: '',
r: '', r: '',
s: '', s: '',
v: 27, v: 27,
}, },
orderTakerAddress: '', orderTakerAddress: ZeroEx.NULL_ADDRESS,
orderSalt: ZeroEx.generatePseudoRandomSalt(), orderSalt: ZeroEx.generatePseudoRandomSalt(),
nodeVersion: undefined, nodeVersion: undefined,
screenWidth: utils.getScreenWidth(), screenWidth: utils.getScreenWidth(),
@@ -188,10 +186,10 @@ export function reducer(state: State = INITIAL_STATE, action: Action) {
lastForceTokenStateRefetch: moment().unix(), lastForceTokenStateRefetch: moment().unix(),
}; };
case ActionTypes.UpdateOrderSignatureData: { case ActionTypes.UpdateOrderECSignature: {
return { return {
...state, ...state,
orderSignatureData: action.data, orderECSignature: action.data,
}; };
} }

View File

@@ -0,0 +1,9 @@
export const orderMetadataSchema = {
id: '/OrderMetadata',
properties: {
makerToken: { $ref: '/PortalTokenMetadata' },
takerToken: { $ref: '/PortalTokenMetadata' },
},
required: ['makerToken', 'takerToken'],
type: 'object',
};

View File

@@ -1,15 +0,0 @@
export const orderSchema = {
id: '/Order',
properties: {
maker: { $ref: '/OrderTaker' },
taker: { $ref: '/OrderTaker' },
salt: { type: 'string' },
signature: { $ref: '/SignatureData' },
expiration: { type: 'string' },
feeRecipient: { type: 'string' },
exchangeContract: { type: 'string' },
networkId: { type: 'number' },
},
required: ['maker', 'taker', 'salt', 'signature', 'expiration', 'feeRecipient', 'exchangeContract', 'networkId'],
type: 'object',
};

View File

@@ -1,11 +0,0 @@
export const orderTakerSchema = {
id: '/OrderTaker',
properties: {
address: { type: 'string' },
token: { $ref: '/Token' },
amount: { type: 'string' },
feeAmount: { type: 'string' },
},
required: ['address', 'token', 'amount', 'feeAmount'],
type: 'object',
};

View File

@@ -0,0 +1,9 @@
export const portalOrderSchema = {
id: '/PortalOrder',
properties: {
signedOrder: { $ref: '/SignedOrder' },
metadata: { $ref: '/OrderMetadata' },
},
required: ['signedOrder', 'metadata'],
type: 'object',
};

View File

@@ -1,11 +1,10 @@
export const tokenSchema = { export const portalTokenMetadataSchema = {
id: '/Token', id: '/PortalTokenMetadata',
properties: { properties: {
name: { type: 'string' }, name: { type: 'string' },
symbol: { type: 'string' }, symbol: { type: 'string' },
decimals: { type: 'number' }, decimals: { type: 'number' },
address: { type: 'string' },
}, },
required: ['name', 'symbol', 'decimals', 'address'], required: ['name', 'symbol', 'decimals'],
type: 'object', type: 'object',
}; };

View File

@@ -1,11 +0,0 @@
export const signatureDataSchema = {
id: '/SignatureData',
properties: {
hash: { type: 'string' },
r: { type: 'string' },
s: { type: 'string' },
v: { type: 'number' },
},
required: ['hash', 'r', 's', 'v'],
type: 'object',
};

View File

@@ -1,19 +1,12 @@
import { SchemaValidator } from '@0xproject/json-schemas';
import { Schema as JSONSchema, Validator } from 'jsonschema'; import { Schema as JSONSchema, Validator } from 'jsonschema';
import { orderSchema } from 'ts/schemas/order_schema'; import { orderMetadataSchema } from 'ts/schemas/metadata_schema';
import { orderTakerSchema } from 'ts/schemas/order_taker_schema'; import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { signatureDataSchema } from 'ts/schemas/signature_data_schema'; import { portalTokenMetadataSchema } from 'ts/schemas/portal_token_metadata';
import { tokenSchema } from 'ts/schemas/token_schema';
export class SchemaValidator { const validator = new SchemaValidator();
private _validator: Validator; validator.addSchema(portalTokenMetadataSchema);
constructor() { validator.addSchema(orderMetadataSchema);
this._validator = new Validator(); validator.addSchema(portalOrderSchema);
this._validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id);
this._validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id); export { validator };
this._validator.addSchema(orderTakerSchema as JSONSchema, orderTakerSchema.id);
this._validator.addSchema(orderSchema as JSONSchema, orderSchema.id);
}
public validate(instance: object, schema: Schema) {
return this._validator.validate(instance, schema);
}
}

View File

@@ -1,3 +1,4 @@
import { ECSignature } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
@@ -34,13 +35,6 @@ export interface SideToAssetToken {
[side: string]: AssetToken; [side: string]: AssetToken;
} }
export interface SignatureData {
hash: string;
r: string;
s: string;
v: number;
}
export interface HashData { export interface HashData {
depositAmount: BigNumber; depositAmount: BigNumber;
depositTokenContractAddr: string; depositTokenContractAddr: string;
@@ -59,25 +53,32 @@ export interface OrderToken {
name: string; name: string;
symbol: string; symbol: string;
decimals: number; decimals: number;
address: string;
} }
export interface OrderParty { export interface SignedOrder {
address: string; maker: string;
token: OrderToken; taker: string;
amount: string; makerTokenAddress: string;
feeAmount: string; takerTokenAddress: string;
makerFee: string;
takerFee: string;
makerTokenAmount: string;
takerTokenAmount: string;
expirationUnixTimestampSec: string;
feeRecipient: string;
salt: string;
ecSignature: ECSignature;
exchangeContractAddress: string;
}
export interface OrderMetadata {
makerToken: OrderToken;
takerToken: OrderToken;
} }
export interface Order { export interface Order {
maker: OrderParty; signedOrder: SignedOrder;
taker: OrderParty; metadata: OrderMetadata;
expiration: string;
feeRecipient: string;
salt: string;
signature: SignatureData;
exchangeContract: string;
networkId: number;
} }
export interface Fill { export interface Fill {
@@ -118,7 +119,7 @@ export enum ActionTypes {
UpdateChosenAssetTokenAddress = 'UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS', UpdateChosenAssetTokenAddress = 'UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS',
UpdateOrderTakerAddress = 'UPDATE_ORDER_TAKER_ADDRESS', UpdateOrderTakerAddress = 'UPDATE_ORDER_TAKER_ADDRESS',
UpdateOrderSalt = 'UPDATE_ORDER_SALT', UpdateOrderSalt = 'UPDATE_ORDER_SALT',
UpdateOrderSignatureData = 'UPDATE_ORDER_SIGNATURE_DATA', UpdateOrderECSignature = 'UPDATE_ORDER_EC_SIGNATURE',
UpdateTokenByAddress = 'UPDATE_TOKEN_BY_ADDRESS', UpdateTokenByAddress = 'UPDATE_TOKEN_BY_ADDRESS',
RemoveTokenFromTokenByAddress = 'REMOVE_TOKEN_FROM_TOKEN_BY_ADDRESS', RemoveTokenFromTokenByAddress = 'REMOVE_TOKEN_FROM_TOKEN_BY_ADDRESS',
ForceTokenStateRefetch = 'FORCE_TOKEN_STATE_REFETCH', ForceTokenStateRefetch = 'FORCE_TOKEN_STATE_REFETCH',

View File

@@ -1,4 +1,4 @@
import { ExchangeContractErrs, ZeroExError } from '0x.js'; import { ECSignature, ExchangeContractErrs, ZeroEx, ZeroExError } from '0x.js';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import deepEqual = require('deep-equal'); import deepEqual = require('deep-equal');
import isMobile = require('is-mobile'); import isMobile = require('is-mobile');
@@ -11,7 +11,6 @@ import {
ScreenWidths, ScreenWidths,
Side, Side,
SideToAssetToken, SideToAssetToken,
SignatureData,
Token, Token,
TokenByAddress, TokenByAddress,
} from 'ts/types'; } from 'ts/types';
@@ -59,50 +58,48 @@ export const utils = {
return formattedDate; return formattedDate;
}, },
generateOrder( generateOrder(
networkId: number, exchangeContractAddress: string,
exchangeContract: string,
sideToAssetToken: SideToAssetToken, sideToAssetToken: SideToAssetToken,
orderExpiryTimestamp: BigNumber, expirationUnixTimestampSec: BigNumber,
orderTakerAddress: string, orderTakerAddress: string,
orderMakerAddress: string, orderMakerAddress: string,
makerFee: BigNumber, makerFee: BigNumber,
takerFee: BigNumber, takerFee: BigNumber,
feeRecipient: string, feeRecipient: string,
signatureData: SignatureData, ecSignature: ECSignature,
tokenByAddress: TokenByAddress, tokenByAddress: TokenByAddress,
orderSalt: BigNumber, orderSalt: BigNumber,
): Order { ): Order {
const makerToken = tokenByAddress[sideToAssetToken[Side.Deposit].address]; const makerToken = tokenByAddress[sideToAssetToken[Side.Deposit].address];
const takerToken = tokenByAddress[sideToAssetToken[Side.Receive].address]; const takerToken = tokenByAddress[sideToAssetToken[Side.Receive].address];
const order = { const order = {
maker: { signedOrder: {
address: orderMakerAddress, maker: orderMakerAddress,
token: { taker: orderTakerAddress,
makerFee: makerFee.toString(),
takerFee: takerFee.toString(),
makerTokenAmount: sideToAssetToken[Side.Deposit].amount.toString(),
takerTokenAmount: sideToAssetToken[Side.Receive].amount.toString(),
makerTokenAddress: makerToken.address,
takerTokenAddress: takerToken.address,
expirationUnixTimestampSec: expirationUnixTimestampSec.toString(),
feeRecipient,
salt: orderSalt.toString(),
ecSignature,
exchangeContractAddress,
},
metadata: {
makerToken: {
name: makerToken.name, name: makerToken.name,
symbol: makerToken.symbol, symbol: makerToken.symbol,
decimals: makerToken.decimals, decimals: makerToken.decimals,
address: makerToken.address,
}, },
amount: sideToAssetToken[Side.Deposit].amount.toString(), takerToken: {
feeAmount: makerFee.toString(),
},
taker: {
address: orderTakerAddress,
token: {
name: takerToken.name, name: takerToken.name,
symbol: takerToken.symbol, symbol: takerToken.symbol,
decimals: takerToken.decimals, decimals: takerToken.decimals,
address: takerToken.address,
}, },
amount: sideToAssetToken[Side.Receive].amount.toString(),
feeAmount: takerFee.toString(),
}, },
expiration: orderExpiryTimestamp.toString(),
feeRecipient,
salt: orderSalt.toString(),
signature: signatureData,
exchangeContract,
networkId,
}; };
return order; return order;
}, },