@0x/contracts-exchange
: Rename WalletOrderValidator
to OrderWallet
signature type
`@0x/contracts-exchange`: Rename `SignatureWalletOrderValidatorError` to `SignatureOrderWalletError` `@0x/contracts-exchange`: Add `IEIP1271Wallet` interface `@0x/contracts-exchange`: Add `EIP1271Wallet` and `EIP1271OrderWallet` to `SignatureType` `@0x/contracts-exchange`: Always check `OrderValidator`, `OrderWallet`, `EIP1271OrderWallet` signature types on every fill `@0x/contracts-exchange`: Add tests for EIP1271 signature types. `@0x/contracts-exchange`: Update `LibExchangeRichErrorDecoder` for new/renamed Error types.
This commit is contained in:
committed by
Amir Bandeali
parent
bd5babf65d
commit
33df11b755
@@ -82,6 +82,26 @@
|
||||
"note": "Always check `OrderValidator` and `WalletOrderValidator` signature types on every fill",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Rename `WalletOrderValidator` to `OrderWallet` signature type",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Rename `SignatureWalletOrderValidatorError` to `SignatureOrderWalletError`",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Add `IEIP1271Wallet` interface",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Add `EIP1271Wallet` and `EIP1271OrderWallet` to `SignatureType`",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Always check `OrderValidator`, `OrderWallet`, `EIP1271OrderWallet` signature types on every fill",
|
||||
"pr": "TODO"
|
||||
},
|
||||
{
|
||||
"note": "Add `validatorAddress` field to `SignatureValidatorError` and `SignatureOrderValidatorError` rich reverts",
|
||||
"pr": "TODO"
|
||||
|
@@ -36,6 +36,7 @@
|
||||
"src/interfaces/ITransactions.sol",
|
||||
"src/interfaces/IValidator.sol",
|
||||
"src/interfaces/IWallet.sol",
|
||||
"src/interfaces/IEIP1271Wallet.sol",
|
||||
"src/interfaces/IWrapperFunctions.sol",
|
||||
"test/ReentrantERC20Token.sol",
|
||||
"test/TestAssetProxyDispatcher.sol",
|
||||
|
@@ -138,7 +138,7 @@ contract MixinExchangeRichErrors is
|
||||
);
|
||||
}
|
||||
|
||||
function SignatureWalletOrderValidatorError(
|
||||
function SignatureOrderWalletError(
|
||||
bytes32 orderHash,
|
||||
address wallet,
|
||||
bytes memory signature,
|
||||
@@ -149,7 +149,7 @@ contract MixinExchangeRichErrors is
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
SIGNATURE_WALLET_ORDER_VALIDATOR_ERROR_SELECTOR,
|
||||
SIGNATURE_ORDER_WALLET_ERROR_SELECTOR,
|
||||
orderHash,
|
||||
wallet,
|
||||
signature,
|
||||
|
@@ -24,6 +24,7 @@ import "@0x/contracts-utils/contracts/src/ReentrancyGuard.sol";
|
||||
import "@0x/contracts-utils/contracts/src/RichErrors.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "./interfaces/IWallet.sol";
|
||||
import "./interfaces/IEIP1271Wallet.sol";
|
||||
import "./interfaces/IValidator.sol";
|
||||
import "./interfaces/IOrderValidator.sol";
|
||||
import "./interfaces/ISignatureValidator.sol";
|
||||
@@ -40,6 +41,9 @@ contract MixinSignatureValidator is
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
|
||||
// Magic bytes returned by EIP1271 wallets on success.
|
||||
bytes4 constant public EIP1271_MAGIC_VALUE = 0x20c13b0b;
|
||||
|
||||
// Mapping of hash => signer => signed
|
||||
mapping (bytes32 => mapping (address => bool)) public preSigned;
|
||||
|
||||
@@ -144,8 +148,11 @@ contract MixinSignatureValidator is
|
||||
);
|
||||
// Only hash-compatible signature types can be handled by this
|
||||
// function.
|
||||
if (signatureType == SignatureType.OrderValidator ||
|
||||
signatureType == SignatureType.WalletOrderValidator) {
|
||||
if (
|
||||
signatureType == SignatureType.OrderValidator ||
|
||||
signatureType == SignatureType.OrderWallet ||
|
||||
signatureType == SignatureType.EIP1271OrderWallet
|
||||
) {
|
||||
_rrevert(SignatureError(
|
||||
SignatureErrorCodes.INAPPROPRIATE_SIGNATURE_TYPE,
|
||||
hash,
|
||||
@@ -186,7 +193,8 @@ contract MixinSignatureValidator is
|
||||
// regularly.
|
||||
return
|
||||
signatureType == SignatureType.OrderValidator ||
|
||||
signatureType == SignatureType.WalletOrderValidator;
|
||||
signatureType == SignatureType.OrderWallet ||
|
||||
signatureType == SignatureType.EIP1271OrderWallet;
|
||||
}
|
||||
|
||||
/// @dev Verifies that an order, with provided order hash, has been signed
|
||||
@@ -220,7 +228,7 @@ contract MixinSignatureValidator is
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
} else if (signatureType == SignatureType.WalletOrderValidator) {
|
||||
} else if (signatureType == SignatureType.OrderWallet) {
|
||||
// The entire order is verified by a wallet contract.
|
||||
isValid = _validateOrderWithWallet(
|
||||
order,
|
||||
@@ -229,6 +237,15 @@ contract MixinSignatureValidator is
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
} else if (signatureType == SignatureType.EIP1271OrderWallet) {
|
||||
// The entire order is verified by a wallet contract.
|
||||
isValid = _validateOrderWithEIP1271Wallet(
|
||||
order,
|
||||
orderHash,
|
||||
signerAddress,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
}
|
||||
// Otherwise, it's one of the hash-compatible signature types.
|
||||
return _validateHashSignatureTypes(
|
||||
@@ -333,6 +350,53 @@ contract MixinSignatureValidator is
|
||||
));
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by an EIP1271 Wallet contract.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param walletAddress Address that should have signed the given hash
|
||||
/// and defines its own signature verification method.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the signature is validated by the Walidator.
|
||||
function _validateHashWithEIP1271Wallet(
|
||||
bytes32 hash,
|
||||
address walletAddress,
|
||||
bytes memory signature
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
uint256 signatureLength = signature.length;
|
||||
// Shave the signature type off the signature.
|
||||
assembly {
|
||||
mstore(signature, sub(signatureLength, 1))
|
||||
}
|
||||
// Encode the call data.
|
||||
bytes memory data = new bytes(32);
|
||||
data.writeBytes32(0, hash);
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
IEIP1271Wallet(walletAddress).isValidSignature.selector,
|
||||
data,
|
||||
signature
|
||||
);
|
||||
// Restore the full signature.
|
||||
assembly {
|
||||
mstore(signature, signatureLength)
|
||||
}
|
||||
// Static call the verification function.
|
||||
(bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData);
|
||||
// Return data should be the `EIP1271_MAGIC_VALUE`.
|
||||
if (didSucceed && returnData.length == 32) {
|
||||
return bytes4(returnData.readBytes32(0)) == EIP1271_MAGIC_VALUE;
|
||||
}
|
||||
// Static call to verifier failed.
|
||||
_rrevert(SignatureWalletError(
|
||||
hash,
|
||||
walletAddress,
|
||||
signature,
|
||||
returnData
|
||||
));
|
||||
}
|
||||
|
||||
/// @dev Verifies signature using logic defined by Validator contract.
|
||||
/// If used with an order, the maker of the order can still be an EOA.
|
||||
/// @param hash Any 32 byte hash.
|
||||
@@ -436,7 +500,55 @@ contract MixinSignatureValidator is
|
||||
return returnData.readUint256(0) == 1;
|
||||
}
|
||||
// Static call to verifier failed.
|
||||
_rrevert(SignatureWalletOrderValidatorError(
|
||||
_rrevert(SignatureOrderWalletError(
|
||||
orderHash,
|
||||
walletAddress,
|
||||
signature,
|
||||
returnData
|
||||
));
|
||||
}
|
||||
|
||||
/// @dev Verifies order AND signature via an EIP1271 Wallet contract.
|
||||
/// @param order The order.
|
||||
/// @param orderHash The order hash.
|
||||
/// @param walletAddress Address that should have signed the given hash
|
||||
/// and defines its own order/signature verification method.
|
||||
/// @param signature Proof that the order has been signed by signer.
|
||||
/// @return True if order and signature are validated by the Wallet.
|
||||
function _validateOrderWithEIP1271Wallet(
|
||||
Order memory order,
|
||||
bytes32 orderHash,
|
||||
address walletAddress,
|
||||
bytes memory signature
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
uint256 signatureLength = signature.length;
|
||||
// Shave the signature type off the signature.
|
||||
assembly {
|
||||
mstore(signature, sub(signatureLength, 1))
|
||||
}
|
||||
// Encode the call data.
|
||||
bytes memory data = abi.encode(order);
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
IEIP1271Wallet(walletAddress).isValidSignature.selector,
|
||||
data,
|
||||
signature
|
||||
);
|
||||
// Restore the full signature.
|
||||
assembly {
|
||||
mstore(signature, signatureLength)
|
||||
}
|
||||
// Static call the verification function.
|
||||
(bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData);
|
||||
// Return data should be the `EIP1271_MAGIC_VALUE`.
|
||||
if (didSucceed && returnData.length == 32) {
|
||||
return bytes4(returnData.readBytes32(0)) == EIP1271_MAGIC_VALUE;
|
||||
}
|
||||
// Static call to verifier failed.
|
||||
_rrevert(SignatureOrderWalletError(
|
||||
orderHash,
|
||||
walletAddress,
|
||||
signature,
|
||||
@@ -509,7 +621,7 @@ contract MixinSignatureValidator is
|
||||
}
|
||||
|
||||
/// Validates a hash-compatible signature type
|
||||
/// (anything but `OrderValidator` and `WalletOrderValidator`).
|
||||
/// (anything but `OrderValidator` and `OrderWallet`).
|
||||
function _validateHashSignatureTypes(
|
||||
SignatureType signatureType,
|
||||
bytes32 hash,
|
||||
@@ -603,6 +715,15 @@ contract MixinSignatureValidator is
|
||||
);
|
||||
return isValid;
|
||||
|
||||
// Signature verified by an EIP1271 wallet contract.
|
||||
// If used with an order, the maker of the order is the wallet contract.
|
||||
} else if (signatureType == SignatureType.EIP1271Wallet) {
|
||||
isValid = _validateHashWithEIP1271Wallet(
|
||||
hash,
|
||||
signerAddress,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
}
|
||||
// Otherwise, signatureType == SignatureType.PreSigned
|
||||
assert(signatureType == SignatureType.PreSigned);
|
||||
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IEIP1271Wallet {
|
||||
|
||||
// Magic bytes returned by EIP1271 wallets on success.
|
||||
bytes4 constant public EIP1271_MAGIC_VALUE = 0x20c13b0b;
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param data Arbitrary data.
|
||||
/// @param signature Signature of `data`.
|
||||
/// @return magicValue .
|
||||
function isValidSignature(
|
||||
bytes calldata data,
|
||||
bytes calldata signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue);
|
||||
}
|
@@ -91,4 +91,12 @@ contract IExchangeCore {
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo memory orderInfo);
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of the order.
|
||||
/// @param order The order structure.
|
||||
/// @return Keccak-256 EIP712 hash of the order.
|
||||
function getOrderHash(LibOrder.Order memory order)
|
||||
public
|
||||
view
|
||||
returns (bytes32 orderHash);
|
||||
}
|
||||
|
@@ -53,9 +53,9 @@ contract IExchangeRichErrors {
|
||||
bytes4 internal constant SIGNATURE_ORDER_VALIDATOR_ERROR_SELECTOR =
|
||||
0xf45375b7;
|
||||
|
||||
// bytes4(keccak256("SignatureWalletOrderValidatorError(bytes32,address,bytes,bytes)"))
|
||||
bytes4 internal constant SIGNATURE_WALLET_ORDER_VALIDATOR_ERROR_SELECTOR =
|
||||
0xa85f3360;
|
||||
// bytes4(keccak256("SignatureOrderWalletError(bytes32,address,bytes,bytes)"))
|
||||
bytes4 internal constant SIGNATURE_ORDER_WALLET_ERROR_SELECTOR =
|
||||
0x37fa88c3;
|
||||
|
||||
// bytes4(keccak256("OrderStatusError(bytes32,uint8)"))
|
||||
bytes4 internal constant ORDER_STATUS_ERROR_SELECTOR =
|
||||
|
@@ -26,16 +26,18 @@ contract ISignatureValidator {
|
||||
|
||||
// Allowed signature types.
|
||||
enum SignatureType {
|
||||
Illegal, // 0x00, default value
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Wallet, // 0x04
|
||||
Validator, // 0x05
|
||||
PreSigned, // 0x06
|
||||
OrderValidator, // 0x07
|
||||
WalletOrderValidator, // 0x08
|
||||
NSignatureTypes // 0x09, number of signature types. Always leave at end.
|
||||
Illegal, // 0x00, default value
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Wallet, // 0x04
|
||||
Validator, // 0x05
|
||||
PreSigned, // 0x06
|
||||
OrderValidator, // 0x07
|
||||
OrderWallet, // 0x08
|
||||
EIP1271Wallet, // 0x09
|
||||
EIP1271OrderWallet, // 0x0A
|
||||
NSignatureTypes // 0x0B, number of signature types. Always leave at end.
|
||||
}
|
||||
|
||||
event SignatureValidatorApproval(
|
||||
|
@@ -154,13 +154,13 @@ contract LibExchangeRichErrorDecoder is
|
||||
errorData = _readErrorParameterAsBytes(encoded, 4);
|
||||
}
|
||||
|
||||
/// @dev Decompose an ABI-encoded SignatureWalletOrderValidatorError.
|
||||
/// @dev Decompose an ABI-encoded SignatureOrderWalletError.
|
||||
/// @param encoded ABI-encoded revert error.
|
||||
/// @return errorCode The error code.
|
||||
/// @return signerAddress The expected signer of the hash.
|
||||
/// @return signature The full signature bytes.
|
||||
/// @return errorData The revert data thrown by the validator contract.
|
||||
function decodeSignatureWalletOrderValidatorError(bytes memory encoded)
|
||||
function decodeSignatureOrderWalletError(bytes memory encoded)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
@@ -170,7 +170,7 @@ contract LibExchangeRichErrorDecoder is
|
||||
bytes memory errorData
|
||||
)
|
||||
{
|
||||
_assertSelectorBytes(encoded, SIGNATURE_WALLET_ORDER_VALIDATOR_ERROR_SELECTOR);
|
||||
_assertSelectorBytes(encoded, SIGNATURE_ORDER_WALLET_ERROR_SELECTOR);
|
||||
hash = _readErrorParameterAsBytes32(encoded, 0);
|
||||
signerAddress = _readErrorParameterAsAddress(encoded, 1);
|
||||
signature = _readErrorParameterAsBytes(encoded, 2);
|
||||
|
@@ -20,12 +20,14 @@ pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../src/MixinSignatureValidator.sol";
|
||||
import "../src/MixinTransactions.sol";
|
||||
|
||||
|
||||
contract TestSignatureValidator is
|
||||
LibEIP712ExchangeDomain,
|
||||
LibOrder,
|
||||
MixinSignatureValidator
|
||||
{
|
||||
|
||||
|
@@ -23,11 +23,22 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
|
||||
|
||||
interface ISimplifiedExchange {
|
||||
function getOrderHash(LibOrder.Order calldata order)
|
||||
external
|
||||
view
|
||||
returns (bytes32 orderHash);
|
||||
}
|
||||
|
||||
// solhint-disable no-unused-vars
|
||||
contract TestValidatorWallet {
|
||||
using LibBytes for bytes;
|
||||
|
||||
// Revert reason for `Revert` `ValidatorAction`.
|
||||
string constant public REVERT_REASON = "you shall not pass";
|
||||
// Magic bytes returned by EIP1271 wallets on success.
|
||||
bytes4 constant public EIP1271_MAGIC_VALUE = 0x20c13b0b;
|
||||
|
||||
enum ValidatorAction {
|
||||
// Return false (default)
|
||||
@@ -42,12 +53,18 @@ contract TestValidatorWallet {
|
||||
ValidateSignature,
|
||||
NTypes
|
||||
}
|
||||
/// @dev The Exchange contract.
|
||||
ISimplifiedExchange internal _EXCHANGE;
|
||||
/// @dev Internal state to modify.
|
||||
uint256 internal _state = 1;
|
||||
/// @dev What action to execute when a hash is validated .
|
||||
mapping (bytes32=>ValidatorAction) internal _hashActions;
|
||||
/// @dev Allowed signers for `ValidateSignature` actions using `Wallet` signature types.
|
||||
mapping (bytes32=>address) internal _hashWalletSigners;
|
||||
/// @dev Allowed signers for hash signature types.
|
||||
mapping (bytes32=>address) internal _validSignerForHash;
|
||||
|
||||
constructor(address exchange) public {
|
||||
_EXCHANGE = ISimplifiedExchange(exchange);
|
||||
}
|
||||
|
||||
/// @dev Set the action to take when validating a hash.
|
||||
/// @param hash The hash.
|
||||
@@ -66,7 +83,75 @@ contract TestValidatorWallet {
|
||||
revert('UNSUPPORTED_VALIDATE_ACTION');
|
||||
}
|
||||
_hashActions[hash] = action;
|
||||
_hashWalletSigners[hash] = allowedSigner;
|
||||
_validSignerForHash[hash] = allowedSigner;
|
||||
}
|
||||
|
||||
/// @dev Validates a hash with the following signature types:
|
||||
/// `EIP1271Wallet` and `EIP1271WalletOrder`signature types.
|
||||
/// The length of `data` will determine which signature type is in use.
|
||||
/// @param data Arbitrary data. Either an Order hash or abi-encoded Order.
|
||||
/// @param signature Signature for `data`.
|
||||
/// @return magicValue Returns `EIP1271_MAGIC_VALUE` if the signature check succeeds.
|
||||
function isValidSignature(
|
||||
bytes memory data,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
bytes32 hash = _getOrderHashFromEIP1271Data(data);
|
||||
ValidatorAction action = _hashActions[hash];
|
||||
if (action == ValidatorAction.Reject) {
|
||||
// NOOP.
|
||||
} else if (action == ValidatorAction.Accept) {
|
||||
magicValue = EIP1271_MAGIC_VALUE;
|
||||
} else if (action == ValidatorAction.Revert) {
|
||||
revert(REVERT_REASON);
|
||||
} else if (action == ValidatorAction.UpdateState) {
|
||||
_updateState();
|
||||
} else { // action == ValidatorAction.ValidateSignature
|
||||
if (data.length != 32) {
|
||||
// `data` is an abi-encoded Order.
|
||||
LibOrder.Order memory order = _getOrderFromEIP1271Data(data);
|
||||
if (order.makerAddress == address(this)) {
|
||||
magicValue = EIP1271_MAGIC_VALUE;
|
||||
}
|
||||
} else if (_validSignerForHash[hash] == address(this)) {
|
||||
magicValue = EIP1271_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _getOrderHashFromEIP1271Data(bytes memory data)
|
||||
private
|
||||
returns (bytes32 hash)
|
||||
{
|
||||
if (data.length == 32) {
|
||||
// `data` is an order hash.
|
||||
hash = data.readBytes32(0);
|
||||
} else {
|
||||
// `data` is an abi-encoded Order.
|
||||
LibOrder.Order memory order = _getOrderFromEIP1271Data(data);
|
||||
// Use the Exchange contract to convert it into a hash.
|
||||
hash = _EXCHANGE.getOrderHash(order);
|
||||
}
|
||||
}
|
||||
|
||||
function _getOrderFromEIP1271Data(bytes memory data)
|
||||
private
|
||||
returns (LibOrder.Order memory order)
|
||||
{
|
||||
require(data.length > 32, "INVALID_EIP1271_ORDER_DATA_LENGTH");
|
||||
assembly {
|
||||
// Skip past the length to find the first parameter.
|
||||
let argsStart := add(data, 32)
|
||||
order := add(argsStart, mload(argsStart))
|
||||
// Destructively point the asset data fields to absolute locations.
|
||||
for {let o := 0x140} lt(o, 0x1C0) {o := add(o, 0x20)} {
|
||||
let arg := add(order, o)
|
||||
mstore(arg, add(argsStart, add(mload(arg), 0x20)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Validates a hash with the `Validator` signature type.
|
||||
@@ -91,7 +176,7 @@ contract TestValidatorWallet {
|
||||
revert(REVERT_REASON);
|
||||
} else if (action == ValidatorAction.ValidateSignature) {
|
||||
isValid = _isSignedBy(hash, signature, signerAddress);
|
||||
} else { // if (action == ValidatorAction.UpdateState) {
|
||||
} else { // action == ValidatorAction.UpdateState
|
||||
_updateState();
|
||||
}
|
||||
}
|
||||
@@ -115,14 +200,14 @@ contract TestValidatorWallet {
|
||||
} else if (action == ValidatorAction.Revert) {
|
||||
revert(REVERT_REASON);
|
||||
} else if (action == ValidatorAction.ValidateSignature) {
|
||||
isValid = _isSignedBy(hash, signature, _hashWalletSigners[hash]);
|
||||
} else { // if (action == ValidatorAction.UpdateState) {
|
||||
isValid = _validSignerForHash[hash] == address(this);
|
||||
} else { // action == ValidatorAction.UpdateState
|
||||
_updateState();
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Validates a hash with the `OrderValidator` and
|
||||
/// `WalletOrderValidator` signature types.
|
||||
/// @dev Validates a hash with the `OrderValidator` and `OrderWallet`
|
||||
/// signature types.
|
||||
/// @param order The order.
|
||||
/// @param orderHash The order hash.
|
||||
/// @param signature Proof of signing.
|
||||
@@ -143,12 +228,14 @@ contract TestValidatorWallet {
|
||||
} else if (action == ValidatorAction.Revert) {
|
||||
revert(REVERT_REASON);
|
||||
} else if (action == ValidatorAction.ValidateSignature) {
|
||||
if (order.makerAddress == address(this)) {
|
||||
isValid = true;
|
||||
if (signature.length == 0) {
|
||||
// OrderWallet type.
|
||||
isValid = order.makerAddress == address(this);
|
||||
} else {
|
||||
// OrderValidator type.
|
||||
isValid = _isSignedBy(orderHash, signature, order.makerAddress);
|
||||
}
|
||||
} else { // if (action == ValidatorAction.UpdateState) {
|
||||
} else { // action == ValidatorAction.UpdateState
|
||||
_updateState();
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,6 @@ import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils, StringRevertError } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as crypto from 'crypto';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
@@ -144,6 +143,7 @@ describe('Exchange core', () => {
|
||||
artifacts.TestValidatorWallet,
|
||||
provider,
|
||||
txDefaults,
|
||||
exchange.address,
|
||||
);
|
||||
reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ReentrantERC20Token,
|
||||
@@ -314,9 +314,9 @@ describe('Exchange core', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if `WalletOrderValidator` signature type rejects during a second fill', async () => {
|
||||
it('should revert if `OrderWallet` signature type rejects during a second fill', async () => {
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.WalletOrderValidator]),
|
||||
ethUtil.toBuffer([SignatureType.OrderWallet]),
|
||||
]);
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
signedOrder.signature = ethUtil.bufferToHex(signature);
|
||||
@@ -352,6 +352,45 @@ describe('Exchange core', () => {
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert if `EIP1271OrderWallet` signature type rejects during a second fill', async () => {
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271OrderWallet]),
|
||||
]);
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
signedOrder.signature = ethUtil.bufferToHex(signature);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
// Allow the signature check for the first fill.
|
||||
await validatorWallet.setValidateAction.awaitTransactionSuccessAsync(
|
||||
orderHashHex,
|
||||
ValidatorWalletAction.Accept,
|
||||
signedOrder.makerAddress,
|
||||
);
|
||||
const fillAmount = signedOrder.takerAssetAmount.div(10);
|
||||
await exchangeWrapper.fillOrderAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
{ takerAssetFillAmount: fillAmount },
|
||||
);
|
||||
// Reject the signature check for the second fill.
|
||||
await validatorWallet.setValidateAction.awaitTransactionSuccessAsync(
|
||||
orderHashHex,
|
||||
ValidatorWalletAction.Reject,
|
||||
signedOrder.makerAddress,
|
||||
);
|
||||
const tx = exchangeWrapper.fillOrderAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
{ takerAssetFillAmount: fillAmount },
|
||||
);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.BadSignature,
|
||||
orderHashHex,
|
||||
signedOrder.makerAddress,
|
||||
signedOrder.signature,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw if fully filled', async () => {
|
||||
|
@@ -84,12 +84,7 @@ describe('LibExchangeRichErrorDecoder', () => {
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureValidatorError, [orderHash, signer, validator, signature, errorData]);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureWalletError, [orderHash, signer, signature, errorData]);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureOrderValidatorError, [orderHash, signer, validator, signature, errorData]);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureWalletOrderValidatorError, [
|
||||
orderHash,
|
||||
signer,
|
||||
signature,
|
||||
errorData,
|
||||
]);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureOrderWalletError, [orderHash, signer, signature, errorData]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
|
@@ -14,7 +14,7 @@ import { SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils, StringRevertError } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as crypto from 'crypto';
|
||||
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import {
|
||||
@@ -38,7 +38,6 @@ describe('MixinSignatureValidator', () => {
|
||||
let orderFactory: OrderFactory;
|
||||
let signatureValidator: TestSignatureValidatorContract;
|
||||
let validatorWallet: TestValidatorWalletContract;
|
||||
let validator: TestValidatorWalletContract;
|
||||
let validatorWalletRevertReason: string;
|
||||
let signerAddress: string;
|
||||
let signerPrivateKey: Buffer;
|
||||
@@ -67,25 +66,24 @@ describe('MixinSignatureValidator', () => {
|
||||
artifacts.TestValidatorWallet,
|
||||
provider,
|
||||
txDefaults,
|
||||
signatureValidator.address,
|
||||
);
|
||||
validator = await TestValidatorWalletContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestValidatorWallet,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
validatorWalletRevertReason = await validator.REVERT_REASON.callAsync();
|
||||
validatorWalletRevertReason = await validatorWallet.REVERT_REASON.callAsync();
|
||||
|
||||
// Approve the validator.
|
||||
signatureValidator.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
true,
|
||||
{ from: signerAddress },
|
||||
);
|
||||
signatureValidator.setOrderValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
true,
|
||||
{ from: signerAddress },
|
||||
);
|
||||
// Approve the validator for both signers.
|
||||
await Promise.all([signerAddress, notSignerAddress].map(async (addr: string) => {
|
||||
const tx1 = signatureValidator.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
true,
|
||||
{ from: addr },
|
||||
);
|
||||
const tx2 = signatureValidator.setOrderValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorWallet.address,
|
||||
true,
|
||||
{ from: addr },
|
||||
);
|
||||
return Promise.all([tx1, tx2]);
|
||||
}));
|
||||
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
@@ -95,6 +93,8 @@ describe('MixinSignatureValidator', () => {
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
domain: {
|
||||
verifyingContractAddress: signatureValidator.address,
|
||||
chainId,
|
||||
@@ -270,8 +270,8 @@ describe('MixinSignatureValidator', () => {
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Wallet and signature is valid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer([SignatureType.Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
@@ -286,15 +286,15 @@ describe('MixinSignatureValidator', () => {
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=Wallet and signature is invalid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
crypto.randomBytes(SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer([SignatureType.Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
notSignerAddress,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.ValidateSignature,
|
||||
);
|
||||
@@ -302,9 +302,9 @@ describe('MixinSignatureValidator', () => {
|
||||
});
|
||||
|
||||
it('should revert when validator attempts to update state and SignatureType=Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer([SignatureType.Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
@@ -324,9 +324,9 @@ describe('MixinSignatureValidator', () => {
|
||||
});
|
||||
|
||||
it('should revert when validator reverts and SignatureType=Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer([SignatureType.Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
@@ -356,7 +356,7 @@ describe('MixinSignatureValidator', () => {
|
||||
signedOrder,
|
||||
signerAddress,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.Accept,
|
||||
ValidatorWalletAction.ValidateSignature,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
@@ -401,9 +401,11 @@ describe('MixinSignatureValidator', () => {
|
||||
});
|
||||
|
||||
it('should revert when validator reverts and SignatureType=Validator', async () => {
|
||||
const validatorAddress = ethUtil.toBuffer(`${validatorWallet.address}`);
|
||||
const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
|
||||
const signature = Buffer.concat([validatorAddress, signatureType]);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer(validatorWallet.address),
|
||||
ethUtil.toBuffer([SignatureType.Validator]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureValidatorError(
|
||||
@@ -429,10 +431,12 @@ describe('MixinSignatureValidator', () => {
|
||||
false,
|
||||
{ from: signerAddress },
|
||||
);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer(validatorWallet.address),
|
||||
ethUtil.toBuffer([SignatureType.Validator]),
|
||||
]);
|
||||
// Validate signature
|
||||
const validatorAddress = ethUtil.toBuffer(`${validatorWallet.address}`);
|
||||
const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
|
||||
const signature = Buffer.concat([validatorAddress, signatureType]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const tx = validateCallAsync(
|
||||
signedOrder,
|
||||
@@ -447,6 +451,82 @@ describe('MixinSignatureValidator', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=EIP1271Wallet and signature is valid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.ValidateSignature,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=EIP1271Wallet and signature is invalid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.Reject,
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when validator attempts to update state and SignatureType=EIP1271Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
constants.NULL_BYTES,
|
||||
);
|
||||
const tx = validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.UpdateState,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert when validator reverts and SignatureType=EIP1271Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271Wallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
);
|
||||
const tx = validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.Revert,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
|
||||
// Presign hash
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
@@ -477,7 +557,7 @@ describe('MixinSignatureValidator', () => {
|
||||
describe('isValidHashSignature', () => {
|
||||
const validateCallAsync = async (
|
||||
order: SignedOrder,
|
||||
signer: string,
|
||||
validSigner: string,
|
||||
signatureHex: string,
|
||||
validatorAction?: ValidatorWalletAction,
|
||||
) => {
|
||||
@@ -486,10 +566,14 @@ describe('MixinSignatureValidator', () => {
|
||||
await validatorWallet.setValidateAction.awaitTransactionSuccessAsync(
|
||||
orderHashHex,
|
||||
validatorAction,
|
||||
order.makerAddress,
|
||||
validSigner,
|
||||
);
|
||||
}
|
||||
return signatureValidator.isValidHashSignature.callAsync(orderHashHex, signer, signatureHex);
|
||||
return signatureValidator.isValidHashSignature.callAsync(
|
||||
orderHashHex,
|
||||
order.makerAddress,
|
||||
signatureHex,
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -556,7 +640,7 @@ describe('MixinSignatureValidator', () => {
|
||||
describe('isValidOrderSignature', () => {
|
||||
const validateCallAsync = async (
|
||||
order: SignedOrder,
|
||||
signer: string,
|
||||
validSigner: string,
|
||||
signatureHex: string,
|
||||
validatorAction?: ValidatorWalletAction,
|
||||
) => {
|
||||
@@ -565,15 +649,18 @@ describe('MixinSignatureValidator', () => {
|
||||
await validatorWallet.setValidateAction.awaitTransactionSuccessAsync(
|
||||
orderHashHex,
|
||||
validatorAction,
|
||||
order.makerAddress,
|
||||
validSigner,
|
||||
);
|
||||
}
|
||||
return signatureValidator.isValidOrderSignature.callAsync(order, signer, signatureHex);
|
||||
return signatureValidator.isValidOrderSignature.callAsync(
|
||||
order,
|
||||
order.makerAddress,
|
||||
signatureHex,
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
// Set up allowances
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=OrderValidator, signature is valid and validator is approved', async () => {
|
||||
@@ -682,10 +769,10 @@ describe('MixinSignatureValidator', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=WalletOrderValidator and signature is valid', async () => {
|
||||
it('should return true when SignatureType=OrderWallet and signature is valid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.WalletOrderValidator]),
|
||||
ethUtil.toBuffer([SignatureType.OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
@@ -698,11 +785,10 @@ describe('MixinSignatureValidator', () => {
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=WalletOrderValidator and signature is invalid', async () => {
|
||||
signedOrder.makerAddress = notSignerAddress;
|
||||
it('should return false when SignatureType=OrderWallet and signature is invalid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer(signedOrder.signature).slice(0, SIGNATURE_LENGTH),
|
||||
ethUtil.toBuffer([SignatureType.WalletOrderValidator]),
|
||||
ethUtil.toBuffer([SignatureType.OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
@@ -710,19 +796,19 @@ describe('MixinSignatureValidator', () => {
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.ValidateSignature,
|
||||
ValidatorWalletAction.Reject,
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when validator attempts to update state and SignatureType=WalletOrderValidator', async () => {
|
||||
it('should revert when validator attempts to update state and SignatureType=OrderWallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.WalletOrderValidator]),
|
||||
ethUtil.toBuffer([SignatureType.OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletOrderValidatorError(
|
||||
const expectedError = new ExchangeRevertErrors.SignatureOrderWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
@@ -737,14 +823,90 @@ describe('MixinSignatureValidator', () => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert when validator reverts and SignatureType=WalletOrderValidator', async () => {
|
||||
it('should revert when validator reverts and SignatureType=OrderWallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.WalletOrderValidator]),
|
||||
ethUtil.toBuffer([SignatureType.OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletOrderValidatorError(
|
||||
const expectedError = new ExchangeRevertErrors.SignatureOrderWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
new StringRevertError(validatorWalletRevertReason).encode(),
|
||||
);
|
||||
const tx = validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.Revert,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should return true when SignatureType=EIP1271OrderWallet and signature is valid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.ValidateSignature,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=EIP1271OrderWallet and signature is invalid', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.Reject,
|
||||
);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when validator attempts to update state and SignatureType=EIP1271OrderWallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureOrderWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
constants.NULL_BYTES,
|
||||
);
|
||||
const tx = validateCallAsync(
|
||||
signedOrder,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
ValidatorWalletAction.UpdateState,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should revert when validator reverts and SignatureType=EIP1271OrderWallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signature = Buffer.concat([
|
||||
ethUtil.toBuffer([SignatureType.EIP1271OrderWallet]),
|
||||
]);
|
||||
const signatureHex = ethUtil.bufferToHex(signature);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureOrderWalletError(
|
||||
orderHashHex,
|
||||
validatorWallet.address,
|
||||
signatureHex,
|
||||
|
Reference in New Issue
Block a user