title: 27. 库调度器 tags: cairo starknet interface abi erc20 dispatcher library WTF Cairo极简教程: 27. 库调度器 我最近在学 ,巩固一下细节,也写一个 ,供小白们使用。教程基于 版本。 推特:@0xAAScience|@WTFAcademy WTF Academy 社群:Discord|微信群|官网 wtf.academy 所有代码和教程开源在 github: github.com/WTFAcademy/WTF-Cairo 在这一讲中,我们将介绍Cairo中的库调度器(Library Dispatcher),它由接口合约自动生成,帮助你调用库合约,使用起来像Solidity中的 。
title: 27. 库调度器 tags: - cairo - starknet - interface - abi - erc20 - dispatcher - library
我最近在学cairo-lang,巩固一下细节,也写一个WTF Cairo极简教程,供小白们使用。教程基于cairo 2.2.0版本。
WTF Academy 社群:Discord|微信群|官网 wtf.academy
所有代码和教程开源在 github: github.com/WTFAcademy/WTF-Cairo
在这一讲中,我们将介绍Cairo中的库调度器(Library Dispatcher),它由接口合约自动生成,帮助你调用库合约,使用起来像Solidity中的delegatecall。
与合约调度器类似,库调度器也是由接口合约自动生成,帮助你调用库合约。但是,使用合约调度器调用目标合约时,上下文是目标合约;而使用库调度器调用目标合约时,上下文是本合约。这也是为什么它用起来像Solidity中的delegatecall。

另外与以太坊不同,Starknet将合约的代码(code)和存储(storage)分开存放。当你declare合约时,会将合约的代码存储到链上,并可以通过class_hash查询;之后deploy合约时,才会初始化合约并分配存储。由于delegatecall仅使用目标合约的代码,而不需要用到状态变量,因此只需要class_hash即可调用。也就是说,每个declare在Starknet上的合约都可以作为库合约使用。
以我们上一讲中的IMiniERC20接口合约为例:
#[starknet::interface] trait IMiniERC20<TContractState> { fn name(self: @TContractState) -> felt252; fn symbol(self: @TContractState) -> felt252; }
编译器自动生成的库调度器如下:
#[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 { // 使用starknet::library_call_syscall调用相应函数 } fn symbol( self: IMiniERC20Dispatcher ) { // 使用starknet::library_call_syscall调用相应函数 } }
下面我们写一个合约,利用库调度器调用mini_erc_20库。
#[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() } }
要注意的几点:
DispatcherTrait和LibraryDispatcher。IMiniERC20LibraryDispatcher并传入目标库的class_hash。这一讲,我们介绍了Cairo中的库调度器,由接口合约自动生成,方便你调用其他合约。但是与合约调度器不同,它在调用时使用的是当前合约的上下文,类似于Solidity中的delegatecall,使用时需要注意。