snip | title | authors | discussions-to | status | type | category | created |
---|---|---|---|---|---|---|---|
6 |
Standard Account Interface |
Martín Triay <martriay@gmail.com>, Julien Niset <julien@argent.xyz>, Eric Nordelo <eric.nordelo39@gmail.com>, Sergio Garcia <sergio@argent.xyz>, Yoav Gaziel <yoav.gaziel@braavos.app> |
Review |
Standards Track |
SRC |
2023-07-06 |
A standard interface for accounts.
The following standard defines a standard API for smart contracts acting as accounts in Starknet. It provides basic functionality for sending transactions through the contract, as well as functionality for validating signatures supporting interoperability among accounts, protocols, and dapps.
With native Account Abstraction, Starknet has a lot of flexibility in the management of accounts rather than having their behavior determined at the protocol level. Different use cases are and will continue to bring different implementations of accounts to the ecosystem.
Having a Standard Account Interface supports different dapps, protocols, and standard contracts (like tokens) that often require predictable interactions with accounts, either by recognizing them or by expecting certain behaviors that may not be implemented otherwise.
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Every SNIP-6 compliant account MUST implement the SRC6
and SRC5
(from SNIP-5) interfaces, and publish both interface ids through supports_interface
:
/// @title Represents a call to a target contract
/// @param to The target contract address
/// @param selector The target function selector
/// @param calldata The serialized function parameters
struct Call {
to: ContractAddress,
selector: felt252,
calldata: Array<felt252>
}
/// @title SRC-6 Standard Account
trait ISRC6 {
/// @notice Execute a transaction through the account
/// @param calls The list of calls to execute
/// @return The list of each call's serialized return value
fn __execute__(calls: Array<Call>) -> Array<Span<felt252>>;
/// @notice Assert whether the transaction is valid to be executed
/// @param calls The list of calls to execute
/// @return The string 'VALID' is represented as felt when is valid
fn __validate__(calls: Array<Call>) -> felt252;
/// @notice Assert whether a given signature for a given hash is valid
/// @param hash The hash of the data
/// @param signature The signature to validate
/// @return The string 'VALID' is represented as felt when the signature is valid
fn is_valid_signature(hash: felt252, signature: Array<felt252>) -> felt252;
}
/// @title SRC-5 Standard Interface Detection
trait ISRC5 {
/// @notice Query if a contract implements an interface
/// @param interface_id The interface identifier, as specified in SRC-5
/// @return `true` if the contract implements `interface_id`, `false` otherwise
fn supports_interface(interface_id: felt252) -> bool;
}
Notice that, if the signature is valid, the return value for is_valid_signature
MUST be the short string literal VALID
.
To guarantee the signature cannot be replayed in other accounts or other chains, the data hashed must be unique to the account and the chain. This is true for starknet transaction signatures and SNIP-12 signatures. However, it's worth noting that this may not necessarily hold for other types of signatures. Wallets are advised not to sign any data unless they know that it includes the account address and the chain ID
(To Do...)
Currently, multiple accounts are using bool
as the is_valid_signature
return value. While in the future we expect that most of the accounts will migrate to this standard, in the meantime, we recommend dapps and protocols using this feature to check for both true
or 'VALID'
.
Copyright and related rights waived via MIT.