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//! - Illiquid Supply Validator script
17
18use super::{ReserveData, TokenAmount, reserve_utxo_input_with_validator_script_reference};
19use crate::{
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::{AssetId, UtxoId};
42
43/// Spends current UTXO at validator address and creates a new UTXO with increased token amount
44pub async fn deposit_to_reserve<
45	T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
46	A: AwaitTx,
47>(
48	amount: u64,
49	genesis_utxo: UtxoId,
50	payment_key: &CardanoPaymentSigningKey,
51	client: &T,
52	await_tx: &A,
53) -> anyhow::Result<MultiSigSmartContractResult> {
54	let payment_context = TransactionContext::for_payment_key(payment_key, client).await?;
55	let governance = GovernanceData::get(genesis_utxo, client).await?;
56	let reserve = ReserveData::get(genesis_utxo, &payment_context, client).await?;
57	let reserve_utxo = reserve.get_reserve_utxo(&payment_context, client).await?;
58	let utxo = reserve_utxo.utxo;
59	let token = reserve_utxo.datum.immutable_settings.token;
60	let current_amount = get_token_amount(&utxo, &token);
61	let token_amount = TokenAmount { token, amount: current_amount + amount };
62
63	submit_or_create_tx_to_sign(
64		&governance,
65		payment_context,
66		|costs, ctx| {
67			deposit_to_reserve_tx(&token_amount, &utxo, &reserve, &governance, costs, &ctx)
68		},
69		"Deposit to Reserve",
70		client,
71		await_tx,
72	)
73	.await
74}
75
76fn get_token_amount(utxo: &OgmiosUtxo, token: &AssetId) -> u64 {
77	let AssetId { policy_id, asset_name } = token;
78	utxo.value
79		.native_tokens
80		.get(&policy_id.0)
81		.and_then(|assets| assets.iter().find(|asset| asset.name == asset_name.0.to_vec()))
82		.map(|asset| asset.amount)
83		.unwrap_or(0) // Token can be not found if the reserve was created with the initial deposit of 0 tokens
84}
85
86fn deposit_to_reserve_tx(
87	parameters: &TokenAmount,
88	current_utxo: &OgmiosUtxo,
89	reserve: &ReserveData,
90	governance: &GovernanceData,
91	costs: Costs,
92	ctx: &TransactionContext,
93) -> anyhow::Result<Transaction> {
94	let mut tx_builder = TransactionBuilder::new(&get_builder_config(ctx)?);
95
96	tx_builder.add_output(&validator_output(parameters, current_utxo, &reserve.scripts, ctx)?)?;
97
98	tx_builder.set_inputs(&reserve_utxo_input_with_validator_script_reference(
99		current_utxo,
100		reserve,
101		ReserveRedeemer::DepositToReserve,
102		&costs.get_one_spend(),
103	)?);
104
105	tx_builder.add_mint_one_script_token_using_reference_script(
106		&governance.policy.script(),
107		&governance.utxo_id_as_tx_input(),
108		&costs,
109	)?;
110
111	tx_builder.add_script_reference_input(
112		&reserve.auth_policy_version_utxo.to_csl_tx_input(),
113		reserve.scripts.auth_policy.bytes.len(),
114	);
115	tx_builder.add_script_reference_input(
116		&reserve.illiquid_circulation_supply_validator_version_utxo.to_csl_tx_input(),
117		reserve.scripts.illiquid_circulation_supply_validator.bytes.len(),
118	);
119	Ok(tx_builder.balance_update_and_build(ctx)?.remove_native_script_witnesses())
120}
121
122// Creates output with reserve token and updated deposit
123fn validator_output(
124	token_amount: &TokenAmount,
125	current_utxo: &OgmiosUtxo,
126	scripts: &ReserveScripts,
127	ctx: &TransactionContext,
128) -> Result<TransactionOutput, JsError> {
129	let amount_builder = TransactionOutputBuilder::new()
130		.with_address(&scripts.validator.address(ctx.network))
131		.with_plutus_data(
132			&current_utxo
133				.get_plutus_data()
134				.expect("Current UTXO datum was parsed hence it exists"),
135		)
136		.next()?;
137	let ma = MultiAsset::new()
138		.with_asset_amount(&token_amount.token, token_amount.amount)?
139		.with_asset_amount(&scripts.auth_policy.empty_name_asset(), 1u64)?;
140
141	amount_builder.with_minimum_ada_and_asset(&ma, ctx)?.build()
142}