Skip to content

Upgradeable Contract

Soroban Upgradeable Contract
#![no_std]
 
use soroban_sdk::{contract, contractimpl, contracterror, contracttype, Address, BytesN, Env, log};
 
#[derive(Clone)]
#[contracttype]
enum DataKey {
    Admin,
}
 
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[contracterror]
#[repr(u32)]
pub enum Error {
    AlreadyInitialized = 1,
}
 
#[contract]
pub struct UpgradeableContract;
 
#[contractimpl]
impl UpgradeableContract {
    pub fn init(env: Env, admin: Address) -> Result<(), Error> {
        if env.storage().instance().has(&DataKey::Admin) {
            return Err(Error::AlreadyInitialized);
        }
 
        env.storage().instance().set(&DataKey::Admin, &admin);
 
        /// @dev should remove logs before deploying smart contracts
        log!(&env, "Admin address: {}", admin);
 
        Ok(())
    }
 
    pub fn version() -> u32 {
        1
    }
 
    pub fn upgrade(env: Env, new_wasm_hash: BytesN<32>) {
        let admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
 
        admin.require_auth();
 
        env.deployer().update_current_contract_wasm(new_wasm_hash);
    }
}

Explanation

#![no_std] This attribute prevents linking to the standard library, making the code lighter and more efficient for Soroban contracts. It's big so we save on size.

use soroban_sdk::{contract, contractimpl, Env, log} Imports stuffs from the Soroban SDK. Env is basic Soroban type, we need it because we can't use the Rust standard library.

DataKey This is an enumerated type (enum) used to define different keys for storing data in the contract's storage. Currently, the only option is Admin.

Error This is another enumerated type defining a specific error code: AlreadyInitialized.

init This function checks if the Admin key already exists in storage. If it does, it returns the AlreadyInitialized error. Otherwise, it sets the Admin key with the provided admin address and returns success (Ok(())).

upgrade This retrieves the current administrator address from storage using the Admin key. It then uses require_auth (likely from the Soroban SDK) to ensure only the administrator can call this function. Finally, it utilizes the deployer functionality from the environment to update the contract's bytecode with the provided new_wasm_hash.

Run in Playground

Loading playground...