identity_iota_core/rebased/proposals/
upgrade.rs1use std::marker::PhantomData;
5
6use iota_interaction::rpc_types::IotaTransactionBlockEffects;
7use product_common::core_client::CoreClientReadOnly;
8use product_common::transaction::transaction_builder::TransactionBuilder;
9
10use crate::rebased::iota::move_calls;
11use crate::rebased::iota::package::identity_package_id;
12use crate::rebased::migration::ControllerToken;
13use async_trait::async_trait;
14use iota_interaction::types::base_types::ObjectID;
15use iota_interaction::types::TypeTag;
16use serde::Deserialize;
17use serde::Serialize;
18
19use crate::rebased::migration::OnChainIdentity;
20use crate::rebased::migration::Proposal;
21use crate::rebased::Error;
22use iota_interaction::MoveType;
23use iota_interaction::OptionalSync;
24
25use super::CreateProposal;
26use super::ExecuteProposal;
27use super::ProposalT;
28
29#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
31pub struct Upgrade;
32
33impl Upgrade {
34 pub const fn new() -> Self {
36 Self
37 }
38}
39
40impl MoveType for Upgrade {
41 fn move_type(package: ObjectID) -> TypeTag {
42 format!("{package}::upgrade_proposal::Upgrade")
43 .parse()
44 .expect("valid utf8")
45 }
46}
47
48#[cfg_attr(not(feature = "send-sync"), async_trait(?Send))]
49#[cfg_attr(feature = "send-sync", async_trait)]
50impl ProposalT for Proposal<Upgrade> {
51 type Action = Upgrade;
52 type Output = ();
53
54 async fn create<'i, C>(
55 _action: Self::Action,
56 expiration: Option<u64>,
57 identity: &'i mut OnChainIdentity,
58 controller_token: &ControllerToken,
59 client: &C,
60 ) -> Result<TransactionBuilder<CreateProposal<'i, Self::Action>>, Error>
61 where
62 C: CoreClientReadOnly + OptionalSync,
63 {
64 if identity.id() != controller_token.controller_of() {
65 return Err(Error::Identity(format!(
66 "token {} doesn't grant access to identity {}",
67 controller_token.id(),
68 identity.id()
69 )));
70 }
71
72 let identity_ref = client
73 .get_object_ref_by_id(identity.id())
74 .await?
75 .expect("identity exists on-chain");
76 let controller_cap_ref = controller_token.controller_ref(client).await?;
77 let sender_vp = identity
78 .controller_voting_power(controller_token.controller_id())
79 .expect("controller exists");
80 let chained_execution = sender_vp >= identity.threshold();
81 let package = identity_package_id(client).await?;
82
83 let tx = move_calls::identity::propose_upgrade(identity_ref, controller_cap_ref, expiration, package)
84 .map_err(|e| Error::TransactionBuildingFailed(e.to_string()))?;
85
86 Ok(TransactionBuilder::new(CreateProposal {
87 identity,
88 ptb: bcs::from_bytes(&tx)?,
89 chained_execution,
90 _action: PhantomData,
91 }))
92 }
93
94 async fn into_tx<'i, C>(
95 self,
96 identity: &'i mut OnChainIdentity,
97 controller_token: &ControllerToken,
98 client: &C,
99 ) -> Result<TransactionBuilder<ExecuteProposal<'i, Self::Action>>, Error>
100 where
101 C: CoreClientReadOnly + OptionalSync,
102 {
103 if identity.id() != controller_token.controller_of() {
104 return Err(Error::Identity(format!(
105 "token {} doesn't grant access to identity {}",
106 controller_token.id(),
107 identity.id()
108 )));
109 }
110
111 let proposal_id = self.id();
112 let identity_ref = client
113 .get_object_ref_by_id(identity.id())
114 .await?
115 .expect("identity exists on-chain");
116 let controller_cap_ref = controller_token.controller_ref(client).await?;
117 let package = identity_package_id(client).await?;
118
119 let tx = move_calls::identity::execute_upgrade(identity_ref, controller_cap_ref, proposal_id, package)
120 .map_err(|e| Error::TransactionBuildingFailed(e.to_string()))?;
121
122 Ok(TransactionBuilder::new(ExecuteProposal {
123 identity,
124 ptb: bcs::from_bytes(&tx)?,
125 _action: PhantomData,
126 }))
127 }
128
129 fn parse_tx_effects(_effects: &IotaTransactionBlockEffects) -> Result<Self::Output, Error> {
130 Ok(())
131 }
132}