RRC-XX: Rarible ExchangeV2 Account Abstraction Support

Author: Vadim Fadeev - Rarible
Reviewer: Anna Riabokon - Rari Foundation


1. Abstract

This proposal upgrades the Rarible ExchangeV2 order validation logic to fully support Account Abstraction (AA) and smart contract wallets while remaining backward compatible with existing EOAs and signatures.

The new implementation:

  • Uses EIP-712 typed data ("Exchange", "2") for deterministic order hashing.
  • Adds robust EIP-1271 signature verification for contract-based accounts (AA wallets, Safes, etc.).
  • Retains standard ECDSA validation for EOAs.
  • Avoids incorrect assumptions based on EXTCODESIZE: AA wallets are contracts and therefore have non-zero code size, but must still be treated as valid signers when compliant with EIP-1271.

This change is implemented via an upgrade of the ExchangeV2 order validation component and executed on-chain through Tally’s executable proposal mechanism.


2. Motivation

2.1 Account Abstraction Compatibility

Modern users increasingly interact through smart contract wallets / AA accounts (e.g. Safe, AA frameworks, modular wallets). These are deployed as contracts, so EXTCODESIZE (and equivalents) returns non-zero, even when they function as primary user wallets.

Legacy patterns that interpret “contract = invalid user” or require EXTCODESIZE == 0 for signature validity break AA flows.

This upgrade:

  • Explicitly supports contract-based accounts as order makers.
  • Verifies their signatures using EIP-1271 (isValidSignature) instead of rejecting or misclassifying them.
  • Ensures AA users can seamlessly create, sign, and execute orders on Rarible Protocol.

2.2 Security & Correctness

  • Uses structured EIP-712 hashing via EIP712Upgradeable for robust domain separation.
  • Separates EOAs and contracts using standard introspection, but does not rely on EXTCODESIZE == 0 as a trust signal.
  • Prevents false negatives for valid AA wallets and reduces attack surface caused by ad hoc signature handling.

2.3 Ecosystem Alignment

  • Aligns Rarible ExchangeV2 with ecosystem standards around:
    • EIP-1271 for contract wallet signatures.
    • Account abstraction–friendly infra across major wallets and bundlers.
  • Simplifies integrations for partners that already support AA and contract wallets.

3. Rationale

The Rarible Protocol must remain compatible with:

  • EOAs signing EIP-712 orders.
  • Smart contract wallets implementing EIP-1271.
  • Future AA patterns that standardize contract-based authentication.

The proposed model:

  • Uses a single canonical EIP-712 hash (LibOrder.hash + _hashTypedDataV4) as the message to verify.
  • For contracts: calls isValidSignature and expects the magic value 0x1626ba7e.
  • For EOAs: uses ECDSA recovery and strict equality to order.maker.
  • Ensures order.maker != address(0) on all accepted paths.
  • Does not assume that non-zero code size implies invalidity; instead, it implies EIP-1271 verification is required.

This keeps the design simple, auditable, and compatible with both existing users and AA-native flows.


4. Specifications

4.1 Validation Logic (High-Level)

Given order (LibOrder.Order) and signature:

  1. Compute:
    • hash = LibOrder.hash(order)
    • typedHash = _hashTypedDataV4(hash)
  2. If order.salt == 0 and order.maker != address(0):
    • Require msg.sender == order.maker.
    • No off-chain signature check required (gas-efficient path).
  3. Otherwise, if msg.sender != order.maker:
    • If order.maker is a contract:
      • Call IERC1271(order.maker).isValidSignature(typedHash, signature).
      • Require returned value equals 0x1626ba7e (MAGICVALUE).
      • If the call reverts or returns anything else, revert with a clear error.
    • If order.maker is not a contract:
      • Recover signer from typedHash using ECDSA.
      • Require recovered signer equals order.maker.
  4. In all valid flows:
    • Require order.maker != address(0).
  5. Maintain storage gap for upgradeable compatibility.

4.2 Reference Implementation Snippet

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

import "./libraries/LibOrder.sol";
import "@rarible/lib-signature/contracts/IERC1271.sol";
import "@rarible/lib-signature/contracts/LibSignature.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/drafts/EIP712Upgradeable.sol";

abstract contract OrderValidator is Initializable, ContextUpgradeable, EIP712Upgradeable {
    using LibSignature for bytes32;
    using AddressUpgradeable for address;

    bytes4 constant internal MAGICVALUE = 0x1626ba7e;

    function __OrderValidator_init_unchained() internal initializer {
        __EIP712_init_unchained("Exchange", "2");
    }

    function validate(LibOrder.Order memory order, bytes memory signature) internal view {
        if (order.salt == 0) {
            if (order.maker != address(0)) {
                require(_msgSender() == order.maker, "maker is not tx sender");
            }
        } else {
            if (_msgSender() != order.maker) {
                bytes32 hash = LibOrder.hash(order);
                bytes32 typedHash = _hashTypedDataV4(hash);

                if (order.maker.isContract()) {
                    bool isValid = false;

                    // AA / smart contract wallet: EIP-1271
                    try IERC1271(order.maker).isValidSignature(typedHash, signature) returns (bytes4 result) {
                        isValid = (result == MAGICVALUE);
                    } catch {
                        isValid = false;
                    }

                    require(isValid, "contract order signature verification error");
                    require(order.maker != address(0), "no maker");
                } else {
                    // EOA: ECDSA
                    address signer = typedHash.recover(signature);
                    require(signer == order.maker, "order signature verification error");
                    require(order.maker != address(0), "no maker");
                }
            }
        }
    }

    uint256[50] private __gap;
}

Note: For AA wallets and smart contract wallets, EXTCODESIZE(order.maker) (or order.maker.code.length) is non-zero, which is expected and supported. These accounts are validated exclusively via EIP-1271, not rejected because they are contracts.


5. Steps to Implement

  1. Specification & Feedback
    • Publish this proposal to the RARI DAO forum for comments from the community, wallet teams, and integrators.
  2. Testing & Audit
    • Extend test suite to cover:
      • EOAs with valid/invalid signatures.
      • EIP-1271-compliant wallets (e.g. Safe).
      • AA flows where maker is a contract with non-zero code size.
    • Optionally commission an external review focused on the new validation path.
  3. On-Chain Proposal
    • Deploy an upgrade contract or use existing upgrade mechanisms.
    • Create a Tally proposal with executable calldata to:
      • Upgrade ExchangeV2 implementation to the new OrderValidator logic.
  4. Governance Process
    • Voting period (~5 days, per DAO rules).
    • Cooldown/veto period (~2 days), if applicable.
  5. Execution
    • Upon approval, execute the upgrade via Tally.
    • New validation logic becomes effective for all new orders.
    • Communicate upgrade details to integrators and ecosystem partners.

6. Summary

This proposal upgrades Rarible ExchangeV2 to be Account Abstraction–ready by:

  • Supporting EIP-1271 signatures for smart contract wallets.
  • Preserving EOA support via ECDSA + EIP-712.
  • Correctly handling the fact that AA wallets are contracts with non-zero EXTCODESIZE, and must be validated via contract-based logic instead of being implicitly disqualified.

The change is minimal in scope, high in impact, and fully aligned with the evolving Ethereum wallet landscape, ensuring Rarible remains a secure, modern, and AA-compatible protocol.

3 Likes

I’m 100% in favor of this proposal.

2 Likes

I’m very positive about this proposal, looks like a valuable upgrade!

1 Like

Great work @forexus! a solid step to keep Rarible technically current and easier to integrate with the broader Ethereum wallet ecosystem, aligning ExchangeV2 with modern standards (EIP-1271 + EIP-712).