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	versioning_system::find_script_utxo,
7};
8use anyhow::anyhow;
9use cardano_serialization_lib::{
10	ExUnits, JsError, PlutusScriptSource, PlutusWitness, Redeemer, RedeemerTag, TxInputsBuilder,
11};
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}
29
30#[derive(Clone, Debug)]
31pub(crate) struct ReserveUtxo {
32	pub(crate) utxo: OgmiosUtxo,
33	pub(crate) datum: ReserveDatum,
34}
35
36impl ReserveData {
37	pub(crate) async fn get<T: QueryLedgerState>(
38		genesis_utxo: UtxoId,
39		ctx: &TransactionContext,
40		client: &T,
41	) -> Result<Self, anyhow::Error> {
42		let version_oracle = scripts_data::version_oracle(genesis_utxo, ctx.network)?;
43		let auth_policy_version_utxo = find_script_utxo(
44			raw_scripts::ScriptId::ReserveAuthPolicy,
45			&version_oracle,
46			ctx,
47			client,
48		)
49		.await?
50		.ok_or_else(|| {
51			anyhow!(
52				"Reserve Auth Version Utxo not found, is the Reserve Token Management initialized?"
53			)
54		})?;
55		let validator_version_utxo =
56			find_script_utxo(raw_scripts::ScriptId::ReserveValidator, &version_oracle, ctx, client)
57				.await?
58				.ok_or_else(|| {
59					anyhow!(
60						"Reserve Validator Version Utxo not found, is the Reserve Token Management initialized?"
61					)
62				})?;
63		let scripts = scripts_data::reserve_scripts(genesis_utxo, ctx.network)?;
64		Ok(ReserveData { scripts, auth_policy_version_utxo, validator_version_utxo })
65	}
66
67	pub(crate) async fn get_reserve_utxo<T: QueryLedgerState>(
68		&self,
69		ctx: &TransactionContext,
70		client: &T,
71	) -> Result<ReserveUtxo, anyhow::Error> {
72		let validator_address = self.scripts.validator.address(ctx.network).to_bech32(None)?;
73		let validator_utxos = client.query_utxos(&[validator_address]).await?;
74
75		let auth_token_asset_id = AssetId {
76			policy_id: self.scripts.auth_policy.policy_id(),
77			asset_name: AssetName::empty(),
78		};
79
80		let (reserve_utxo, reserve_settings) = validator_utxos
81			.into_iter()
82			.find_map(|utxo| {
83				if utxo.get_asset_amount(&auth_token_asset_id) != 1u64 {
84					return None;
85				}
86				utxo.get_plutus_data()
87					.and_then(|d| ReserveDatum::try_from(d).ok())
88					.map(|d| (utxo, d))
89			})
90			.ok_or_else(|| {
91				anyhow!("Reserve Utxo not found, is the Reserve Token Management initialized?")
92			})?;
93
94		Ok(ReserveUtxo { utxo: reserve_utxo, datum: reserve_settings })
95	}
96}
97
98pub(crate) fn reserve_utxo_input_with_validator_script_reference(
99	reserve_utxo: &OgmiosUtxo,
100	reserve: &ReserveData,
101	redeemer: ReserveRedeemer,
102	cost: &ExUnits,
103) -> Result<TxInputsBuilder, JsError> {
104	let mut inputs = TxInputsBuilder::new();
105	add_reserve_utxo_input_with_validator_script_reference(
106		&mut inputs,
107		reserve_utxo,
108		reserve,
109		redeemer,
110		cost,
111	)?;
112	Ok(inputs)
113}
114
115pub(crate) fn add_reserve_utxo_input_with_validator_script_reference(
116	inputs: &mut TxInputsBuilder,
117	reserve_utxo: &OgmiosUtxo,
118	reserve: &ReserveData,
119	redeemer: ReserveRedeemer,
120	cost: &ExUnits,
121) -> Result<(), JsError> {
122	let input = reserve_utxo.to_csl_tx_input();
123	let amount = reserve_utxo.value.to_csl()?;
124	let script = &reserve.scripts.validator;
125	let witness = PlutusWitness::new_with_ref_without_datum(
126		&PlutusScriptSource::new_ref_input(
127			&script.csl_script_hash(),
128			&reserve.validator_version_utxo.to_csl_tx_input(),
129			&script.language,
130			script.bytes.len(),
131		),
132		&Redeemer::new(&RedeemerTag::new_spend(), &0u32.into(), &redeemer.into(), cost),
133	);
134	inputs.add_plutus_script_input(&witness, &input, &amount);
135	Ok(())
136}