partner_chains_cardano_offchain/reserve/
deposit.rs

1//!
2//! Specification for deposit transaction:
3//!
4//! Consumes:
5//! - UTXO at the validator address
6//! - UTXOs at payment address that have tokens to be deposited
7//!
8//! Produces:
9//! - UTXO at the validator address with increased token amount
10//! - UTXO at the payment address with change
11//!
12//! Reference UTOXs:
13//! - Version Oracle Validator script
14//! - Reserve Auth Policy script
15//! - Reserve Validator script
16
17use super::{ReserveData, reserve_utxo_input_with_validator_script_reference};
18use crate::{
19	TokenAmount,
20	await_tx::AwaitTx,
21	cardano_keys::CardanoPaymentSigningKey,
22	csl::{
23		CostStore, Costs, MultiAssetExt, OgmiosUtxoExt, TransactionBuilderExt, TransactionContext,
24		TransactionExt, TransactionOutputAmountBuilderExt, get_builder_config,
25	},
26	governance::GovernanceData,
27	multisig::{MultiSigSmartContractResult, submit_or_create_tx_to_sign},
28	scripts_data::ReserveScripts,
29};
30use cardano_serialization_lib::{
31	JsError, MultiAsset, Transaction, TransactionBuilder, TransactionOutput,
32	TransactionOutputBuilder,
33};
34use ogmios_client::{
35	query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
36	query_network::QueryNetwork,
37	transactions::Transactions,
38	types::OgmiosUtxo,
39};
40use partner_chains_plutus_data::reserve::ReserveRedeemer;
41use sidechain_domain::UtxoId;
42use std::num::NonZero;
43
44/// Spends current UTXO at validator address and creates a new UTXO with increased token amount
45pub async fn deposit_to_reserve<
46	T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
47	A: AwaitTx,
48>(
49	amount: NonZero<u64>,
50	genesis_utxo: UtxoId,
51	payment_key: &CardanoPaymentSigningKey,
52	client: &T,
53	await_tx: &A,
54) -> anyhow::Result<MultiSigSmartContractResult> {
55	let payment_context = TransactionContext::for_payment_key(payment_key, client).await?;
56	let governance = GovernanceData::get(genesis_utxo, client).await?;
57	let reserve = ReserveData::get(genesis_utxo, &payment_context, client).await?;
58	let reserve_utxo = reserve.get_reserve_utxo(&payment_context, client).await?;
59	let utxo = reserve_utxo.utxo;
60	let token = reserve_utxo.datum.immutable_settings.token;
61	let current_amount = utxo.get_asset_amount(&token);
62	let token_amount = TokenAmount { token, amount: current_amount + amount.get() };
63
64	submit_or_create_tx_to_sign(
65		&governance,
66		payment_context,
67		|costs, ctx| {
68			deposit_to_reserve_tx(&token_amount, &utxo, &reserve, &governance, costs, &ctx)
69		},
70		"Deposit to Reserve",
71		client,
72		await_tx,
73	)
74	.await
75}
76
77fn deposit_to_reserve_tx(
78	parameters: &TokenAmount,
79	current_utxo: &OgmiosUtxo,
80	reserve: &ReserveData,
81	governance: &GovernanceData,
82	costs: Costs,
83	ctx: &TransactionContext,
84) -> anyhow::Result<Transaction> {
85	let mut tx_builder = TransactionBuilder::new(&get_builder_config(ctx)?);
86
87	tx_builder.add_output(&validator_output(parameters, current_utxo, &reserve.scripts, ctx)?)?;
88
89	tx_builder.set_inputs(&reserve_utxo_input_with_validator_script_reference(
90		current_utxo,
91		reserve,
92		ReserveRedeemer::DepositToReserve,
93		&costs.get_one_spend(),
94	)?);
95
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	tx_builder.add_script_reference_input(
103		&reserve.auth_policy_version_utxo.to_csl_tx_input(),
104		reserve.scripts.auth_policy.bytes.len(),
105	);
106	Ok(tx_builder.balance_update_and_build(ctx)?.remove_native_script_witnesses())
107}
108
109// Creates output with reserve token and updated deposit
110fn validator_output(
111	token_amount: &TokenAmount,
112	current_utxo: &OgmiosUtxo,
113	scripts: &ReserveScripts,
114	ctx: &TransactionContext,
115) -> Result<TransactionOutput, JsError> {
116	let amount_builder = TransactionOutputBuilder::new()
117		.with_address(&scripts.validator.address(ctx.network))
118		.with_plutus_data(
119			&current_utxo
120				.get_plutus_data()
121				.expect("Current UTXO datum was parsed hence it exists"),
122		)
123		.next()?;
124	let ma = MultiAsset::new()
125		.with_asset_amount(&token_amount.token, token_amount.amount)?
126		.with_asset_amount(&scripts.auth_policy.empty_name_asset(), 1u64)?;
127
128	amount_builder.with_minimum_ada_and_asset(&ma, ctx)?.build()
129}