Constructor
Constructors are a special type of function that runs only once when deploying a contract, and can be used to initialize the state of the contract. Your contract must not have more than one constructor, and that constructor function must be annotated with the #[constructor]
attribute. Also, a good practice consists in naming that function constructor
.
Here's a simple example that demonstrates how to initialize the state of a contract on deployment by defining logic inside a constructor.
#[starknet::contract]
pub mod ExampleConstructor {
use starknet::ContractAddress;
use starknet::storage::{Map, StorageMapWriteAccess};
#[storage]
struct Storage {
pub names: Map::<ContractAddress, felt252>,
}
// The constructor is decorated with a `#[constructor]` attribute.
// It is not inside an `impl` block.
#[constructor]
fn constructor(ref self: ContractState, name: felt252, address: ContractAddress) {
self.names.write(address, name);
}
}
#[cfg(test)]
mod tests {
use super::ExampleConstructor;
use starknet::{ContractAddress, SyscallResultTrait, syscalls::deploy_syscall};
use starknet::{contract_address_const, testing::{set_contract_address}};
use starknet::storage::StorageMapReadAccess;
#[test]
fn should_deploy_with_constructor_init_value() {
let name: felt252 = 'bob';
let address: ContractAddress = contract_address_const::<'caller'>();
let (contract_address, _) = deploy_syscall(
ExampleConstructor::TEST_CLASS_HASH.try_into().unwrap(),
0,
array![name, address.into()].span(),
false
)
.unwrap_syscall();
let state = @ExampleConstructor::contract_state_for_testing();
set_contract_address(contract_address);
let name = state.names.read(address);
assert_eq!(name, 'bob');
}
}