1use std::collections::BTreeMap;
6
7use fastcrypto::traits::KeyPair as KeypairTraits;
8use iota_protocol_config::ProtocolConfig;
9use iota_sdk_crypto::{
10 Signer, ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey,
11 secp256r1::Secp256r1PrivateKey, simple::SimpleKeypair,
12};
13use iota_sdk_types::{
14 Address, Argument, Command, ObjectId, ProgrammableTransaction, SenderSignedTransaction,
15 SharedObjectReference, SimpleSignature, Transaction, TransactionKind, TransferObjects,
16 UserSignature, Version,
17 crypto::{Intent, MultisigAggregatedSignature, MultisigCommittee, MultisigMember},
18};
19use rand::{SeedableRng, rngs::StdRng};
20
21use crate::{
22 base_types::{dbg_addr, random_object_ref},
23 committee::Committee,
24 crypto::{
25 AccountPrivateKey, AuthorityKeyPair, AuthorityPublicKeyBytes, get_key_pair,
26 get_key_pair_from_rng,
27 },
28 error::UserInputError,
29 object::Object,
30 programmable_transaction_builder::ProgrammableTransactionBuilder,
31 transaction::{CallArg, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, TransactionAPI, TransactionEnvelope},
32};
33
34pub fn make_committee_key<R>(rand: &mut R) -> (Vec<AuthorityKeyPair>, Committee)
35where
36 R: rand::CryptoRng + rand::RngCore,
37{
38 make_committee_key_num(4, rand)
39}
40
41pub fn make_committee_key_num<R>(num: usize, rand: &mut R) -> (Vec<AuthorityKeyPair>, Committee)
42where
43 R: rand::CryptoRng + rand::RngCore,
44{
45 let mut authorities: BTreeMap<AuthorityPublicKeyBytes, u64> = BTreeMap::new();
46 let mut keys = Vec::new();
47
48 for _ in 0..num {
49 let (_, inner_authority_key): (_, AuthorityKeyPair) = get_key_pair_from_rng(rand);
50 authorities.insert(
51 AuthorityPublicKeyBytes::from(inner_authority_key.public()),
53 1,
55 );
56 keys.push(inner_authority_key);
57 }
58
59 let committee = Committee::new_for_testing_with_normalized_voting_power(0, authorities);
60 (keys, committee)
61}
62
63pub fn create_fake_transaction() -> TransactionEnvelope {
66 let (sender, sender_key): (_, AccountPrivateKey) = get_key_pair();
67 let recipient = dbg_addr(2);
68 let object_id = ObjectId::random();
69 let object = Object::immutable_with_id_for_testing(object_id);
70 let pt = {
71 let mut builder = ProgrammableTransactionBuilder::new();
72 builder.transfer_iota(recipient, None);
73 builder.finish()
74 };
75 let tx = Transaction::new_programmable(
76 sender,
77 vec![object.object_ref()],
78 pt,
79 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, 1,
81 );
82 to_sender_signed_transaction(tx, &sender_key)
83}
84
85pub fn make_transaction_data(sender: Address) -> Transaction {
86 let object =
87 Object::immutable_with_id_for_testing(ObjectId::random_with(StdRng::from_seed([0; 32])));
88 let pt = {
89 let mut builder = ProgrammableTransactionBuilder::new();
90 builder.transfer_iota(dbg_addr(2), None);
91 builder.finish()
92 };
93 Transaction::new_programmable(
94 sender,
95 vec![object.object_ref()],
96 pt,
97 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, 1,
99 )
100}
101
102pub fn make_sponsored_transaction_data(sender: Address, sponsor: Address) -> Transaction {
105 let pt = {
106 let mut builder = ProgrammableTransactionBuilder::new();
107 builder.transfer_iota(dbg_addr(2), None);
108 builder.finish()
109 };
110 Transaction::new_with_gas_coins_allow_sponsor(
111 TransactionKind::new_programmable(pt),
112 sender,
113 vec![random_object_ref()],
114 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, 1,
116 sponsor,
117 )
118}
119
120pub fn make_transaction(sender: Address, kp: &SimpleKeypair) -> TransactionEnvelope {
123 let data = make_transaction_data(sender);
124 TransactionEnvelope::from_data_and_signer(data, vec![kp])
125}
126
127pub fn to_sender_signed_transaction(
129 tx: Transaction,
130 signer: &impl Signer<SimpleSignature>,
131) -> TransactionEnvelope {
132 to_sender_signed_transaction_with_multi_signers(tx, vec![signer])
133}
134
135pub fn to_sender_signed_transaction_with_optional_sponsor(
136 tx: Transaction,
137 sender_signature: UserSignature,
138 sponsor_signer_opt: Option<&impl Signer<SimpleSignature>>,
139) -> TransactionEnvelope {
140 let mut signatures = vec![sender_signature];
141 if let Some(sponsor) = sponsor_signer_opt {
142 let sponsor_sig = TransactionEnvelope::signature_from_signer(
143 tx.clone(),
144 Intent::iota_transaction(),
145 sponsor,
146 )
147 .into();
148 signatures.push(sponsor_sig);
149 };
150
151 TransactionEnvelope::from_user_sig_data(tx, signatures)
152}
153
154pub fn to_sender_signed_transaction_with_multi_signers(
155 tx: Transaction,
156 signers: Vec<&impl Signer<SimpleSignature>>,
157) -> TransactionEnvelope {
158 TransactionEnvelope::from_data_and_signer(tx, signers)
159}
160
161pub fn make_upgraded_multisig_tx() -> TransactionEnvelope {
162 let kp1 = Ed25519PrivateKey::random();
163 let kp2 = Secp256k1PrivateKey::random();
164 let kp3 = Secp256r1PrivateKey::random();
165 let pk1 = kp1.public_key();
166 let pk2 = kp2.public_key();
167 let pk3 = kp3.public_key();
168
169 let multisig_pk = MultisigCommittee::new(
170 vec![
171 MultisigMember::new(pk1, 1),
172 MultisigMember::new(pk2, 1),
173 MultisigMember::new(pk3, 1),
174 ],
175 2,
176 )
177 .unwrap();
178 let addr = Address::from(&multisig_pk);
179 let tx = make_transaction(addr, &SimpleKeypair::from(kp1.clone()));
180
181 let msg = tx.transaction().signing_digest();
182 let sig1: SimpleSignature = kp1.sign(&msg);
183 let sig2: SimpleSignature = kp2.sign(&msg);
184
185 let multi_sig1 =
187 MultisigAggregatedSignature::new(vec![sig1.into(), sig2.into()], multisig_pk).unwrap();
188 TransactionEnvelope::new(SenderSignedTransaction::new(
189 tx.transaction().clone(),
190 vec![UserSignature::Multisig(multi_sig1)],
191 ))
192}
193
194pub fn make_sponsored_regular_sig_tx() -> (TransactionEnvelope, Address, Address) {
200 let (sender, sender_key): (_, AccountPrivateKey) = get_key_pair();
201 let (sponsor, sponsor_key): (_, AccountPrivateKey) = get_key_pair();
202 let tx_data = make_sponsored_transaction_data(sender, sponsor);
203 let sender_sig: UserSignature = TransactionEnvelope::signature_from_signer(
204 tx_data.clone(),
205 Intent::iota_transaction(),
206 &sender_key,
207 )
208 .into();
209 let tx =
210 to_sender_signed_transaction_with_optional_sponsor(tx_data, sender_sig, Some(&sponsor_key));
211 (tx, sender, sponsor)
212}
213
214mod move_authenticator {
215 use fastcrypto::hash::HashFunction;
216 use iota_sdk_types::{
217 Address, Digest, MoveAuthenticator, MoveAuthenticatorV1, SenderSignedTransaction,
218 SharedObjectReference, UserSignature,
219 };
220
221 use crate::{
222 crypto::DefaultHash,
223 object::OBJECT_START_VERSION,
224 transaction::TransactionEnvelope,
225 utils::{make_sponsored_transaction_data, make_transaction_data},
226 };
227
228 pub fn make_move_authenticator_tx(address: Address) -> TransactionEnvelope {
230 let data = make_transaction_data(address);
231 let (authenticator, _) = make_move_authenticator_sig(address);
232 TransactionEnvelope::new(SenderSignedTransaction::new(data, vec![authenticator]))
233 }
234
235 pub fn make_move_authenticator_sig(address: Address) -> (UserSignature, MoveAuthenticator) {
243 let authenticator =
244 MoveAuthenticator::from(MoveAuthenticatorV1::new_with_shared_account_object(
245 vec![],
246 vec![],
247 SharedObjectReference::new(address.into(), OBJECT_START_VERSION, false),
248 ));
249 let sig = UserSignature::MoveAuthenticator(authenticator.clone());
250 (sig, authenticator)
251 }
252
253 pub fn make_sponsored_move_authenticator_tx(
260 sender_addr: Address,
261 sponsor_addr: Address,
262 ) -> (TransactionEnvelope, MoveAuthenticator, MoveAuthenticator) {
263 let (sender_sig, sender_auth) = make_move_authenticator_sig(sender_addr);
264 let (sponsor_sig, sponsor_auth) = make_move_authenticator_sig(sponsor_addr);
265 let tx_data = make_sponsored_transaction_data(sender_addr, sponsor_addr);
266 let tx = TransactionEnvelope::new(SenderSignedTransaction::new(
267 tx_data,
268 vec![sender_sig, sponsor_sig],
269 ));
270 (tx, sender_auth, sponsor_auth)
271 }
272
273 pub fn blake2b256_of_sig(sig: &UserSignature) -> Digest {
278 let mut hasher = DefaultHash::default();
279 hasher.update(sig.to_bytes());
280 Digest::new(hasher.finalize().into())
281 }
282}
283
284pub use move_authenticator::*;
285
286mod passkey {
287 use iota_sdk_crypto::secp256r1::Secp256r1PrivateKey;
288 use iota_sdk_types::crypto::PasskeyAuthenticator;
289
290 use super::*;
291
292 pub fn make_passkey_authenticator_sig() -> UserSignature {
299 let r1_kp = Secp256r1PrivateKey::random();
300 let user_sig: SimpleSignature = r1_kp.sign(&[0u8; 32]);
301 let client_data_json = r#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","origin":"https://test.iota.org"}"#;
302 let passkey =
303 PasskeyAuthenticator::new(vec![], client_data_json.to_string(), user_sig).unwrap();
304 UserSignature::PasskeyAuthenticator(passkey)
305 }
306}
307
308pub use passkey::*;
309
310#[track_caller]
313pub fn assert_size_limit_err(err: &UserInputError, limit_name: &str) {
314 let UserInputError::SizeLimitExceeded { limit, .. } = err else {
315 panic!("expected a size limit, got {err:?}");
316 };
317 assert!(
318 limit == limit_name || limit.starts_with(&format!("{limit_name} of ")),
319 "expected {limit_name}, got {limit}"
320 );
321}
322
323pub fn ptb_with_pure_inputs(
327 count: usize,
328 size: usize,
329 with_randomness: bool,
330) -> ProgrammableTransaction {
331 let mut inputs = vec![CallArg::Pure(vec![0; size]); count];
332 if with_randomness {
333 inputs.push(CallArg::Shared(SharedObjectReference {
334 object_id: ObjectId::RANDOMNESS_STATE,
335 initial_shared_version: Version::from_u64(1),
336 mutable: false,
337 }));
338 }
339 assert!(inputs.len() >= 2, "the command names the first two inputs");
340 let commands = vec![Command::TransferObjects(TransferObjects {
341 objects: vec![Argument::Input(0)],
342 address: Argument::Input(1),
343 })];
344 ProgrammableTransaction { inputs, commands }
345}
346
347pub fn ptb_above_max_tx_size(config: &ProtocolConfig) -> ProgrammableTransaction {
351 let pure_size = config.max_pure_argument_size() as usize - 1;
352 let count = config.max_tx_size_bytes() as usize / pure_size + 1;
353 ptb_with_pure_inputs(count, pure_size, false)
354}