title | tags | |||||||
---|---|---|---|---|---|---|---|---|
27. Library Dispatcher |
|
I've been learning cairo-lang
recently, solidifying my understanding of the details, and creating a "WTF Cairo Simple Tutorial" for beginners. This tutorial is based on cairo 2.2.0
version.
Twitter: @0xAA_Science|@WTFAcademy_
WTF Academy Community: Discord|WeChat Group|Official Website wtf.academy
All code and tutorials are open-source on GitHub: github.com/WTFAcademy/WTF-Cairo
In this chapter, we will introduce the Library Dispatcher in Cairo, which is automatically generated by interface contracts to help you call library contracts, similar to delegatecall
in Solidity.
Similar to the Contract Dispatcher, the Library Dispatcher is also automatically generated by interface contracts to assist you in calling library contracts. However, when using the Contract Dispatcher to call a target contract, the context is the target contract; whereas when using the Library Dispatcher to call a target contract, the context is the current contract. This is why it behaves like Solidity's delegatecall
.
Additionally, unlike Ethereum, Starknet separates the code and storage of contracts. When you declare
a contract, the contract's code is stored on the chain and can be queried via class_hash
. Later, when you deploy
the contract, it initializes and allocates storage. Since delegatecall
only uses the target contract's code and does not require access to state variables, only the class_hash
is needed for invocation. This means that every declare
contract on Starknet can be used as a library contract.
Let's take the IMiniERC20
interface contract from our previous lesson as an example:
#[starknet::interface]
trait IMiniERC20<TContractState> {
fn name(self: @TContractState) -> felt252;
fn symbol(self: @TContractState) -> felt252;
}
The library dispatcher generated by the compiler looks like this:
#[derive(Copy, Drop, starknet::Store, Serde)]
struct IMiniERC20LibraryDispatcher {
class_hash: starknet::ClassHash,
}
trait IMiniERC20DispatcherTrait<T> {
fn name(self: T) -> felt252;
fn symbol(self: T) -> felt252;
}
impl IMiniERC20LibraryDispatcherImpl of IMiniERC20DispatcherTrait<IMiniERC20LibraryDispatcher> {
fn name(
self: IMiniERC20Dispatcher
) -> felt252 {
// Call the corresponding function using starknet::library_call_syscall
}
fn symbol(
self: IMiniERC20Dispatcher
) {
// Call the corresponding function using starknet::library_call_syscall
}
}
Now, let's write a contract using the Library Dispatcher to call the mini_erc_20
library.
#[starknet::contract]
mod librarycall_mini_erc_20 {
use starknet::ContractAddress;
use super::IMiniERC20DispatcherTrait;
use super::IMiniERC20LibraryDispatcher;
#[storage]
struct Storage {
name: felt252,
symbol: felt252,
}
#[constructor]
fn constructor(
ref self: ContractState,
name_: felt252,
symbol_: felt252,
) {
self.name.write(name_);
self.symbol.write(symbol_);
}
#[external(v0)]
fn get_name(self: @ContractState, class_hash: starknet::ClassHash) -> felt252 {
IMiniERC20LibraryDispatcher { class_hash }.name()
}
#[external(v0)]
fn get_symbol(self: @ContractState, class_hash: starknet::ClassHash) -> felt252 {
IMiniERC20LibraryDispatcher { class_hash }.symbol()
}
}
A few points to note:
- In the contract, you need to import
DispatcherTrait
andLibraryDispatcher
. - Ensure that the layout of state variables in the contract matches that of the library contract, similar to Solidity's proxy contracts.
- When calling, use
IMiniERC20LibraryDispatcher
and pass the target library'sclass_hash
.
In this chapter, we introduced the Library Dispatcher in Cairo, which is automatically generated by interface contracts, making it convenient for you to call library contracts. Unlike the Contract Dispatcher, it uses the context of the current contract during invocation, similar to Solidity's delegatecall
. Pay attention to this when using it.