In @0x/order-utils
: Add TransactionSignatureError
to ExchangeRevertErrors
.
In `@0x/contracts-exchange`: Add `TransactionSignatureError`, supplanting `TransactionErrorCodes.BAD_SIGNATURE`, and associated test.
This commit is contained in:
parent
a0223835b8
commit
3c88ede02c
@ -216,6 +216,23 @@ contract MixinExchangeRichErrors is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TransactionSignatureError(
|
||||||
|
bytes32 transactionHash,
|
||||||
|
address signer,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
TRANSACTION_SIGNATURE_ERROR_SELECTOR,
|
||||||
|
transactionHash,
|
||||||
|
signer,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function TransactionExecutionError(
|
function TransactionExecutionError(
|
||||||
bytes32 transactionHash,
|
bytes32 transactionHash,
|
||||||
bytes memory errorData
|
bytes memory errorData
|
||||||
|
@ -272,24 +272,23 @@ contract MixinSignatureValidator is
|
|||||||
assembly {
|
assembly {
|
||||||
mstore(signature, sub(signatureLength, 1))
|
mstore(signature, sub(signatureLength, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode the call data.
|
// Encode the call data.
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
IWallet(walletAddress).isValidSignature.selector,
|
IWallet(walletAddress).isValidSignature.selector,
|
||||||
hash,
|
hash,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
// Restore the full signature.
|
||||||
|
assembly {
|
||||||
|
mstore(signature, signatureLength)
|
||||||
|
}
|
||||||
|
|
||||||
// Static call the verification function.
|
// Static call the verification function.
|
||||||
(bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData);
|
(bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData);
|
||||||
// Return data should be a single bool.
|
// Return data should be a single bool.
|
||||||
if (didSucceed && returnData.length == 32)
|
if (didSucceed && returnData.length == 32)
|
||||||
return returnData.readUint256(0) != 0;
|
return returnData.readUint256(0) != 0;
|
||||||
|
|
||||||
// Static call to verifier failed.
|
// Static call to verifier failed.
|
||||||
// Restore the full signature.
|
|
||||||
assembly {
|
|
||||||
mstore(signature, signatureLength)
|
|
||||||
}
|
|
||||||
rrevert(SignatureError(
|
rrevert(SignatureError(
|
||||||
SignatureErrorCodes.WALLET_ERROR,
|
SignatureErrorCodes.WALLET_ERROR,
|
||||||
hash,
|
hash,
|
||||||
@ -323,7 +322,6 @@ contract MixinSignatureValidator is
|
|||||||
assembly {
|
assembly {
|
||||||
mstore(signature, sub(signatureLength, 21))
|
mstore(signature, sub(signatureLength, 21))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode the call data.
|
// Encode the call data.
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
IValidator(validatorAddress).isValidSignature.selector,
|
IValidator(validatorAddress).isValidSignature.selector,
|
||||||
@ -331,17 +329,16 @@ contract MixinSignatureValidator is
|
|||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
// Restore the full signature.
|
||||||
|
assembly {
|
||||||
|
mstore(signature, signatureLength)
|
||||||
|
}
|
||||||
// Static call the verification function.
|
// Static call the verification function.
|
||||||
(bool didSucceed, bytes memory returnData) = validatorAddress.staticcall(callData);
|
(bool didSucceed, bytes memory returnData) = validatorAddress.staticcall(callData);
|
||||||
// Return data should be a single bool.
|
// Return data should be a single bool.
|
||||||
if (didSucceed && returnData.length == 32)
|
if (didSucceed && returnData.length == 32)
|
||||||
return returnData.readUint256(0) != 0;
|
return returnData.readUint256(0) != 0;
|
||||||
|
|
||||||
// Static call to verifier failed.
|
// Static call to verifier failed.
|
||||||
// Restore the full signature.
|
|
||||||
assembly {
|
|
||||||
mstore(signature, signatureLength)
|
|
||||||
}
|
|
||||||
rrevert(SignatureError(
|
rrevert(SignatureError(
|
||||||
SignatureErrorCodes.VALIDATOR_ERROR,
|
SignatureErrorCodes.VALIDATOR_ERROR,
|
||||||
hash,
|
hash,
|
||||||
|
@ -74,9 +74,10 @@ contract MixinTransactions is
|
|||||||
transactionHash,
|
transactionHash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature)) {
|
signature)) {
|
||||||
rrevert(TransactionError(
|
rrevert(TransactionSignatureError(
|
||||||
TransactionErrorCodes.BAD_SIGNATURE,
|
transactionHash,
|
||||||
transactionHash
|
signerAddress,
|
||||||
|
signature
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,7 @@ contract MExchangeRichErrors is
|
|||||||
|
|
||||||
enum TransactionErrorCodes {
|
enum TransactionErrorCodes {
|
||||||
NO_REENTRANCY,
|
NO_REENTRANCY,
|
||||||
ALREADY_EXECUTED,
|
ALREADY_EXECUTED
|
||||||
BAD_SIGNATURE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// solhint-disable func-name-mixedcase
|
// solhint-disable func-name-mixedcase
|
||||||
@ -189,6 +188,18 @@ contract MExchangeRichErrors is
|
|||||||
pure
|
pure
|
||||||
returns (bytes memory);
|
returns (bytes memory);
|
||||||
|
|
||||||
|
bytes4 internal constant TRANSACTION_SIGNATURE_ERROR_SELECTOR =
|
||||||
|
bytes4(keccak256("TransactionSignatureError(bytes32,address,bytes)"));
|
||||||
|
|
||||||
|
function TransactionSignatureError(
|
||||||
|
bytes32 transactionHash,
|
||||||
|
address signer,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory);
|
||||||
|
|
||||||
bytes4 internal constant TRANSACTION_EXECUTION_ERROR_SELECTOR =
|
bytes4 internal constant TRANSACTION_EXECUTION_ERROR_SELECTOR =
|
||||||
bytes4(keccak256("TransactionExecutionError(bytes32,bytes)"));
|
bytes4(keccak256("TransactionExecutionError(bytes32,bytes)"));
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import {
|
|||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
import { BigNumber, providerUtils } from '@0x/utils';
|
import { BigNumber, providerUtils } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { artifacts, ExchangeContract, ExchangeWrapper, ExchangeWrapperContract, WhitelistContract } from '../src/';
|
import { artifacts, ExchangeContract, ExchangeWrapper, ExchangeWrapperContract, WhitelistContract } from '../src/';
|
||||||
@ -136,7 +137,7 @@ describe('Exchange transactions', () => {
|
|||||||
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address, chainId);
|
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address, chainId);
|
||||||
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId);
|
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId);
|
||||||
});
|
});
|
||||||
describe('executeTransaction', () => {
|
describe.only('executeTransaction', () => {
|
||||||
describe('fillOrder', () => {
|
describe('fillOrder', () => {
|
||||||
let takerAssetFillAmount: BigNumber;
|
let takerAssetFillAmount: BigNumber;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -153,6 +154,24 @@ describe('Exchange transactions', () => {
|
|||||||
signedTx = takerTransactionFactory.newSignedTransaction(data);
|
signedTx = takerTransactionFactory.newSignedTransaction(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw if signature is invalid', async () => {
|
||||||
|
const v = ethUtil.toBuffer(signedTx.signature.slice(0, 4));
|
||||||
|
const invalidR = ethUtil.sha3('invalidR');
|
||||||
|
const invalidS = ethUtil.sha3('invalidS');
|
||||||
|
const signatureType = ethUtil.toBuffer(`0x${signedTx.signature.slice(-2)}`);
|
||||||
|
const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
|
||||||
|
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
|
||||||
|
signedTx.signature = invalidSigHex;
|
||||||
|
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
|
||||||
|
const expectedError = new ExchangeRevertErrors.TransactionSignatureError(
|
||||||
|
transactionHashHex,
|
||||||
|
signedTx.signerAddress,
|
||||||
|
signedTx.signature,
|
||||||
|
);
|
||||||
|
const tx = exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw if not called by specified sender', async () => {
|
it('should throw if not called by specified sender', async () => {
|
||||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
|
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTx);
|
||||||
|
@ -28,14 +28,13 @@ export enum AssetProxyDispatchErrorCode {
|
|||||||
export enum TransactionErrorCode {
|
export enum TransactionErrorCode {
|
||||||
NoReentrancy,
|
NoReentrancy,
|
||||||
AlreadyExecuted,
|
AlreadyExecuted,
|
||||||
BadSignature,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SignatureError extends RevertError {
|
export class SignatureError extends RevertError {
|
||||||
constructor(error?: SignatureErrorCode, orderHash?: string, signer?: string, signature?: string) {
|
constructor(error?: SignatureErrorCode, hash?: string, signer?: string, signature?: string) {
|
||||||
super('SignatureError(uint8 error, bytes32 orderHash, address signer, bytes signature)', {
|
super('SignatureError(uint8 error, bytes32 hash, address signer, bytes signature)', {
|
||||||
error,
|
error,
|
||||||
orderHash,
|
hash,
|
||||||
signer,
|
signer,
|
||||||
signature,
|
signature,
|
||||||
});
|
});
|
||||||
@ -120,6 +119,16 @@ export class TransactionError extends RevertError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TransactionSignatureError extends RevertError {
|
||||||
|
constructor(transactionHash?: string, signer?: string, signature?: string) {
|
||||||
|
super('TransactionSignatureError(bytes32 transactionHash, address signer, bytes signature)', {
|
||||||
|
transactionHash,
|
||||||
|
signer,
|
||||||
|
signature,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TransactionExecutionError extends RevertError {
|
export class TransactionExecutionError extends RevertError {
|
||||||
constructor(transactionHash?: string, errorData?: string) {
|
constructor(transactionHash?: string, errorData?: string) {
|
||||||
super('TransactionExecutionError(bytes32 transactionHash, bytes errorData)', { transactionHash, errorData });
|
super('TransactionExecutionError(bytes32 transactionHash, bytes errorData)', { transactionHash, errorData });
|
||||||
@ -145,6 +154,7 @@ const types = [
|
|||||||
AssetProxyTransferError,
|
AssetProxyTransferError,
|
||||||
NegativeSpreadError,
|
NegativeSpreadError,
|
||||||
TransactionError,
|
TransactionError,
|
||||||
|
TransactionSignatureError,
|
||||||
TransactionExecutionError,
|
TransactionExecutionError,
|
||||||
IncompleteFillError,
|
IncompleteFillError,
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user