iota_transaction_builder/
package.rs1use std::result::Result;
6
7use anyhow::{Ok, anyhow, bail};
8use iota_json_rpc_types::IotaObjectDataOptions;
9use iota_sdk_types::{
10 Argument, Identifier, ObjectId, Owner, TransactionKind, move_package::MovePackage,
11};
12use iota_types::{
13 base_types::IotaAddress,
14 programmable_transaction_builder::ProgrammableTransactionBuilder,
15 transaction::{CallArg, SharedObjectRef, TransactionData, TransactionDataAPI},
16};
17
18use crate::TransactionBuilder;
19
20impl TransactionBuilder {
21 pub async fn publish_tx_kind(
24 &self,
25 sender: IotaAddress,
26 modules: Vec<Vec<u8>>,
27 dep_ids: Vec<ObjectId>,
28 ) -> Result<TransactionKind, anyhow::Error> {
29 let pt = {
30 let mut builder = ProgrammableTransactionBuilder::new();
31 let upgrade_cap = builder.publish_upgradeable(modules, dep_ids);
32 builder.transfer_arg(sender, upgrade_cap);
33 builder.finish()
34 };
35 Ok(TransactionKind::new_programmable(pt))
36 }
37
38 pub async fn publish(
40 &self,
41 sender: IotaAddress,
42 compiled_modules: Vec<Vec<u8>>,
43 dep_ids: Vec<ObjectId>,
44 gas: impl Into<Option<ObjectId>>,
45 gas_budget: u64,
46 ) -> anyhow::Result<TransactionData> {
47 let gas_price = self.0.get_reference_gas_price().await?;
48 let gas = self
49 .select_gas(sender, gas, gas_budget, vec![], gas_price)
50 .await?;
51 Ok(TransactionData::new_module(
52 sender,
53 gas,
54 compiled_modules,
55 dep_ids,
56 gas_budget,
57 gas_price,
58 ))
59 }
60
61 pub async fn upgrade_tx_kind(
64 &self,
65 package_id: ObjectId,
66 modules: Vec<Vec<u8>>,
67 dep_ids: Vec<ObjectId>,
68 upgrade_capability: ObjectId,
69 upgrade_policy: u8,
70 digest: Vec<u8>,
71 ) -> Result<TransactionKind, anyhow::Error> {
72 let upgrade_capability = self
73 .0
74 .get_object_with_options(
75 upgrade_capability,
76 IotaObjectDataOptions::new().with_owner(),
77 )
78 .await?
79 .into_object()?;
80 let capability_owner = upgrade_capability
81 .owner
82 .ok_or_else(|| anyhow!("Unable to determine ownership of upgrade capability"))?;
83 let pt = {
84 let mut builder = ProgrammableTransactionBuilder::new();
85 let capability_arg = match capability_owner {
86 Owner::Address(_) => CallArg::ImmutableOrOwned(upgrade_capability.object_ref()),
87 Owner::Shared(initial_shared_version) => CallArg::Shared(SharedObjectRef::new(
88 upgrade_capability.object_ref().object_id,
89 initial_shared_version,
90 true,
91 )),
92 Owner::Immutable => {
93 bail!("Upgrade capability is stored immutably and cannot be used for upgrades")
94 }
95 Owner::Object(_) => {
98 bail!("Upgrade capability controlled by object");
99 }
100 _ => unimplemented!("a new Owner enum variant was added and needs to be handled"),
101 };
102 builder.obj(capability_arg).unwrap();
103 let upgrade_arg = builder.pure(upgrade_policy).unwrap();
104 let digest_arg = builder.pure(digest).unwrap();
105 let upgrade_ticket = builder.programmable_move_call(
106 ObjectId::FRAMEWORK,
107 Identifier::PACKAGE_MODULE,
108 Identifier::from_static("authorize_upgrade"),
109 vec![],
110 vec![Argument::Input(0), upgrade_arg, digest_arg],
111 );
112 let upgrade_receipt = builder.upgrade(package_id, upgrade_ticket, dep_ids, modules);
113
114 builder.programmable_move_call(
115 ObjectId::FRAMEWORK,
116 Identifier::PACKAGE_MODULE,
117 Identifier::from_static("commit_upgrade"),
118 vec![],
119 vec![Argument::Input(0), upgrade_receipt],
120 );
121
122 builder.finish()
123 };
124
125 Ok(TransactionKind::new_programmable(pt))
126 }
127
128 pub async fn upgrade(
130 &self,
131 sender: IotaAddress,
132 package_id: ObjectId,
133 compiled_modules: Vec<Vec<u8>>,
134 dep_ids: Vec<ObjectId>,
135 upgrade_capability: ObjectId,
136 upgrade_policy: u8,
137 gas: impl Into<Option<ObjectId>>,
138 gas_budget: u64,
139 ) -> anyhow::Result<TransactionData> {
140 let gas_price = self.0.get_reference_gas_price().await?;
141 let gas = self
142 .select_gas(sender, gas, gas_budget, vec![], gas_price)
143 .await?;
144 let upgrade_cap = self
145 .0
146 .get_object_with_options(
147 upgrade_capability,
148 IotaObjectDataOptions::new().with_owner(),
149 )
150 .await?
151 .into_object()?;
152 let cap_owner = upgrade_cap
153 .owner
154 .ok_or_else(|| anyhow!("Unable to determine ownership of upgrade capability"))?;
155 let digest = MovePackage::compute_digest_for_modules_and_deps(&compiled_modules, &dep_ids)
156 .into_inner()
157 .to_vec();
158 TransactionData::new_upgrade(
159 sender,
160 gas,
161 package_id,
162 compiled_modules,
163 dep_ids,
164 (upgrade_cap.object_ref(), cap_owner),
165 upgrade_policy,
166 digest,
167 gas_budget,
168 gas_price,
169 )
170 }
171}