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;

    #[storage]
    struct Storage {
        names: LegacyMap::<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, ExampleConstructor::namesContractMemberStateTrait};
    use starknet::{ContractAddress, SyscallResultTrait, syscalls::deploy_syscall};
    use starknet::{contract_address_const, testing::{set_contract_address}};

    #[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');
    }
}
Last change: 2024-04-12, commit: a768477