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