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