partner_chains_cardano_offchain/reserve/
update_settings.rs

1//! Transaction that updates reserve settings.
2//!
3//! Specification:
4//! 1. The transaction should mint one token:
5//!   * 1 Governance Policy Token (using reference script)
6//! 2. The transaction should spend one token:
7//!   * 1 Reserve Auth Policy Token (using reference script)
8//! 3. The transaction should have two outputs:
9//!   * Reserve Validator output that:
10//!   * * has value from existing reserve UTXO
11//!   * * has the updated Plutus Data (in our "versioned format"): `[[<Encoded Token>, [Bytes(v_function_hash), Int(initial_incentive)], [Int(0)]], Constr(0, []), Int(0)]`,
12//!       where `<Encoded Token>` is `Constr(0, [Bytes(policy_id), Bytes(asset_name)])`.
13//!   * Change output that keeps the Governance Token and change of other tokens
14//! 4. The transaction should have three script reference inputs:
15//!   * Reserve Auth Version Utxo
16//!   * Reserve Validator Version Utxo
17//!   * Governance Policy Script
18
19use super::{ReserveData, reserve_utxo_input_with_validator_script_reference};
20use crate::{
21	await_tx::AwaitTx,
22	bridge::ICSData,
23	cardano_keys::CardanoPaymentSigningKey,
24	csl::*,
25	governance::GovernanceData,
26	multisig::{MultiSigSmartContractResult, submit_or_create_tx_to_sign},
27	reserve::ReserveUtxo,
28};
29use cardano_serialization_lib::*;
30use ogmios_client::types::OgmiosUtxo;
31use ogmios_client::{
32	query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
33	query_network::QueryNetwork,
34	transactions::Transactions,
35};
36use partner_chains_plutus_data::reserve::{ReserveDatum, ReserveRedeemer};
37use sidechain_domain::{ScriptHash, UtxoId};
38
39/// Updates reserve settings.
40pub async fn update_reserve_settings<
41	T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
42	A: AwaitTx,
43>(
44	genesis_utxo: UtxoId,
45	payment_key: &CardanoPaymentSigningKey,
46	total_accrued_function_script_hash: ScriptHash,
47	client: &T,
48	await_tx: &A,
49) -> anyhow::Result<Option<MultiSigSmartContractResult>> {
50	let ctx = TransactionContext::for_payment_key(payment_key, client).await?;
51	let governance = GovernanceData::get(genesis_utxo, client).await?;
52	let reserve = ReserveData::get(genesis_utxo, &ctx, client).await?;
53	let ReserveUtxo { utxo: reserve_utxo, datum: mut reserve_datum } =
54		reserve.get_reserve_utxo(&ctx, client).await?;
55	let ics_data = ICSData::get(genesis_utxo, &ctx, client).await?;
56
57	if total_accrued_function_script_hash
58		== reserve_datum.mutable_settings.total_accrued_function_asset_name
59	{
60		log::info!(
61			"Reserve V function hash is already set to {:?}. Nothing to update.",
62			total_accrued_function_script_hash
63		);
64		return Ok(None);
65	}
66	reserve_datum.mutable_settings.total_accrued_function_asset_name =
67		total_accrued_function_script_hash.clone();
68
69	Ok(Some(
70		submit_or_create_tx_to_sign(
71			&governance,
72			ctx,
73			|costs, ctx| {
74				update_reserve_settings_tx(
75					&reserve_datum,
76					&reserve,
77					&ics_data,
78					&governance,
79					&reserve_utxo,
80					costs,
81					&ctx,
82				)
83			},
84			"Update Reserve Settings",
85			client,
86			await_tx,
87		)
88		.await?,
89	))
90}
91
92fn update_reserve_settings_tx(
93	datum: &ReserveDatum,
94	reserve: &ReserveData,
95	ics_data: &ICSData,
96	governance: &GovernanceData,
97	reserve_utxo: &OgmiosUtxo,
98	costs: Costs,
99	ctx: &TransactionContext,
100) -> anyhow::Result<Transaction> {
101	let mut tx_builder = TransactionBuilder::new(&get_builder_config(ctx)?);
102	// spend old settings
103	tx_builder.set_inputs(&reserve_utxo_input_with_validator_script_reference(
104		reserve_utxo,
105		reserve,
106		ReserveRedeemer::UpdateReserve,
107		&costs.get_one_spend(),
108	)?);
109
110	{
111		let amount_builder = TransactionOutputBuilder::new()
112			.with_address(&reserve.scripts.validator.address(ctx.network))
113			.with_plutus_data(&(datum.clone().into()))
114			.next()?;
115		let mut val = reserve_utxo.value.to_csl()?;
116		let output = amount_builder.with_value(&val).build()?;
117		let min_ada = MinOutputAdaCalculator::new(
118			&output,
119			&DataCost::new_coins_per_byte(
120				&ctx.protocol_parameters.min_utxo_deposit_coefficient.into(),
121			),
122		)
123		.calculate_ada()?;
124		val.set_coin(&min_ada);
125		let a = amount_builder.with_value(&val).build()?;
126		tx_builder.add_output(&a)?;
127	}
128
129	tx_builder.add_mint_one_script_token_using_reference_script(
130		&governance.policy.script(),
131		&governance.utxo_id_as_tx_input(),
132		&costs,
133	)?;
134	tx_builder.add_script_reference_input(
135		&ics_data.validator_version_utxo.to_csl_tx_input(),
136		ics_data.scripts.validator.bytes.len(),
137	);
138	tx_builder.add_script_reference_input(
139		&reserve.auth_policy_version_utxo.to_csl_tx_input(),
140		reserve.scripts.auth_policy.bytes.len(),
141	);
142	Ok(tx_builder.balance_update_and_build(ctx)?.remove_native_script_witnesses())
143}