1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use cosmwasm_std::{Api, Binary, CanonicalAddr, ContractInfo, StdResult};
use secret_toolkit::storage::Item;
use serde::{Deserialize, Serialize};

/// storage for MigratedFromState singleton
pub static MIGRATED_FROM: Item<MigratedFromState> = Item::new(b"migrtdFrom");
/// storage for MigratedToState singleton
pub static MIGRATED_TO: Item<MigratedToState> = Item::new(b"migrtdTo");
/// storage for list of contracts to notify when this contract has been migrated
pub static MIGRATION_COMPLETE_EVENT_SUBSCRIBERS: Item<Vec<CanonicalContractInfo>> =
    Item::new(b"ntifyOnMigrtd");
/// storage for an optional remaining number of contracts that can be registered to be notified of migration
pub static REMAINING_MIGRATION_COMPLETE_EVENT_SUB_SLOTS: Item<u8> = Item::new(b"ntifyMigrtdSlts");
/// storage for current ContractMode
pub static CONTRACT_MODE: Item<ContractMode> = Item::new(b"cntrkMode");

#[derive(
    serde_repr::Serialize_repr, serde_repr::Deserialize_repr, Debug, PartialEq, strum::EnumIter,
)]
#[repr(u8)]
pub enum ContractMode {
    MigrateDataIn = 1,
    Running = 2,
    // MigrateOutStarted is applicable when a migration can take more than one transaction to complete
    // For example when migrating a snip721 contract. A takes a least two transactions
    // The first execute migration message put's the contract in this state.
    // Which disables the contract's state from being altered but allows queries until migration
    // is complete (after all the tokens are migrated in a second transaction).
    // After all tokens are migrated. the contract switches to ContractMode::MigratedOut
    MigrateOutStarted = 3,
    MigratedOut = 4,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct MigratedFromState {
    /// the info of the contract being migrated from
    pub contract: CanonicalContractInfo,
    /// the secret generated by the contract being migrated from
    pub migration_secret: Binary,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct MigratedToState {
    /// the info of the contract being migrated to
    pub contract: CanonicalContractInfo,
    /// the secret needed by another contract to migrate data out
    pub migration_secret: Binary,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct CanonicalContractInfo {
    pub address: CanonicalAddr,
    #[serde(default)]
    pub code_hash: String,
}

pub fn canonicalize(api: &dyn Api, value: &ContractInfo) -> StdResult<CanonicalContractInfo> {
    let c = CanonicalContractInfo {
        address: api.addr_canonicalize(value.address.as_str())?,
        code_hash: value.code_hash.clone(),
    };
    Ok(c)
}

impl CanonicalContractInfo {
    pub fn humanize(&self, api: &dyn Api) -> StdResult<ContractInfo> {
        let c = ContractInfo {
            address: api.addr_humanize(&self.address)?,
            code_hash: self.code_hash.clone(),
        };
        Ok(c)
    }

    pub fn into_humanized(self, api: &dyn Api) -> StdResult<ContractInfo> {
        let c = ContractInfo {
            address: api.addr_humanize(&self.address)?,
            code_hash: self.code_hash,
        };
        Ok(c)
    }
}