Skip to content

Commit

Permalink
doc: SNIP-6 implementation (#200)
Browse files Browse the repository at this point in the history
* test: SNIP-6 implementation

* docs: errors recheck

* test: SNIP-6 implementation

* docs: errors recheck

* feat: add simple account example

* feat/fix: revisions on #200

* feat:implement SRC5

* feat: implementation with oz

* fix: oz impl src5 for account

---------

Co-authored-by: Oluwaseun Jeremiah <jeremiah@Jemiah>
Co-authored-by: julio4 <30329843+julio4@users.noreply.github.com>
  • Loading branch information
3 people committed Jul 1, 2024
1 parent 6f4d055 commit 630092f
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 3 deletions.
5 changes: 4 additions & 1 deletion Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,11 @@ name = "scarb"
version = "0.1.0"

[[package]]
name = "simple_storage"
name = "simple_account"
version = "0.1.0"
dependencies = [
"openzeppelin",
]

[[package]]
name = "simple_vault"
Expand Down
1 change: 1 addition & 0 deletions listings/advanced-concepts/simple_account/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
6 changes: 6 additions & 0 deletions listings/advanced-concepts/simple_account/Scarb.lock
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 = "ecdsa_verification"
version = "0.1.0"
14 changes: 14 additions & 0 deletions listings/advanced-concepts/simple_account/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "simple_account"
version.workspace = true
edition = '2023_11'


[dependencies]
starknet.workspace = true
openzeppelin.workspace = true

[scripts]
test.workspace = true

[[target.starknet-contract]]
4 changes: 4 additions & 0 deletions listings/advanced-concepts/simple_account/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod simple_account;

#[cfg(test)]
mod tests;
90 changes: 90 additions & 0 deletions listings/advanced-concepts/simple_account/src/simple_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use starknet::account::Call;

#[starknet::interface]
trait ISRC6<TContractState> {
fn execute_calls(self: @TContractState, calls: Array<Call>) -> Array<Span<felt252>>;
fn validate_calls(self: @TContractState, calls: Array<Call>) -> felt252;
fn is_valid_signature(
self: @TContractState, hash: felt252, signature: Array<felt252>
) -> felt252;
}

#[starknet::contract]
mod simpleAccount {
use super::ISRC6;
use starknet::account::Call;
use core::num::traits::Zero;
use core::ecdsa::check_ecdsa_signature;

// Implement SRC5 with openzeppelin
use openzeppelin::account::interface;
use openzeppelin::introspection::src5::SRC5Component;
component!(path: SRC5Component, storage: src5, event: SRC5Event);

#[abi(embed_v0)]
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
src5: SRC5Component::Storage,
public_key: felt252
}

#[constructor]
fn constructor(ref self: ContractState, public_key: felt252) {
self.src5.register_interface(interface::ISRC6_ID);
self.public_key.write(public_key);
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
SRC5Event: SRC5Component::Event
}

#[abi(embed_v0)]
impl SRC6 of ISRC6<ContractState> {
fn execute_calls(self: @ContractState, calls: Array<Call>) -> Array<Span<felt252>> {
assert(starknet::get_caller_address().is_zero(), 'Not Starknet Protocol');
let Call { to, selector, calldata } = calls.at(0);
let res = starknet::syscalls::call_contract_syscall(*to, *selector, *calldata).unwrap();
array![res]
}

fn validate_calls(self: @ContractState, calls: Array<Call>) -> felt252 {
assert(starknet::get_caller_address().is_zero(), 'Not Starknet Protocol');
let tx_info = starknet::get_tx_info().unbox();
let tx_hash = tx_info.transaction_hash;
let signature = tx_info.signature;
if self._is_valid_signature(tx_hash, signature) {
starknet::VALIDATED
} else {
0
}
}

fn is_valid_signature(
self: @ContractState, hash: felt252, signature: Array<felt252>
) -> felt252 {
if self._is_valid_signature(hash, signature.span()) {
starknet::VALIDATED
} else {
0
}
}
}

#[generate_trait]
impl SignatureVerificationImpl of SignatureVerification {
fn _is_valid_signature(
self: @ContractState, hash: felt252, signature: Span<felt252>
) -> bool {
check_ecdsa_signature(
hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32)
)
}
}
}
3 changes: 3 additions & 0 deletions listings/advanced-concepts/simple_account/src/tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#[cfg(test)]
mod tests { // TODO
}
6 changes: 4 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,12 @@ Summary
- [Struct as mapping key](./advanced-concepts/struct-mapping-key.md)
- [Hashing](./advanced-concepts/hashing.md)
<!-- Hidden until #123 is solved -->
<!-- - [Hash Solidity Compatible](./advanced-concepts/hash-solidity-compatible.md) -->
<!-- - [Hash Solidity Compatible](./ch02/hash-solidity-compatible.md) -->
- [Optimisations](./advanced-concepts/optimisations/optimisations.md)
- [Storage Optimisations](./advanced-concepts/optimisations/store_using_packing.md)
- [Account Abstraction](./advanced-concepts/account_abstraction/index.md)
- [Account Contract](./advanced-concepts/account_abstraction/account_contract.md)
- [List](./advanced-concepts/list.md)
- [Library Calls](./advanced-concepts/library_calls.md)
- [Plugins](./advanced-concepts/plugins.md)
- [Signature Verification](./advanced-concepts/signature_verification.md)
- [Library Calls](./advanced-concepts/library_calls.md)
73 changes: 73 additions & 0 deletions src/advanced-concepts/account_abstraction/account_contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Account Contract

A smart contract must follow the Standard Account Interface specification defined in the [SNIP-6](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-6.md).
In practice, this means that the contract must implement the `SRC6` and `SRC5` interfaces to be considered an account contract.

## SNIP-6: SRC6 + SRC5

```rust
/// @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>
}
```

The `Call` struct is used to represent a call to a function (`selector`) in a target contract (`to`) with parameters (`calldata`). It is available under the `starknet::account` module.

```rust
/// @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' 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' represented as felt when the signature is valid
fn is_valid_signature(hash: felt252, signature: Array<felt252>) -> felt252;
}
```

A transaction can be represented as a list of calls `Array<Call>` to other contracts, with atleast one call.

- `__execute__`: Executes a transaction after the validation phase. Returns an array of the serialized return of value (`Span<felt252>`) of each call.

- `__validate__`: Validates a transaction by verifying some predefined rules, such as the signature of the transaction. Returns the `VALID` short string (as a felt252) if the transaction is valid.

- `is_valid_signature`: Verify that a given signature is valid. This is mainly used by applications for authentication purposes.

Both `__execute__` and `__validate__` functions are exclusively called by the Starknet protocol.

<!-- TODO replace with link to SRC5 example #109 -->

```rust
/// @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;
}
```

The interface identifiers of both `SRC5` and `SRC6` must be published with `supports_interface`.

## Minimal account contract Executing Transactions

In this example, we will implement a minimal account contract that can validate and execute transactions.

```rust
{{#rustdoc_include ../../../listings/advanced-concepts/simple_account/src/simple_account.cairo}}
```
13 changes: 13 additions & 0 deletions src/advanced-concepts/account_abstraction/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Account Abstraction

An account is an unique entity that can send transactions, users usually use wallets to manage their accounts.

Historically, in Ethereum, all accounts were Externally Owned Accounts (_EOA_) and were controlled by private keys. This is a simple and secure way to manage accounts, but it has limitations as the account logic is hardcoded in the protocol.

Account Abstraction (_AA_) is the concept behind abstracting parts of the account logic to allow for a more flexible account system.
This replaces EOA with Account Contracts, which are smart contracts that implement the account logic. This opens up a lot of possibilities that can significantly improve the user experience when dealing with accounts.

On Starknet, Account Abstraction is natively supported, and all accounts are Account Contracts.

In this section we will how to implement an Account.
<!-- and common customizations that can be done to it. -->

0 comments on commit 630092f

Please sign in to comment.