-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: src-5 implement #233
base: main
Are you sure you want to change the base?
Changes from 8 commits
434e473
16f9f3e
9d2d4c1
7ca2112
27fee4b
4bb6302
cf325d8
4018036
2757850
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
target |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Code generated by scarb DO NOT EDIT. | ||
version = 1 | ||
|
||
[[package]] | ||
name = "src5_interface" | ||
version = "0.1.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "src5_interface" | ||
version = "0.1.0" | ||
edition = "2023_11" | ||
|
||
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html | ||
|
||
[dependencies] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pub mod user_account; | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
julio4 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not valid cairo syntax, please refer to official documentation, or our counter example, and don't use AI generated content. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
use openzeppelin::account::interface::ISRC5_ID; | ||
use openzeppelin::introspection::src5::SRC5Component; | ||
use starknet::contract::ContractAddress; | ||
use starknet::syscalls::call_contract_syscall; | ||
use starknet::alloc::arrays::ArrayTrait; | ||
use starknet::core::keccak::starknet_keccak; | ||
// Define ISRC5 interface | ||
trait ISRC5 { | ||
fn supports_interface(interface_id: felt252) -> bool; | ||
} | ||
// Define example interfaces | ||
trait IExample1 { | ||
fn example_function1(param1: felt252) -> felt252; | ||
} | ||
trait IExample2 { | ||
fn example_function2(param1: felt252, param2: felt252) -> felt252; | ||
} | ||
// Storage structure | ||
struct Storage { | ||
public_key: felt252, | ||
src5: SRC5Component::Storage, | ||
} | ||
// Event definitions | ||
enum Event { | ||
AccountCreated: felt252, | ||
SRC5Event: SRC5Component::Event, | ||
} | ||
// Contract implementation | ||
@contract | ||
namespace ExampleContract { | ||
struct State { | ||
storage: Storage, | ||
} | ||
// Constructor | ||
#[constructor] | ||
fn constructor(ref state: State, public_key: felt252) { | ||
state.storage.public_key = public_key; | ||
emit(Event::AccountCreated(public_key)); | ||
state.storage.src5.register_interface(ISRC5_ID); | ||
} | ||
// Implementation of ISRC5 | ||
#[external] | ||
fn supports_interface(ref state: State, interface_id: felt252) -> bool { | ||
state.storage.src5.supports_interface(interface_id) | ||
} | ||
// Implementation of IExample1 | ||
#[external] | ||
fn example_function1(param1: felt252) -> felt252 { | ||
// Your implementation here | ||
return starknet_keccak(param1.to_bytes()); | ||
} | ||
// Implementation of IExample2 | ||
#[external] | ||
fn example_function2(param1: felt252, param2: felt252) -> felt252 { | ||
// Your implementation here | ||
return param1 + param2; | ||
} | ||
// Additional functions or internal logic can be added here | ||
} | ||
// ISRC5 trait implementation | ||
impl ISRC5 for State { | ||
fn supports_interface(ref self, interface_id: felt252) -> bool { | ||
self.storage.src5.supports_interface(interface_id) | ||
} | ||
} | ||
|
||
|
||
|
||
#[cfg(test)] | ||
mod tests { // TODO | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong format, please try to run the code before pushing it |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from starkware.starknet.public.abi import starknet_keccak | ||
|
||
signatures = [ | ||
'supports_interface(felt252)->E((),())', | ||
'is_valid_signature(felt252,Array<felt252>)->E((),())', | ||
'__execute__(Array<(ContractAddress,felt252,Array<felt252>)>)->Array<(@Array<felt252>)>', | ||
'__validate__(Array<(ContractAddress,felt252,Array<felt252>)>)->felt252', | ||
'__validate_declare__(felt252)->felt252' | ||
] | ||
|
||
def compute_interface_id(): | ||
interface_id = 0x0 | ||
for sig in signatures: | ||
function_id = starknet_keccak(sig.encode()) | ||
interface_id ^= function_id | ||
print('IAccount ID:', hex(interface_id)) | ||
|
||
compute_interface_id() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
## SRC-5: A comprehensive Overview | ||
|
||
SRC-5 is a standard for smart contract interface introspection in Starknet, inspired by the [Ethereum ERC-165 standard](https://eips.ethereum.org/EIPS/eip-165). It provides a standardize method for contracts to publish and detect the interfaces they implement, ensuring consistent interaction. For more information, refer to the [SRC-5 specification](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md#simple-summary). | ||
|
||
### SRC-5 offers a standardized method to: | ||
|
||
* Identify interfaces. | ||
* Publish the interfaces a contract implements. | ||
* Detect if a contract implements any given interface. (including SRC-5) | ||
|
||
### Interface Definition | ||
julio4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
An interface is a set of function signatures with specific type parameters, represented as traits. These traits are meant to be implemented externally by compliant contracts. | ||
|
||
Example: | ||
|
||
|
||
```rust | ||
trait IMyContract { | ||
fn foo(some: u256) -> felt252; | ||
} | ||
``` | ||
|
||
With Cairo, generic traits can represent a set of interfaces: | ||
|
||
```rust | ||
#[starknet::interface] | ||
trait IMyContract<TContractState, TNumber> { | ||
fn foo(self: @TContractState, some: TNumber) -> felt252; | ||
} | ||
``` | ||
|
||
#### Extended Function Selector | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing linebreak |
||
|
||
The function selector in Starknet is the starknet_keccak hash of the function name. The extended function selector, for SRC-5, is the starknet_keccak hash of the function signature: | ||
|
||
`fn_name(param1_type,param2_type,...)->output_type` | ||
|
||
For example, for a function with zero parameters and no return value: `fn_name()` | ||
|
||
Special Types: | ||
|
||
* Tuples: (elem1_type,elem2_type,...) | ||
* Structs: (field1_type,field2_type,...) | ||
* Enums: E(variant1_type,variant2_type,...) | ||
|
||
#### Interface Identification | ||
|
||
An interface identifier is the XOR of all extended function selectors in the interface. | ||
|
||
This Python code computes the interface id: | ||
|
||
```rust | ||
{{#rustdoc_include ../../../listings/src5_interface/src5_snippet.py}} | ||
``` | ||
|
||
For more details refer to the [SRC-5 repository on GitHub](https://github.com/ericnordelo/src5-rs). | ||
|
||
### Publishing and Detecting Interfaces | ||
|
||
To comply with SRC-5, a contract must implement the ISRC5 trait: | ||
|
||
```rust | ||
trait ISRC5 { | ||
fn supports_interface(interface_id: felt252) -> bool; | ||
} | ||
``` | ||
|
||
The supports_interface function returns a boolean that indicate if the contract implements a given interface. | ||
|
||
The interface identifier for ISRC5 is | ||
|
||
```0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055``` | ||
|
||
#### Detecting SRC-5 Implementation | ||
julio4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
To check if a contract implements SRC-5: | ||
|
||
* Call `contract.supports_interface(0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055)`. | ||
* If the call fails or returns false, the contract does not implement SRC-5. | ||
* Otherwise, it implements SRC-5. | ||
|
||
#### Detecting Any Given Interface | ||
julio4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
* Confirm if the contract implements SRC-5. | ||
* If confirmed, `call supports_interface(interface_id)` to check for specific interfaces. | ||
* If not, manually inspect the contract methods. | ||
|
||
Below shows a contract implementing the `SRC5` to expose the `Isupports_interface(interface_id)`: | ||
|
||
```rust | ||
{{#rustdoc_include ../../../listings/src5_interface/src/src5_interface.cairo}} | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add test module directly inside main module behind a test anchor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You moved test functions so you can remove tests module definition here