需求

升级方法只能owner调用

代码改造

改造之前v0和v1合约,引入oz owner功能合约

构造方法传入owner地址

upgrade方法添加owner权限判断

v0完整代码如下:

#[starknet::interface]
trait IHelloStarknet<TContractState> {
    fn increase_balance(ref self: TContractState, amount: felt252);
    fn get_balance(self: @TContractState) -> felt252;
}

#[starknet::contract]
mod HelloStarknet {
    use openzeppelin::access::ownable::Ownable as ownable_component;
    use openzeppelin::upgrades::Upgradeable as upgradeable_component;
    use openzeppelin::upgrades::interface::IUpgradeable;
    use starknet::ClassHash;
    use starknet::ContractAddress;

    component!(path: ownable_component, storage: ownable, event: OwnableEvent);
    component!(path: upgradeable_component, storage: upgradeable, event: UpgradeableEvent);

    /// Ownable
    #[abi(embed_v0)]
    impl OwnableImpl = ownable_component::OwnableImpl<ContractState>;
    impl OwnableInternalImpl = ownable_component::InternalImpl<ContractState>;
    /// Upgradeable
    impl UpgradeableInternalImpl = upgradeable_component::InternalImpl<ContractState>;

    #[storage]
    struct Storage {
        balance: felt252, 
        #[substorage(v0)]
        ownable: ownable_component::Storage,
        #[substorage(v0)]
        upgradeable: upgradeable_component::Storage
    }

    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        OwnableEvent: ownable_component::Event,
        #[flat]
        UpgradeableEvent: upgradeable_component::Event
    }

    #[constructor]
    fn constructor(ref self: ContractState, owner: ContractAddress) {
        self.ownable.initializer(owner);
    }

    #[external(v0)]
    impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
        fn increase_balance(ref self: ContractState, amount: felt252) {
            assert(amount != 0, 'Amount cannot be 0');
            self.balance.write(self.balance.read() + amount);
        }

        fn get_balance(self: @ContractState) -> felt252 {
            self.balance.read()
        }
    }

    #[external(v0)]
    impl UpgradeableImpl of IUpgradeable<ContractState> {
        fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
            // This function can only be called by the owner
            self.ownable.assert_only_owner();
            // Replace the class hash upgrading the contract
            self.upgradeable._upgrade(new_class_hash);
        }
    }

    #[external(v0)]
    #[generate_trait]
    impl HelloStarknetExtImpl of IHelloStarknetExtTrait {
        fn version(self: @ContractState) -> u8 {
            0
        }
    }
}

实际部署和调用

test_user_0:0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff 默认账户

test_user_1:0xdc64f74f50383703de669eb9dd4b7eb7f6ecbc792f34232112193c6ed86d9a

声明并部署v0

//declare v0
sncast declare -c HelloStarknet

command: declare
class_hash: 0x5359355e7b25ae30462f422ee97077610465bbe1de6f4ac7cea1f37e70c44d9
transaction_hash: 0xeefac5abd0436687203f6a8ccc7fb3d4e947f101300096dbfe5f642bd97e76

//deploy v0
sncast deploy -g 0x5359355e7b25ae30462f422ee97077610465bbe1de6f4ac7cea1f37e70c44d9 -c 0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff

command: deploy
contract_address: 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c
transaction_hash: 0x4ed0878a70cee1dba7f9ea17263d2f91345ff2381cc3920ef5ac21401533e8e

//call version=0
sncast call -a 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c -f version

command: call
response: [0x0]

//call owner
sncast call -a 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c -f owner  

command: call
response: [0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff]

声明v1

//declare v1
sncast declare -c HelloStarknet

command: declare
class_hash: 0x7800859d93e00a66539c191d5ec202a62920100eee2a7ad870be69db2072ee0
transaction_hash: 0x19ced6525f84a69d1bf9dfce82247c28ecd1f76daa72f5258e21bf6cd7f85d8

test_user_1 调用升级方法-失败

//invoke update test_user_1 失败, foundry未输出错误原因WTF
sncast -a test_user_1 invoke -a 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c -f upgrade -c 0x7800859d93e00a66539c191d5ec202a62920100eee2a7ad870be69db2072ee0

command: invoke
error: Internal error

test_user_0 调用升级方法-成功


//invoke update test_user_0 成功
sncast -a test_user_0 invoke -a 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c -f upgrade -c 0x7800859d93e00a66539c191d5ec202a62920100eee2a7ad870be69db2072ee0
command: invoke
transaction_hash: 0x1bee36b2f1996826e15049d9cf7e2bce71ee9cccf23b149011adb94387f322

//call version=1
sncast call -a 0x708d0f5fe0ab97c5b79f889d7f272d5640d17fba6ce9f998f95771369d2b59c -f version
command: call
response: [0x1]