0xProject/ZEIPs

Support EIP-1271 Signature Types

Closed this issue · 1 comments

Summary

Add support for two new order signature types to orders:

  • EIP1271Wallet
  • EIP1271OrderWallet.

Respectively, these new signature are analagous to OrderValidator (proposed in #33) and the Wallet signature type introduced in 2.0. However, their callbacks implement the EIP-1271 standard, which takes an arbitrary bytes payload for the data that is signed.

Motivation

EIP-1271 provides a more flexible way for wallets to validate arbitrary data (not just Orders). A wallet implementing this standard could use the same callback/function to parse different types of data and validate signatures based on some context.

Status

Branch: 3.0

  • #1885 in review: Initial implementation.

Specification

Restrictions

  • Callbacks will be called via staticcall(). If the contract attempts to update state during call, the validation will fail.

Encoding of data

  • EIP1271Wallet
    • data is simply the 32-byte hash placed in a bytes array.
  • EIP1271OrderWallet
    • data is the abi-encoded Order. E.g, abi.encode(order).

The callback contract

In both cases, the callback contract is determined by the order maker.

Implementation

Contracts validating the EIP1271Wallet and EIP1271OrderWallet signature types must expose an isValidSignature function with the following signature:

function isValidSignature(
    bytes memory data,
    bytes memory signature
)
    public
    view
    returns (bytes4 magicBytes);

Example

Here is a trivial implementation of EIP1271OrderWallet:

pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;

contract MyEIP1271Wallet {
    bytes4 constant public EIP1271_MAGIC_VALUE = 0x20c13b0b;
    address constant public AUTHORIZED_MAKER = 0x645b6e008c70efa2e5d9ac897740a21dc59eda0e;

    // 0x order structure
    struct Order {
        address makerAddress;
        address takerAddress;
        address feeRecipientAddress;
        address senderAddress;
        uint256 makerAssetAmount;
        uint256 takerAssetAmount;
        uint256 makerFee;
        uint256 takerFee;
        uint256 expirationTimeSeconds;
        uint256 salt;
        bytes makerAssetData;
        bytes takerAssetData;
        bytes makerFeeAssetData;
        bytes takerFeeAssetData;
    }

    /// @dev EIP1271 wallet callback.
    /// @param data The ABI-encoded `Order`.
    /// @param signature Signature data for the order.
    /// @return magicValue `EIP1271_MAGIC_VALUE` if valid.
    function isValidSignature(
        bytes memory data
        bytes memory signature
    )
        public
        view
        returns (bytes4 magicValue)
    {
        // Decode the order.
        Order memory order = abi.decode(data, (Order));
        if (order.makerAddress == AUTHORIZED_MAKER) {
            magicValue = EIP1271_MAGIC_VALUE;
        }
    }
}

Retiring since we're consolidating signature types with the EIP-1271 pattern in #33