Skip to main content

EIP-1271: Contract wallet signatures

Every signature-verifying function on the token — permit, transferWithAuthorization, receiveWithAuthorization, and cancelAuthorization — accepts signatures from smart contract wallets, not only externally owned accounts (EOAs). Contract wallet support applies on every EVM token contract except Polygon PoS, Tempo, and Hedera (see Availability). The token picks the verification path based on the signer address:

  • If the signer (owner / from / authorizer) has no code, the token verifies it as a standard Elliptic Curve Digital Signature Algorithm (ECDSA) signature through ecrecover.
  • If the signer is a contract, the token makes a static call to isValidSignature(bytes32 hash, bytes signature) on it. The token accepts the signature if the call returns the EIP-1271 magic value 0x1626ba7e.

Interface

The signer contract implements the following interface:

interface IERC1271 {
function isValidSignature(
bytes32 hash, bytes memory signature
) external view returns (bytes4 magicValue);
}

Gasless approvals and transfers therefore work for Safe multisigs, ERC-4337 smart accounts, and any other wallet that implements EIP-1271, with no extra integration work. For the token-side function signatures, see EIP-2612: Gasless approvals and EIP-3009: Gasless transfers.

Integration notes

Keep the following in mind when you integrate contract wallets:

  • For contract wallets, use the bytes signature variants — contract wallet signatures are usually not 65 bytes (for example, a Safe concatenates one signature per owner). For EOAs, pack the signature as r (32 bytes) || s (32 bytes) || v (1 byte).
  • Contract signatures are revocable. Unlike an ECDSA signature, the result of isValidSignature can change, for example after a Safe owner rotation. An authorization that was valid when signed can therefore fail later.