工厂模式
工厂模式是面向对象编程中众所周知的模式。它提供了有关如何实例化类的抽象。
在智能合约里,我们可以通过定义一个工厂合约来使用这种模式,该合约全权负责创建和管理其他合约。
类哈希(Class hash)和合约实例
在Starknet中,合约的类和实例是分开的。合约类充当蓝图,由底层 Cairo 字节码、合约的入口点、ABI 和 Sierra 程序哈希定义。合约类由类哈希标识。当您想向网络添加一个新类时,首先需要声明它。
部署合约时,需要指定要部署的合约的类哈希值。合约的每个实例都有自己的存储,这与类哈希无关。
使用工厂模式,我们可以部署同一合约类的多个实例,并轻松处理升级。
最小范例
下面是部署SimpleCounter
合约的工厂合约的最小范例:
use starknet::{ContractAddress, ClassHash};
#[starknet::interface]
trait ICounterFactory<TContractState> {
/// Create a new counter contract from stored arguments
fn create_counter(ref self: TContractState) -> ContractAddress;
/// Create a new counter contract from the given arguments
fn create_counter_at(ref self: TContractState, init_value: u128) -> ContractAddress;
/// Update the argument
fn update_init_value(ref self: TContractState, init_value: u128);
/// Update the class hash of the Counter contract to deploy when creating a new counter
fn update_counter_class_hash(ref self: TContractState, counter_class_hash: ClassHash);
}
#[starknet::contract]
mod CounterFactory {
use starknet::{ContractAddress, ClassHash};
use starknet::syscalls::deploy_syscall;
#[storage]
struct Storage {
/// Store the constructor arguments of the contract to deploy
init_value: u128,
/// Store the class hash of the contract to deploy
counter_class_hash: ClassHash,
}
#[constructor]
fn constructor(ref self: ContractState, init_value: u128, class_hash: ClassHash) {
self.init_value.write(init_value);
self.counter_class_hash.write(class_hash);
}
#[abi(embed_v0)]
impl Factory of super::ICounterFactory<ContractState> {
fn create_counter_at(ref self: ContractState, init_value: u128) -> ContractAddress {
// Contructor arguments
let mut constructor_calldata: Array::<felt252> = array![init_value.into()];
// Contract deployment
let (deployed_address, _) = deploy_syscall(
self.counter_class_hash.read(), 0, constructor_calldata.span(), false
)
.expect('failed to deploy counter');
deployed_address
}
fn create_counter(ref self: ContractState) -> ContractAddress {
self.create_counter_at(self.init_value.read())
}
fn update_init_value(ref self: ContractState, init_value: u128) {
self.init_value.write(init_value);
}
fn update_counter_class_hash(ref self: ContractState, counter_class_hash: ClassHash) {
self.counter_class_hash.write(counter_class_hash);
}
}
}
此工厂可用于通过调用SimpleCounter
和create_counter
函数来部署create_counter_at
合约的多个实例。
SimpleCounter
类哈希存储在工厂内部,可以使用update_counter_class_hash
函数进行升级,该函数允许在升级SimpleCounter
合约时重用相同的工厂合约。
这个最小的范例缺少几个有用的功能,例如访问控制、跟踪已部署的合约、事件......