partner_chains_cardano_offchain/reserve/
handover.rs

1//!
2//! Specification for deposit transaction:
3//!
4//! Consumes:
5//! - UTXO at the Reserve Validator address
6//!
7//! Outputs:
8//! - UTXO at the illiquid supply validator address with all the Reserve Tokens, plutus data Constr 0 []
9//! - UTXO at the payment address with change and governance token
10//!
11//! Mints:
12//! - Governance Token
13//! - Reserve Auth Policy Token token -1 (burn)
14//!
15//! Reference UTOXs:
16//! - Version Oracle Validator script
17//! - Reserve Auth Policy script
18//! - Reserve Validator script
19//! - Illiquid Supply Validator script
20
21use super::{ReserveUtxo, reserve_utxo_input_with_validator_script_reference};
22use crate::{
23	TokenAmount,
24	await_tx::AwaitTx,
25	bridge::ICSData,
26	cardano_keys::CardanoPaymentSigningKey,
27	csl::{
28		AssetIdExt, CostStore, Costs, OgmiosUtxoExt, Script, TransactionBuilderExt,
29		TransactionContext, TransactionExt, TransactionOutputAmountBuilderExt, get_builder_config,
30	},
31	governance::GovernanceData,
32	multisig::{MultiSigSmartContractResult, submit_or_create_tx_to_sign},
33	reserve::ReserveData,
34	scripts_data::ICSScripts,
35};
36use cardano_serialization_lib::*;
37use ogmios_client::{
38	query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
39	query_network::QueryNetwork,
40	transactions::Transactions,
41	types::OgmiosUtxo,
42};
43use partner_chains_plutus_data::{bridge::TokenTransferDatumV1, reserve::ReserveRedeemer};
44use sidechain_domain::UtxoId;
45
46/// Spends current UTXO at validator address to illiquid supply validator and burn reserve auth policy token, preventing further operations.
47pub async fn handover_reserve<
48	T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
49	A: AwaitTx,
50>(
51	genesis_utxo: UtxoId,
52	payment_key: &CardanoPaymentSigningKey,
53	client: &T,
54	await_tx: &A,
55) -> anyhow::Result<MultiSigSmartContractResult> {
56	let ctx = TransactionContext::for_payment_key(payment_key, client).await?;
57	let governance = GovernanceData::get(genesis_utxo, client).await?;
58	let reserve = ReserveData::get(genesis_utxo, &ctx, client).await?;
59	let ics_data = ICSData::get(genesis_utxo, &ctx, client).await?;
60
61	let ref reserve_utxo @ ReserveUtxo { ref utxo, .. } =
62		reserve.get_reserve_utxo(&ctx, client).await?;
63	let amount = get_amount_to_release(reserve_utxo);
64
65	submit_or_create_tx_to_sign(
66		&governance,
67		ctx,
68		|costs, ctx| build_tx(&amount, utxo, &reserve, &ics_data, &governance, costs, &ctx),
69		"Handover Reserve",
70		client,
71		await_tx,
72	)
73	.await
74}
75
76fn get_amount_to_release(reserve_utxo: &ReserveUtxo) -> TokenAmount {
77	let token = reserve_utxo.datum.immutable_settings.token.clone();
78	let amount = reserve_utxo.utxo.get_asset_amount(&token);
79	TokenAmount { token, amount }
80}
81
82fn build_tx(
83	handover_amount: &TokenAmount,
84	reserve_utxo: &OgmiosUtxo,
85	reserve: &ReserveData,
86	ics_data: &ICSData,
87	governance: &GovernanceData,
88	costs: Costs,
89	ctx: &TransactionContext,
90) -> anyhow::Result<Transaction> {
91	let mut tx_builder = TransactionBuilder::new(&get_builder_config(ctx)?);
92
93	let reserve_auth_policy_spend_cost = costs.get_one_spend();
94
95	// mint goveranance token
96	tx_builder.add_mint_one_script_token_using_reference_script(
97		&governance.policy.script(),
98		&governance.utxo_id_as_tx_input(),
99		&costs,
100	)?;
101
102	// Spends UTXO with Reserve Auth Policy Token and Reserve (Reward) tokens
103	tx_builder.set_inputs(&reserve_utxo_input_with_validator_script_reference(
104		reserve_utxo,
105		reserve,
106		ReserveRedeemer::Handover,
107		&reserve_auth_policy_spend_cost,
108	)?);
109
110	// burn reserve auth policy token
111	tx_builder.add_mint_script_token_using_reference_script(
112		&Script::Plutus(reserve.scripts.auth_policy.clone()),
113		&reserve.auth_policy_version_utxo.to_csl_tx_input(),
114		&Int::new_i32(-1),
115		&costs,
116	)?;
117
118	tx_builder.add_output(&illiquid_supply_validator_output(
119		handover_amount,
120		&ics_data.scripts,
121		ctx,
122	)?)?;
123	// This reference input is needed by the Reserve Validator with 'Handover' redeemer.
124	tx_builder.add_script_reference_input(
125		&ics_data.validator_version_utxo.to_csl_tx_input(),
126		ics_data.scripts.validator.bytes.len(),
127	);
128	Ok(tx_builder.balance_update_and_build(ctx)?.remove_native_script_witnesses())
129}
130
131// Creates output with reserve token and updated deposit
132fn illiquid_supply_validator_output(
133	output_value: &TokenAmount,
134	scripts: &ICSScripts,
135	ctx: &TransactionContext,
136) -> Result<TransactionOutput, JsError> {
137	let tx_output_builder =
138		TransactionOutputBuilder::new().with_address(&scripts.validator.address(ctx.network));
139	if output_value.amount > 0 {
140		let ma = output_value.token.to_multi_asset(output_value.amount)?;
141		let amount_builder = tx_output_builder
142			.with_plutus_data(&TokenTransferDatumV1::ReserveTransfer.into())
143			.next()?;
144		amount_builder.with_minimum_ada_and_asset(&ma, ctx)?.build()
145	} else {
146		// Smart-contract requires to deposit exactly one UTXO in the illiquid supply validator,
147		// otherwise it returns ERROR-RESERVE-16: No unique output utxo at the illiquid circulation supply address
148		let amount_builder = tx_output_builder.next()?;
149		amount_builder.with_minimum_ada(ctx)?.build()
150	}
151}