@0x/base-contract
: Make PromiseWithTransactionHash
fully compatible with regular Promise
types.
`@0x/contracts/exchange` Make `OrderValidator` and `WalletOrderValidator` signature types checked for every fill (not just first)'
This commit is contained in:
parent
2e5645108b
commit
5f8ebc3601
@ -354,9 +354,15 @@ contract MixinExchangeCore is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate Maker signature (check only if first time seen)
|
// Validate either on the first fill or if the signature type requires
|
||||||
if (orderInfo.orderTakerAssetFilledAmount == 0) {
|
// regular validation.
|
||||||
address makerAddress = order.makerAddress;
|
address makerAddress = order.makerAddress;
|
||||||
|
if (orderInfo.orderTakerAssetFilledAmount == 0 ||
|
||||||
|
doesSignatureRequireRegularValidation(
|
||||||
|
orderInfo.orderHash,
|
||||||
|
makerAddress,
|
||||||
|
signature
|
||||||
|
)) {
|
||||||
if (!_isValidOrderWithHashSignature(
|
if (!_isValidOrderWithHashSignature(
|
||||||
order,
|
order,
|
||||||
orderInfo.orderHash,
|
orderInfo.orderHash,
|
||||||
|
@ -31,13 +31,13 @@ import "./MixinTransactions.sol";
|
|||||||
import "./MixinExchangeRichErrors.sol";
|
import "./MixinExchangeRichErrors.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinSignatureValidator is
|
contract MixinSignatureValidator is
|
||||||
MixinExchangeRichErrors,
|
MixinExchangeRichErrors,
|
||||||
ReentrancyGuard,
|
ReentrancyGuard,
|
||||||
LibOrder,
|
LibOrder,
|
||||||
ISignatureValidator,
|
ISignatureValidator,
|
||||||
MixinTransactions
|
MixinTransactions
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
// Mapping of hash => signer => signed
|
// Mapping of hash => signer => signed
|
||||||
@ -161,13 +161,41 @@ contract MixinSignatureValidator is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Checks if a signature is of a type that should be verified for
|
||||||
|
/// every subsequent fill.
|
||||||
|
/// @param orderHash The hash of the order.
|
||||||
|
/// @param signerAddress The address of the signer.
|
||||||
|
/// @param signature The signature for `orderHash`.
|
||||||
|
/// @return needsRegularValidation True if the signature should be validated
|
||||||
|
/// for every operation.
|
||||||
|
function doesSignatureRequireRegularValidation(
|
||||||
|
bytes32 orderHash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bool needsRegularValidation)
|
||||||
|
{
|
||||||
|
SignatureType signatureType = _readValidSignatureType(
|
||||||
|
orderHash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
// Only signature types that take a full order should be validated
|
||||||
|
// regularly.
|
||||||
|
return
|
||||||
|
signatureType == SignatureType.OrderValidator ||
|
||||||
|
signatureType == SignatureType.WalletOrderValidator;
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Verifies that an order, with provided order hash, has been signed
|
/// @dev Verifies that an order, with provided order hash, has been signed
|
||||||
/// by the given signer.
|
/// by the given signer.
|
||||||
/// @param order The order.
|
/// @param order The order.
|
||||||
/// @param orderHash The hash of the order.
|
/// @param orderHash The hash of the order.
|
||||||
/// @param signerAddress Address that should have signed the.Signat given hash.
|
/// @param signerAddress Address that should have signed the.Signat given hash.
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
/// @param signature Proof that the hash has been signed by signer.
|
||||||
/// @return True if the signature is valid for the given hash and signer.
|
/// @return isValid True if the signature is valid for the given hash and signer.
|
||||||
function _isValidOrderWithHashSignature(
|
function _isValidOrderWithHashSignature(
|
||||||
Order memory order,
|
Order memory order,
|
||||||
bytes32 orderHash,
|
bytes32 orderHash,
|
||||||
|
@ -96,4 +96,20 @@ contract ISignatureValidator {
|
|||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (bool isValid);
|
returns (bool isValid);
|
||||||
|
|
||||||
|
/// @dev Checks if a signature is of a type that should be verified for
|
||||||
|
/// every subsequent fill.
|
||||||
|
/// @param orderHash The hash of the order.
|
||||||
|
/// @param signerAddress The address of the signer.
|
||||||
|
/// @param signature The signature for `orderHash`.
|
||||||
|
/// @return needsRegularValidation True if the signature should be validated
|
||||||
|
/// for every operation.
|
||||||
|
function doesSignatureRequireRegularValidation(
|
||||||
|
bytes32 orderHash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bool needsRegularValidation);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import { assetDataUtils, ExchangeRevertErrors, orderHashUtils, signatureUtils }
|
|||||||
import { SignatureType, SignedOrder } from '@0x/types';
|
import { SignatureType, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, providerUtils, StringRevertError } from '@0x/utils';
|
import { BigNumber, providerUtils, StringRevertError } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
import ethUtil = require('ethereumjs-util');
|
import ethUtil = require('ethereumjs-util');
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -31,7 +31,7 @@ const expect = chai.expect;
|
|||||||
|
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
// tslint:disable:no-unnecessary-type-assertion
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
describe('MixinSignatureValidator', () => {
|
describe.only('MixinSignatureValidator', () => {
|
||||||
let chainId: number;
|
let chainId: number;
|
||||||
let signedOrder: SignedOrder;
|
let signedOrder: SignedOrder;
|
||||||
let orderFactory: OrderFactory;
|
let orderFactory: OrderFactory;
|
||||||
@ -93,12 +93,9 @@ describe('MixinSignatureValidator', () => {
|
|||||||
|
|
||||||
signatureValidatorLogDecoder = new LogDecoder(web3Wrapper, artifacts);
|
signatureValidatorLogDecoder = new LogDecoder(web3Wrapper, artifacts);
|
||||||
const approveValidator = async (validatorAddress: string) => {
|
const approveValidator = async (validatorAddress: string) => {
|
||||||
type SendApproveTx = (address: string, approved: boolean, txData: { from: string }) => Promise<string>;
|
type SendApproveTx = (address: string, approved: boolean, txData: { from: string }) => Promise<any>;
|
||||||
const sendTx = async (fn: { sendTransactionAsync: SendApproveTx }) => {
|
const sendTx = async (fn: { awaitTransactionSuccessAsync: SendApproveTx }) => {
|
||||||
return web3Wrapper.awaitTransactionSuccessAsync(
|
return fn.awaitTransactionSuccessAsync(validatorAddress, true, { from: signerAddress }) as Promise<any>;
|
||||||
await fn.sendTransactionAsync(validatorAddress, true, { from: signerAddress }),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
await sendTx(signatureValidator.setSignatureValidatorApproval);
|
await sendTx(signatureValidator.setSignatureValidatorApproval);
|
||||||
await sendTx(signatureValidator.setOrderValidatorApproval);
|
await sendTx(signatureValidator.setOrderValidatorApproval);
|
||||||
@ -410,13 +407,10 @@ describe('MixinSignatureValidator', () => {
|
|||||||
|
|
||||||
it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
|
||||||
// Set approval of signature validator to false
|
// Set approval of signature validator to false
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await signatureValidator.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||||
await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
|
testValidator.address,
|
||||||
testValidator.address,
|
false,
|
||||||
false,
|
{ from: signerAddress },
|
||||||
{ from: signerAddress },
|
|
||||||
),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
);
|
||||||
// Validate signature
|
// Validate signature
|
||||||
const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
|
const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
|
||||||
@ -430,10 +424,7 @@ describe('MixinSignatureValidator', () => {
|
|||||||
it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
|
it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
|
||||||
// Presign hash
|
// Presign hash
|
||||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await signatureValidator.preSign.awaitTransactionSuccessAsync(orderHashHex, { from: signedOrder.makerAddress });
|
||||||
await signatureValidator.preSign.sendTransactionAsync(orderHashHex, { from: signedOrder.makerAddress }),
|
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
|
||||||
// Validate presigned signature
|
// Validate presigned signature
|
||||||
const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
|
const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
|
||||||
const signatureHex = ethUtil.bufferToHex(signature);
|
const signatureHex = ethUtil.bufferToHex(signature);
|
||||||
@ -574,11 +565,10 @@ describe('MixinSignatureValidator', () => {
|
|||||||
|
|
||||||
it('should return false when SignatureType=OrderValidator, signature is valid and validator is not approved', async () => {
|
it('should return false when SignatureType=OrderValidator, signature is valid and validator is not approved', async () => {
|
||||||
// Set approval of signature validator to false
|
// Set approval of signature validator to false
|
||||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
await signatureValidator.setOrderValidatorApproval.awaitTransactionSuccessAsync(
|
||||||
await signatureValidator.setOrderValidatorApproval.sendTransactionAsync(testValidator.address, false, {
|
testValidator.address,
|
||||||
from: signerAddress,
|
false,
|
||||||
}),
|
{ from: signerAddress },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
|
||||||
);
|
);
|
||||||
// Validate signature
|
// Validate signature
|
||||||
const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
|
const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
|
||||||
|
@ -38,19 +38,27 @@ export interface AbiEncoderByFunctionSignature {
|
|||||||
* `awaitTransactionSuccessAsync()`.
|
* `awaitTransactionSuccessAsync()`.
|
||||||
* Maybe there's a better place for this.
|
* Maybe there's a better place for this.
|
||||||
*/
|
*/
|
||||||
export class PromiseWithTransactionHash<T> implements PromiseLike<T> {
|
export class PromiseWithTransactionHash<T> implements Promise<T> {
|
||||||
public readonly txHashPromise: Promise<string>;
|
public readonly txHashPromise: Promise<string>;
|
||||||
private readonly _promise: Promise<T>;
|
private readonly _promise: Promise<T>;
|
||||||
constructor(txHashPromise: Promise<string>, promise: Promise<T>) {
|
constructor(txHashPromise: Promise<string>, promise: Promise<T>) {
|
||||||
this.txHashPromise = txHashPromise;
|
this.txHashPromise = txHashPromise;
|
||||||
this._promise = promise;
|
this._promise = promise;
|
||||||
}
|
}
|
||||||
|
// tslint:disable-next-line:async-suffix
|
||||||
public then<TResult>(
|
public then<TResult>(
|
||||||
onFulfilled?: (v: T) => TResult | PromiseLike<TResult>,
|
onFulfilled?: (v: T) => TResult | Promise<TResult>,
|
||||||
onRejected?: (reason: any) => PromiseLike<never>,
|
onRejected?: (reason: any) => Promise<never>,
|
||||||
): PromiseLike<TResult> {
|
): Promise<TResult> {
|
||||||
return this._promise.then<TResult>(onFulfilled, onRejected);
|
return this._promise.then<TResult>(onFulfilled, onRejected);
|
||||||
}
|
}
|
||||||
|
// tslint:disable-next-line:async-suffix
|
||||||
|
public catch<TResult>(onRejected?: (reason: any) => Promise<TResult>): Promise<TResult | T> {
|
||||||
|
return this._promise.catch(onRejected);
|
||||||
|
}
|
||||||
|
get [Symbol.toStringTag](): 'Promise' {
|
||||||
|
return this._promise[Symbol.toStringTag];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseContract {
|
export class BaseContract {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user