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"): `[[[Int(t0), <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	cardano_keys::CardanoPaymentSigningKey,
23	csl::*,
24	governance::GovernanceData,
25	multisig::{MultiSigSmartContractResult, submit_or_create_tx_to_sign},
26	reserve::ReserveUtxo,
27};
28use cardano_serialization_lib::*;
29use ogmios_client::types::OgmiosUtxo;
30use ogmios_client::{
31	query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
32	query_network::QueryNetwork,
33	transactions::Transactions,
34};
35use partner_chains_plutus_data::reserve::{ReserveDatum, ReserveRedeemer};
36use sidechain_domain::{ScriptHash, UtxoId};
37
38/// Updates reserve settings.
39pub async fn update_reserve_settings<
40	T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
41	A: AwaitTx,
42>(
43	genesis_utxo: UtxoId,
44	payment_key: &CardanoPaymentSigningKey,
45	total_accrued_function_script_hash: ScriptHash,
46	client: &T,
47	await_tx: &A,
48) -> anyhow::Result<Option<MultiSigSmartContractResult>> {
49	let ctx = TransactionContext::for_payment_key(payment_key, client).await?;
50	let governance = GovernanceData::get(genesis_utxo, client).await?;
51	let reserve = ReserveData::get(genesis_utxo, &ctx, client).await?;
52	let ReserveUtxo { utxo: reserve_utxo, datum: mut reserve_datum } =
53		reserve.get_reserve_utxo(&ctx, client).await?;
54
55	if total_accrued_function_script_hash
56		== reserve_datum.mutable_settings.total_accrued_function_asset_name
57	{
58		log::info!(
59			"Reserve V function hash is already set to {:?}. Nothing to update.",
60			total_accrued_function_script_hash
61		);
62		return Ok(None);
63	}
64	reserve_datum.mutable_settings.total_accrued_function_asset_name =
65		total_accrued_function_script_hash.clone();
66
67	Ok(Some(
68		submit_or_create_tx_to_sign(
69			&governance,
70			ctx,
71			|costs, ctx| {
72				update_reserve_settings_tx(
73					&reserve_datum,
74					&reserve,
75					&governance,
76					&reserve_utxo,
77					costs,
78					&ctx,
79				)
80			},
81			"Update Reserve Settings",
82			client,
83			await_tx,
84		)
85		.await?,
86	))
87}
88
89fn update_reserve_settings_tx(
90	datum: &ReserveDatum,
91	reserve: &ReserveData,
92	governance: &GovernanceData,
93	reserve_utxo: &OgmiosUtxo,
94	costs: Costs,
95	ctx: &TransactionContext,
96) -> anyhow::Result<Transaction> {
97	let mut tx_builder = TransactionBuilder::new(&get_builder_config(ctx)?);
98
99	// spend old settings
100	tx_builder.set_inputs(&reserve_utxo_input_with_validator_script_reference(
101		reserve_utxo,
102		reserve,
103		ReserveRedeemer::UpdateReserve,
104		&costs.get_one_spend(),
105	)?);
106	{
107		let amount_builder = TransactionOutputBuilder::new()
108			.with_address(&reserve.scripts.validator.address(ctx.network))
109			.with_plutus_data(&(datum.clone().into()))
110			.next()?;
111		let mut val = reserve_utxo.value.to_csl()?;
112		let output = amount_builder.with_value(&val).build()?;
113		let min_ada = MinOutputAdaCalculator::new(
114			&output,
115			&DataCost::new_coins_per_byte(
116				&ctx.protocol_parameters.min_utxo_deposit_coefficient.into(),
117			),
118		)
119		.calculate_ada()?;
120		val.set_coin(&min_ada);
121		let a = amount_builder.with_value(&val).build()?;
122		tx_builder.add_output(&a)?;
123	}
124
125	tx_builder.add_mint_one_script_token_using_reference_script(
126		&governance.policy.script(),
127		&governance.utxo_id_as_tx_input(),
128		&costs,
129	)?;
130	tx_builder.add_script_reference_input(
131		&reserve.illiquid_circulation_supply_validator_version_utxo.to_csl_tx_input(),
132		reserve.scripts.illiquid_circulation_supply_validator.bytes.len(),
133	);
134	tx_builder.add_script_reference_input(
135		&reserve.auth_policy_version_utxo.to_csl_tx_input(),
136		reserve.scripts.auth_policy.bytes.len(),
137	);
138	Ok(tx_builder.balance_update_and_build(ctx)?.remove_native_script_witnesses())
139}