partner_chains_cardano_offchain/reserve/
mod.rs

1//! All smart-contracts related to Rewards Token Reserve Management
2
3use crate::{
4	csl::{OgmiosUtxoExt, OgmiosValueExt, TransactionContext},
5	scripts_data,
6};
7use anyhow::anyhow;
8use cardano_serialization_lib::{
9	ExUnits, JsError, PlutusScriptSource, PlutusWitness, Redeemer, RedeemerTag, TxInputsBuilder,
10};
11use init::find_script_utxo;
12use ogmios_client::{query_ledger_state::QueryLedgerState, types::OgmiosUtxo};
13use partner_chains_plutus_data::reserve::{ReserveDatum, ReserveRedeemer};
14use sidechain_domain::{AssetId, AssetName, UtxoId};
15
16pub mod create;
17pub mod deposit;
18pub mod handover;
19pub mod init;
20pub mod release;
21pub mod update_settings;
22
23#[derive(Clone, Debug)]
24pub(crate) struct ReserveData {
25	pub(crate) scripts: scripts_data::ReserveScripts,
26	pub(crate) auth_policy_version_utxo: OgmiosUtxo,
27	pub(crate) validator_version_utxo: OgmiosUtxo,
28	pub(crate) illiquid_circulation_supply_validator_version_utxo: OgmiosUtxo,
29}
30
31#[derive(Clone, Debug)]
32pub(crate) struct ReserveUtxo {
33	pub(crate) utxo: OgmiosUtxo,
34	pub(crate) datum: ReserveDatum,
35}
36
37impl ReserveData {
38	pub(crate) async fn get<T: QueryLedgerState>(
39		genesis_utxo: UtxoId,
40		ctx: &TransactionContext,
41		client: &T,
42	) -> Result<Self, anyhow::Error> {
43		let version_oracle = scripts_data::version_oracle(genesis_utxo, ctx.network)?;
44		let auth_policy_version_utxo = find_script_utxo(
45			raw_scripts::ScriptId::ReserveAuthPolicy as u32,
46			&version_oracle,
47			ctx,
48			client,
49		)
50		.await?
51		.ok_or_else(|| {
52			anyhow!(
53				"Reserve Auth Version Utxo not found, is the Reserve Token Management initialized?"
54			)
55		})?;
56		let validator_version_utxo = find_script_utxo(
57			raw_scripts::ScriptId::ReserveValidator as u32,
58			&version_oracle,
59			ctx,
60			client,
61		)
62		.await?
63		.ok_or_else(|| {
64			anyhow!(
65				"Reserve Validator Version Utxo not found, is the Reserve Token Management initialized?"
66			)
67		})?;
68		let illiquid_circulation_supply_validator_version_utxo = find_script_utxo(
69			raw_scripts::ScriptId::IlliquidCirculationSupplyValidator as u32,
70			&version_oracle,
71			ctx,
72			client,
73		)
74		.await?
75		.ok_or_else(|| {
76			anyhow!("Illiquid Circulation Supply Validator Version Utxo not found, is the Reserve Token Management initialized?")
77		})?;
78		let scripts = scripts_data::reserve_scripts(genesis_utxo, ctx.network)?;
79		Ok(ReserveData {
80			scripts,
81			auth_policy_version_utxo,
82			validator_version_utxo,
83			illiquid_circulation_supply_validator_version_utxo,
84		})
85	}
86
87	pub(crate) async fn get_reserve_utxo<T: QueryLedgerState>(
88		&self,
89		ctx: &TransactionContext,
90		client: &T,
91	) -> Result<ReserveUtxo, anyhow::Error> {
92		let validator_address = self.scripts.validator.address(ctx.network).to_bech32(None)?;
93		let validator_utxos = client.query_utxos(&[validator_address]).await?;
94
95		let auth_token_asset_id = AssetId {
96			policy_id: self.scripts.auth_policy.policy_id(),
97			asset_name: AssetName::empty(),
98		};
99
100		let (reserve_utxo, reserve_settings) = validator_utxos
101			.into_iter()
102			.find_map(|utxo| {
103				if utxo.get_asset_amount(&auth_token_asset_id) != 1u64 {
104					return None;
105				}
106				utxo.get_plutus_data()
107					.and_then(|d| ReserveDatum::try_from(d).ok())
108					.map(|d| (utxo, d))
109			})
110			.ok_or_else(|| {
111				anyhow!("Reserve Utxo not found, is the Reserve Token Management initialized?")
112			})?;
113
114		Ok(ReserveUtxo { utxo: reserve_utxo, datum: reserve_settings })
115	}
116}
117
118pub(crate) struct TokenAmount {
119	pub token: AssetId,
120	pub amount: u64,
121}
122
123pub(crate) fn reserve_utxo_input_with_validator_script_reference(
124	reserve_utxo: &OgmiosUtxo,
125	reserve: &ReserveData,
126	redeemer: ReserveRedeemer,
127	cost: &ExUnits,
128) -> Result<TxInputsBuilder, JsError> {
129	let mut inputs = TxInputsBuilder::new();
130	let input = reserve_utxo.to_csl_tx_input();
131	let amount = reserve_utxo.value.to_csl()?;
132	let script = &reserve.scripts.validator;
133	let witness = PlutusWitness::new_with_ref_without_datum(
134		&PlutusScriptSource::new_ref_input(
135			&script.csl_script_hash(),
136			&reserve.validator_version_utxo.to_csl_tx_input(),
137			&script.language,
138			script.bytes.len(),
139		),
140		&Redeemer::new(&RedeemerTag::new_spend(), &0u32.into(), &redeemer.into(), cost),
141	);
142	inputs.add_plutus_script_input(&witness, &input, &amount);
143	Ok(inputs)
144}