@0x/contracts-exchange
: Consolidate signature types.
`@0x/contracts-exchange`: Fighting with linearization issues.
This commit is contained in:
committed by
Amir Bandeali
parent
cf6144599d
commit
eb9b2f355e
@@ -31,10 +31,8 @@
|
|||||||
"src/interfaces/IExchange.sol",
|
"src/interfaces/IExchange.sol",
|
||||||
"src/interfaces/IExchangeCore.sol",
|
"src/interfaces/IExchangeCore.sol",
|
||||||
"src/interfaces/IMatchOrders.sol",
|
"src/interfaces/IMatchOrders.sol",
|
||||||
"src/interfaces/IOrderValidator.sol",
|
|
||||||
"src/interfaces/ISignatureValidator.sol",
|
"src/interfaces/ISignatureValidator.sol",
|
||||||
"src/interfaces/ITransactions.sol",
|
"src/interfaces/ITransactions.sol",
|
||||||
"src/interfaces/IValidator.sol",
|
|
||||||
"src/interfaces/IWallet.sol",
|
"src/interfaces/IWallet.sol",
|
||||||
"src/interfaces/IEIP1271Wallet.sol",
|
"src/interfaces/IEIP1271Wallet.sol",
|
||||||
"src/interfaces/IWrapperFunctions.sol",
|
"src/interfaces/IWrapperFunctions.sol",
|
||||||
|
64
contracts/exchange/contracts/src/MixinCommon.sol
Normal file
64
contracts/exchange/contracts/src/MixinCommon.sol
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinCommon {
|
||||||
|
// Defined in MixinSignatureValidator
|
||||||
|
function _isValidOrderWithHashSignature(
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
bytes32 orderHash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (bool isValid);
|
||||||
|
|
||||||
|
// Defined in MixinSignatureValidator
|
||||||
|
function _isValidTransactionWithHashSignature(
|
||||||
|
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
||||||
|
bytes32 transactionHash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (bool isValid);
|
||||||
|
|
||||||
|
// Defined in MixinSignatureValidator
|
||||||
|
function doesSignatureRequireRegularValidation(
|
||||||
|
bytes32 hash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (bool needsRegularValidation);
|
||||||
|
|
||||||
|
// Defined in MixinTransactions
|
||||||
|
function _getCurrentContextAddress()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (address);
|
||||||
|
}
|
@@ -24,14 +24,10 @@ import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
|
|||||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
import "./interfaces/IAssetProxyDispatcher.sol";
|
|
||||||
import "./interfaces/IExchangeCore.sol";
|
import "./interfaces/IExchangeCore.sol";
|
||||||
import "./interfaces/ISignatureValidator.sol";
|
|
||||||
import "./MixinAssetProxyDispatcher.sol";
|
import "./MixinAssetProxyDispatcher.sol";
|
||||||
import "./MixinExchangeRichErrors.sol";
|
import "./MixinExchangeRichErrors.sol";
|
||||||
import "./MixinSignatureValidator.sol";
|
import "./MixinCommon.sol";
|
||||||
import "./MixinAssetProxyDispatcher.sol";
|
|
||||||
import "./MixinTransactions.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract MixinExchangeCore is
|
contract MixinExchangeCore is
|
||||||
@@ -39,8 +35,10 @@ contract MixinExchangeCore is
|
|||||||
LibExchangeSelectors,
|
LibExchangeSelectors,
|
||||||
LibMath,
|
LibMath,
|
||||||
LibFillResults,
|
LibFillResults,
|
||||||
MixinAssetProxyDispatcher,
|
LibOrder,
|
||||||
MixinSignatureValidator
|
ReentrancyGuard,
|
||||||
|
MixinCommon,
|
||||||
|
MixinAssetProxyDispatcher
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
@@ -62,21 +62,6 @@ contract MixinExchangeRichErrors is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SignatureOrderValidatorNotApprovedError(
|
|
||||||
address signerAddress,
|
|
||||||
address validatorAddress
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
SIGNATURE_ORDER_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR,
|
|
||||||
signerAddress,
|
|
||||||
validatorAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SignatureValidatorError(
|
function SignatureValidatorError(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
@@ -117,46 +102,6 @@ contract MixinExchangeRichErrors is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SignatureOrderValidatorError(
|
|
||||||
bytes32 orderHash,
|
|
||||||
address signerAddress,
|
|
||||||
address validatorAddress,
|
|
||||||
bytes memory signature,
|
|
||||||
bytes memory errorData
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
SIGNATURE_ORDER_VALIDATOR_ERROR_SELECTOR,
|
|
||||||
orderHash,
|
|
||||||
signerAddress,
|
|
||||||
validatorAddress,
|
|
||||||
signature,
|
|
||||||
errorData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SignatureOrderWalletError(
|
|
||||||
bytes32 orderHash,
|
|
||||||
address wallet,
|
|
||||||
bytes memory signature,
|
|
||||||
bytes memory errorData
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
SIGNATURE_ORDER_WALLET_ERROR_SELECTOR,
|
|
||||||
orderHash,
|
|
||||||
wallet,
|
|
||||||
signature,
|
|
||||||
errorData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function OrderStatusError(
|
function OrderStatusError(
|
||||||
bytes32 orderHash,
|
bytes32 orderHash,
|
||||||
LibOrder.OrderStatus orderStatus
|
LibOrder.OrderStatus orderStatus
|
||||||
|
@@ -22,24 +22,23 @@ pragma experimental ABIEncoderV2;
|
|||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
|
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/ReentrancyGuard.sol";
|
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 "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||||
import "./interfaces/IWallet.sol";
|
import "./interfaces/IWallet.sol";
|
||||||
import "./interfaces/IEIP1271Wallet.sol";
|
import "./interfaces/IEIP1271Wallet.sol";
|
||||||
import "./interfaces/IValidator.sol";
|
|
||||||
import "./interfaces/IOrderValidator.sol";
|
|
||||||
import "./interfaces/ISignatureValidator.sol";
|
import "./interfaces/ISignatureValidator.sol";
|
||||||
import "./MixinTransactions.sol";
|
|
||||||
import "./MixinExchangeRichErrors.sol";
|
import "./MixinExchangeRichErrors.sol";
|
||||||
|
import "./MixinCommon.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinSignatureValidator is
|
contract MixinSignatureValidator is
|
||||||
MixinExchangeRichErrors,
|
|
||||||
ReentrancyGuard,
|
|
||||||
LibOrder,
|
|
||||||
LibEIP1271,
|
|
||||||
ISignatureValidator,
|
ISignatureValidator,
|
||||||
MixinTransactions
|
LibOrder,
|
||||||
|
LibZeroExTransaction,
|
||||||
|
LibEIP1271,
|
||||||
|
ReentrancyGuard,
|
||||||
|
MixinCommon,
|
||||||
|
MixinExchangeRichErrors
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
@@ -49,9 +48,6 @@ contract MixinSignatureValidator is
|
|||||||
// Mapping of signer => validator => approved
|
// Mapping of signer => validator => approved
|
||||||
mapping (address => mapping (address => bool)) public allowedValidators;
|
mapping (address => mapping (address => bool)) public allowedValidators;
|
||||||
|
|
||||||
// Mapping of signer => order validator => approved
|
|
||||||
mapping (address => mapping (address => bool)) public allowedOrderValidators;
|
|
||||||
|
|
||||||
/// @dev Approves a hash on-chain.
|
/// @dev Approves a hash on-chain.
|
||||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||||
/// @param hash Any 32-byte hash.
|
/// @param hash Any 32-byte hash.
|
||||||
@@ -83,31 +79,11 @@ contract MixinSignatureValidator is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Approves/unnapproves an OrderValidator contract to verify signatures on signer's behalf
|
|
||||||
/// using the `OrderValidator` signature type.
|
|
||||||
/// @param validatorAddress Address of Validator contract.
|
|
||||||
/// @param approval Approval or disapproval of Validator contract.
|
|
||||||
function setOrderValidatorApproval(
|
|
||||||
address validatorAddress,
|
|
||||||
bool approval
|
|
||||||
)
|
|
||||||
external
|
|
||||||
nonReentrant
|
|
||||||
{
|
|
||||||
address signerAddress = _getCurrentContextAddress();
|
|
||||||
allowedOrderValidators[signerAddress][validatorAddress] = approval;
|
|
||||||
emit SignatureValidatorApproval(
|
|
||||||
signerAddress,
|
|
||||||
validatorAddress,
|
|
||||||
approval
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Verifies that a signature for an order is valid.
|
/// @dev Verifies that a signature for an order is valid.
|
||||||
/// @param order The order.
|
/// @param order The order.
|
||||||
/// @param signerAddress Address that should have signed the given order.
|
/// @param signerAddress Address that should have signed the given order.
|
||||||
/// @param signature Proof that the order has been signed by signer.
|
/// @param signature Proof that the order has been signed by signer.
|
||||||
/// @return True if the signature is valid for the given order and signer.
|
/// @return isValid true if the signature is valid for the given order and signer.
|
||||||
function isValidOrderSignature(
|
function isValidOrderSignature(
|
||||||
Order memory order,
|
Order memory order,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
@@ -126,13 +102,13 @@ contract MixinSignatureValidator is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies that a hash has been signed by the given signer.
|
/// @dev Verifies that a signature for a transaction is valid.
|
||||||
/// @param hash Any 32-byte hash.
|
/// @param transaction The transaction.
|
||||||
/// @param signerAddress Address that should have signed the given hash.
|
/// @param signerAddress Address that should have signed the given order.
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
/// @param signature Proof that the order 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 transaction and signer.
|
||||||
function isValidHashSignature(
|
function isValidTransactionSignature(
|
||||||
bytes32 hash,
|
ZeroExTransaction memory transaction,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
)
|
)
|
||||||
@@ -140,42 +116,24 @@ contract MixinSignatureValidator is
|
|||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
SignatureType signatureType = _readValidSignatureType(
|
bytes32 transactionHash = getTransactionHash(transaction);
|
||||||
hash,
|
return _isValidTransactionWithHashSignature(
|
||||||
signerAddress,
|
transaction,
|
||||||
signature
|
transactionHash,
|
||||||
);
|
|
||||||
// Only hash-compatible signature types can be handled by this
|
|
||||||
// function.
|
|
||||||
if (
|
|
||||||
signatureType == SignatureType.OrderValidator ||
|
|
||||||
signatureType == SignatureType.OrderWallet ||
|
|
||||||
signatureType == SignatureType.EIP1271OrderWallet
|
|
||||||
) {
|
|
||||||
_rrevert(SignatureError(
|
|
||||||
SignatureErrorCodes.INAPPROPRIATE_SIGNATURE_TYPE,
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return _validateHashSignatureTypes(
|
|
||||||
signatureType,
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Checks if a signature is of a type that should be verified for
|
/// @dev Checks if a signature is of a type that should be verified for
|
||||||
/// every subsequent fill.
|
/// every action.
|
||||||
/// @param orderHash The hash of the order.
|
/// @param hash The hash of the order/transaction.
|
||||||
/// @param signerAddress The address of the signer.
|
/// @param signerAddress The address of the signer.
|
||||||
/// @param signature The signature for `orderHash`.
|
/// @param signature The signature for `hash`.
|
||||||
/// @return needsRegularValidation True if the signature should be validated
|
/// @return needsRegularValidation True if the signature should be validated
|
||||||
/// for every operation.
|
/// for every action.
|
||||||
function doesSignatureRequireRegularValidation(
|
function doesSignatureRequireRegularValidation(
|
||||||
bytes32 orderHash,
|
bytes32 hash,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
)
|
)
|
||||||
@@ -184,16 +142,14 @@ contract MixinSignatureValidator is
|
|||||||
returns (bool needsRegularValidation)
|
returns (bool needsRegularValidation)
|
||||||
{
|
{
|
||||||
SignatureType signatureType = _readValidSignatureType(
|
SignatureType signatureType = _readValidSignatureType(
|
||||||
orderHash,
|
hash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
// Only signature types that take a full order should be validated
|
|
||||||
// regularly.
|
|
||||||
return
|
return
|
||||||
signatureType == SignatureType.OrderValidator ||
|
signatureType == SignatureType.Wallet ||
|
||||||
signatureType == SignatureType.OrderWallet ||
|
signatureType == SignatureType.Validator ||
|
||||||
signatureType == SignatureType.EIP1271OrderWallet;
|
signatureType == SignatureType.EIP1271Wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies that an order, with provided order hash, has been signed
|
/// @dev Verifies that an order, with provided order hash, has been signed
|
||||||
@@ -202,7 +158,7 @@ contract MixinSignatureValidator is
|
|||||||
/// @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 isValid True if the signature is valid for the given hash and signer.
|
/// @return isValid True if the signature is valid for the given order and signer.
|
||||||
function _isValidOrderWithHashSignature(
|
function _isValidOrderWithHashSignature(
|
||||||
Order memory order,
|
Order memory order,
|
||||||
bytes32 orderHash,
|
bytes32 orderHash,
|
||||||
@@ -218,42 +174,169 @@ contract MixinSignatureValidator is
|
|||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
if (signatureType == SignatureType.OrderValidator) {
|
if (signatureType == SignatureType.Validator) {
|
||||||
// The entire order is verified by validator contract.
|
// The entire order is verified by a validator contract.
|
||||||
isValid = _validateOrderWithValidator(
|
isValid = _validateBytesWithValidator(
|
||||||
order,
|
abi.encode(order, orderHash),
|
||||||
orderHash,
|
orderHash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
return isValid;
|
} else if (signatureType == SignatureType.EIP1271Wallet) {
|
||||||
} else if (signatureType == SignatureType.OrderWallet) {
|
|
||||||
// The entire order is verified by a wallet contract.
|
// The entire order is verified by a wallet contract.
|
||||||
isValid = _validateOrderWithWallet(
|
isValid = _validateBytesWithWallet(
|
||||||
order,
|
abi.encode(order, orderHash),
|
||||||
orderHash,
|
orderHash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
return isValid;
|
} else {
|
||||||
} else if (signatureType == SignatureType.EIP1271OrderWallet) {
|
// Otherwise, it's one of the hash-only signature types.
|
||||||
// The entire order is verified by a wallet contract.
|
isValid = _validateHashSignatureTypes(
|
||||||
isValid = _validateOrderWithEIP1271Wallet(
|
|
||||||
order,
|
|
||||||
orderHash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
);
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
// Otherwise, it's one of the hash-compatible signature types.
|
|
||||||
return _validateHashSignatureTypes(
|
|
||||||
signatureType,
|
signatureType,
|
||||||
orderHash,
|
orderHash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Verifies that a transaction, with provided order hash, has been signed
|
||||||
|
/// by the given signer.
|
||||||
|
/// @param transaction The transaction.
|
||||||
|
/// @param transactionHash The hash of the transaction.
|
||||||
|
/// @param signerAddress Address that should have signed the.Signat given hash.
|
||||||
|
/// @param signature Proof that the hash has been signed by signer.
|
||||||
|
/// @return isValid True if the signature is valid for the given transaction and signer.
|
||||||
|
function _isValidTransactionWithHashSignature(
|
||||||
|
ZeroExTransaction memory transaction,
|
||||||
|
bytes32 transactionHash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (bool isValid)
|
||||||
|
{
|
||||||
|
SignatureType signatureType = _readValidSignatureType(
|
||||||
|
transactionHash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
if (signatureType == SignatureType.Validator) {
|
||||||
|
// The entire transaction is verified by a validator contract.
|
||||||
|
isValid = _validateBytesWithValidator(
|
||||||
|
abi.encode(transaction, transactionHash),
|
||||||
|
transactionHash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
} else if (signatureType == SignatureType.EIP1271Wallet) {
|
||||||
|
// The entire transaction is verified by a wallet contract.
|
||||||
|
isValid = _validateBytesWithWallet(
|
||||||
|
abi.encode(transaction, transactionHash),
|
||||||
|
transactionHash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Otherwise, it's one of the hash-only signature types.
|
||||||
|
isValid = _validateHashSignatureTypes(
|
||||||
|
signatureType,
|
||||||
|
transactionHash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates a hash-only signature type
|
||||||
|
/// (anything but `Validator` and `EIP1271Wallet`).
|
||||||
|
function _validateHashSignatureTypes(
|
||||||
|
SignatureType signatureType,
|
||||||
|
bytes32 hash,
|
||||||
|
address signerAddress,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
private
|
||||||
|
view
|
||||||
|
returns (bool isValid)
|
||||||
|
{
|
||||||
|
// Always invalid signature.
|
||||||
|
// Like Illegal, this is always implicitly available and therefore
|
||||||
|
// offered explicitly. It can be implicitly created by providing
|
||||||
|
// a correctly formatted but incorrect signature.
|
||||||
|
if (signatureType == SignatureType.Invalid) {
|
||||||
|
if (signature.length != 1) {
|
||||||
|
_rrevert(SignatureError(
|
||||||
|
SignatureErrorCodes.INVALID_LENGTH,
|
||||||
|
hash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
));
|
||||||
|
}
|
||||||
|
isValid = false;
|
||||||
|
|
||||||
|
// Signature using EIP712
|
||||||
|
} else if (signatureType == SignatureType.EIP712) {
|
||||||
|
if (signature.length != 66) {
|
||||||
|
_rrevert(SignatureError(
|
||||||
|
SignatureErrorCodes.INVALID_LENGTH,
|
||||||
|
hash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
));
|
||||||
|
}
|
||||||
|
uint8 v = uint8(signature[0]);
|
||||||
|
bytes32 r = signature.readBytes32(1);
|
||||||
|
bytes32 s = signature.readBytes32(33);
|
||||||
|
address recovered = ecrecover(
|
||||||
|
hash,
|
||||||
|
v,
|
||||||
|
r,
|
||||||
|
s
|
||||||
|
);
|
||||||
|
isValid = signerAddress == recovered;
|
||||||
|
|
||||||
|
// Signed using web3.eth_sign
|
||||||
|
} else if (signatureType == SignatureType.EthSign) {
|
||||||
|
if (signature.length != 66) {
|
||||||
|
_rrevert(SignatureError(
|
||||||
|
SignatureErrorCodes.INVALID_LENGTH,
|
||||||
|
hash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
));
|
||||||
|
}
|
||||||
|
uint8 v = uint8(signature[0]);
|
||||||
|
bytes32 r = signature.readBytes32(1);
|
||||||
|
bytes32 s = signature.readBytes32(33);
|
||||||
|
address recovered = ecrecover(
|
||||||
|
keccak256(abi.encodePacked(
|
||||||
|
"\x19Ethereum Signed Message:\n32",
|
||||||
|
hash
|
||||||
|
)),
|
||||||
|
v,
|
||||||
|
r,
|
||||||
|
s
|
||||||
|
);
|
||||||
|
isValid = signerAddress == recovered;
|
||||||
|
|
||||||
|
// Signature verified by wallet contract.
|
||||||
|
} else if (signatureType == SignatureType.Wallet) {
|
||||||
|
isValid = _validateHashWithWallet(
|
||||||
|
hash,
|
||||||
|
signerAddress,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
|
||||||
|
// Otherwise, signatureType == SignatureType.PreSigned
|
||||||
|
} else {
|
||||||
|
assert(signatureType == SignatureType.PreSigned);
|
||||||
|
// Signer signed hash previously using the preSign function.
|
||||||
|
isValid = preSigned[hash][signerAddress];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the `SignatureType` from the end of a signature and validates it.
|
/// Reads the `SignatureType` from the end of a signature and validates it.
|
||||||
function _readValidSignatureType(
|
function _readValidSignatureType(
|
||||||
@@ -304,12 +387,12 @@ contract MixinSignatureValidator is
|
|||||||
return SignatureType(signatureTypeRaw);
|
return SignatureType(signatureTypeRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies signature using logic defined by Wallet contract.
|
/// @dev Verifies a hash and signature using logic defined by Wallet contract.
|
||||||
/// @param hash Any 32 byte hash.
|
/// @param hash Any 32 byte hash.
|
||||||
/// @param walletAddress Address that should have signed the given hash
|
/// @param walletAddress Address that should have signed the given hash
|
||||||
/// and defines its own signature verification method.
|
/// and defines its own signature verification method.
|
||||||
/// @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 validated by the Walidator.
|
/// @return isValid True if the signature is validated by the Wallet.
|
||||||
function _validateHashWithWallet(
|
function _validateHashWithWallet(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address walletAddress,
|
address walletAddress,
|
||||||
@@ -319,6 +402,11 @@ contract MixinSignatureValidator is
|
|||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
|
// A signature using this type should be encoded as:
|
||||||
|
// | Offset | Length | Contents |
|
||||||
|
// | 0x00 | x | Signature to validate |
|
||||||
|
// | 0x00 + x | 1 | Signature type is always "\x04" |
|
||||||
|
|
||||||
uint256 signatureLength = signature.length;
|
uint256 signatureLength = signature.length;
|
||||||
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
||||||
// from the signature for the encode call then restore
|
// from the signature for the encode call then restore
|
||||||
@@ -351,13 +439,15 @@ contract MixinSignatureValidator is
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies signature using logic defined by an EIP1271 Wallet contract.
|
/// @dev Verifies arbitrary data and a signature via an EIP1271 Wallet
|
||||||
/// @param hash Any 32 byte hash.
|
/// contract, where the wallet address is also the signer address.
|
||||||
/// @param walletAddress Address that should have signed the given hash
|
/// @param data Arbitrary signed data.
|
||||||
/// and defines its own signature verification method.
|
/// @param hash The hash associated with the data.
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
/// @param walletAddress Contract that will verify the data and signature.
|
||||||
/// @return True if the signature is validated by the Walidator.
|
/// @param signature Proof that the data has been signed by signer.
|
||||||
function _validateHashWithEIP1271Wallet(
|
/// @return isValid True if the signature is validated by the Wallet.
|
||||||
|
function _validateBytesWithWallet(
|
||||||
|
bytes memory data,
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address walletAddress,
|
address walletAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
@@ -366,6 +456,11 @@ contract MixinSignatureValidator is
|
|||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
|
// A signature using this type should be encoded as:
|
||||||
|
// | Offset | Length | Contents |
|
||||||
|
// | 0x00 | x | Signature to validate |
|
||||||
|
// | 0x00 + x | 1 | Signature type is always "\x07" |
|
||||||
|
|
||||||
uint256 signatureLength = signature.length;
|
uint256 signatureLength = signature.length;
|
||||||
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
||||||
// from the signature for the encode call then restore
|
// from the signature for the encode call then restore
|
||||||
@@ -374,8 +469,6 @@ contract MixinSignatureValidator is
|
|||||||
mstore(signature, sub(signatureLength, 1))
|
mstore(signature, sub(signatureLength, 1))
|
||||||
}
|
}
|
||||||
// Encode the call data.
|
// Encode the call data.
|
||||||
bytes memory data = new bytes(32);
|
|
||||||
data.writeBytes32(0, hash);
|
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
IEIP1271Wallet(walletAddress).isValidSignature.selector,
|
IEIP1271Wallet(walletAddress).isValidSignature.selector,
|
||||||
data,
|
data,
|
||||||
@@ -400,13 +493,15 @@ contract MixinSignatureValidator is
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies signature using logic defined by Validator contract.
|
/// @dev Verifies arbitrary data and a signature via an EIP1271 contract
|
||||||
/// If used with an order, the maker of the order can still be an EOA.
|
/// whose address is encoded in the signature.
|
||||||
/// @param hash Any 32 byte hash.
|
/// @param data Arbitrary signed data.
|
||||||
|
/// @param hash The hash associated with the data.
|
||||||
/// @param signerAddress Address that should have signed the given hash.
|
/// @param signerAddress Address that should have signed the given hash.
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
/// @param signature Proof that the data has been signed by signer.
|
||||||
/// @return True if the signature is validated by the Validator.
|
/// @return isValid True if the signature is validated by the validator contract.
|
||||||
function _validateHashWithValidator(
|
function _validateBytesWithValidator(
|
||||||
|
bytes memory data,
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
@@ -415,12 +510,11 @@ contract MixinSignatureValidator is
|
|||||||
view
|
view
|
||||||
returns (bool isValid)
|
returns (bool isValid)
|
||||||
{
|
{
|
||||||
// If used with an order, the maker of the order can still be an EOA.
|
|
||||||
// A signature using this type should be encoded as:
|
// A signature using this type should be encoded as:
|
||||||
// | Offset | Length | Contents |
|
// | Offset | Length | Contents |
|
||||||
// | 0x00 | x | Signature to validate |
|
// | 0x00 | x | Signature to validate |
|
||||||
// | 0x00 + x | 20 | Address of validator contract |
|
// | 0x00 + x | 20 | Address of validator contract |
|
||||||
// | 0x14 + x | 1 | Signature type is always "\x06" |
|
// | 0x14 + x | 1 | Signature type is always "\x05" |
|
||||||
|
|
||||||
uint256 signatureLength = signature.length;
|
uint256 signatureLength = signature.length;
|
||||||
// Read the validator address from the signature.
|
// Read the validator address from the signature.
|
||||||
@@ -440,9 +534,8 @@ contract MixinSignatureValidator is
|
|||||||
}
|
}
|
||||||
// Encode the call data.
|
// Encode the call data.
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
bytes memory callData = abi.encodeWithSelector(
|
||||||
IValidator(validatorAddress).isValidSignature.selector,
|
IEIP1271Wallet(validatorAddress).isValidSignature.selector,
|
||||||
hash,
|
data,
|
||||||
signerAddress,
|
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
// Restore the full signature.
|
// Restore the full signature.
|
||||||
@@ -451,9 +544,9 @@ contract MixinSignatureValidator is
|
|||||||
}
|
}
|
||||||
// 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 the `EIP1271_MAGIC_VALUE`.
|
||||||
if (didSucceed && returnData.length == 32) {
|
if (didSucceed && returnData.length <= 32) {
|
||||||
return returnData.readUint256(0) == 1;
|
return returnData.readBytes4(0) == EIP1271_MAGIC_VALUE;
|
||||||
}
|
}
|
||||||
// Static call to verifier failed.
|
// Static call to verifier failed.
|
||||||
_rrevert(SignatureValidatorError(
|
_rrevert(SignatureValidatorError(
|
||||||
@@ -465,280 +558,4 @@ contract MixinSignatureValidator is
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies order AND signature via a 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 _validateOrderWithWallet(
|
|
||||||
Order memory order,
|
|
||||||
bytes32 orderHash,
|
|
||||||
address walletAddress,
|
|
||||||
bytes memory signature
|
|
||||||
)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (bool isValid)
|
|
||||||
{
|
|
||||||
uint256 signatureLength = signature.length;
|
|
||||||
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
|
||||||
// from the signature for the encode call then restore
|
|
||||||
// it immediately after because we want to keep signatures intact.
|
|
||||||
assembly {
|
|
||||||
mstore(signature, sub(signatureLength, 1))
|
|
||||||
}
|
|
||||||
// Encode the call data.
|
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
|
||||||
IWallet(walletAddress).isValidOrderSignature.selector,
|
|
||||||
order,
|
|
||||||
orderHash,
|
|
||||||
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 a single bool.
|
|
||||||
if (didSucceed && returnData.length == 32) {
|
|
||||||
return returnData.readUint256(0) == 1;
|
|
||||||
}
|
|
||||||
// Static call to verifier failed.
|
|
||||||
_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;
|
|
||||||
// HACK(dorothy-zbornak): Temporarily shave the signature type
|
|
||||||
// from the signature for the encode call then restore
|
|
||||||
// it immediately after because we want to keep signatures intact.
|
|
||||||
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 returnData.readBytes4(0) == EIP1271_MAGIC_VALUE;
|
|
||||||
}
|
|
||||||
// Static call to verifier failed.
|
|
||||||
_rrevert(SignatureOrderWalletError(
|
|
||||||
orderHash,
|
|
||||||
walletAddress,
|
|
||||||
signature,
|
|
||||||
returnData
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Verifies order AND signature via Validator contract.
|
|
||||||
/// If used with an order, the maker of the order can still be an EOA.
|
|
||||||
/// @param order The order.
|
|
||||||
/// @param orderHash The order hash.
|
|
||||||
/// @param signerAddress Address that should have signed the given hash.
|
|
||||||
/// @param signature Proof that the hash has been signed by signer.
|
|
||||||
/// @return True if order and signature are validated by the Validator.
|
|
||||||
function _validateOrderWithValidator(
|
|
||||||
Order memory order,
|
|
||||||
bytes32 orderHash,
|
|
||||||
address signerAddress,
|
|
||||||
bytes memory signature
|
|
||||||
)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (bool isValid)
|
|
||||||
{
|
|
||||||
// A signature using this type should be encoded as:
|
|
||||||
// | Offset | Length | Contents |
|
|
||||||
// | 0x00 | x | Signature to validate |
|
|
||||||
// | 0x00 + x | 20 | Address of validator contract |
|
|
||||||
// | 0x14 + x | 1 | Signature type is always "\x07" |
|
|
||||||
|
|
||||||
uint256 signatureLength = signature.length;
|
|
||||||
// Read the validator address from the signature.
|
|
||||||
address validatorAddress = signature.readAddress(signatureLength - 21);
|
|
||||||
// Ensure signer has approved validator.
|
|
||||||
if (!allowedOrderValidators[signerAddress][validatorAddress]) {
|
|
||||||
_rrevert(SignatureOrderValidatorNotApprovedError(
|
|
||||||
signerAddress,
|
|
||||||
validatorAddress
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// HACK(dorothy-zbornak): Temporarily shave the validator address
|
|
||||||
// and signature type from the signature for the encode call then restore
|
|
||||||
// it immediately after because we want to keep signatures intact.
|
|
||||||
assembly {
|
|
||||||
mstore(signature, sub(signatureLength, 21))
|
|
||||||
}
|
|
||||||
// Encode the call data.
|
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
|
||||||
IOrderValidator(validatorAddress).isValidOrderSignature.selector,
|
|
||||||
order,
|
|
||||||
orderHash,
|
|
||||||
signature
|
|
||||||
);
|
|
||||||
// Restore the full signature.
|
|
||||||
assembly {
|
|
||||||
mstore(signature, signatureLength)
|
|
||||||
}
|
|
||||||
// Static call the verification function.
|
|
||||||
(bool didSucceed, bytes memory returnData) = validatorAddress.staticcall(callData);
|
|
||||||
// Return data should be a single bool.
|
|
||||||
if (didSucceed && returnData.length == 32) {
|
|
||||||
return returnData.readUint256(0) == 1;
|
|
||||||
}
|
|
||||||
// Static call to verifier failed.
|
|
||||||
_rrevert(SignatureOrderValidatorError(
|
|
||||||
orderHash,
|
|
||||||
signerAddress,
|
|
||||||
validatorAddress,
|
|
||||||
signature,
|
|
||||||
returnData
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Validates a hash-compatible signature type
|
|
||||||
/// (anything but `OrderValidator` and `OrderWallet`).
|
|
||||||
function _validateHashSignatureTypes(
|
|
||||||
SignatureType signatureType,
|
|
||||||
bytes32 hash,
|
|
||||||
address signerAddress,
|
|
||||||
bytes memory signature
|
|
||||||
)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (bool isValid)
|
|
||||||
{
|
|
||||||
// Always invalid signature.
|
|
||||||
// Like Illegal, this is always implicitly available and therefore
|
|
||||||
// offered explicitly. It can be implicitly created by providing
|
|
||||||
// a correctly formatted but incorrect signature.
|
|
||||||
if (signatureType == SignatureType.Invalid) {
|
|
||||||
if (signature.length != 1) {
|
|
||||||
_rrevert(SignatureError(
|
|
||||||
SignatureErrorCodes.INVALID_LENGTH,
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
));
|
|
||||||
}
|
|
||||||
isValid = false;
|
|
||||||
return isValid;
|
|
||||||
|
|
||||||
// Signature using EIP712
|
|
||||||
} else if (signatureType == SignatureType.EIP712) {
|
|
||||||
if (signature.length != 66) {
|
|
||||||
_rrevert(SignatureError(
|
|
||||||
SignatureErrorCodes.INVALID_LENGTH,
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
));
|
|
||||||
}
|
|
||||||
uint8 v = uint8(signature[0]);
|
|
||||||
bytes32 r = signature.readBytes32(1);
|
|
||||||
bytes32 s = signature.readBytes32(33);
|
|
||||||
address recovered = ecrecover(
|
|
||||||
hash,
|
|
||||||
v,
|
|
||||||
r,
|
|
||||||
s
|
|
||||||
);
|
|
||||||
isValid = signerAddress == recovered;
|
|
||||||
return isValid;
|
|
||||||
|
|
||||||
// Signed using web3.eth_sign
|
|
||||||
} else if (signatureType == SignatureType.EthSign) {
|
|
||||||
if (signature.length != 66) {
|
|
||||||
_rrevert(SignatureError(
|
|
||||||
SignatureErrorCodes.INVALID_LENGTH,
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
));
|
|
||||||
}
|
|
||||||
uint8 v = uint8(signature[0]);
|
|
||||||
bytes32 r = signature.readBytes32(1);
|
|
||||||
bytes32 s = signature.readBytes32(33);
|
|
||||||
address recovered = ecrecover(
|
|
||||||
keccak256(abi.encodePacked(
|
|
||||||
"\x19Ethereum Signed Message:\n32",
|
|
||||||
hash
|
|
||||||
)),
|
|
||||||
v,
|
|
||||||
r,
|
|
||||||
s
|
|
||||||
);
|
|
||||||
isValid = signerAddress == recovered;
|
|
||||||
return isValid;
|
|
||||||
|
|
||||||
// Signature verified by wallet contract.
|
|
||||||
// If used with an order, the maker of the order is the wallet contract.
|
|
||||||
} else if (signatureType == SignatureType.Wallet) {
|
|
||||||
isValid = _validateHashWithWallet(
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
);
|
|
||||||
return isValid;
|
|
||||||
|
|
||||||
// Signature verified by validator contract.
|
|
||||||
// If used with an order, the maker of the order can still be an EOA.
|
|
||||||
} else if (signatureType == SignatureType.Validator) {
|
|
||||||
isValid = _validateHashWithValidator(
|
|
||||||
hash,
|
|
||||||
signerAddress,
|
|
||||||
signature
|
|
||||||
);
|
|
||||||
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);
|
|
||||||
// Signer signed hash previously using the preSign function.
|
|
||||||
return preSigned[hash][signerAddress];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -20,16 +20,16 @@ pragma solidity ^0.5.9;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||||
import "./interfaces/ISignatureValidator.sol";
|
|
||||||
import "./interfaces/ITransactions.sol";
|
import "./interfaces/ITransactions.sol";
|
||||||
import "./MixinExchangeRichErrors.sol";
|
import "./MixinExchangeRichErrors.sol";
|
||||||
|
import "./MixinSignatureValidator.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinTransactions is
|
contract MixinTransactions is
|
||||||
MixinExchangeRichErrors,
|
ITransactions,
|
||||||
LibZeroExTransaction,
|
LibZeroExTransaction,
|
||||||
ISignatureValidator,
|
MixinExchangeRichErrors,
|
||||||
ITransactions
|
MixinSignatureValidator
|
||||||
{
|
{
|
||||||
// Mapping of transaction hash => executed
|
// Mapping of transaction hash => executed
|
||||||
// This prevents transactions from being executed more than once.
|
// This prevents transactions from being executed more than once.
|
||||||
@@ -113,7 +113,8 @@ contract MixinTransactions is
|
|||||||
address signerAddress = transaction.signerAddress;
|
address signerAddress = transaction.signerAddress;
|
||||||
if (signerAddress != msg.sender) {
|
if (signerAddress != msg.sender) {
|
||||||
// Validate signature
|
// Validate signature
|
||||||
if (!isValidHashSignature(
|
if (!_isValidTransactionWithHashSignature(
|
||||||
|
transaction,
|
||||||
transactionHash,
|
transactionHash,
|
||||||
signerAddress,
|
signerAddress,
|
||||||
signature)) {
|
signature)) {
|
||||||
|
@@ -37,10 +37,6 @@ contract IExchangeRichErrors {
|
|||||||
bytes4 internal constant SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR =
|
bytes4 internal constant SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR =
|
||||||
0xa15c0d06;
|
0xa15c0d06;
|
||||||
|
|
||||||
// bytes4(keccak256("SignatureOrderValidatorNotApprovedError(address,address)"))
|
|
||||||
bytes4 internal constant SIGNATURE_ORDER_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR =
|
|
||||||
0x6d273c5a;
|
|
||||||
|
|
||||||
// bytes4(keccak256("SignatureValidatorError(bytes32,address,address,bytes,bytes)"))
|
// bytes4(keccak256("SignatureValidatorError(bytes32,address,address,bytes,bytes)"))
|
||||||
bytes4 internal constant SIGNATURE_VALIDATOR_ERROR_SELECTOR =
|
bytes4 internal constant SIGNATURE_VALIDATOR_ERROR_SELECTOR =
|
||||||
0xa23838b8;
|
0xa23838b8;
|
||||||
@@ -49,14 +45,6 @@ contract IExchangeRichErrors {
|
|||||||
bytes4 internal constant SIGNATURE_WALLET_ERROR_SELECTOR =
|
bytes4 internal constant SIGNATURE_WALLET_ERROR_SELECTOR =
|
||||||
0x1b8388f7;
|
0x1b8388f7;
|
||||||
|
|
||||||
// bytes4(keccak256("SignatureOrderValidatorError(bytes32,address,address,bytes,bytes)"))
|
|
||||||
bytes4 internal constant SIGNATURE_ORDER_VALIDATOR_ERROR_SELECTOR =
|
|
||||||
0xf45375b7;
|
|
||||||
|
|
||||||
// bytes4(keccak256("SignatureOrderWalletError(bytes32,address,bytes,bytes)"))
|
|
||||||
bytes4 internal constant SIGNATURE_ORDER_WALLET_ERROR_SELECTOR =
|
|
||||||
0x37fa88c3;
|
|
||||||
|
|
||||||
// bytes4(keccak256("OrderStatusError(bytes32,uint8)"))
|
// bytes4(keccak256("OrderStatusError(bytes32,uint8)"))
|
||||||
bytes4 internal constant ORDER_STATUS_ERROR_SELECTOR =
|
bytes4 internal constant ORDER_STATUS_ERROR_SELECTOR =
|
||||||
0xfdb6ca8d;
|
0xfdb6ca8d;
|
||||||
|
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract IOrderValidator {
|
|
||||||
|
|
||||||
/// @dev Verifies that an order AND a signature is valid.
|
|
||||||
/// @param order The order.
|
|
||||||
/// @param orderHash The order hash.
|
|
||||||
/// @param signature Proof of signing.
|
|
||||||
/// @return Validity of order and signature.
|
|
||||||
function isValidOrderSignature(
|
|
||||||
LibOrder.Order calldata order,
|
|
||||||
bytes32 orderHash,
|
|
||||||
bytes calldata signature
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bool isValid);
|
|
||||||
}
|
|
@@ -20,6 +20,7 @@ pragma solidity ^0.5.9;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ISignatureValidator {
|
contract ISignatureValidator {
|
||||||
@@ -33,11 +34,8 @@ contract ISignatureValidator {
|
|||||||
Wallet, // 0x04
|
Wallet, // 0x04
|
||||||
Validator, // 0x05
|
Validator, // 0x05
|
||||||
PreSigned, // 0x06
|
PreSigned, // 0x06
|
||||||
OrderValidator, // 0x07
|
EIP1271Wallet, // 0x07
|
||||||
OrderWallet, // 0x08
|
NSignatureTypes // 0x08, number of signature types. Always leave at end.
|
||||||
EIP1271Wallet, // 0x09
|
|
||||||
EIP1271OrderWallet, // 0x0A
|
|
||||||
NSignatureTypes // 0x0B, number of signature types. Always leave at end.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event SignatureValidatorApproval(
|
event SignatureValidatorApproval(
|
||||||
@@ -71,13 +69,13 @@ contract ISignatureValidator {
|
|||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Verifies that a signature for a hash is valid.
|
/// @dev Verifies that a signature for an order is valid.
|
||||||
/// @param hash Message hash that is signed.
|
/// @param order The order.
|
||||||
/// @param signerAddress Address of signer.
|
/// @param signerAddress Address that should have signed the given order.
|
||||||
/// @param signature Proof of signing.
|
/// @param signature Proof that the order has been signed by signer.
|
||||||
/// @return Validity of order signature.
|
/// @return isValid true if the signature is valid for the given order and signer.
|
||||||
function isValidHashSignature(
|
function isValidOrderSignature(
|
||||||
bytes32 hash,
|
LibOrder.Order memory order,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
)
|
)
|
||||||
@@ -85,13 +83,13 @@ contract ISignatureValidator {
|
|||||||
view
|
view
|
||||||
returns (bool isValid);
|
returns (bool isValid);
|
||||||
|
|
||||||
/// @dev Verifies that a signature for an order is valid.
|
/// @dev Verifies that a signature for a transaction is valid.
|
||||||
/// @param order The order.
|
/// @param transaction The transaction.
|
||||||
/// @param signerAddress Address of signer.
|
/// @param signerAddress Address that should have signed the given order.
|
||||||
/// @param signature Proof of signing.
|
/// @param signature Proof that the order has been signed by signer.
|
||||||
/// @return Validity of order signature.
|
/// @return isValid true if the signature is valid for the given transaction and signer.
|
||||||
function isValidOrderSignature(
|
function isValidTransactionSignature(
|
||||||
LibOrder.Order memory order,
|
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
)
|
)
|
||||||
|
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract IValidator {
|
|
||||||
|
|
||||||
/// @dev Verifies that a signature is valid.
|
|
||||||
/// @param hash Message hash that is signed.
|
|
||||||
/// @param signerAddress Address that should have signed the given hash.
|
|
||||||
/// @param signature Proof of signing.
|
|
||||||
/// @return Validity of order signature.
|
|
||||||
function isValidSignature(
|
|
||||||
bytes32 hash,
|
|
||||||
address signerAddress,
|
|
||||||
bytes calldata signature
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bool isValid);
|
|
||||||
}
|
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2018 ZeroEx Intl.
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ pragma solidity ^0.5.5;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
|
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
|
||||||
@@ -30,6 +31,11 @@ interface ISimplifiedExchange {
|
|||||||
external
|
external
|
||||||
view
|
view
|
||||||
returns (bytes32 orderHash);
|
returns (bytes32 orderHash);
|
||||||
|
|
||||||
|
function getTransactionHash(LibZeroExTransaction.ZeroExTransaction calldata transaction)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes32 transactionHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,20 +45,30 @@ contract TestValidatorWallet is
|
|||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
|
|
||||||
// Revert reason for `Revert` `ValidatorAction`.
|
/// @dev Revert reason for `Revert` `ValidatorAction`.
|
||||||
string constant public REVERT_REASON = "you shall not pass";
|
string constant public REVERT_REASON = "you shall not pass";
|
||||||
|
|
||||||
|
enum DataType {
|
||||||
|
// No data type; only expecting a hash (default)
|
||||||
|
None,
|
||||||
|
// An Order
|
||||||
|
Order,
|
||||||
|
// A ZeroExTransaction
|
||||||
|
ZeroExTransaction,
|
||||||
|
NTypes
|
||||||
|
}
|
||||||
|
|
||||||
enum ValidatorAction {
|
enum ValidatorAction {
|
||||||
// Return false (default)
|
// Return failure (default)
|
||||||
Reject,
|
Reject,
|
||||||
// Return true
|
// Return success
|
||||||
Accept,
|
Accept,
|
||||||
// Revert
|
// Revert
|
||||||
Revert,
|
Revert,
|
||||||
// Update state
|
// Update state
|
||||||
UpdateState,
|
UpdateState,
|
||||||
// Validate signature
|
// Ensure the signature hash matches what was prepared
|
||||||
ValidateSignature,
|
MatchSignatureHash,
|
||||||
NTypes
|
NTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +78,10 @@ contract TestValidatorWallet is
|
|||||||
uint256 internal _state = 1;
|
uint256 internal _state = 1;
|
||||||
/// @dev What action to execute when a hash is validated .
|
/// @dev What action to execute when a hash is validated .
|
||||||
mapping (bytes32 => ValidatorAction) internal _hashActions;
|
mapping (bytes32 => ValidatorAction) internal _hashActions;
|
||||||
/// @dev Allowed signers for hash signature types.
|
/// @dev The data type of a hash.
|
||||||
mapping (bytes32 => address) internal _validSignerForHash;
|
mapping (bytes32 => DataType) internal _hashDataTypes;
|
||||||
|
/// @dev keccak256 of the expected signature data for a hash.
|
||||||
|
mapping (bytes32 => DataType) internal _hashSignatureHashes;
|
||||||
|
|
||||||
constructor(address exchange) public {
|
constructor(address exchange) public {
|
||||||
_exchange = ISimplifiedExchange(exchange);
|
_exchange = ISimplifiedExchange(exchange);
|
||||||
@@ -83,32 +101,34 @@ contract TestValidatorWallet is
|
|||||||
IERC20Token(token).approve(spender, value);
|
IERC20Token(token).approve(spender, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Set the action to take when validating a hash.
|
/// @dev Prepares this contract to validate a signature.
|
||||||
/// @param hash The hash.
|
/// @param hash The hash.
|
||||||
/// @param action action to take.
|
/// @param dataType The data type associated with the hash.
|
||||||
/// @param allowedSigner Signer that must be recovered with
|
/// @param action Action to take.
|
||||||
/// `ValidateSignature` action type and `Wallet` or
|
/// @param signatureHash keccak256 of the expected signature data.
|
||||||
/// `OrderWallet` signature types.
|
function prepare(
|
||||||
function setValidateAction(
|
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
|
DataType dataType,
|
||||||
ValidatorAction action,
|
ValidatorAction action,
|
||||||
address allowedSigner
|
bytes32 signatureHash
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
{
|
{
|
||||||
if (uint8(action) >= uint8(ValidatorAction.NTypes)) {
|
if (uint8(dataType) >= uint8(DataType.NTypes)) {
|
||||||
revert("UNSUPPORTED_VALIDATE_ACTION");
|
revert("UNSUPPORTED_DATA_TYPE");
|
||||||
}
|
}
|
||||||
|
if (uint8(action) >= uint8(ValidatorAction.NTypes)) {
|
||||||
|
revert("UNSUPPORTED_VALIDATOR_ACTION");
|
||||||
|
}
|
||||||
|
_hashDataTypes[hash] = dataType;
|
||||||
_hashActions[hash] = action;
|
_hashActions[hash] = action;
|
||||||
_validSignerForHash[hash] = allowedSigner;
|
_hashSignatureHashes[hash] = signatureHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Validates a hash with the following signature types:
|
/// @dev Validates data signed by either `EIP1271Wallet` or `Validator` signature types.
|
||||||
/// `EIP1271Wallet` and `EIP1271WalletOrder`signature types.
|
/// @param data Abi-encoded data (Order or ZeroExTransaction) and a hash.
|
||||||
/// 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`.
|
/// @param signature Signature for `data`.
|
||||||
/// @return magicValue Returns `EIP1271_MAGIC_VALUE` if the signature check succeeds.
|
/// @return magicValue `EIP1271_MAGIC_VALUE` if the signature check succeeds.
|
||||||
function isValidSignature(
|
function isValidSignature(
|
||||||
bytes memory data,
|
bytes memory data,
|
||||||
bytes memory signature
|
bytes memory signature
|
||||||
@@ -116,35 +136,30 @@ contract TestValidatorWallet is
|
|||||||
public
|
public
|
||||||
returns (bytes4 magicValue)
|
returns (bytes4 magicValue)
|
||||||
{
|
{
|
||||||
bytes32 hash = _getOrderHashFromEIP1271Data(data);
|
bytes32 hash = _decodeAndValidateHashFromEncodedData(data);
|
||||||
ValidatorAction action = _hashActions[hash];
|
ValidatorAction action = _hashActions[hash];
|
||||||
// solhint-disable-next-line no-empty-blocks
|
|
||||||
if (action == ValidatorAction.Reject) {
|
if (action == ValidatorAction.Reject) {
|
||||||
// NOOP.
|
magicValue = 0x0;
|
||||||
} else if (action == ValidatorAction.Accept) {
|
} else if (action == ValidatorAction.Accept) {
|
||||||
magicValue = EIP1271_MAGIC_VALUE;
|
magicValue = EIP1271_MAGIC_VALUE;
|
||||||
} else if (action == ValidatorAction.Revert) {
|
} else if (action == ValidatorAction.Revert) {
|
||||||
revert(REVERT_REASON);
|
revert(REVERT_REASON);
|
||||||
} else if (action == ValidatorAction.UpdateState) {
|
} else if (action == ValidatorAction.UpdateState) {
|
||||||
_updateState();
|
_updateState();
|
||||||
} else { // action == ValidatorAction.ValidateSignature
|
} else {
|
||||||
if (data.length != 32) {
|
assert(action == ValidatorAction.MatchSignatureHash);
|
||||||
// `data` is an abi-encoded Order.
|
bytes32 expectedSignatureHash = _hashSignatureHashes[hash];
|
||||||
LibOrder.Order memory order = _getOrderFromEIP1271Data(data);
|
if (keccak256(signature) == expectedSignatureHash) {
|
||||||
if (order.makerAddress == address(this)) {
|
|
||||||
magicValue = EIP1271_MAGIC_VALUE;
|
|
||||||
}
|
|
||||||
} else if (_validSignerForHash[hash] == address(this)) {
|
|
||||||
magicValue = EIP1271_MAGIC_VALUE;
|
magicValue = EIP1271_MAGIC_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Validates a hash with the `Validator` signature type.
|
/// @dev Validates a hash with the `Wallet` signature type.
|
||||||
/// @param hash Message hash that is signed.
|
/// @param hash Message hash that is signed.
|
||||||
/// @param signerAddress Address that should have signed the given hash.
|
/// @param signerAddress Address that should have signed the given hash.
|
||||||
/// @param signature Proof of signing.
|
/// @param signature Proof of signing.
|
||||||
/// @return Validity of order signature.
|
/// @return isValid `true` if the signature check succeeds.
|
||||||
function isValidSignature(
|
function isValidSignature(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
address signerAddress,
|
address signerAddress,
|
||||||
@@ -160,129 +175,61 @@ contract TestValidatorWallet is
|
|||||||
isValid = true;
|
isValid = true;
|
||||||
} else if (action == ValidatorAction.Revert) {
|
} else if (action == ValidatorAction.Revert) {
|
||||||
revert(REVERT_REASON);
|
revert(REVERT_REASON);
|
||||||
} else if (action == ValidatorAction.ValidateSignature) {
|
} else if (action == ValidatorAction.UpdateState) {
|
||||||
isValid = _isSignedBy(hash, signature, signerAddress);
|
|
||||||
} else { // action == ValidatorAction.UpdateState
|
|
||||||
_updateState();
|
_updateState();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Validates a hash with the `Wallet` signature type.
|
|
||||||
/// @param hash Message hash that is signed.
|
|
||||||
/// @param signature Proof of signing.
|
|
||||||
/// @return Validity of order signature.
|
|
||||||
function isValidSignature(
|
|
||||||
bytes32 hash,
|
|
||||||
bytes memory signature
|
|
||||||
)
|
|
||||||
public
|
|
||||||
returns (bool isValid)
|
|
||||||
{
|
|
||||||
ValidatorAction action = _hashActions[hash];
|
|
||||||
if (action == ValidatorAction.Reject) {
|
|
||||||
isValid = false;
|
|
||||||
} else if (action == ValidatorAction.Accept) {
|
|
||||||
isValid = true;
|
|
||||||
} else if (action == ValidatorAction.Revert) {
|
|
||||||
revert(REVERT_REASON);
|
|
||||||
} else if (action == ValidatorAction.ValidateSignature) {
|
|
||||||
isValid = _validSignerForHash[hash] == address(this);
|
|
||||||
} else { // action == ValidatorAction.UpdateState
|
|
||||||
_updateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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.
|
|
||||||
/// @return Validity of order signature.
|
|
||||||
function isValidOrderSignature(
|
|
||||||
LibOrder.Order memory order,
|
|
||||||
bytes32 orderHash,
|
|
||||||
bytes memory signature
|
|
||||||
)
|
|
||||||
public
|
|
||||||
returns (bool isValid)
|
|
||||||
{
|
|
||||||
ValidatorAction action = _hashActions[orderHash];
|
|
||||||
if (action == ValidatorAction.Reject) {
|
|
||||||
isValid = false;
|
|
||||||
} else if (action == ValidatorAction.Accept) {
|
|
||||||
isValid = true;
|
|
||||||
} else if (action == ValidatorAction.Revert) {
|
|
||||||
revert(REVERT_REASON);
|
|
||||||
} else if (action == ValidatorAction.ValidateSignature) {
|
|
||||||
if (signature.length == 0) {
|
|
||||||
// OrderWallet type.
|
|
||||||
isValid = order.makerAddress == address(this);
|
|
||||||
} else {
|
} else {
|
||||||
// OrderValidator type.
|
assert(action == ValidatorAction.MatchSignatureHash);
|
||||||
isValid = _isSignedBy(orderHash, signature, order.makerAddress);
|
bytes32 expectedSignatureHash = _hashSignatureHashes[hash];
|
||||||
|
if (keccak256(signature) == expectedSignatureHash) {
|
||||||
|
isValid = true;
|
||||||
}
|
}
|
||||||
} else { // action == ValidatorAction.UpdateState
|
|
||||||
_updateState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Increments state variable.
|
/// @dev Increments state variable to trigger a state change.
|
||||||
function _updateState()
|
function _updateState()
|
||||||
private
|
private
|
||||||
{
|
{
|
||||||
_state++;
|
_state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Verifies the signer of a hash is correct.
|
function _decodeAndValidateHashFromEncodedData(bytes memory data)
|
||||||
function _isSignedBy(
|
|
||||||
bytes32 hash,
|
|
||||||
bytes memory signature,
|
|
||||||
address signerAddress
|
|
||||||
)
|
|
||||||
private
|
|
||||||
pure
|
|
||||||
returns (bool isSignedBy)
|
|
||||||
{
|
|
||||||
require(signature.length == 65, "LENGTH_65_REQUIRED");
|
|
||||||
uint8 v = uint8(signature[0]);
|
|
||||||
bytes32 r = signature.readBytes32(1);
|
|
||||||
bytes32 s = signature.readBytes32(33);
|
|
||||||
// Try a naked signature.
|
|
||||||
address recovered = ecrecover(hash, v, r, s);
|
|
||||||
if (recovered != signerAddress) {
|
|
||||||
// Try an eth_sign signature.
|
|
||||||
bytes32 ethSignHash = keccak256(
|
|
||||||
abi.encodePacked(
|
|
||||||
"\x19Ethereum Signed Message:\n32",
|
|
||||||
hash
|
|
||||||
)
|
|
||||||
);
|
|
||||||
recovered = ecrecover(ethSignHash, v, r, s);
|
|
||||||
}
|
|
||||||
isSignedBy = recovered == signerAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _getOrderHashFromEIP1271Data(bytes memory data)
|
|
||||||
private
|
private
|
||||||
|
view
|
||||||
returns (bytes32 hash)
|
returns (bytes32 hash)
|
||||||
{
|
{
|
||||||
if (data.length == 32) {
|
// HACK(dorothy-zbornak): First we want the hash, which is the second
|
||||||
// `data` is an order hash.
|
// encoded parameter. We will initially treat all fields as inline
|
||||||
hash = data.readBytes32(0);
|
// `bytes32`s and ignore the first one to extract it.
|
||||||
|
(,hash) = abi.decode(data, (bytes32, bytes32));
|
||||||
|
// Now we can figure out what the data type is from a previous call to
|
||||||
|
// `prepare()`.
|
||||||
|
DataType dataType = _hashDataTypes[hash];
|
||||||
|
require(
|
||||||
|
dataType != DataType.None,
|
||||||
|
"EXPECTED_NO_DATA_TYPE"
|
||||||
|
);
|
||||||
|
if (dataType == DataType.Order) {
|
||||||
|
// Decode the first parameter as an `Order` type.
|
||||||
|
LibOrder.Order memory order = abi.decode(data, (LibOrder.Order));
|
||||||
|
// Use the Exchange to calculate the hash of the order and assert
|
||||||
|
// that it matches the one we extracted previously.
|
||||||
|
require(
|
||||||
|
_exchange.getOrderHash(order) == hash,
|
||||||
|
"UNEXPECTED_ORDER_HASH"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// `data` is an abi-encoded Order.
|
assert(dataType == DataType.ZeroExTransaction);
|
||||||
LibOrder.Order memory order = _getOrderFromEIP1271Data(data);
|
// Decode the first parameter as a `ZeroExTransaction` type.
|
||||||
// Use the Exchange contract to convert it into a hash.
|
LibZeroExTransaction.ZeroExTransaction memory transaction =
|
||||||
hash = _exchange.getOrderHash(order);
|
abi.decode(data, (LibZeroExTransaction.ZeroExTransaction));
|
||||||
|
// Use the Exchange to calculate the hash of the transaction and assert
|
||||||
|
// that it matches the one we extracted previously.
|
||||||
|
require(
|
||||||
|
_exchange.getTransactionHash(transaction) == hash,
|
||||||
|
"UNEXPECTED_TRANSACTION_HASH"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getOrderFromEIP1271Data(bytes memory data)
|
|
||||||
private
|
|
||||||
returns (LibOrder.Order memory order)
|
|
||||||
{
|
|
||||||
require(data.length > 32, "INVALID_EIP1271_ORDER_DATA_LENGTH");
|
|
||||||
return abi.decode(data, (LibOrder.Order));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user