Skip to content

Component-Contract Storage Collisions

Components can declare their own storage variables.

When a contract uses a component, the component storage is merged with the contract storage. The storage layout is only determined by the variables names, so variables with the same name will collide.

A good practice is to prefix the component storage variables with the component name, as shown in the Switchable component example.

Example

Here's an example of a collision on the switchable_value storage variable of the Switchable component.

Interface:

#[starknet::interface]
pub trait ISwitchCollision<TContractState> {
    fn set(ref self: TContractState, value: bool);
    fn get(ref self: TContractState) -> bool;
}

Here's the storage of the contract:

    #[storage]
    #[allow(starknet::colliding_storage_paths)]
    struct Storage {
        switchable_value: bool,
        #[substorage(v0)]
        switch: switchable_component::Storage,
    }

Both the contract and the component have a switchable_value storage variable, so they collide:

    fn test_collision() {
        let (mut contract, mut contract_iswitch) = deploy();
 
        assert_eq!(contract.get(), false);
        assert_eq!(contract_iswitch.is_on(), false);
 
        contract_iswitch.switch();
        assert_eq!(contract_iswitch.is_on(), true);
        assert_eq!(contract.get(), true);
 
        // `collision` between component storage 'value' and contract storage 'value'
        assert_eq!(contract.get(), contract_iswitch.is_on());
 
        contract.set(false);
        assert_eq!(contract.get(), contract_iswitch.is_on());
    }
Powered By Nethermind