This ERC improves on EIP-712 signatures to better support smart contract accounts by 1) introducing signing domains as a way to prevent replay attacks when private keys are shared across accounts, and 2) allowing dapps and wallets to coordinate on the method that will be used to authenticate the signature.
Standards like ERC-1271 and ERC-6492 give smart contract accounts (SCAs) the ability to produce signatures that an application can authenticate without knowledge of the abstract rules of the account. This is an important primitive for applications, as the account owner is able to authorize a third-party to act on its behalf without interacting with the chain.
Smart contract accounts may be "owned" by cryptographic keys whose signatures are used to authorize the use of the account. There is not necessarily a one-to-one mapping between keys and accounts, because a single key may control multiple accounts, so care must be taken to prevent replay attacks across them. This is done by binding a signature to a particular account.
EIP-712 introduced a scheme where signatures can be bound to a verifying domain, which corresponds to the protocol contract that will authenticate a signature. Reusing this mechanism to additionally bind a signature to the domain of the smart contract account runs into a large amount of complexity and attack surface (see ERC-7739), as well as yet unresolved issues with account composability (SCAs that control other SCAs). This ERC introduces signing domains in addition to verifying domains to natively enable wallets to generate smart contract account signatures with replay protection.
ERC-1271 is a minimal and very general interface that has been very effective. It requires the contract code to be already deployed by the time the signature needs to be authenticated, so ERC-6492 extends ERC-1271 to support that use case. In the future additional methods may need to be developed.
Support for these methods across protocols is currently lacking and is a major pain point for the Account Abstraction roadmap. Where ERC-1271 is supported, it is not necessarily used uniformly, in particular some contracts attempt ECRECOVER
prior to invoking isValidSignature
while others do the opposite, which will result in very different semantics post EIP-7702.
This ERC addresses this by allowing dapps to communicate the types of signatures a protocol's contracts support, i.e., which authentication methods will be used, and in what order.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Requests for typed data signatures via JSON-RPC (eth_signTypedData
) or client libraries are extended with the following optional properties:
signingDomains
authMethods
These new properties are used alongside the existing ones, i.e., types
, primaryType
, domain
, and message
.
The signature returned in response to the request MAY be of any size, and in the absence of authMethods
it MUST be treated opaquely as the type of the signature is not known.
signingDomains
This property is an array of smart contract account domains. Each member of the array is an object with the following keys:
types
: An object with the same format as EIP-712 types
with at least an EIP712Domain
key.domain
: An object that is valid with respect to the type EIP712Domain
described in types
.From right to left the array lists the chain of accounts through which the signer ultimately has control over the "outermost" signing domain (i.e., that listed first).
For example:
signingDomains
is empty or undefined.signingDomains
, which is now an array of length 1.signingDomains
, which is now an array of length 2.In the presence of signingDomains
the account should encode the message to be signed according to the following recursive procedure:
encodeForSigningDomains(signingDomainSeparators : [𝔹²⁵⁶], verifyingDomainSeparator : 𝔹²⁵⁶, message : 𝕊) =
signingDomainSeparators = [first, ...others]
: "\x19\x02" ‖ first ‖ encodeForSigningDomains(others, verifyingDomainSeparator, message)
signingDomainSeparators = []
: encode(domainSeparator, message)
, where encode
is defined by EIP-712.signingDomainSeparators
is the array of hashes of the domains included in signingDomains
, in the same order, computed according to EIP-712's hashStruct
.
authMethods
This property is an array of supported signature authentication methods, listed in the order that the verifying domain tries them.
Each member of the array is an object with the following keys:
id
: An string that identifies the method. It may be one of:ECDSA
: ECDSA signatures by Externally Owned Accounts.ERC-{n}
: A standard type of signature specified by an ERC. n
must not be padded with zeros.parameters
(optional): An array of method-specific parameters.{
type: 'object',
properties: {
types: {$ref: '#/$defs/EIP712Types'},
primaryType: {type: 'string'},
domain: {type: 'object'},
message: {type: 'object'},
signingDomains: {
type: 'array',
items: {$ref: '#/$defs/EIP712Types'}
}
authMethods: {
type: 'array',
items: {
type: 'object',
id: {type: 'string'},
parameters: {type: 'array'},
required: ['id'],
},
}
},
required: ['types', 'primaryType', 'domain', 'message'],
$defs: {
EIP712Types: {
type: 'object',
properties: {
EIP712Domain: {type: 'array'},
},
additionalProperties: {
type: 'array',
items: {
type: 'object',
properties: {
name: {type: 'string'},
type: {type: 'string'}
},
required: ['name', 'type']
}
},
required: ['EIP712Domain']
}
}
}
Needs discussion.
Copyright and related rights waived via CC0.