avail_rust_client/
transaction_api.rs

1//! Builders for transactions targeting specific Avail pallets.
2
3use crate::{Client, SubmittableTransaction};
4use avail_rust_core::{
5	AccountId, AccountIdLike, ExtrinsicCall, H256, MultiAddress,
6	avail::{
7		self,
8		multisig::types::Timepoint,
9		nomination_pools::types::{BondExtraValue, ClaimPermission, ConfigOpAccount, PoolState},
10		proxy::types::ProxyType,
11		staking::types::{RewardDestination, ValidatorPrefs},
12	},
13	types::{
14		HashString,
15		metadata::{MultiAddressLike, StringOrBytes},
16		substrate::Weight,
17	},
18};
19
20/// Entry point for constructing pallet-specific transaction builders.
21///
22/// Each accessor clones the underlying [`Client`] and returns a lightweight helper that can compose
23/// extrinsics without contacting the node. The returned builders produce [`SubmittableTransaction`]s
24/// which must be signed—and optionally submitted—separately.
25pub struct TransactionApi(pub(crate) Client);
26impl TransactionApi {
27	/// Returns helpers for composing `balances` pallet extrinsics.
28	pub fn balances(&self) -> Balances {
29		Balances(self.0.clone())
30	}
31
32	/// Returns helpers for composing data availability submissions.
33	pub fn data_availability(&self) -> DataAvailability {
34		DataAvailability(self.0.clone())
35	}
36
37	/// Returns helpers for multisig transaction approval flows.
38	pub fn multisig(&self) -> Multisig {
39		Multisig(self.0.clone())
40	}
41
42	/// Returns helpers for batching extrinsics via the utility pallet.
43	pub fn utility(&self) -> Utility {
44		Utility(self.0.clone())
45	}
46
47	/// Returns helpers for proxy management extrinsics.
48	pub fn proxy(&self) -> Proxy {
49		Proxy(self.0.clone())
50	}
51
52	/// Returns helpers for staking-related extrinsics.
53	pub fn staking(&self) -> Staking {
54		Staking(self.0.clone())
55	}
56
57	/// Returns helpers for Vector message passing extrinsics.
58	pub fn vector(&self) -> Vector {
59		Vector(self.0.clone())
60	}
61
62	/// Returns helpers for system-level extrinsics.
63	pub fn system(&self) -> System {
64		System(self.0.clone())
65	}
66
67	/// Returns helpers for nomination pool extrinsics.
68	pub fn nomination_pools(&self) -> NominationPools {
69		NominationPools(self.0.clone())
70	}
71
72	/// Returns helpers for validator session key management.
73	pub fn session(&self) -> Session {
74		Session(self.0.clone())
75	}
76}
77
78/// Builds extrinsics for the `session` pallet.
79///
80/// The helper clones the underlying client; composing calls does not contact the node until the
81/// resulting [`SubmittableTransaction`] is signed or submitted.
82pub struct Session(Client);
83impl Session {
84	/// Updates the node's session keys with new authorities and proof data.
85	///
86	/// # Panics
87	/// Panics when any supplied key fails to decode into an `H256` hash.
88	pub fn set_key(
89		&self,
90		babe: impl Into<HashString>,
91		grandpa: impl Into<HashString>,
92		authority_discovery: impl Into<HashString>,
93		im_online: impl Into<HashString>,
94		proof: Vec<u8>,
95	) -> SubmittableTransaction {
96		let babe: HashString = babe.into();
97		let babe: H256 = babe.try_into().expect("Invalid string for H256");
98
99		let grandpa: HashString = grandpa.into();
100		let grandpa: H256 = grandpa.try_into().expect("Invalid string for H256");
101
102		let authority_discovery: HashString = authority_discovery.into();
103		let authority_discovery: H256 = authority_discovery.try_into().expect("Invalid string for H256");
104
105		let im_online: HashString = im_online.into();
106		let im_online: H256 = im_online.try_into().expect("Invalid string for H256");
107
108		let value = avail::session::tx::SetKeys { babe, grandpa, authority_discovery, im_online, proof };
109		SubmittableTransaction::from_encodable(self.0.clone(), value)
110	}
111
112	/// Removes the stored session keys from on-chain storage.
113	pub fn purge_key(&self) -> SubmittableTransaction {
114		let value = avail::session::tx::PurgeKeys {};
115		SubmittableTransaction::from_encodable(self.0.clone(), value)
116	}
117}
118
119/// Builds extrinsics for the `nomination_pools` pallet.
120///
121/// Many helpers accept `MultiAddressLike` values and will panic if those cannot be converted into
122/// on-chain account identifiers. Constructing the [`SubmittableTransaction`] itself does not hit the
123/// network; signing or submitting it will.
124pub struct NominationPools(Client);
125impl NominationPools {
126	/// Contributes additional stake from the pool's bonded account.
127	pub fn bond_extra(&self, value: BondExtraValue) -> SubmittableTransaction {
128		let value = avail::nomination_pools::tx::BondExtra { value };
129		SubmittableTransaction::from_encodable(self.0.clone(), value)
130	}
131
132	/// Bonds additional stake on behalf of another member.
133	///
134	/// # Panics
135	/// Panics if `member` cannot be converted into a `MultiAddress`.
136	pub fn bond_extra_other(
137		&self,
138		member: impl Into<MultiAddressLike>,
139		value: BondExtraValue,
140	) -> SubmittableTransaction {
141		let member: MultiAddressLike = member.into();
142		let member: MultiAddress = member.try_into().expect("Malformed string is passed for AccountId");
143
144		let value = avail::nomination_pools::tx::BondExtraOther { member, value };
145		SubmittableTransaction::from_encodable(self.0.clone(), value)
146	}
147
148	/// Requests the pool to chill its nominations.
149	pub fn chill(&self, pool_id: u32) -> SubmittableTransaction {
150		let value = avail::nomination_pools::tx::Chill { pool_id };
151		SubmittableTransaction::from_encodable(self.0.clone(), value)
152	}
153
154	/// Claims pending commission for the given pool.
155	pub fn claim_commission(&self, pool_id: u32) -> SubmittableTransaction {
156		let value = avail::nomination_pools::tx::ClaimCommission { pool_id };
157		SubmittableTransaction::from_encodable(self.0.clone(), value)
158	}
159
160	/// Claims a pending payout for the caller.
161	pub fn claim_payout(&self) -> SubmittableTransaction {
162		let value = avail::nomination_pools::tx::ClaimPayout {};
163		SubmittableTransaction::from_encodable(self.0.clone(), value)
164	}
165
166	/// Claims a pending payout for another pool member.
167	///
168	/// # Panics
169	/// Panics if `owner` cannot be converted into an `AccountId`.
170	pub fn claim_payout_other(&self, owner: impl Into<AccountIdLike>) -> SubmittableTransaction {
171		let owner: AccountIdLike = owner.into();
172		let owner: AccountId = owner.try_into().expect("Malformed string is passed for AccountId");
173
174		let value = avail::nomination_pools::tx::ClaimPayoutOther { owner };
175		SubmittableTransaction::from_encodable(self.0.clone(), value)
176	}
177
178	/// Creates a new nomination pool with freshly provided roles.
179	///
180	/// # Panics
181	/// Panics if any of `root`, `nominator`, or `bouncer` cannot be converted into a `MultiAddress`.
182	pub fn create(
183		&self,
184		amount: u128,
185		root: impl Into<MultiAddressLike>,
186		nominator: impl Into<MultiAddressLike>,
187		bouncer: impl Into<MultiAddressLike>,
188	) -> SubmittableTransaction {
189		let root: MultiAddressLike = root.into();
190		let root: MultiAddress = root.try_into().expect("Malformed string is passed for AccountId");
191		let nominator: MultiAddressLike = nominator.into();
192		let nominator: MultiAddress = nominator.try_into().expect("Malformed string is passed for AccountId");
193		let bouncer: MultiAddressLike = bouncer.into();
194		let bouncer: MultiAddress = bouncer.try_into().expect("Malformed string is passed for AccountId");
195
196		let value = avail::nomination_pools::tx::Create { amount, root, nominator, bouncer };
197		SubmittableTransaction::from_encodable(self.0.clone(), value)
198	}
199
200	/// Creates a new nomination pool using a specific pool identifier.
201	///
202	/// # Panics
203	/// Panics if any of `root`, `nominator`, or `bouncer` cannot be converted into a `MultiAddress`.
204	pub fn create_with_pool_id(
205		&self,
206		amount: u128,
207		root: impl Into<MultiAddressLike>,
208		nominator: impl Into<MultiAddressLike>,
209		bouncer: impl Into<MultiAddressLike>,
210		pool_id: u32,
211	) -> SubmittableTransaction {
212		let root: MultiAddressLike = root.into();
213		let root: MultiAddress = root.try_into().expect("Malformed string is passed for AccountId");
214		let nominator: MultiAddressLike = nominator.into();
215		let nominator: MultiAddress = nominator.try_into().expect("Malformed string is passed for AccountId");
216		let bouncer: MultiAddressLike = bouncer.into();
217		let bouncer: MultiAddress = bouncer.try_into().expect("Malformed string is passed for AccountId");
218
219		let value = avail::nomination_pools::tx::CreateWithPoolId { amount, root, nominator, bouncer, pool_id };
220		SubmittableTransaction::from_encodable(self.0.clone(), value)
221	}
222
223	/// Joins an existing pool by contributing the requested amount.
224	pub fn join(&self, amount: u128, pool_id: u32) -> SubmittableTransaction {
225		let value = avail::nomination_pools::tx::Join { amount, pool_id };
226		SubmittableTransaction::from_encodable(self.0.clone(), value)
227	}
228
229	/// Sets nominations for the pool to a new validator set.
230	///
231	/// # Panics
232	/// Panics if any validator identifier cannot be converted into an `AccountId`.
233	pub fn nominate(&self, pool_id: u32, validators: Vec<impl Into<AccountIdLike>>) -> SubmittableTransaction {
234		let validators: Vec<AccountIdLike> = validators.into_iter().map(|x| x.into()).collect();
235		let validators: Result<Vec<AccountId>, _> = validators.into_iter().map(AccountId::try_from).collect();
236		let validators = validators.expect("Malformed string is passed for AccountId");
237
238		let value = avail::nomination_pools::tx::Nominate { pool_id, validators };
239		SubmittableTransaction::from_encodable(self.0.clone(), value)
240	}
241
242	/// Updates who is allowed to claim rewards for the pool.
243	pub fn set_claim_permission(&self, permission: ClaimPermission) -> SubmittableTransaction {
244		let value = avail::nomination_pools::tx::SetClaimPermission { permission };
245		SubmittableTransaction::from_encodable(self.0.clone(), value)
246	}
247
248	/// Updates the commission settings for the pool, optionally setting a payee.
249	///
250	/// # Panics
251	/// Panics if the payee provided in `new_commission` cannot be converted into an `AccountId`.
252	pub fn set_commission(&self, pool_id: u32, new_commission: Option<(u32, AccountIdLike)>) -> SubmittableTransaction {
253		let new_commission =
254			new_commission.map(|x| (x.0, AccountId::try_from(x.1).expect("Malformed string is passed for AccountId")));
255		let value = avail::nomination_pools::tx::SetCommission { pool_id, new_commission };
256		SubmittableTransaction::from_encodable(self.0.clone(), value)
257	}
258
259	/// Configures how frequently pool commission may change.
260	pub fn set_commission_change_rate(
261		&self,
262		pool_id: u32,
263		max_increase: u32,
264		min_delay: u32,
265	) -> SubmittableTransaction {
266		let value = avail::nomination_pools::tx::SetCommissionChangeRate { pool_id, max_increase, min_delay };
267		SubmittableTransaction::from_encodable(self.0.clone(), value)
268	}
269
270	/// Caps commission at the provided maximum percentage.
271	pub fn set_commission_max(&self, pool_id: u32, max_commission: u32) -> SubmittableTransaction {
272		let value = avail::nomination_pools::tx::SetCommissionMax { pool_id, max_commission };
273		SubmittableTransaction::from_encodable(self.0.clone(), value)
274	}
275
276	/// Updates pool metadata stored on chain.
277	pub fn set_metadata<'a>(&self, pool_id: u32, metadata: impl Into<StringOrBytes<'a>>) -> SubmittableTransaction {
278		let metadata: StringOrBytes = metadata.into();
279		let metadata: Vec<u8> = metadata.into();
280		let value = avail::nomination_pools::tx::SetMetadata { pool_id, metadata };
281		SubmittableTransaction::from_encodable(self.0.clone(), value)
282	}
283
284	/// Transitions the pool into a new lifecycle state.
285	pub fn set_state(&self, pool_id: u32, state: PoolState) -> SubmittableTransaction {
286		let value = avail::nomination_pools::tx::SetState { pool_id, state };
287		SubmittableTransaction::from_encodable(self.0.clone(), value)
288	}
289
290	/// Starts the unbonding process for the specified member account.
291	///
292	/// # Panics
293	/// Panics if `member_account` cannot be converted into a `MultiAddress`.
294	pub fn unbond(
295		&self,
296		member_account: impl Into<MultiAddressLike>,
297		unbonding_points: u128,
298	) -> SubmittableTransaction {
299		let member_account: MultiAddressLike = member_account.into();
300		let member_account: MultiAddress = member_account
301			.try_into()
302			.expect("Malformed string is passed for AccountId");
303
304		let value = avail::nomination_pools::tx::Unbond { member_account, unbonding_points };
305		SubmittableTransaction::from_encodable(self.0.clone(), value)
306	}
307
308	/// Updates the pool's root, nominator, and bouncer roles.
309	pub fn update_roles(
310		&self,
311		pool_id: u32,
312		new_root: ConfigOpAccount,
313		new_nominator: ConfigOpAccount,
314		new_bouncer: ConfigOpAccount,
315	) -> SubmittableTransaction {
316		let value = avail::nomination_pools::tx::UpdateRoles { pool_id, new_root, new_nominator, new_bouncer };
317		SubmittableTransaction::from_encodable(self.0.clone(), value)
318	}
319
320	/// Withdraws fully unbonded funds for the given member account.
321	///
322	/// # Panics
323	/// Panics if `member_account` cannot be converted into a `MultiAddress`.
324	pub fn withdraw_unbonded(
325		&self,
326		member_account: impl Into<MultiAddressLike>,
327		num_slashing_spans: u32,
328	) -> SubmittableTransaction {
329		let member_account: MultiAddressLike = member_account.into();
330		let member_account: MultiAddress = member_account
331			.try_into()
332			.expect("Malformed string is passed for AccountId");
333
334		let value = avail::nomination_pools::tx::WithdrawUnbonded { member_account, num_slashing_spans };
335		SubmittableTransaction::from_encodable(self.0.clone(), value)
336	}
337}
338
339/// Builds extrinsics for the `staking` pallet.
340///
341/// Methods that accept `AccountIdLike` or `MultiAddressLike` parameters will panic if the provided
342/// value cannot be converted into the expected on-chain representation.
343pub struct Staking(Client);
344impl Staking {
345	/// Bonds funds from the controller with the provided reward destination.
346	pub fn bond(&self, value: u128, payee: RewardDestination) -> SubmittableTransaction {
347		let value = avail::staking::tx::Bond { value, payee };
348		SubmittableTransaction::from_encodable(self.0.clone(), value)
349	}
350
351	/// Adds additional stake on top of an existing bond.
352	pub fn bond_extra(&self, value: u128) -> SubmittableTransaction {
353		let value = avail::staking::tx::BondExtra { value };
354		SubmittableTransaction::from_encodable(self.0.clone(), value)
355	}
356
357	/// Starts unbonding the given amount of funds.
358	pub fn unbond(&self, value: u128) -> SubmittableTransaction {
359		let value = avail::staking::tx::Unbond { value };
360		SubmittableTransaction::from_encodable(self.0.clone(), value)
361	}
362
363	/// Re-bonds a portion of funds that are currently unbonding.
364	pub fn rebond(&self, value: u128) -> SubmittableTransaction {
365		let value = avail::staking::tx::Rebond { value };
366		SubmittableTransaction::from_encodable(self.0.clone(), value)
367	}
368
369	/// Advertises validator preferences for the caller.
370	pub fn validate(&self, commission: u32, blocked: bool) -> SubmittableTransaction {
371		let value = avail::staking::tx::Validate { prefs: ValidatorPrefs { commission, blocked } };
372		SubmittableTransaction::from_encodable(self.0.clone(), value)
373	}
374
375	/// Nominates a new set of validator targets.
376	///
377	/// # Panics
378	/// Panics if any provided target cannot be converted into a `MultiAddress`.
379	pub fn nominate(&self, targets: Vec<impl Into<MultiAddressLike>>) -> SubmittableTransaction {
380		let targets: Vec<MultiAddressLike> = targets.into_iter().map(|x| x.into()).collect();
381		let targets: Result<Vec<MultiAddress>, _> = targets.into_iter().map(MultiAddress::try_from).collect();
382		let targets = targets.expect("Malformed string is passed for AccountId");
383
384		let value = avail::staking::tx::Nominate { targets };
385		SubmittableTransaction::from_encodable(self.0.clone(), value)
386	}
387
388	/// Pays out staking rewards for the given validator and era.
389	///
390	/// # Panics
391	/// Panics if `validator_stash` cannot be converted into an `AccountId`.
392	pub fn payout_stakers(&self, validator_stash: impl Into<AccountIdLike>, era: u32) -> SubmittableTransaction {
393		let validator_stash: AccountIdLike = validator_stash.into();
394		let validator_stash = AccountId::try_from(validator_stash).expect("Malformed string is passed for AccountId");
395
396		let value = avail::staking::tx::PayoutStakers { validator_stash, era };
397		SubmittableTransaction::from_encodable(self.0.clone(), value)
398	}
399
400	/// Switches the controller account for the stash.
401	pub fn set_controller(&self) -> SubmittableTransaction {
402		let value = avail::staking::tx::SetController {};
403		SubmittableTransaction::from_encodable(self.0.clone(), value)
404	}
405
406	/// Updates the staking reward destination.
407	pub fn set_payee(&self, payee: RewardDestination) -> SubmittableTransaction {
408		let value = avail::staking::tx::SetPayee { payee };
409		SubmittableTransaction::from_encodable(self.0.clone(), value)
410	}
411
412	/// Stops nominating for the caller.
413	pub fn chill(&self) -> SubmittableTransaction {
414		let value = avail::staking::tx::Chill {};
415		SubmittableTransaction::from_encodable(self.0.clone(), value)
416	}
417
418	/// Issues a chill for another stash account.
419	///
420	/// # Panics
421	/// Panics if `stash` cannot be converted into an `AccountId`.
422	pub fn chill_other(&self, stash: impl Into<AccountIdLike>) -> SubmittableTransaction {
423		let stash: AccountIdLike = stash.into();
424		let stash = AccountId::try_from(stash).expect("Malformed string is passed for AccountId");
425
426		let value = avail::staking::tx::ChillOther { stash };
427		SubmittableTransaction::from_encodable(self.0.clone(), value)
428	}
429
430	/// Withdraws funds that have completed the unbonding period.
431	pub fn withdraw_unbonded(&self, num_slashing_spans: u32) -> SubmittableTransaction {
432		let value = avail::staking::tx::WithdrawUnbonded { num_slashing_spans };
433		SubmittableTransaction::from_encodable(self.0.clone(), value)
434	}
435
436	/// Removes a stash that no longer has bonded funds.
437	///
438	/// # Panics
439	/// Panics if `stash` cannot be converted into an `AccountId`.
440	pub fn reap_stash(&self, stash: impl Into<AccountIdLike>, num_slashing_spans: u32) -> SubmittableTransaction {
441		let stash: AccountIdLike = stash.into();
442		let stash = AccountId::try_from(stash).expect("Malformed string is passed for AccountId");
443
444		let value = avail::staking::tx::ReapStash { stash, num_slashing_spans };
445		SubmittableTransaction::from_encodable(self.0.clone(), value)
446	}
447
448	/// Removes the provided nominees from the caller's nomination list.
449	///
450	/// # Panics
451	/// Panics if any identifier in `who` cannot be converted into a `MultiAddress`.
452	pub fn kick(&self, who: Vec<impl Into<MultiAddressLike>>) -> SubmittableTransaction {
453		let who: Vec<MultiAddressLike> = who.into_iter().map(|x| x.into()).collect();
454		let who: Result<Vec<MultiAddress>, _> = who.into_iter().map(MultiAddress::try_from).collect();
455		let who = who.expect("Malformed string is passed for AccountId");
456
457		let value = avail::staking::tx::Kick { who };
458		SubmittableTransaction::from_encodable(self.0.clone(), value)
459	}
460
461	/// Forces the commission for the given validator to the chain minimum.
462	///
463	/// # Panics
464	/// Panics if `validator_stash` cannot be converted into an `AccountId`.
465	pub fn force_apply_min_commission(&self, validator_stash: impl Into<AccountIdLike>) -> SubmittableTransaction {
466		let validator_stash: AccountIdLike = validator_stash.into();
467		let validator_stash = AccountId::try_from(validator_stash).expect("Malformed string is passed for AccountId");
468
469		let value = avail::staking::tx::ForceApplyMinCommission { validator_stash };
470		SubmittableTransaction::from_encodable(self.0.clone(), value)
471	}
472
473	/// Pays out staking rewards for a subset of nominators.
474	///
475	/// # Panics
476	/// Panics if `validator_stash` cannot be converted into an `AccountId`.
477	pub fn payout_stakers_by_page(
478		&self,
479		validator_stash: impl Into<AccountIdLike>,
480		era: u32,
481		page: u32,
482	) -> SubmittableTransaction {
483		let validator_stash: AccountIdLike = validator_stash.into();
484		let validator_stash = AccountId::try_from(validator_stash).expect("Malformed string is passed for AccountId");
485
486		let value = avail::staking::tx::PayoutStakersByPage { validator_stash, era, page };
487		SubmittableTransaction::from_encodable(self.0.clone(), value)
488	}
489}
490
491/// Builds extrinsics for the `balances` pallet.
492///
493/// All helpers expect account identifiers that can be converted into `MultiAddress` values and will
494/// panic if the conversion fails.
495pub struct Balances(Client);
496impl Balances {
497	/// Transfers funds allowing the sender's account to be removed if depleted.
498	///
499	/// # Panics
500	/// Panics if `dest` cannot be converted into a `MultiAddress`.
501	pub fn transfer_allow_death(&self, dest: impl Into<MultiAddressLike>, amount: u128) -> SubmittableTransaction {
502		let dest: MultiAddressLike = dest.into();
503		let dest: MultiAddress = dest.try_into().expect("Malformed string is passed for AccountId");
504
505		let value = avail::balances::tx::TransferAllowDeath { dest, value: amount };
506		SubmittableTransaction::from_encodable(self.0.clone(), value)
507	}
508
509	/// Transfers funds while keeping the sender's account alive.
510	///
511	/// # Panics
512	/// Panics if `dest` cannot be converted into a `MultiAddress`.
513	pub fn transfer_keep_alive(&self, dest: impl Into<MultiAddressLike>, amount: u128) -> SubmittableTransaction {
514		let dest: MultiAddressLike = dest.into();
515		let dest: MultiAddress = dest.try_into().expect("Malformed string is passed for AccountId");
516
517		let value = avail::balances::tx::TransferKeepAlive { dest, value: amount };
518		SubmittableTransaction::from_encodable(self.0.clone(), value)
519	}
520
521	/// Transfers the entire free balance to the destination.
522	///
523	/// # Panics
524	/// Panics if `dest` cannot be converted into a `MultiAddress`.
525	pub fn transfer_all(&self, dest: impl Into<MultiAddressLike>, keep_alive: bool) -> SubmittableTransaction {
526		let dest: MultiAddressLike = dest.into();
527		let dest: MultiAddress = dest.try_into().expect("Malformed string is passed for AccountId");
528
529		let value = avail::balances::tx::TransferAll { dest, keep_alive };
530		SubmittableTransaction::from_encodable(self.0.clone(), value)
531	}
532}
533
534/// Builds extrinsics for the `multisig` pallet.
535///
536/// Helper methods convert `AccountIdLike` and `HashString` inputs into on-chain representations and
537/// panic if the conversion fails; they also sort the provided signatories to match runtime
538/// expectations.
539pub struct Multisig(Client);
540impl Multisig {
541	/// Approves a multisig call by reference to its hash.
542	///
543	/// # Panics
544	/// Panics if any signatory identifier fails to convert into an `AccountId` or if `call_hash`
545	/// cannot be converted into `H256`.
546	pub fn approve_as_multi(
547		&self,
548		threshold: u16,
549		other_signatories: Vec<impl Into<AccountIdLike>>,
550		maybe_timepoint: Option<Timepoint>,
551		call_hash: impl Into<HashString>,
552		max_weight: Weight,
553	) -> SubmittableTransaction {
554		fn inner(
555			client: Client,
556			threshold: u16,
557			other_signatories: Vec<AccountIdLike>,
558			maybe_timepoint: Option<Timepoint>,
559			call_hash: HashString,
560			max_weight: Weight,
561		) -> SubmittableTransaction {
562			let other_signatories: Result<Vec<AccountId>, _> =
563				other_signatories.into_iter().map(|x| x.try_into()).collect();
564			let mut other_signatories = other_signatories.expect("Malformed string is passed for AccountId");
565			other_signatories.sort();
566
567			let call_hash: H256 = call_hash.try_into().expect("Malformed string is passed for H256");
568
569			let value = avail::multisig::tx::ApproveAsMulti {
570				threshold,
571				other_signatories,
572				maybe_timepoint,
573				call_hash,
574				max_weight,
575			};
576			SubmittableTransaction::from_encodable(client, value)
577		}
578
579		let other_signatories: Vec<AccountIdLike> = other_signatories.into_iter().map(|x| x.into()).collect();
580		let call_hash: HashString = call_hash.into();
581		inner(self.0.clone(), threshold, other_signatories, maybe_timepoint, call_hash, max_weight)
582	}
583
584	/// Executes a multisig call with full call data.
585	///
586	/// # Panics
587	/// Panics if any signatory identifier fails to convert into an `AccountId`.
588	pub fn as_multi(
589		&self,
590		threshold: u16,
591		other_signatories: Vec<impl Into<AccountIdLike>>,
592		maybe_timepoint: Option<Timepoint>,
593		call: impl Into<ExtrinsicCall>,
594		max_weight: Weight,
595	) -> SubmittableTransaction {
596		fn inner(
597			client: Client,
598			threshold: u16,
599			other_signatories: Vec<AccountIdLike>,
600			maybe_timepoint: Option<Timepoint>,
601			call: ExtrinsicCall,
602			max_weight: Weight,
603		) -> SubmittableTransaction {
604			let other_signatories: Result<Vec<AccountId>, _> =
605				other_signatories.into_iter().map(|x| x.try_into()).collect();
606			let mut other_signatories = other_signatories.expect("Malformed string is passed for AccountId");
607			other_signatories.sort();
608
609			let value = avail::multisig::tx::AsMulti {
610				threshold,
611				other_signatories,
612				maybe_timepoint,
613				call,
614				max_weight,
615			};
616			SubmittableTransaction::from_encodable(client, value)
617		}
618
619		let other_signatories: Vec<AccountIdLike> = other_signatories.into_iter().map(|x| x.into()).collect();
620		inner(self.0.clone(), threshold, other_signatories, maybe_timepoint, call.into(), max_weight)
621	}
622
623	/// Executes a multisig call with a threshold of one.
624	///
625	/// # Panics
626	/// Panics if any signatory identifier fails to convert into an `AccountId`.
627	pub fn as_multi_threshold_1(
628		&self,
629		other_signatories: Vec<impl Into<AccountIdLike>>,
630		call: impl Into<ExtrinsicCall>,
631	) -> SubmittableTransaction {
632		fn inner(client: Client, other_signatories: Vec<AccountIdLike>, call: ExtrinsicCall) -> SubmittableTransaction {
633			let other_signatories: Result<Vec<AccountId>, _> =
634				other_signatories.into_iter().map(|x| x.try_into()).collect();
635			let mut other_signatories = other_signatories.expect("Malformed string is passed for AccountId");
636			other_signatories.sort();
637
638			let value = avail::multisig::tx::AsMultiThreshold1 { other_signatories, call };
639			SubmittableTransaction::from_encodable(client, value)
640		}
641
642		let other_signatories: Vec<AccountIdLike> = other_signatories.into_iter().map(|x| x.into()).collect();
643		inner(self.0.clone(), other_signatories, call.into())
644	}
645
646	/// Cancels a previously scheduled multisig call.
647	///
648	/// # Panics
649	/// Panics if any signatory identifier fails to convert into an `AccountId` or if `call_hash`
650	/// cannot be converted into `H256`.
651	pub fn cancel_as_multi(
652		&self,
653		threshold: u16,
654		other_signatories: Vec<impl Into<AccountIdLike>>,
655		timepoint: Timepoint,
656		call_hash: impl Into<HashString>,
657	) -> SubmittableTransaction {
658		fn inner(
659			client: Client,
660			threshold: u16,
661			other_signatories: Vec<AccountIdLike>,
662			timepoint: Timepoint,
663			call_hash: HashString,
664		) -> SubmittableTransaction {
665			let other_signatories: Result<Vec<AccountId>, _> =
666				other_signatories.into_iter().map(|x| x.try_into()).collect();
667			let mut other_signatories = other_signatories.expect("Malformed string is passed for AccountId");
668			other_signatories.sort();
669
670			let call_hash: H256 = call_hash.try_into().expect("Malformed string is passed for H256");
671
672			let value = avail::multisig::tx::CancelAsMulti { threshold, other_signatories, timepoint, call_hash };
673			SubmittableTransaction::from_encodable(client, value)
674		}
675
676		let other_signatories: Vec<AccountIdLike> = other_signatories.into_iter().map(|x| x.into()).collect();
677		let call_hash: HashString = call_hash.into();
678		inner(self.0.clone(), threshold, other_signatories, timepoint, call_hash)
679	}
680}
681
682/// Builds extrinsics for the `data_availability` pallet.
683pub struct DataAvailability(Client);
684impl DataAvailability {
685	/// Registers a new application key for data availability submissions.
686	pub fn create_application_key<'a>(&self, key: impl Into<StringOrBytes<'a>>) -> SubmittableTransaction {
687		let key: Vec<u8> = Into::<StringOrBytes>::into(key).into();
688		let value = avail::data_availability::tx::CreateApplicationKey { key };
689		SubmittableTransaction::from_encodable(self.0.clone(), value)
690	}
691
692	/// Submits application data for availability guarantees.
693	pub fn submit_data<'a>(&self, data: impl Into<StringOrBytes<'a>>) -> SubmittableTransaction {
694		let data: Vec<u8> = Into::<StringOrBytes>::into(data).into();
695		let value = avail::data_availability::tx::SubmitData { data };
696		SubmittableTransaction::from_encodable(self.0.clone(), value)
697	}
698
699	#[cfg(feature = "next")]
700	pub fn submit_blob_metadata(&self, blob_hash: H256, size: u64, commitments: Vec<u8>) -> SubmittableTransaction {
701		let value = avail::data_availability::tx::SubmitBlobMetadata { blob_hash, size, commitments };
702		SubmittableTransaction::from_encodable(self.0.clone(), value)
703	}
704}
705
706/// Builds extrinsics for the `utility` pallet.
707pub struct Utility(Client);
708impl Utility {
709	/// Dispatches a set of calls sequentially, aborting on failure.
710	pub fn batch(&self, calls: Vec<impl Into<ExtrinsicCall>>) -> SubmittableTransaction {
711		let mut batch = avail::utility::tx::Batch::new();
712		batch.add_calls(calls.into_iter().map(|x| x.into()).collect());
713		SubmittableTransaction::from_encodable(self.0.clone(), batch)
714	}
715
716	/// Dispatches a set of calls and reverts the whole batch if any fail.
717	pub fn batch_all(&self, calls: Vec<impl Into<ExtrinsicCall>>) -> SubmittableTransaction {
718		let mut batch = avail::utility::tx::BatchAll::new();
719		batch.add_calls(calls.into_iter().map(|x| x.into()).collect());
720		SubmittableTransaction::from_encodable(self.0.clone(), batch)
721	}
722
723	/// Dispatches a set of calls while ignoring failures.
724	pub fn force_batch(&self, calls: Vec<impl Into<ExtrinsicCall>>) -> SubmittableTransaction {
725		let mut batch = avail::utility::tx::ForceBatch::new();
726		batch.add_calls(calls.into_iter().map(|x| x.into()).collect());
727		SubmittableTransaction::from_encodable(self.0.clone(), batch)
728	}
729}
730
731/// Builds extrinsics for the `proxy` pallet.
732///
733/// Methods converting `MultiAddressLike` parameters will panic if the provided values cannot be
734/// decoded into `MultiAddress` instances.
735pub struct Proxy(Client);
736impl Proxy {
737	/// Dispatches a call through an existing proxy relationship.
738	///
739	/// # Panics
740	/// Panics if `id` cannot be converted into a `MultiAddress`.
741	pub fn proxy(
742		&self,
743		id: impl Into<MultiAddressLike>,
744		force_proxy_type: Option<ProxyType>,
745		call: impl Into<ExtrinsicCall>,
746	) -> SubmittableTransaction {
747		let id: MultiAddressLike = id.into();
748		let id: MultiAddress = id.try_into().expect("Malformed string is passed for AccountId");
749
750		let value = avail::proxy::tx::Proxy { id, force_proxy_type, call: call.into() };
751		SubmittableTransaction::from_encodable(self.0.clone(), value)
752	}
753
754	/// Registers a new proxy delegate for the caller.
755	///
756	/// # Panics
757	/// Panics if `id` cannot be converted into a `MultiAddress`.
758	pub fn add_proxy(
759		&self,
760		id: impl Into<MultiAddressLike>,
761		proxy_type: ProxyType,
762		delay: u32,
763	) -> SubmittableTransaction {
764		let id: MultiAddressLike = id.into();
765		let id: MultiAddress = id.try_into().expect("Malformed string is passed for AccountId");
766
767		let value = avail::proxy::tx::AddProxy { id, proxy_type, delay };
768		SubmittableTransaction::from_encodable(self.0.clone(), value)
769	}
770
771	/// Removes a specific proxy delegate.
772	///
773	/// # Panics
774	/// Panics if `delegate` cannot be converted into a `MultiAddress`.
775	pub fn remove_proxy(
776		&self,
777		delegate: impl Into<MultiAddressLike>,
778		proxy_type: ProxyType,
779		delay: u32,
780	) -> SubmittableTransaction {
781		let delegate: MultiAddressLike = delegate.into();
782		let delegate: MultiAddress = delegate.try_into().expect("Malformed string is passed for AccountId");
783
784		let value = avail::proxy::tx::RemoveProxy { delegate, proxy_type, delay };
785		SubmittableTransaction::from_encodable(self.0.clone(), value)
786	}
787
788	/// Removes all proxies belonging to the caller.
789	pub fn remove_proxies(&self) -> SubmittableTransaction {
790		let value = avail::proxy::tx::RemoveProxies {};
791		SubmittableTransaction::from_encodable(self.0.clone(), value)
792	}
793
794	/// Creates a pure proxy account with the requested parameters.
795	pub fn create_pure(&self, proxy_type: ProxyType, delay: u32, index: u16) -> SubmittableTransaction {
796		let value = avail::proxy::tx::CreatePure { proxy_type, delay, index };
797		SubmittableTransaction::from_encodable(self.0.clone(), value)
798	}
799
800	/// Kills a pure proxy that was previously spawned by the provided account.
801	///
802	/// # Panics
803	/// Panics if `spawner` cannot be converted into a `MultiAddress`.
804	pub fn kill_pure(
805		&self,
806		spawner: impl Into<MultiAddressLike>,
807		proxy_type: ProxyType,
808		index: u16,
809		height: u32,
810		ext_index: u32,
811	) -> SubmittableTransaction {
812		let spawner: MultiAddressLike = spawner.into();
813		let spawner: MultiAddress = spawner.try_into().expect("Malformed string is passed for AccountId");
814
815		let value = avail::proxy::tx::KillPure { spawner, proxy_type, index, height, ext_index };
816		SubmittableTransaction::from_encodable(self.0.clone(), value)
817	}
818}
819
820/// Builds extrinsics for the `vector` pallet.
821///
822/// Several helpers convert hash-like parameters into `H256` values and will panic if the provided
823/// data cannot be parsed.
824pub struct Vector(Client);
825impl Vector {
826	/// Submits a fulfillment proof for a pending cross-chain call.
827	pub fn batch(
828		&self,
829		function_id: H256,
830		input: Vec<u8>,
831		output: Vec<u8>,
832		proof: Vec<u8>,
833		slot: u64,
834	) -> SubmittableTransaction {
835		let value = avail::vector::tx::FulfillCall { function_id, input, output, proof, slot };
836		SubmittableTransaction::from_encodable(self.0.clone(), value)
837	}
838
839	/// Executes a vector addressed message with witness data.
840	pub fn execute(
841		&self,
842		slot: u64,
843		addr_message: avail::vector::types::AddressedMessage,
844		account_proof: Vec<Vec<u8>>,
845		storage_proof: Vec<Vec<u8>>,
846	) -> SubmittableTransaction {
847		let value = avail::vector::tx::Execute { slot, addr_message, account_proof, storage_proof };
848		SubmittableTransaction::from_encodable(self.0.clone(), value)
849	}
850
851	/// Toggles whether a source chain is frozen.
852	pub fn source_chain_froze(&self, source_chain_id: u32, frozen: bool) -> SubmittableTransaction {
853		let value = avail::vector::tx::SourceChainFroze { source_chain_id, frozen };
854		SubmittableTransaction::from_encodable(self.0.clone(), value)
855	}
856
857	/// Sends a vector message to the specified domain.
858	///
859	/// # Panics
860	/// Panics if `to` cannot be converted into an `H256`.
861	pub fn send_message(
862		&self,
863		message: avail::vector::types::Message,
864		to: impl Into<HashString>,
865		domain: u32,
866	) -> SubmittableTransaction {
867		let to: HashString = to.into();
868		let to: H256 = to.try_into().expect("Malformed string is passed for H256");
869
870		let value = avail::vector::tx::SendMessage { message, to, domain };
871		SubmittableTransaction::from_encodable(self.0.clone(), value)
872	}
873
874	/// Marks previous outbound messages as failed by index.
875	pub fn failed_send_message_txs(&self, failed_txs: Vec<u32>) -> SubmittableTransaction {
876		let value = avail::vector::tx::FailedSendMessageTxs { failed_txs };
877		SubmittableTransaction::from_encodable(self.0.clone(), value)
878	}
879
880	/// Updates the Poseidon hash commitment for a sync period.
881	pub fn set_poseidon_hash(&self, period: u64, poseidon_hash: Vec<u8>) -> SubmittableTransaction {
882		let value = avail::vector::tx::SetPoseidonHash { period: period.into(), poseidon_hash };
883		SubmittableTransaction::from_encodable(self.0.clone(), value)
884	}
885
886	/// Registers the broadcaster for a specific domain.
887	pub fn set_broadcaster(&self, broadcaster_domain: u32, broadcaster: H256) -> SubmittableTransaction {
888		let value = avail::vector::tx::SetBroadcaster { broadcaster_domain: broadcaster_domain.into(), broadcaster };
889		SubmittableTransaction::from_encodable(self.0.clone(), value)
890	}
891
892	/// Overwrites the set of domains allowed to send messages.
893	pub fn set_whitelisted_domains(&self, value: Vec<u32>) -> SubmittableTransaction {
894		let value = avail::vector::tx::SetWhitelistedDomains { value };
895		SubmittableTransaction::from_encodable(self.0.clone(), value)
896	}
897
898	/// Updates the vector configuration parameters.
899	pub fn set_configuration(&self, value: avail::vector::types::Configuration) -> SubmittableTransaction {
900		let value = avail::vector::tx::SetConfiguration { value };
901		SubmittableTransaction::from_encodable(self.0.clone(), value)
902	}
903
904	/// Updates the function identifiers used by the pallet.
905	pub fn set_function_ids(&self, value: Option<(H256, H256)>) -> SubmittableTransaction {
906		let value = avail::vector::tx::SetFunctionIds { value };
907		SubmittableTransaction::from_encodable(self.0.clone(), value)
908	}
909
910	/// Sets the verification key for the step circuit.
911	pub fn set_step_verification_key(&self, value: Option<Vec<u8>>) -> SubmittableTransaction {
912		let value = avail::vector::tx::SetStepVerificationKey { value };
913		SubmittableTransaction::from_encodable(self.0.clone(), value)
914	}
915
916	/// Updates the updater account hash.
917	pub fn set_updater(&self, updater: H256) -> SubmittableTransaction {
918		let value = avail::vector::tx::SetUpdater { updater };
919		SubmittableTransaction::from_encodable(self.0.clone(), value)
920	}
921
922	/// Submits a zero-knowledge proof fulfilling a pending message.
923	pub fn fulfill(&self, proof: Vec<u8>, public_values: Vec<u8>) -> SubmittableTransaction {
924		let value = avail::vector::tx::Fulfill { proof, public_values };
925		SubmittableTransaction::from_encodable(self.0.clone(), value)
926	}
927
928	/// Sets the verification key for SP1 proofs.
929	pub fn set_sp1_verification_key(&self, sp1_vk: H256) -> SubmittableTransaction {
930		let value = avail::vector::tx::SetSp1VerificationKey { sp1_vk };
931		SubmittableTransaction::from_encodable(self.0.clone(), value)
932	}
933
934	/// Updates the sync committee hash for the provided period.
935	pub fn set_sync_committee_hash(&self, period: u64, hash: H256) -> SubmittableTransaction {
936		let value = avail::vector::tx::SetSyncCommitteeHash { period, hash };
937		SubmittableTransaction::from_encodable(self.0.clone(), value)
938	}
939
940	/// Enables or disables mock execution mode.
941	pub fn enable_mock(&self, value: bool) -> SubmittableTransaction {
942		let value = avail::vector::tx::EnableMock { value };
943		SubmittableTransaction::from_encodable(self.0.clone(), value)
944	}
945
946	/// Fulfills a message when running in mock mode.
947	pub fn mock_fulfill(&self, public_values: Vec<u8>) -> SubmittableTransaction {
948		let value = avail::vector::tx::MockFulfill { public_values };
949		SubmittableTransaction::from_encodable(self.0.clone(), value)
950	}
951}
952
953/// Builds extrinsics for the `system` pallet.
954pub struct System(Client);
955impl System {
956	/// Emits a remark event containing arbitrary bytes.
957	pub fn remark(&self, remark: Vec<u8>) -> SubmittableTransaction {
958		let value = avail::system::tx::Remark { remark };
959		SubmittableTransaction::from_encodable(self.0.clone(), value)
960	}
961
962	/// Replaces the runtime code with a new version.
963	pub fn set_code(&self, code: Vec<u8>) -> SubmittableTransaction {
964		let value = avail::system::tx::SetCode { code };
965		SubmittableTransaction::from_encodable(self.0.clone(), value)
966	}
967
968	/// Replaces the runtime code without performing standard checks.
969	pub fn set_code_without_checks(&self, code: Vec<u8>) -> SubmittableTransaction {
970		let value = avail::system::tx::SetCodeWithoutChecks { code };
971		SubmittableTransaction::from_encodable(self.0.clone(), value)
972	}
973
974	/// Emits a remark while guaranteeing an event is produced.
975	pub fn remark_with_event(&self, remark: Vec<u8>) -> SubmittableTransaction {
976		let value = avail::system::tx::RemarkWithEvent { remark };
977		SubmittableTransaction::from_encodable(self.0.clone(), value)
978	}
979}