Skip to content

Commit

Permalink
Add Interface & Dispatchers docs (#730)
Browse files Browse the repository at this point in the history
* feat: update format and add api

* fix: typo

* feat: add counterfactual deployment doc

* feat: add API entries

* feat: add events

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* feat: update from reviews

* feat: apply review updates

* feat: update docs

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/guides/deployment.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* feat: apply review updates

* fix: account casing

* feat: add headers

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* feat: add link

* feat: move API

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/accounts.adoc

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* refactor: update wording

* Update docs/antora.yml

Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* feat: apply update reviews

* Update docs/modules/ROOT/pages/api/account.adoc

Co-authored-by: Martín Triay <martriay@gmail.com>

* refactor: UI

* fix: UI

* feat: focus on SRC6

* add interface & dispatchers docs

* apply review feedback

* address feedback comments

---------

Co-authored-by: Eric Nordelo <eric.nordelo39@gmail.com>
Co-authored-by: Andrew Fleming <fleming.andrew@protonmail.com>
  • Loading branch information
3 people authored Sep 20, 2023
1 parent 7373daa commit cbb5bf5
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 11 deletions.
25 changes: 14 additions & 11 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
* xref:index.adoc[Overview]
* xref:wizard.adoc[Wizard]
* xref:extensibility.adoc[Extensibility]
* xref:proxies.adoc[Proxies and Upgrades]
//* xref:wizard.adoc[Wizard]
//* xref:extensibility.adoc[Extensibility]
//* xref:proxies.adoc[Proxies and Upgrades]
* xref:interfaces.adoc[Interfaces and Dispatchers]
* xref:accounts.adoc[Accounts]
** xref:/guides/deployment.adoc[Counterfactual deployments]
** xref:/api/account.adoc[API Reference]
* xref:access.adoc[Access Control]
* Tokens
** xref:erc20.adoc[ERC20]
** xref:erc721.adoc[ERC721]
** xref:erc1155.adoc[ERC1155]
//* xref:access.adoc[Access Control]

* xref:security.adoc[Security]
* xref:introspection.adoc[Introspection]
* xref:udc.adoc[Universal Deployer Contract]
* xref:utilities.adoc[Utilities]
//* Tokens
//** xref:erc20.adoc[ERC20]
//** xref:erc721.adoc[ERC721]
//** xref:erc1155.adoc[ERC1155]

//* xref:security.adoc[Security]
//* xref:introspection.adoc[Introspection]
//* xref:udc.adoc[Universal Deployer Contract]
//* xref:utilities.adoc[Utilities]

* xref:contracts::index.adoc[Contracts for Solidity]
185 changes: 185 additions & 0 deletions docs/modules/ROOT/pages/interfaces.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
:great-interface-migration: link:https://community.starknet.io/t/the-great-interface-migration/92107[Great Interface Migration]

= Interfaces and Dispatchers

This section describes the interfaces OpenZeppelin Contracts for Cairo offer, and explains the design choices behind them.

Interfaces can be found in the module tree under the `interface` submodule, such as `token::erc20::interface`. For example:

```javascript
use openzeppelin::token::erc20::interface::IERC20;
```

or

```javascript
use openzeppelin::token::erc20::dual20::DualCaseERC20;
```

NOTE: For simplicity, we'll use ERC20 as example but the same concepts apply to other modules.

== Interface traits
The library offers three types of traits to implement or interact with contracts:

=== Standard traits

These are associated with a predefined interface such as a standard.
This includes only the functions defined in the interface, and is the standard way to interact with a compliant contract.

```javascript
#[starknet::interface]
trait IERC20<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
```

=== ABI traits

They describe a contract's complete interface. This is useful to interface with a preset contract offered by this library, such as the ERC20 preset that includes non-standard functions like `increase_allowance`.

```javascript
#[starknet::interface]
trait ERC20ABI<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
fn increase_allowance(ref self: TState, spender: ContractAddress, added_value: u256) -> bool;
fn decrease_allowance(
ref self: TState, spender: ContractAddress, subtracted_value: u256
) -> bool;
}
```

=== Dispatcher traits
This is a utility trait to interface with contracts whose interface is unknown. Read more in the xref:#dualcase_dispatchers[DualCase Dispatchers] section.

```javascript
#[derive(Copy, Drop)]
struct DualCaseERC20 {
contract_address: ContractAddress
}

trait DualCaseERC20Trait {
fn name(self: @DualCaseERC20) -> felt252;
fn symbol(self: @DualCaseERC20) -> felt252;
fn decimals(self: @DualCaseERC20) -> u8;
fn total_supply(self: @DualCaseERC20) -> u256;
fn balance_of(self: @DualCaseERC20, account: ContractAddress) -> u256;
fn allowance(self: @DualCaseERC20, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(self: @DualCaseERC20, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
self: @DualCaseERC20, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(self: @DualCaseERC20, spender: ContractAddress, amount: u256) -> bool;
}
```

== Dual interfaces

Following the {great-interface-migration} plan, we added `snake_case` functions to all of our preexisting `camelCase` contracts with the goal of eventually dropping support for the latter.

In short, we offer two types of interfaces and utilities to handle them:

1. `camelCase` interfaces, which are the ones we've been using so far.
2. `snake_case` interfaces, which are the ones we're migrating to.

This means that currently most of our contracts implement _dual interfaces_. For example, the ERC20 preset contract exposes `transferFrom`, `transfer_from`, `balanceOf`, `balance_of`, etc.

NOTE: Dual interfaces are available for all external functions present in previous versions of OpenZeppelin Contracts for Cairo (https://github.com/OpenZeppelin/cairo-contracts/releases/tag/v0.6.1[v0.6.1] and below).

=== `IERC20`

The default version of the ERC20 interface trait exposes `snake_case` functions:

```javascript
#[starknet::interface]
trait IERC20<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
```

=== `IERC20Camel`

On top of that, we also offer a `camelCase` version of the same interface:

```javascript
#[starknet::interface]
trait IERC20Camel<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
```

== `DualCase` dispatchers

WARNING: `DualCase` dispatchers won't work on live chains (`mainnet` or testnets) until they implement panic handling in their runtime. Dispatchers work fine in testing environments.

In order to ease this transition, OpenZeppelin Contracts for Cairo offer what we call `DualCase` dispatchers such as `DualCaseERC721` or `DualCaseAccount`.

These modules wrap a target contract with a compatibility layer to expose a `snake_case` interface no matter what casing the underlying contract uses.
This way, an AMM wouldn't have problems integrating tokens independently of their interface.

For example:

```javascript
let token = DualCaseERC20 { contract_address: target };
token.transfer_from(OWNER(), RECIPIENT(), VALUE);
```

This is done by simply executing the `snake_case` version of the function (e.g. `transfer_from`) and falling back to the `camelCase` one (e.g. `transferFrom`) in case it reverts with `ENTRYPOINT_NOT_FOUND`, like this:

```javascript
fn try_selector_with_fallback(
target: ContractAddress, snake_selector: felt252, camel_selector: felt252, args: Span<felt252>
) -> SyscallResult<Span<felt252>> {
match call_contract_syscall(target, snake_selector, args) {
Result::Ok(ret) => Result::Ok(ret),
Result::Err(errors) => {
if *errors.at(0) == 'ENTRYPOINT_NOT_FOUND' {
return call_contract_syscall(target, camel_selector, args);
} else {
Result::Err(errors)
}
}
}
}
```

Trying the `snake_case` interface first renders `camelCase` calls a bit more expensive since a failed `snake_case` call will always happen before. This is a design choice to incentivize casing adoption/transition as per the {great-interface-migration}.

0 comments on commit cbb5bf5

Please sign in to comment.