iota_transaction_builder/
package.rs1use std::result::Result;
6
7use anyhow::{Ok, anyhow, bail};
8use iota_json_rpc_types::IotaObjectDataOptions;
9use iota_types::{
10 base_types::{Identifier, IotaAddress, ObjectID},
11 move_package::MovePackage,
12 object::Owner,
13 programmable_transaction_builder::ProgrammableTransactionBuilder,
14 transaction::{
15 Argument, CallArg, SharedObjectRef, TransactionData, TransactionDataAPI, TransactionKind,
16 },
17};
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::new_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::Address(_) => CallArg::ImmutableOrOwned(upgrade_capability.object_ref()),
88 Owner::Shared(initial_shared_version) => CallArg::Shared(SharedObjectRef::new(
89 upgrade_capability.object_ref().object_id,
90 initial_shared_version,
91 true,
92 )),
93 Owner::Immutable => {
94 bail!("Upgrade capability is stored immutably and cannot be used for upgrades")
95 }
96 Owner::Object(_) => {
99 bail!("Upgrade capability controlled by object");
100 }
101 _ => unimplemented!("a new Owner enum variant was added and needs to be handled"),
102 };
103 builder.obj(capability_arg).unwrap();
104 let upgrade_arg = builder.pure(upgrade_policy).unwrap();
105 let digest_arg = builder.pure(digest).unwrap();
106 let upgrade_ticket = builder.programmable_move_call(
107 ObjectID::FRAMEWORK,
108 Identifier::PACKAGE_MODULE,
109 Identifier::from_static("authorize_upgrade"),
110 vec![],
111 vec![Argument::Input(0), upgrade_arg, digest_arg],
112 );
113 let upgrade_receipt = builder.upgrade(package_id, upgrade_ticket, dep_ids, modules);
114
115 builder.programmable_move_call(
116 ObjectID::FRAMEWORK,
117 Identifier::PACKAGE_MODULE,
118 Identifier::from_static("commit_upgrade"),
119 vec![],
120 vec![Argument::Input(0), upgrade_receipt],
121 );
122
123 builder.finish()
124 };
125
126 Ok(TransactionKind::new_programmable(pt))
127 }
128
129 pub async fn upgrade(
131 &self,
132 sender: IotaAddress,
133 package_id: ObjectID,
134 compiled_modules: Vec<Vec<u8>>,
135 dep_ids: Vec<ObjectID>,
136 upgrade_capability: ObjectID,
137 upgrade_policy: u8,
138 gas: impl Into<Option<ObjectID>>,
139 gas_budget: u64,
140 ) -> anyhow::Result<TransactionData> {
141 let gas_price = self.0.get_reference_gas_price().await?;
142 let gas = self
143 .select_gas(sender, gas, gas_budget, vec![], gas_price)
144 .await?;
145 let upgrade_cap = self
146 .0
147 .get_object_with_options(
148 upgrade_capability,
149 IotaObjectDataOptions::new().with_owner(),
150 )
151 .await?
152 .into_object()?;
153 let cap_owner = upgrade_cap
154 .owner
155 .ok_or_else(|| anyhow!("Unable to determine ownership of upgrade capability"))?;
156 let digest = MovePackage::compute_digest_for_modules_and_deps(&compiled_modules, &dep_ids)
157 .into_inner()
158 .to_vec();
159 TransactionData::new_upgrade(
160 sender,
161 gas,
162 package_id,
163 compiled_modules,
164 dep_ids,
165 (upgrade_cap.object_ref(), cap_owner),
166 upgrade_policy,
167 digest,
168 gas_budget,
169 gas_price,
170 )
171 }
172}