cw_migratable_contract_std/
execute.rs

1use cosmwasm_std::{
2    to_binary, Binary, CanonicalAddr, ContractInfo, CosmosMsg, Deps, DepsMut, ReplyOn, Response,
3    StdError, StdResult, Storage, SubMsg, WasmMsg,
4};
5
6use crate::msg::MigrationListenerExecuteMsg;
7use crate::state::{
8    CanonicalContractInfo, MIGRATION_COMPLETE_EVENT_SUBSCRIBERS,
9    REMAINING_MIGRATION_COMPLETE_EVENT_SUB_SLOTS,
10};
11
12pub fn register_to_notify_on_migration_complete(
13    deps: DepsMut,
14    address: String,
15    code_hash: String,
16) -> StdResult<Response> {
17    let validated = deps.api.addr_validate(address.as_str())?;
18    add_migration_complete_event_subscriber(
19        deps.storage,
20        &deps.api.addr_canonicalize(validated.as_str())?,
21        &code_hash,
22    )?;
23    Ok(Response::new())
24}
25
26pub fn create_broadcast_migration_complete_notification_msgs(
27    deps: Deps,
28    reply_on: ReplyOn,
29    reply_id: u64,
30    migrated_to: &ContractInfo,
31    notification_recipients: Vec<ContractInfo>,
32    data: Option<Binary>,
33) -> StdResult<Vec<SubMsg>> {
34    let msg = to_binary(
35        &MigrationListenerExecuteMsg::MigrationCompleteNotification {
36            to: migrated_to.clone(),
37            data,
38        },
39    )?;
40    let sub_msgs = notification_recipients
41        .into_iter()
42        .map(|contract| {
43            let contract_addr = deps
44                .api
45                .addr_validate(contract.address.as_str())?
46                .to_string();
47            Ok(SubMsg {
48                msg: CosmosMsg::Wasm(WasmMsg::Execute {
49                    msg: msg.clone(),
50                    contract_addr,
51                    code_hash: contract.code_hash,
52                    funds: vec![],
53                }),
54                id: reply_id,
55                reply_on: reply_on.clone(),
56                gas_limit: None,
57            })
58        })
59        .collect::<StdResult<Vec<SubMsg>>>()?;
60
61    Ok(sub_msgs)
62}
63
64pub fn add_migration_complete_event_subscriber(
65    storage: &mut dyn Storage,
66    address: &CanonicalAddr,
67    code_hash: &str,
68) -> StdResult<()> {
69    if let Some(remaining_slots) = REMAINING_MIGRATION_COMPLETE_EVENT_SUB_SLOTS.may_load(storage)? {
70        if remaining_slots == 0 {
71            return Err(StdError::generic_err(
72                "No migration complete notification slots available",
73            ));
74        }
75        REMAINING_MIGRATION_COMPLETE_EVENT_SUB_SLOTS.save(storage, &(remaining_slots - 1))?
76    }
77    // todo: consider using a keyset if it does not increase gas usage
78    let mut contracts = MIGRATION_COMPLETE_EVENT_SUBSCRIBERS
79        .load(storage)
80        .unwrap_or_default();
81    let mut update = false;
82    let new_contract = CanonicalContractInfo {
83        address: address.clone(),
84        code_hash: code_hash.to_string(),
85    };
86    if !contracts.contains(&new_contract) {
87        contracts.push(new_contract);
88        update = true;
89    }
90
91    // only save if the list changed
92    if update {
93        MIGRATION_COMPLETE_EVENT_SUBSCRIBERS.save(storage, &contracts)?;
94    }
95    Ok(())
96}
97
98pub fn update_migrated_subscriber(
99    storage: &mut dyn Storage,
100    raw_sender: &CanonicalAddr,
101    raw_migrated_to: &CanonicalContractInfo,
102) -> StdResult<()> {
103    let notify_on_migration_contracts = MIGRATION_COMPLETE_EVENT_SUBSCRIBERS.may_load(storage)?;
104    if let Some(mut notify_on_migration_contracts) = notify_on_migration_contracts {
105        let mut update = false;
106
107        for contract in notify_on_migration_contracts.iter_mut() {
108            if &contract.address == raw_sender {
109                contract.address = raw_migrated_to.address.clone();
110                contract.code_hash = raw_migrated_to.code_hash.clone();
111                update = true;
112                break;
113            }
114        }
115        if update {
116            MIGRATION_COMPLETE_EVENT_SUBSCRIBERS.save(storage, &notify_on_migration_contracts)?;
117        }
118    }
119    Ok(())
120}