From dbc4949b59e759868ace7f25c56dd68ab5892782 Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Tue, 4 Nov 2025 19:09:05 +0100 Subject: [PATCH 001/146] fix react bug nullish check --- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 25d4734ee1..cb29ef6ffe 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -175,6 +175,10 @@ export function StateAlert({ timelock: ExpiredTimelocks | null; isRunning: boolean; }) { + if (swap == null) { + return null; + } + switch (swap.state_name) { // This is the state where the swap is safe because the other party has redeemed the Bitcoin // It cannot be punished anymore @@ -243,7 +247,11 @@ export default function SwapStatusAlert({ swap: GetSwapInfoResponseExt | null; onlyShowIfUnusualAmountOfTimeHasPassed?: boolean; }) { +<<<<<<< HEAD const swapId = swap?.swap_id ?? null; +======= + const swapId = swap?.swap_id ?? ""; +>>>>>>> b539b31b (fix react bug nullish check) const timelock = useAppSelector(selectSwapTimelock(swapId)); const isRunning = useIsSpecificSwapRunning(swapId); @@ -269,7 +277,7 @@ export default function SwapStatusAlert({ return ( +<<<<<<< HEAD Swap {swap.swap_id} is not running +======= + Swap {swapId} is not running +>>>>>>> b539b31b (fix react bug nullish check) )} From f46f4ee0696a0b30221ab032a391b4c3e6860a4d Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Tue, 4 Nov 2025 19:55:47 +0100 Subject: [PATCH 002/146] add tx_refund_amnesty --- swap-core/src/bitcoin.rs | 2 + swap-core/src/bitcoin/cancel.rs | 36 ++++++++ swap-core/src/bitcoin/refund.rs | 67 ++++++++++++-- swap-core/src/bitcoin/refund_amnesty.rs | 118 ++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 swap-core/src/bitcoin/refund_amnesty.rs diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 113195cae4..e3bf6011d0 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -6,6 +6,7 @@ mod lock; mod punish; mod redeem; mod refund; +mod refund_amnesty; mod timelocks; pub use crate::bitcoin::cancel::TxCancel; @@ -14,6 +15,7 @@ pub use crate::bitcoin::lock::TxLock; pub use crate::bitcoin::punish::TxPunish; pub use crate::bitcoin::redeem::TxRedeem; pub use crate::bitcoin::refund::TxRefund; +pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock}; pub use ::bitcoin::amount::Amount; diff --git a/swap-core/src/bitcoin/cancel.rs b/swap-core/src/bitcoin/cancel.rs index a04d3898be..3dbb892c31 100644 --- a/swap-core/src/bitcoin/cancel.rs +++ b/swap-core/src/bitcoin/cancel.rs @@ -193,6 +193,42 @@ impl TxCancel { } } + pub fn build_refund_with_amnesty_transaction( + &self, + refund_address: &Address, + amnesty_descriptor: &Descriptor<::bitcoin::PublicKey>, + amnesty_amount: Amount, + spending_fee: Amount, + ) -> Transaction { + let previous_output = self.as_outpoint(); + + let tx_in = TxIn { + previous_output, + script_sig: Default::default(), + sequence: Sequence(0xFFFF_FFFF), + witness: Default::default(), + }; + + let refund_amount = self.amount() - amnesty_amount - spending_fee; + + let tx_out_refund = TxOut { + value: refund_amount, + script_pubkey: refund_address.script_pubkey(), + }; + + let tx_out_amnesty = TxOut { + value: amnesty_amount, + script_pubkey: amnesty_descriptor.script_pubkey(), + }; + + Transaction { + version: Version(2), + lock_time: PackedLockTime::from_height(0).expect("0 to be below lock time threshold"), + input: vec![tx_in], + output: vec![tx_out_refund, tx_out_amnesty], + } + } + pub fn weight() -> Weight { Weight::from_wu(596) } diff --git a/swap-core/src/bitcoin/refund.rs b/swap-core/src/bitcoin/refund.rs index 77fe2080ab..27bee44892 100644 --- a/swap-core/src/bitcoin/refund.rs +++ b/swap-core/src/bitcoin/refund.rs @@ -2,8 +2,8 @@ use crate::bitcoin; use crate::bitcoin::{ - verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, - TooManyInputs, Transaction, TxCancel, + build_shared_output_descriptor, verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, + NotThreeWitnesses, PublicKey, TooManyInputs, Transaction, TxCancel, }; use ::bitcoin::sighash::SighashCache; use ::bitcoin::{secp256k1, ScriptBuf, Weight}; @@ -23,16 +23,32 @@ pub struct TxRefund { inner: Transaction, digest: Sighash, cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>, + pub(in crate::bitcoin) amnesty_output_descriptor: Descriptor<::bitcoin::PublicKey>, watch_script: ScriptBuf, } impl TxRefund { - pub fn new(tx_cancel: &TxCancel, refund_address: &Address, spending_fee: Amount) -> Self { - let tx_refund = tx_cancel.build_spend_transaction(refund_address, None, spending_fee); + pub fn new( + tx_cancel: &TxCancel, + refund_address: &Address, + A: PublicKey, + B: PublicKey, + amnesty_amount: Amount, + spending_fee: Amount, + ) -> Result { + let amnesty_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; + + let tx_refund = tx_cancel.build_refund_with_amnesty_transaction( + refund_address, + &amnesty_output_descriptor, + amnesty_amount, + spending_fee, + ); let digest = SighashCache::new(&tx_refund) .p2wsh_signature_hash( - 0, // Only one input: cancel transaction + // Only one input: cancel transaction + 0, &tx_cancel .output_descriptor .script_code() @@ -42,12 +58,13 @@ impl TxRefund { ) .expect("sighash"); - Self { + Ok(Self { inner: tx_refund, digest, cancel_output_descriptor: tx_cancel.output_descriptor.clone(), + amnesty_output_descriptor, watch_script: refund_address.script_pubkey(), - } + }) } pub fn txid(&self) -> Txid { @@ -58,6 +75,41 @@ impl TxRefund { self.digest } + pub fn amnesty_amount(&self) -> Amount { + self.inner.output[1].value + } + + pub fn amnesty_outpoint(&self) -> ::bitcoin::OutPoint { + ::bitcoin::OutPoint::new(self.txid(), 1) + } + + pub fn build_amnesty_spend_transaction( + &self, + refund_address: &Address, + spending_fee: Amount, + ) -> Transaction { + use ::bitcoin::{transaction::Version, locktime::absolute::LockTime as PackedLockTime, Sequence, TxIn, TxOut}; + + let tx_in = TxIn { + previous_output: self.amnesty_outpoint(), + script_sig: Default::default(), + sequence: Sequence(0xFFFF_FFFF), + witness: Default::default(), + }; + + let tx_out = TxOut { + value: self.amnesty_amount() - spending_fee, + script_pubkey: refund_address.script_pubkey(), + }; + + Transaction { + version: Version(2), + lock_time: PackedLockTime::from_height(0).expect("0 to be below lock time threshold"), + input: vec![tx_in], + output: vec![tx_out], + } + } + pub fn add_signatures( self, (A, sig_a): (PublicKey, Signature), @@ -77,6 +129,7 @@ impl TxRefund { let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; + // The order in which these are inserted doesn't matter satisfier.insert( A, diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/refund_amnesty.rs new file mode 100644 index 0000000000..ef4e2a6e87 --- /dev/null +++ b/swap-core/src/bitcoin/refund_amnesty.rs @@ -0,0 +1,118 @@ +use crate::bitcoin; +use crate::bitcoin::{ + verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, + TooManyInputs, Transaction, TxRefund, +}; +use ::bitcoin::sighash::SighashCache; +use ::bitcoin::{secp256k1, ScriptBuf, Weight}; +use ::bitcoin::{sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, Txid}; +use anyhow::{bail, Context, Result}; +use bdk_wallet::miniscript::Descriptor; +use bitcoin_wallet::primitives::Watchable; +use curve25519_dalek::scalar::Scalar; +use ecdsa_fun::Signature; +use std::collections::HashMap; +use std::sync::Arc; + +use super::extract_ecdsa_sig; + +#[derive(Debug, Clone)] +pub struct TxRefundAmnesty { + inner: Transaction, + digest: Sighash, + amensty_output_descriptor: Descriptor<::bitcoin::PublicKey>, + watch_script: ScriptBuf, +} + +impl TxRefundAmnesty { + pub fn new(tx_refund: &TxRefund, refund_address: &Address, spending_fee: Amount) -> Self { + let tx_refund_amnesty = tx_refund.build_amnesty_spend_transaction(refund_address, spending_fee); + + let digest = SighashCache::new(&tx_refund_amnesty) + .p2wsh_signature_hash( + 0, // Only one input: amnesty box from tx_refund + &tx_refund + .amnesty_output_descriptor + .script_code() + .expect("scriptcode"), + tx_refund.amnesty_amount(), + EcdsaSighashType::All, + ) + .expect("sighash"); + + Self { + inner: tx_refund_amnesty, + digest, + amensty_output_descriptor: tx_refund.amnesty_output_descriptor.clone(), + watch_script: refund_address.script_pubkey(), + } + } + + pub fn txid(&self) -> Txid { + self.inner.compute_txid() + } + + pub fn digest(&self) -> Sighash { + self.digest + } + + pub fn add_signatures( + self, + (A, sig_a): (PublicKey, Signature), + (B, sig_b): (PublicKey, Signature), + ) -> Result { + let satisfier = { + let mut satisfier = HashMap::with_capacity(2); + + let A = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, + }; + let B = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, + }; + + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; + + // The order in which these are inserted doesn't matter + satisfier.insert( + A, + ::bitcoin::ecdsa::Signature { + signature: sig_a, + sighash_type: EcdsaSighashType::All, + }, + ); + satisfier.insert( + B, + ::bitcoin::ecdsa::Signature { + signature: sig_b, + sighash_type: EcdsaSighashType::All, + }, + ); + + satisfier + }; + + let mut tx_refund = self.inner; + self.amensty_output_descriptor + .satisfy(&mut tx_refund.input[0], satisfier)?; + + Ok(tx_refund) + } + + pub fn weight() -> Weight { + Weight::from_wu(548) + } +} + +impl Watchable for TxRefundAmnesty { + fn id(&self) -> Txid { + self.txid() + } + + fn script(&self) -> ScriptBuf { + self.watch_script.clone() + } +} From 95b9e3212b1b7477a4bea58179715d3cb6609384 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 1 Dec 2025 18:28:01 +0100 Subject: [PATCH 003/146] move TxPartialRefund to partial_refund.rs and TxFullRefund to full_refund.rs and add backwards compatible BobRefundType for abstracting over refund signatures --- swap-core/src/bitcoin.rs | 5 +- swap-core/src/bitcoin/full_refund.rs | 177 ++++++++++++++++++ .../bitcoin/{refund.rs => partial_refund.rs} | 6 +- swap-core/src/bitcoin/refund_amnesty.rs | 13 +- swap-machine/src/alice/mod.rs | 8 +- swap-machine/src/bob/mod.rs | 104 +++++++++- swap/src/bitcoin/wallet.rs | 4 +- swap/src/protocol/bob/swap.rs | 4 +- 8 files changed, 292 insertions(+), 29 deletions(-) create mode 100644 swap-core/src/bitcoin/full_refund.rs rename swap-core/src/bitcoin/{refund.rs => partial_refund.rs} (98%) diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index e3bf6011d0..c74f437c48 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -5,7 +5,8 @@ mod early_refund; mod lock; mod punish; mod redeem; -mod refund; +mod full_refund; +mod partial_refund; mod refund_amnesty; mod timelocks; @@ -14,7 +15,7 @@ pub use crate::bitcoin::early_refund::TxEarlyRefund; pub use crate::bitcoin::lock::TxLock; pub use crate::bitcoin::punish::TxPunish; pub use crate::bitcoin::redeem::TxRedeem; -pub use crate::bitcoin::refund::TxRefund; +pub use crate::bitcoin::full_refund::TxFullRefund; pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock}; diff --git a/swap-core/src/bitcoin/full_refund.rs b/swap-core/src/bitcoin/full_refund.rs new file mode 100644 index 0000000000..5e36ce875a --- /dev/null +++ b/swap-core/src/bitcoin/full_refund.rs @@ -0,0 +1,177 @@ +#![allow(non_snake_case)] + +use crate::bitcoin; +use crate::bitcoin::{ + verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, + TooManyInputs, Transaction, TxCancel, +}; +use ::bitcoin::sighash::SighashCache; +use ::bitcoin::{secp256k1, ScriptBuf, Weight}; +use ::bitcoin::{sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, Txid}; +use anyhow::{bail, Context, Result}; +use bdk_wallet::miniscript::Descriptor; +use bitcoin_wallet::primitives::Watchable; +use curve25519_dalek::scalar::Scalar; +use ecdsa_fun::Signature; +use std::collections::HashMap; +use std::sync::Arc; + +use super::extract_ecdsa_sig; + +/// A transaction that refunds 100% of the locked Bitcoin. +/// Previously to the partial refund protocol change, this was the only type of refund transaction. +/// +/// Now there also is the partial refund transaction, which refunds only a portion of the locked Bitcoin. +/// For more information, see [#675](https://github.com/eigenwallet/core/pull/675). +/// +/// The main reason this struct is still here is to 1) keep backwards compatibility in the database +/// and 2) avoid having to pay fees for 2 Bitcoin transactions when we want to get a full refund anyway. +#[derive(Debug, Clone)] +pub struct TxFullRefund { + inner: Transaction, + digest: Sighash, + cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>, + watch_script: ScriptBuf, +} + +impl TxFullRefund { + pub fn new(tx_cancel: &TxCancel, refund_address: &Address, spending_fee: Amount) -> Self { + let tx_refund = tx_cancel.build_spend_transaction(refund_address, None, spending_fee); + + let digest = SighashCache::new(&tx_refund) + .p2wsh_signature_hash( + 0, // Only one input: cancel transaction + &tx_cancel + .output_descriptor + .script_code() + .expect("scriptcode"), + tx_cancel.amount(), + EcdsaSighashType::All, + ) + .expect("sighash"); + + Self { + inner: tx_refund, + digest, + cancel_output_descriptor: tx_cancel.output_descriptor.clone(), + watch_script: refund_address.script_pubkey(), + } + } + + pub fn txid(&self) -> Txid { + self.inner.compute_txid() + } + + pub fn digest(&self) -> Sighash { + self.digest + } + + pub fn add_signatures( + self, + (A, sig_a): (PublicKey, Signature), + (B, sig_b): (PublicKey, Signature), + ) -> Result { + let satisfier = { + let mut satisfier = HashMap::with_capacity(2); + + let A = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, + }; + let B = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, + }; + + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; + // The order in which these are inserted doesn't matter + satisfier.insert( + A, + ::bitcoin::ecdsa::Signature { + signature: sig_a, + sighash_type: EcdsaSighashType::All, + }, + ); + satisfier.insert( + B, + ::bitcoin::ecdsa::Signature { + signature: sig_b, + sighash_type: EcdsaSighashType::All, + }, + ); + + satisfier + }; + + let mut tx_refund = self.inner; + self.cancel_output_descriptor + .satisfy(&mut tx_refund.input[0], satisfier)?; + + Ok(tx_refund) + } + + pub fn extract_monero_private_key( + &self, + signed_refund_tx: Arc, + s_a: Scalar, + a: bitcoin::SecretKey, + S_b_bitcoin: bitcoin::PublicKey, + ) -> Result { + let tx_refund_sig = self + .extract_signature_by_key(signed_refund_tx, a.public()) + .context("Failed to extract signature from Bitcoin refund tx")?; + let tx_refund_encsig = a.encsign(S_b_bitcoin, self.digest()); + + let s_b = bitcoin::recover(S_b_bitcoin, tx_refund_sig, tx_refund_encsig) + .context("Failed to recover Monero secret key from Bitcoin signature")?; + + let s_b = crate::monero::primitives::private_key_from_secp256k1_scalar(s_b.into()); + + let spend_key = s_a + s_b; + + Ok(spend_key) + } + + fn extract_signature_by_key( + &self, + candidate_transaction: Arc, + B: PublicKey, + ) -> Result { + let input = match candidate_transaction.input.as_slice() { + [input] => input, + [] => bail!(NoInputs), + inputs => bail!(TooManyInputs(inputs.len())), + }; + + let sigs = match input.witness.to_vec().as_slice() { + [sig_1, sig_2, _script] => [sig_1, sig_2] + .into_iter() + .map(|sig| extract_ecdsa_sig(sig)) + .collect::, _>>(), + [] => bail!(EmptyWitnessStack), + witnesses => bail!(NotThreeWitnesses(witnesses.len())), + }?; + + let sig = sigs + .into_iter() + .find(|sig| verify_sig(&B, &self.digest(), sig).is_ok()) + .context("Neither signature on witness stack verifies against B")?; + + Ok(sig) + } + + pub fn weight() -> Weight { + Weight::from_wu(548) + } +} + +impl Watchable for TxFullRefund { + fn id(&self) -> Txid { + self.txid() + } + + fn script(&self) -> ScriptBuf { + self.watch_script.clone() + } +} diff --git a/swap-core/src/bitcoin/refund.rs b/swap-core/src/bitcoin/partial_refund.rs similarity index 98% rename from swap-core/src/bitcoin/refund.rs rename to swap-core/src/bitcoin/partial_refund.rs index 27bee44892..50d93e9554 100644 --- a/swap-core/src/bitcoin/refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use super::extract_ecdsa_sig; #[derive(Debug, Clone)] -pub struct TxRefund { +pub struct TxPartialRefund { inner: Transaction, digest: Sighash, cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>, @@ -27,7 +27,7 @@ pub struct TxRefund { watch_script: ScriptBuf, } -impl TxRefund { +impl TxPartialRefund { pub fn new( tx_cancel: &TxCancel, refund_address: &Address, @@ -211,7 +211,7 @@ impl TxRefund { } } -impl Watchable for TxRefund { +impl Watchable for TxPartialRefund { fn id(&self) -> Txid { self.txid() } diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/refund_amnesty.rs index ef4e2a6e87..3ffc3c04ea 100644 --- a/swap-core/src/bitcoin/refund_amnesty.rs +++ b/swap-core/src/bitcoin/refund_amnesty.rs @@ -1,20 +1,15 @@ -use crate::bitcoin; +use crate::bitcoin::partial_refund::TxPartialRefund; use crate::bitcoin::{ - verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, - TooManyInputs, Transaction, TxRefund, + Address, Amount, PublicKey, Transaction, }; use ::bitcoin::sighash::SighashCache; use ::bitcoin::{secp256k1, ScriptBuf, Weight}; use ::bitcoin::{sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, Txid}; -use anyhow::{bail, Context, Result}; +use anyhow::Result; use bdk_wallet::miniscript::Descriptor; use bitcoin_wallet::primitives::Watchable; -use curve25519_dalek::scalar::Scalar; use ecdsa_fun::Signature; use std::collections::HashMap; -use std::sync::Arc; - -use super::extract_ecdsa_sig; #[derive(Debug, Clone)] pub struct TxRefundAmnesty { @@ -25,7 +20,7 @@ pub struct TxRefundAmnesty { } impl TxRefundAmnesty { - pub fn new(tx_refund: &TxRefund, refund_address: &Address, spending_fee: Amount) -> Self { + pub fn new(tx_refund: &TxPartialRefund, refund_address: &Address, spending_fee: Amount) -> Self { let tx_refund_amnesty = tx_refund.build_amnesty_spend_transaction(refund_address, spending_fee); let digest = SighashCache::new(&tx_refund_amnesty) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 72390a6eda..ebabb79c07 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -9,7 +9,7 @@ use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, - TxEarlyRefund, TxPunish, TxRedeem, TxRefund, Txid, + TxEarlyRefund, TxPunish, TxRedeem, TxFullRefund, Txid, }; use swap_core::monero; use swap_core::monero::primitives::{BlockHeight, TransferProof, TransferRequest, WatchRequest}; @@ -348,7 +348,7 @@ impl State2 { .expect("valid cancel tx"); let tx_refund = - swap_core::bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + swap_core::bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); // Alice encsigns the refund transaction(bitcoin) digest with Bob's monero // pubkey(S_b). The refund transaction spends the output of // tx_lock_bitcoin to Bob's refund address. @@ -535,8 +535,8 @@ impl State3 { .expect("valid cancel tx") } - pub fn tx_refund(&self) -> TxRefund { - swap_core::bitcoin::TxRefund::new( + pub fn tx_refund(&self) -> TxFullRefund { + swap_core::bitcoin::TxFullRefund::new( &self.tx_cancel(), &self.refund_address, self.tx_refund_fee, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 28c678801f..dbf725ea86 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -66,6 +66,30 @@ pub enum BobState { SafelyAborted, } +/// !IMPORTANT: This enum must be #[untagged] and maintain the field names in order to be backwards compatible +/// with the database. +/// Changing any of that is a breaking change +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum BobRefundType { + /// Alice has only signed the partial refund transaction (most cases). + Partial { + tx_partial_refund_encsig: bitcoin::EncryptedSignature, + }, + /// Alice has signed both the partial and full refund transactions. + Full { + tx_partial_refund_encsig: bitcoin::EncryptedSignature, + tx_refund_encsig: bitcoin::EncryptedSignature, + }, + /// Alice has only signed the full refund transaction. + /// This is only used to maintain backwards compatibility for older swaps + /// from before the partial refund protocol change. + /// See [#675](https://github.com/eigenwallet/core/pull/675). + Legacy { + tx_refund_encsig: bitcoin::EncryptedSignature, + } +} + impl fmt::Display for BobState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -311,7 +335,7 @@ impl State1 { )?; let tx_refund = - bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_encsig( @@ -366,7 +390,14 @@ pub struct State2 { punish_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, tx_cancel_sig_a: Signature, - tx_refund_encsig: bitcoin::EncryptedSignature, + /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). + /// It boils down to the same json except that it now may also contain a partial refund signature. + #[serde(flatten)] + bob_refund_type: BobRefundType, + /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). + /// It allows Bob to retrieve the refund fee introduced in the PR. + /// This signature is voluntarily revealed by alice. + tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, @@ -456,7 +487,14 @@ pub struct State3 { redeem_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, tx_cancel_sig_a: Signature, - tx_refund_encsig: bitcoin::EncryptedSignature, + /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). + /// It boils down to the same json except that it now may also contain a partial refund signature. + #[serde(flatten)] + bob_refund_type: BobRefundType, + /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). + /// It allows Bob to retrieve the refund fee introduced in the PR. + /// This signature is voluntarily revealed by alice. + tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, @@ -593,7 +631,14 @@ pub struct State4 { redeem_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, tx_cancel_sig_a: Signature, - tx_refund_encsig: bitcoin::EncryptedSignature, + /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). + /// It boils down to the same json except that it now may also contain a partial refund signature. + #[serde(flatten)] + bob_refund_type: BobRefundType, + /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). + /// It allows Bob to retrieve the refund fee introduced in the PR. + /// This signature is voluntarily revealed by alice. + tx_refund_amnesty_sig: Option, monero_wallet_restore_blockheight: BlockHeight, lock_transfer_proof: TransferProof, #[serde(with = "::bitcoin::amount::serde::as_sat")] @@ -767,7 +812,14 @@ pub struct State6 { refund_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, tx_cancel_sig_a: Signature, - tx_refund_encsig: bitcoin::EncryptedSignature, + /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). + /// It boils down to the same json except that it now may also contain a partial refund signature. + #[serde(flatten)] + bob_refund_type: BobRefundType, + /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). + /// It allows Bob to retrieve the refund fee introduced in the PR. + /// This signature is voluntarily revealed by alice. + tx_refund_amnesty_sig: Option, #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] @@ -847,11 +899,11 @@ impl State6 { Ok(signed_tx_refund_txid) } - pub fn construct_tx_refund(&self) -> Result { + pub fn construct_tx_refund(&self) -> Result { let tx_cancel = self.construct_tx_cancel()?; let tx_refund = - bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); Ok(tx_refund) } @@ -911,3 +963,41 @@ impl State6 { Ok(tx) } } + +impl BobRefundType { + pub fn legacy_full_refund(full_refund_encsig: bitcoin::EncryptedSignature) -> Self { + Self::Legacy { tx_refund_encsig: full_refund_encsig } + } + + pub fn partial_refund(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { + Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } + } + + pub fn full_refund(partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: bitcoin::EncryptedSignature) -> Self { + Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_refund_encsig: full_refund_encsig } + } + + pub fn upgrade_with_full_refund(&self, full_refund_encsig: bitcoin::EncryptedSignature) -> Self { + match self { + BobRefundType::Partial { tx_partial_refund_encsig } => BobRefundType::Full { tx_partial_refund_encsig: tx_partial_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, + BobRefundType::Full { tx_partial_refund_encsig, .. } => BobRefundType::Full { tx_partial_refund_encsig: tx_partial_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, + BobRefundType::Legacy { tx_refund_encsig } => BobRefundType::Full { tx_partial_refund_encsig: tx_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, + } + } + + pub fn tx_full_refund_encsig(&self) -> Option { + match self { + BobRefundType::Partial { .. } => None, + BobRefundType::Full { tx_refund_encsig, .. } => Some(tx_refund_encsig.clone()), + BobRefundType::Legacy { tx_refund_encsig } => Some(tx_refund_encsig.clone()), + } + } + + pub fn tx_partial_refund_encsig(&self) -> Option { + match self { + BobRefundType::Partial { tx_partial_refund_encsig } => Some(tx_partial_refund_encsig.clone()), + BobRefundType::Full { tx_partial_refund_encsig, .. } => Some(tx_partial_refund_encsig.clone()), + BobRefundType::Legacy { .. } => None, + } + } +} diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index c1148fc578..a4a97d9595 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3810,7 +3810,7 @@ mod swap_core_bitcoin_tests { assert_weight(redeem_transaction, TxRedeem::weight().to_wu(), "TxRedeem"); assert_weight(cancel_transaction, TxCancel::weight().to_wu(), "TxCancel"); assert_weight(punish_transaction, TxPunish::weight().to_wu(), "TxPunish"); - assert_weight(refund_transaction, TxRefund::weight().to_wu(), "TxRefund"); + assert_weight(refund_transaction, TxFullRefund::weight().to_wu(), "TxRefund"); // Test TxEarlyRefund transaction let early_refund_transaction = alice_state3 @@ -3932,7 +3932,7 @@ mod swap_core_bitcoin_tests { // It should be the same as TxRedeem and TxRefund weights since they have similar structure assert_eq!(TxEarlyRefund::weight() as u64, TxRedeem::weight().to_wu()); - assert_eq!(TxEarlyRefund::weight() as u64, TxRefund::weight().to_wu()); + assert_eq!(TxEarlyRefund::weight() as u64, TxFullRefund::weight().to_wu()); } // Weights fluctuate because of the length of the signatures. Valid ecdsa diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 46a86c9d69..ccfbea4933 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -11,7 +11,7 @@ use crate::protocol::{bob, Database}; use anyhow::{Context as AnyContext, Result}; use std::sync::Arc; use std::time::Duration; -use swap_core::bitcoin::{ExpiredTimelocks, TxCancel, TxRefund}; +use swap_core::bitcoin::{ExpiredTimelocks, TxCancel, TxFullRefund}; use swap_core::monero::TxHash; use swap_env::env; use swap_machine::bob::State5; @@ -107,7 +107,7 @@ async fn next_state( tx_lock_fee, } => { let tx_refund_fee = bitcoin_wallet - .estimate_fee(TxRefund::weight(), Some(btc_amount)) + .estimate_fee(TxFullRefund::weight(), Some(btc_amount)) .await?; let tx_cancel_fee = bitcoin_wallet .estimate_fee(TxCancel::weight(), Some(btc_amount)) From 2d8f8438bc00e71ad42d3f7ced2e4b4bcf49104d Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 11:06:37 +0100 Subject: [PATCH 004/146] remove unnecessary functions on BobRefundType --- swap-core/src/bitcoin.rs | 1 + swap-machine/src/bob/mod.rs | 19 ++----------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index c74f437c48..ab9d102c89 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -12,6 +12,7 @@ mod timelocks; pub use crate::bitcoin::cancel::TxCancel; pub use crate::bitcoin::early_refund::TxEarlyRefund; +pub use crate::bitcoin::partial_refund::TxPartialRefund; pub use crate::bitcoin::lock::TxLock; pub use crate::bitcoin::punish::TxPunish; pub use crate::bitcoin::redeem::TxRedeem; diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index dbf725ea86..17d0ea33a4 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -334,6 +334,7 @@ impl State1 { self.tx_cancel_fee, )?; + // TODO: send and receive and verify _partial_ refund signature instead of full refund signature. let tx_refund = bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); @@ -965,26 +966,10 @@ impl State6 { } impl BobRefundType { - pub fn legacy_full_refund(full_refund_encsig: bitcoin::EncryptedSignature) -> Self { - Self::Legacy { tx_refund_encsig: full_refund_encsig } - } - - pub fn partial_refund(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { + pub fn from_partial_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } } - pub fn full_refund(partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: bitcoin::EncryptedSignature) -> Self { - Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_refund_encsig: full_refund_encsig } - } - - pub fn upgrade_with_full_refund(&self, full_refund_encsig: bitcoin::EncryptedSignature) -> Self { - match self { - BobRefundType::Partial { tx_partial_refund_encsig } => BobRefundType::Full { tx_partial_refund_encsig: tx_partial_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, - BobRefundType::Full { tx_partial_refund_encsig, .. } => BobRefundType::Full { tx_partial_refund_encsig: tx_partial_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, - BobRefundType::Legacy { tx_refund_encsig } => BobRefundType::Full { tx_partial_refund_encsig: tx_refund_encsig.clone(), tx_refund_encsig: full_refund_encsig }, - } - } - pub fn tx_full_refund_encsig(&self) -> Option { match self { BobRefundType::Partial { .. } => None, From 6cdf50721b6ec711211295d3edd4c9663164ea87 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 11:27:47 +0100 Subject: [PATCH 005/146] move run_swap_setup of alice into seperate function --- swap-p2p/src/protocols/swap_setup/alice.rs | 293 +++++++++++---------- 1 file changed, 157 insertions(+), 136 deletions(-) diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 42a8bf4cff..7123aa084f 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -297,7 +297,7 @@ where ConnectionEvent::FullyNegotiatedInbound(substream) => { self.keep_alive_until = None; - let mut substream = substream.protocol; + let substream = substream.protocol; let (sender, receiver) = bmrng::channel_with_timeout::< bitcoin::Amount, @@ -307,145 +307,22 @@ where let resume_only = self.resume_only; let min_buy = self.min_buy; let max_buy = self.max_buy; - let latest_rate = self.latest_rate.latest_rate(); + let latest_rate = self.latest_rate.latest_rate().map_err(anyhow::Error::from); let env_config = self.env_config; // We wrap the entire handshake in a timeout future - let protocol = tokio::time::timeout(self.negotiation_timeout, async move { - let request = swap_setup::read_cbor_message::(&mut substream) - .await - .context("Failed to read spot price request")?; - - let wallet_snapshot = sender - .send_receive(request.btc) - .await - .context("Failed to receive wallet snapshot")?; - - // wrap all of these into another future so we can `return` from all the - // different blocks - let validate = async { - if resume_only { - return Err(Error::ResumeOnlyMode); - }; - - let blockchain_network = BlockchainNetwork { - bitcoin: env_config.bitcoin_network, - monero: env_config.monero_network, - }; - - if request.blockchain_network != blockchain_network { - return Err(Error::BlockchainNetworkMismatch { - cli: request.blockchain_network, - asb: blockchain_network, - }); - } - - let btc = request.btc; - - if btc < min_buy { - return Err(Error::AmountBelowMinimum { - min: min_buy, - buy: btc, - }); - } - - if btc > max_buy { - return Err(Error::AmountAboveMaximum { - max: max_buy, - buy: btc, - }); - } - - let rate = - latest_rate.map_err(|e| Error::LatestRateFetchFailed(Box::new(e)))?; - let xmr = rate - .sell_quote(btc) - .map_err(Error::SellQuoteCalculationFailed)?; - - let unlocked = wallet_snapshot.unlocked_balance; - - let needed_balance = xmr + wallet_snapshot.lock_fee.into(); - if unlocked.as_piconero() < needed_balance.as_pico() { - tracing::warn!( - unlocked_balance = %unlocked, - needed_balance = %needed_balance, - "Rejecting swap, unlocked balance too low" - ); - return Err(Error::BalanceTooLow { - balance: wallet_snapshot.unlocked_balance, - buy: btc, - }); - } - - Ok(xmr) - }; - - let result = validate.await; - - let converted_result = match result { - Ok(xmr) => Ok(xmr.into()), - Err(e) => Err(e), - }; - swap_setup::write_cbor_message( - &mut substream, - SpotPriceResponse::from_result_ref(&converted_result), - ) - .await - .context("Failed to write spot price response")?; - - let xmr = converted_result?; - - let state0 = State0::new( - request.btc, - xmr, + let protocol = tokio::time::timeout( + self.negotiation_timeout, + run_swap_setup( + substream, + sender, + resume_only, env_config, - wallet_snapshot.redeem_address, - wallet_snapshot.punish_address, - wallet_snapshot.redeem_fee, - wallet_snapshot.punish_fee, - &mut rand::thread_rng(), - ); - - let message0 = swap_setup::read_cbor_message::(&mut substream) - .await - .context("Failed to read message0")?; - let (swap_id, state1) = state0 - .receive(message0) - .context("Failed to transition state0 -> state1 using message0")?; - - swap_setup::write_cbor_message(&mut substream, state1.next_message()) - .await - .context("Failed to send message1")?; - - let message2 = swap_setup::read_cbor_message::(&mut substream) - .await - .context("Failed to read message2")?; - let state2 = state1 - .receive(message2) - .context("Failed to transition state1 -> state2 using message2")?; - - swap_setup::write_cbor_message(&mut substream, state2.next_message()) - .await - .context("Failed to send message3")?; - - let message4 = swap_setup::read_cbor_message::(&mut substream) - .await - .context("Failed to read message4")?; - let state3 = state2 - .receive(message4) - .context("Failed to transition state2 -> state3 using message4")?; - - substream - .flush() - .await - .context("Failed to flush substream after all messages were sent")?; - substream - .close() - .await - .context("Failed to close substream after all messages were sent")?; - - Ok((swap_id, state3)) - }); + min_buy, + max_buy, + latest_rate, + ), + ); let max_seconds = self.negotiation_timeout.as_secs(); self.inbound_stream = OptionFuture::from(Some( @@ -572,3 +449,147 @@ impl Error { } } } + +async fn run_swap_setup( + mut substream: libp2p::swarm::Stream, + sender: bmrng::RequestSender, + resume_only: bool, + env_config: env::Config, + min_buy: bitcoin::Amount, + max_buy: bitcoin::Amount, + latest_rate: Result, +) -> Result<(Uuid, State3)> { + let request = swap_setup::read_cbor_message::(&mut substream) + .await + .context("Failed to read spot price request")?; + + let wallet_snapshot = sender + .send_receive(request.btc) + .await + .context("Failed to receive wallet snapshot")?; + + // wrap all of these into another future so we can `return` from all the + // different blocks + let validate = async { + if resume_only { + return Err(Error::ResumeOnlyMode); + }; + + let blockchain_network = BlockchainNetwork { + bitcoin: env_config.bitcoin_network, + monero: env_config.monero_network, + }; + + if request.blockchain_network != blockchain_network { + return Err(Error::BlockchainNetworkMismatch { + cli: request.blockchain_network, + asb: blockchain_network, + }); + } + + let btc = request.btc; + + if btc < min_buy { + return Err(Error::AmountBelowMinimum { + min: min_buy, + buy: btc, + }); + } + + if btc > max_buy { + return Err(Error::AmountAboveMaximum { + max: max_buy, + buy: btc, + }); + } + + let rate = + latest_rate.map_err(|e| Error::LatestRateFetchFailed(Box::new(e)))?; + let xmr = rate + .sell_quote(btc) + .map_err(Error::SellQuoteCalculationFailed)?; + + let unlocked = wallet_snapshot.unlocked_balance; + + let needed_balance = xmr + wallet_snapshot.lock_fee.into(); + if unlocked.as_piconero() < needed_balance.as_pico() { + tracing::warn!( + unlocked_balance = %unlocked, + needed_balance = %needed_balance, + "Rejecting swap, unlocked balance too low" + ); + return Err(Error::BalanceTooLow { + balance: wallet_snapshot.unlocked_balance, + buy: btc, + }); + } + + Ok(xmr) + }; + + let result = validate.await; + + let converted_result = match result { + Ok(xmr) => Ok(xmr.into()), + Err(e) => Err(e), + }; + swap_setup::write_cbor_message( + &mut substream, + SpotPriceResponse::from_result_ref(&converted_result), + ) + .await + .context("Failed to write spot price response")?; + + let xmr = converted_result?; + + let state0 = State0::new( + request.btc, + xmr, + env_config, + wallet_snapshot.redeem_address, + wallet_snapshot.punish_address, + wallet_snapshot.redeem_fee, + wallet_snapshot.punish_fee, + &mut rand::thread_rng(), + ); + + let message0 = swap_setup::read_cbor_message::(&mut substream) + .await + .context("Failed to read message0")?; + let (swap_id, state1) = state0 + .receive(message0) + .context("Failed to transition state0 -> state1 using message0")?; + + swap_setup::write_cbor_message(&mut substream, state1.next_message()) + .await + .context("Failed to send message1")?; + + let message2 = swap_setup::read_cbor_message::(&mut substream) + .await + .context("Failed to read message2")?; + let state2 = state1 + .receive(message2) + .context("Failed to transition state1 -> state2 using message2")?; + + swap_setup::write_cbor_message(&mut substream, state2.next_message()) + .await + .context("Failed to send message3")?; + + let message4 = swap_setup::read_cbor_message::(&mut substream) + .await + .context("Failed to read message4")?; + let state3 = state2 + .receive(message4) + .context("Failed to transition state2 -> state3 using message4")?; + + substream + .flush() + .await + .context("Failed to flush substream after all messages were sent")?; + substream + .close() + .await + .context("Failed to close substream after all messages were sent")?; + + Ok((swap_id, state3)) +} From 208f4851f8f0b09da828f88c3574380736d49333 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 11:39:06 +0100 Subject: [PATCH 006/146] change tx_refund_encsig to tx_partial_refund_encsig in Message3 --- swap-machine/src/alice/mod.rs | 2 +- swap-machine/src/bob/mod.rs | 6 +++--- swap-machine/src/common/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index ebabb79c07..3cd86c985f 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -359,7 +359,7 @@ impl State2 { let tx_cancel_sig = self.a.sign(tx_cancel.digest()); Message3 { tx_cancel_sig, - tx_refund_encsig, + tx_partial_refund_encsig: tx_refund_encsig, } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 17d0ea33a4..fff1006783 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -336,14 +336,14 @@ impl State1 { // TODO: send and receive and verify _partial_ refund signature instead of full refund signature. let tx_refund = - bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + bitcoin::TxPartialRefund::new(&tx_cancel, &self.refund_address, self.A, self.b.public(), spending_fee) bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_encsig( self.A, bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), &tx_refund.digest(), - &msg.tx_refund_encsig, + &msg.tx_partial_refund_encsig, )?; Ok(State2 { @@ -361,7 +361,7 @@ impl State1 { punish_address: self.punish_address, tx_lock: self.tx_lock, tx_cancel_sig_a: msg.tx_cancel_sig, - tx_refund_encsig: msg.tx_refund_encsig, + bob_refund_type: BobRefundType::from_partial_refund_sig(msg.tx_partial_refund_encsig), min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index ff72483064..18d90267fc 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -69,7 +69,7 @@ pub struct Message2 { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Message3 { pub tx_cancel_sig: bitcoin::Signature, - pub tx_refund_encsig: bitcoin::EncryptedSignature, + pub tx_partial_refund_encsig: bitcoin::EncryptedSignature, } #[allow(non_snake_case)] From 9e4cfff8fb8613c0bdf91bb25ebe3a3bf71a9da3 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:00:33 +0100 Subject: [PATCH 007/146] add amnesty_amount and tx_partial_refund_fee to swap_setup --- swap-machine/src/alice/mod.rs | 8 ++++++++ swap-machine/src/bob/mod.rs | 31 +++++++++++++++++++++++-------- swap-machine/src/common/mod.rs | 6 ++++++ swap/src/bitcoin/wallet.rs | 2 +- swap/src/protocol/bob/swap.rs | 4 ++-- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 3cd86c985f..dd51f411db 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -148,6 +148,7 @@ pub struct State0 { dleq_proof_s_a: CrossCurveDLEQProof, btc: bitcoin::Amount, xmr: monero::Amount, + btc_amnesty_amount: bitcoin::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, redeem_address: bitcoin::Address, @@ -161,6 +162,7 @@ impl State0 { pub fn new( btc: bitcoin::Amount, xmr: monero::Amount, + btc_amnesty_amount: bitcoin::Amount, env_config: Config, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -186,6 +188,7 @@ impl State0 { point: S_a_monero.compress(), }, dleq_proof_s_a, + btc_amnesty_amount, redeem_address, punish_address, btc, @@ -230,6 +233,7 @@ impl State0 { dleq_proof_s_a: self.dleq_proof_s_a, btc: self.btc, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: msg.refund_address, @@ -238,6 +242,7 @@ impl State0 { tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: msg.tx_refund_fee, + tx_partial_refund_fee: msg.tx_partial_refund_fee, tx_cancel_fee: msg.tx_cancel_fee, }, )) @@ -259,6 +264,7 @@ pub struct State1 { dleq_proof_s_a: CrossCurveDLEQProof, btc: bitcoin::Amount, xmr: monero::Amount, + btc_amnesty_amount: bitcoin::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -267,6 +273,7 @@ pub struct State1 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, + tx_partial_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, } @@ -282,6 +289,7 @@ impl State1 { punish_address: self.punish_address.clone(), tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, + amnesty_amount: self.btc_amnesty_amount, } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index fff1006783..19278ac9d5 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -178,6 +178,7 @@ pub struct State0 { punish_timelock: PunishTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u64, + tx_partial_refund_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -194,6 +195,7 @@ impl State0 { punish_timelock: PunishTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u64, + tx_partial_refund_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -221,6 +223,7 @@ impl State0 { punish_timelock, refund_address, min_monero_confirmations, + tx_partial_refund_fee, tx_refund_fee, tx_cancel_fee, tx_lock_fee, @@ -237,6 +240,7 @@ impl State0 { v_b: self.v_b, refund_address: self.refund_address.clone(), tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, tx_cancel_fee: self.tx_cancel_fee, } } @@ -280,6 +284,7 @@ impl State0 { S_a_bitcoin: msg.S_a_bitcoin, v, xmr: self.xmr, + btc_amnesty_amount: msg.amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -289,6 +294,7 @@ impl State0 { min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: msg.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, tx_punish_fee: msg.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -305,6 +311,7 @@ pub struct State1 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, xmr: monero::Amount, + btc_amnesty_amount: bitcoin::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -312,6 +319,7 @@ pub struct State1 { punish_address: bitcoin::Address, tx_lock: bitcoin::TxLock, min_monero_confirmations: u64, + tx_partial_refund_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -336,7 +344,7 @@ impl State1 { // TODO: send and receive and verify _partial_ refund signature instead of full refund signature. let tx_refund = - bitcoin::TxPartialRefund::new(&tx_cancel, &self.refund_address, self.A, self.b.public(), spending_fee) + bitcoin::TxPartialRefund::new(&tx_cancel, &self.refund_address, self.A, self.b.public(), self.btc_amnesty_amount, self.tx_partial_refund_fee)?; bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_encsig( @@ -362,6 +370,7 @@ impl State1 { tx_lock: self.tx_lock, tx_cancel_sig_a: msg.tx_cancel_sig, bob_refund_type: BobRefundType::from_partial_refund_sig(msg.tx_partial_refund_encsig), + tx_refund_amnesty_sig: compile_error!("TODO: Mechanism for sometimes sending this during swap setup, sometimes not"), min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, @@ -459,7 +468,8 @@ impl State2 { redeem_address: self.redeem_address, tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a, - tx_refund_encsig: self.tx_refund_encsig, + bob_refund_type: self.bob_refund_type, + tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, @@ -542,7 +552,8 @@ impl State3 { redeem_address: self.redeem_address, tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, - tx_refund_encsig: self.tx_refund_encsig, + bob_refund_type: self.bob_refund_type, + tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, monero_wallet_restore_blockheight, lock_transfer_proof, tx_redeem_fee: self.tx_redeem_fee, @@ -563,7 +574,8 @@ impl State3 { refund_address: self.refund_address.clone(), tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), - tx_refund_encsig: self.tx_refund_encsig.clone(), + bob_refund_type: self.bob_refund_type.clone(), + tx_refund_amnesty_sig: self.tx_refund_amnesty_sig.clone(), tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, @@ -744,7 +756,8 @@ impl State4 { refund_address: self.refund_address, tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, - tx_refund_encsig: self.tx_refund_encsig, + bob_refund_type: self.bob_refund_type, + tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, @@ -893,7 +906,7 @@ impl State6 { &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, ) -> Result { - let signed_tx_refund = self.signed_refund_transaction()?; + let signed_tx_refund = self.signed_full_refund_transaction()?; let signed_tx_refund_txid = signed_tx_refund.compute_txid(); bitcoin_wallet.broadcast(signed_tx_refund, "refund").await?; @@ -909,14 +922,16 @@ impl State6 { Ok(tx_refund) } - pub fn signed_refund_transaction(&self) -> Result { + pub fn signed_full_refund_transaction(&self) -> Result { + let tx_full_refund_encsig = self.bob_refund_type.tx_full_refund_encsig().context("Can't sign full refund transaction because we don't have the necessary signature")?; + let tx_refund = self.construct_tx_refund()?; let adaptor = Adaptor::, Deterministic>::default(); let sig_b = self.b.sign(tx_refund.digest()); let sig_a = - adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), self.tx_refund_encsig.clone()); + adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), tx_full_refund_encsig); let signed_tx_refund = tx_refund.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?; diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 18d90267fc..4b14706919 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -38,6 +38,8 @@ pub struct Message0 { #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] + pub tx_partial_refund_fee: bitcoin::Amount, + #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, } @@ -57,6 +59,10 @@ pub struct Message1 { pub tx_redeem_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_punish_fee: bitcoin::Amount, + #[serde(with = "::bitcoin::amount::serde::as_sat")] + /// The amount of Bitcoin that Bob will only receive in case of a refund + /// _and_ if Alice decides to. Introduced in [#675](https://github.com/eigenwallet/core/pull/675). + pub amnesty_amount: bitcoin::Amount, } #[allow(non_snake_case)] diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index a4a97d9595..fe6494742e 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3805,7 +3805,7 @@ mod swap_core_bitcoin_tests { let redeem_transaction = alice_state3 .signed_redeem_transaction(encrypted_signature) .unwrap(); - let refund_transaction = bob_state6.signed_refund_transaction().unwrap(); + let refund_transaction = bob_state6.signed_full_refund_transaction().unwrap(); assert_weight(redeem_transaction, TxRedeem::weight().to_wu(), "TxRedeem"); assert_weight(cancel_transaction, TxCancel::weight().to_wu(), "TxCancel"); diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index ccfbea4933..4def0656f0 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -797,7 +797,7 @@ async fn next_state( event_emitter.emit_swap_progress_event( swap_id, TauriSwapProgressEvent::BtcRefundPublished { - btc_refund_txid: state.signed_refund_transaction()?.compute_txid(), + btc_refund_txid: state.signed_full_refund_transaction()?.compute_txid(), }, ); @@ -894,7 +894,7 @@ async fn next_state( event_emitter.emit_swap_progress_event( swap_id, TauriSwapProgressEvent::BtcRefunded { - btc_refund_txid: state.signed_refund_transaction()?.compute_txid(), + btc_refund_txid: state.signed_full_refund_transaction()?.compute_txid(), }, ); From 1842cacd22aa1fc35a480ce2a0af89ea049d9838 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:07:19 +0100 Subject: [PATCH 008/146] add tx_partial_refund_fee to NewSwap --- swap-p2p/src/protocols/swap_setup/alice.rs | 1 + swap-p2p/src/protocols/swap_setup/bob.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 7123aa084f..be290df8c0 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -545,6 +545,7 @@ async fn run_swap_setup( let state0 = State0::new( request.btc, xmr, + compile_error!("TODO: Implement system for alice to decide amnesty amount"), env_config, wallet_snapshot.redeem_address, wallet_snapshot.punish_address, diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 279eb0e746..651e26d9bc 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -346,6 +346,7 @@ pub struct NewSwap { pub btc: bitcoin::Amount, pub tx_lock_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, + pub tx_partial_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, pub bitcoin_refund_address: bitcoin::Address, } @@ -530,9 +531,11 @@ async fn run_swap_setup( env_config.bitcoin_punish_timelock.into(), new_swap_request.bitcoin_refund_address.clone(), env_config.monero_finality_confirmations, + new_swap_request.tx_partial_refund_fee, new_swap_request.tx_refund_fee, new_swap_request.tx_cancel_fee, new_swap_request.tx_lock_fee, + ); tracing::trace!( From f5b7984737347859a2152223a15cf48a50894ac4 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:21:56 +0100 Subject: [PATCH 009/146] fix compilation errors in bitcoin wallet tests --- swap/src/bitcoin/wallet.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index fe6494742e..32509a5947 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3725,6 +3725,7 @@ mod swap_core_bitcoin_tests { .await; let spending_fee = Amount::from_sat(1_000); let btc_amount = Amount::from_sat(500_000); + let btc_amnesty_amount = Amount::from_sat(0); let xmr_amount = crate::monero::Amount::from_piconero(10000); let tx_redeem_fee = alice_wallet @@ -3747,6 +3748,7 @@ mod swap_core_bitcoin_tests { let alice_state0 = alice::State0::new( btc_amount, xmr_amount, + btc_amnesty_amount, config, redeem_address, punish_address, @@ -3766,6 +3768,7 @@ mod swap_core_bitcoin_tests { config.monero_finality_confirmations, spending_fee, spending_fee, + spending_fee, tx_lock_fee, ); @@ -3835,6 +3838,7 @@ mod swap_core_bitcoin_tests { let spending_fee = Amount::from_sat(1_000); let btc_amount = Amount::from_sat(500_000); let xmr_amount = crate::monero::Amount::from_piconero(10000); + let btc_amnesty_amount = Amount::from_sat(0); let tx_redeem_fee = alice_wallet .estimate_fee(TxRedeem::weight(), Some(btc_amount)) @@ -3852,6 +3856,7 @@ mod swap_core_bitcoin_tests { let alice_state0 = alice::State0::new( btc_amount, xmr_amount, + btc_amnesty_amount, config, refund_address.clone(), punish_address, @@ -3872,6 +3877,7 @@ mod swap_core_bitcoin_tests { spending_fee, spending_fee, spending_fee, + spending_fee, ); // Complete the state machine up to State3 From ea5bcf3006135d24265fcf647d343ae767fe388c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:22:34 +0100 Subject: [PATCH 010/146] bob: estimate partial refund fee --- swap/src/protocol/bob/swap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 4def0656f0..3adb456f67 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -109,6 +109,12 @@ async fn next_state( let tx_refund_fee = bitcoin_wallet .estimate_fee(TxFullRefund::weight(), Some(btc_amount)) .await?; + let tx_partial_refund_fee = bitcoin_wallet. + // The actual amount of partial refund may be smaller than btc_amount, + // but at this point we don't know how much smaller. + // We still use btc_amount to set an upper limit on the tx fee - + // Even if this limit is higher than it would be given the actual amount. + estimate_fee(TxPartialRefund::weight(), Some(btc_amount)).await?; let tx_cancel_fee = bitcoin_wallet .estimate_fee(TxCancel::weight(), Some(btc_amount)) .await?; @@ -127,6 +133,7 @@ async fn next_state( btc: btc_amount, tx_lock_fee, tx_refund_fee, + tx_partial_refund_fee, tx_cancel_fee, bitcoin_refund_address: change_address, }) From 46cd40c0d58e592a5dddc4ae93d7958f13b8ad62 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:44:08 +0100 Subject: [PATCH 011/146] allow Alice to send full refund encisg and amnesty sig during swap setup (optional) --- swap-machine/src/alice/mod.rs | 3 +++ swap-machine/src/bob/mod.rs | 18 +++++++++++++----- swap-machine/src/common/mod.rs | 9 +++++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index dd51f411db..663cc3d946 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -365,9 +365,12 @@ impl State2 { let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest()); let tx_cancel_sig = self.a.sign(tx_cancel.digest()); + let (tx_full_refund_encsig, tx_refund_amnesty_sig) = compile_error!("TODO: Implement system for Alice to decide commiting to full refund"); Message3 { tx_cancel_sig, tx_partial_refund_encsig: tx_refund_encsig, + tx_full_refund_encsig, + tx_refund_amnesty_sig, } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 19278ac9d5..c011918dbb 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -342,18 +342,18 @@ impl State1 { self.tx_cancel_fee, )?; - // TODO: send and receive and verify _partial_ refund signature instead of full refund signature. - let tx_refund = + let tx_partial_refund = bitcoin::TxPartialRefund::new(&tx_cancel, &self.refund_address, self.A, self.b.public(), self.btc_amnesty_amount, self.tx_partial_refund_fee)?; bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_encsig( self.A, bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), - &tx_refund.digest(), + &tx_partial_refund.digest(), &msg.tx_partial_refund_encsig, )?; + let bob_refund_type = BobRefundType::from_possibly_full_refund_sig(msg.tx_partial_refund_encsig, msg.tx_full_refund_encsig); Ok(State2 { A: self.A, b: self.b, @@ -369,8 +369,8 @@ impl State1 { punish_address: self.punish_address, tx_lock: self.tx_lock, tx_cancel_sig_a: msg.tx_cancel_sig, - bob_refund_type: BobRefundType::from_partial_refund_sig(msg.tx_partial_refund_encsig), - tx_refund_amnesty_sig: compile_error!("TODO: Mechanism for sometimes sending this during swap setup, sometimes not"), + bob_refund_type, + tx_refund_amnesty_sig: msg.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, @@ -981,6 +981,14 @@ impl State6 { } impl BobRefundType { + pub fn from_possibly_full_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option) -> Self { + if let Some(full_refund_encsig) = full_refund_encsig { + Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_refund_encsig: full_refund_encsig } + } else { + Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } + } + } + pub fn from_partial_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 4b14706919..77b3cf015f 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -60,8 +60,8 @@ pub struct Message1 { #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_punish_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] - /// The amount of Bitcoin that Bob will only receive in case of a refund - /// _and_ if Alice decides to. Introduced in [#675](https://github.com/eigenwallet/core/pull/675). + /// The amount of Bitcoin that Bob not get refunded unless Alice decides so. + /// Introduced in [#675](https://github.com/eigenwallet/core/pull/675) to combat spam. pub amnesty_amount: bitcoin::Amount, } @@ -75,7 +75,12 @@ pub struct Message2 { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Message3 { pub tx_cancel_sig: bitcoin::Signature, + /// The following fields were reworked in [#675](https://github.com/eigenwallet/core/pull/675). + /// Alice _may_ choose to commit to a full refund during the swap setup already, but doesn't + /// have to. pub tx_partial_refund_encsig: bitcoin::EncryptedSignature, + pub tx_full_refund_encsig: Option, + pub tx_refund_amnesty_sig: Option, } #[allow(non_snake_case)] From 0a42da89f8c86411b28bd077ede7e228651e180c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 12:51:28 +0100 Subject: [PATCH 012/146] add tx_partial_refund_fee and btc_amnesty_amoutn to all Alice states --- swap-machine/src/alice/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 663cc3d946..5d57071355 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -307,6 +307,7 @@ impl State1 { v: self.v, btc: self.btc, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -316,6 +317,7 @@ impl State1 { tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -332,6 +334,7 @@ pub struct State2 { v: monero::PrivateViewKey, btc: bitcoin::Amount, xmr: monero::Amount, + btc_amnesty_amount: bitcoin::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -341,6 +344,7 @@ pub struct State2 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, + tx_partial_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, } @@ -424,6 +428,7 @@ impl State2 { v: self.v, btc: self.btc, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -436,6 +441,7 @@ impl State2 { tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -453,6 +459,7 @@ pub struct State3 { #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc: bitcoin::Amount, pub xmr: monero::Amount, + pub btc_amnesty_amount: bitcoin::Amount, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, #[serde(with = "swap_serde::bitcoin::address_serde")] @@ -482,6 +489,8 @@ pub struct State3 { #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] + pub tx_partial_refund_fee: bitcoin::Amount, + #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, } From a596087ea9e0a8d6ed255b8f7a07a61932a33de3 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 13:19:14 +0100 Subject: [PATCH 013/146] rename tx_refund_encsig to tx_full_refund_encsig while keeping db backwards compatible --- swap-machine/src/bob/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index c011918dbb..dd999f720d 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -79,14 +79,18 @@ pub enum BobRefundType { /// Alice has signed both the partial and full refund transactions. Full { tx_partial_refund_encsig: bitcoin::EncryptedSignature, - tx_refund_encsig: bitcoin::EncryptedSignature, + // Serde rename keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. + #[serde(rename = "tx_refund_encsig")] + tx_full_refund_encsig: bitcoin::EncryptedSignature, }, /// Alice has only signed the full refund transaction. /// This is only used to maintain backwards compatibility for older swaps /// from before the partial refund protocol change. /// See [#675](https://github.com/eigenwallet/core/pull/675). Legacy { - tx_refund_encsig: bitcoin::EncryptedSignature, + // Serde raname keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. + #[serde(rename = "tx_refund_encsig")] + tx_full_refund_encsig: bitcoin::EncryptedSignature, } } @@ -983,7 +987,7 @@ impl State6 { impl BobRefundType { pub fn from_possibly_full_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option) -> Self { if let Some(full_refund_encsig) = full_refund_encsig { - Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_refund_encsig: full_refund_encsig } + Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_full_refund_encsig: full_refund_encsig } } else { Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } } @@ -996,8 +1000,8 @@ impl BobRefundType { pub fn tx_full_refund_encsig(&self) -> Option { match self { BobRefundType::Partial { .. } => None, - BobRefundType::Full { tx_refund_encsig, .. } => Some(tx_refund_encsig.clone()), - BobRefundType::Legacy { tx_refund_encsig } => Some(tx_refund_encsig.clone()), + BobRefundType::Full { tx_full_refund_encsig, .. } => Some(tx_full_refund_encsig.clone()), + BobRefundType::Legacy { tx_full_refund_encsig } => Some(tx_full_refund_encsig.clone()), } } From 0d5be57ff681a0554bd2255f8d087601dd63906f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 13:39:04 +0100 Subject: [PATCH 014/146] add tx_refund_amnesty_fee to swap setup messages and alice/bob states --- swap-machine/src/alice/mod.rs | 4 ++++ swap-machine/src/bob/mod.rs | 4 ++++ swap-machine/src/common/mod.rs | 2 ++ swap-p2p/src/protocols/swap_setup/bob.rs | 2 ++ swap/src/bitcoin/wallet.rs | 2 ++ swap/src/protocol/bob/swap.rs | 19 ++++++++++++------- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 5d57071355..3b68ed80c1 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -243,6 +243,7 @@ impl State0 { tx_punish_fee: self.tx_punish_fee, tx_refund_fee: msg.tx_refund_fee, tx_partial_refund_fee: msg.tx_partial_refund_fee, + tx_refund_amnesty_fee: msg.tx_refund_amnesty_fee, tx_cancel_fee: msg.tx_cancel_fee, }, )) @@ -274,6 +275,7 @@ pub struct State1 { tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: bitcoin::Amount, + tx_refund_amnesty_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, } @@ -318,6 +320,7 @@ impl State1 { tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -345,6 +348,7 @@ pub struct State2 { tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: bitcoin::Amount, + tx_refund_amnesty_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index dd999f720d..bf4f6d1162 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -183,6 +183,7 @@ pub struct State0 { refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, + tx_refund_amnesty_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -200,6 +201,7 @@ impl State0 { refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, + tx_refund_amnesty_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -228,6 +230,7 @@ impl State0 { refund_address, min_monero_confirmations, tx_partial_refund_fee, + tx_refund_amnesty_fee, tx_refund_fee, tx_cancel_fee, tx_lock_fee, @@ -245,6 +248,7 @@ impl State0 { refund_address: self.refund_address.clone(), tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, } } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 77b3cf015f..05e1a99c4a 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -40,6 +40,8 @@ pub struct Message0 { #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_partial_refund_fee: bitcoin::Amount, #[serde(with = "::bitcoin::amount::serde::as_sat")] + pub tx_refund_amnesty_fee: bitcoin::Amount, + #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, } diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 651e26d9bc..ca1541a90c 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -347,6 +347,7 @@ pub struct NewSwap { pub tx_lock_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, pub tx_partial_refund_fee: bitcoin::Amount, + pub tx_refund_amnesty_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, pub bitcoin_refund_address: bitcoin::Address, } @@ -532,6 +533,7 @@ async fn run_swap_setup( new_swap_request.bitcoin_refund_address.clone(), env_config.monero_finality_confirmations, new_swap_request.tx_partial_refund_fee, + new_swap_request.tx_refund_amnesty_fee, new_swap_request.tx_refund_fee, new_swap_request.tx_cancel_fee, new_swap_request.tx_lock_fee, diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 32509a5947..07bb0fb269 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3769,6 +3769,7 @@ mod swap_core_bitcoin_tests { spending_fee, spending_fee, spending_fee, + spending_fee, tx_lock_fee, ); @@ -3878,6 +3879,7 @@ mod swap_core_bitcoin_tests { spending_fee, spending_fee, spending_fee, + spending_fee, ); // Complete the state machine up to State3 diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 3adb456f67..f968506a35 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -106,19 +106,23 @@ async fn next_state( change_address, tx_lock_fee, } => { + let tx_cancel_fee = bitcoin_wallet + .estimate_fee(TxCancel::weight(), Some(btc_amount)) + .await?; let tx_refund_fee = bitcoin_wallet .estimate_fee(TxFullRefund::weight(), Some(btc_amount)) .await?; + + // At this point we don't know how high btc_amnesty_amount is. + // This means we don't know how large the amount of the partial refund and amnesty transactions will be. + // We therefore specify the same upper limit on tx fees as for the other transactions, even though + // the maximum fee percentage might be higher due to that. let tx_partial_refund_fee = bitcoin_wallet. - // The actual amount of partial refund may be smaller than btc_amount, - // but at this point we don't know how much smaller. - // We still use btc_amount to set an upper limit on the tx fee - - // Even if this limit is higher than it would be given the actual amount. estimate_fee(TxPartialRefund::weight(), Some(btc_amount)).await?; - let tx_cancel_fee = bitcoin_wallet - .estimate_fee(TxCancel::weight(), Some(btc_amount)) + let tx_refund_amnesty_fee = bitcoin_wallet + .estimate_fee(TxRefundAmnesty::weight(), Some(btc_amount)) .await?; - + // Emit an event to tauri that we are negotiating with the maker to lock the Bitcoin event_emitter.emit_swap_progress_event( swap_id, @@ -134,6 +138,7 @@ async fn next_state( tx_lock_fee, tx_refund_fee, tx_partial_refund_fee, + tx_refund_amnesty_fee, tx_cancel_fee, bitcoin_refund_address: change_address, }) From bcdbec7ba56d8cb9b29af2d2e1afe9bc1077cb8c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 2 Dec 2025 13:57:24 +0100 Subject: [PATCH 015/146] add tx_refund_amnesty_fee to Bob State1, verify partial_refund and refund_amnesty signatures before accepting --- swap-machine/src/alice/mod.rs | 2 +- swap-machine/src/bob/mod.rs | 19 +++++++++++++++++++ swap-p2p/src/protocols/swap_setup/alice.rs | 10 +++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 3b68ed80c1..c8e85841aa 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -373,7 +373,7 @@ impl State2 { let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest()); let tx_cancel_sig = self.a.sign(tx_cancel.digest()); - let (tx_full_refund_encsig, tx_refund_amnesty_sig) = compile_error!("TODO: Implement system for Alice to decide commiting to full refund"); + let (tx_full_refund_encsig, tx_refund_amnesty_sig) = todo!("TODO: Implement system for Alice to decide commiting to full refund"); Message3 { tx_cancel_sig, tx_partial_refund_encsig: tx_refund_encsig, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index bf4f6d1162..eb3c589548 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -303,6 +303,7 @@ impl State0 { tx_redeem_fee: msg.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_punish_fee: msg.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -328,6 +329,7 @@ pub struct State1 { tx_lock: bitcoin::TxLock, min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, + tx_refund_amnesty_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -361,6 +363,23 @@ impl State1 { &msg.tx_partial_refund_encsig, )?; + // Verify the full refund signature if it is present + if let Some(tx_full_refund_encsig) = &msg.tx_full_refund_encsig { + let tx_full_refund = bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + bitcoin::verify_encsig( + self.A, + bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), + &tx_full_refund.digest(), + tx_full_refund_encsig, + )?; + } + + // Verify the refund amnesty signature if it is present + if let Some(tx_refund_amnesty_sig) = &msg.tx_refund_amnesty_sig { + let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new(&tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee); + bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig)?; + } + let bob_refund_type = BobRefundType::from_possibly_full_refund_sig(msg.tx_partial_refund_encsig, msg.tx_full_refund_encsig); Ok(State2 { A: self.A, diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index be290df8c0..7bbb39d583 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -307,7 +307,7 @@ where let resume_only = self.resume_only; let min_buy = self.min_buy; let max_buy = self.max_buy; - let latest_rate = self.latest_rate.latest_rate().map_err(anyhow::Error::from); + let latest_rate = self.latest_rate.latest_rate(); let env_config = self.env_config; // We wrap the entire handshake in a timeout future @@ -320,7 +320,7 @@ where env_config, min_buy, max_buy, - latest_rate, + latest_rate.map_err(|error| Box::new(error) as Box), ), ); @@ -457,7 +457,7 @@ async fn run_swap_setup( env_config: env::Config, min_buy: bitcoin::Amount, max_buy: bitcoin::Amount, - latest_rate: Result, + latest_rate: Result>, ) -> Result<(Uuid, State3)> { let request = swap_setup::read_cbor_message::(&mut substream) .await @@ -504,7 +504,7 @@ async fn run_swap_setup( } let rate = - latest_rate.map_err(|e| Error::LatestRateFetchFailed(Box::new(e)))?; + latest_rate.map_err(Error::LatestRateFetchFailed)?; let xmr = rate .sell_quote(btc) .map_err(Error::SellQuoteCalculationFailed)?; @@ -545,7 +545,7 @@ async fn run_swap_setup( let state0 = State0::new( request.btc, xmr, - compile_error!("TODO: Implement system for alice to decide amnesty amount"), + todo!("TODO: Implement system for alice to decide amnesty amount"), env_config, wallet_snapshot.redeem_address, wallet_snapshot.punish_address, From 80bdcd4aa1d22b6491bf9a17325ab79364494a8b Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 15:47:33 +0100 Subject: [PATCH 016/146] remove unnecessary serde(with = bitcoin::amount::serde::as_sats) as it is the default --- swap-db/src/bob.rs | 1 - swap-machine/src/alice/mod.rs | 13 ++++--------- swap-machine/src/bob/mod.rs | 21 ++++++++------------- swap-machine/src/common/mod.rs | 7 ------- swap-p2p/src/protocols/quote.rs | 3 --- swap-p2p/src/protocols/swap_setup.rs | 6 ------ swap/src/cli/api/request.rs | 8 +------- swap/src/cli/api/tauri_bindings.rs | 6 ------ 8 files changed, 13 insertions(+), 52 deletions(-) diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 039b325206..cbb79974bb 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -7,7 +7,6 @@ use swap_machine::bob::BobState; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] pub enum Bob { Started { - #[serde(with = "::bitcoin::amount::serde::as_sat")] btc_amount: bitcoin::Amount, #[serde(with = "swap_serde::bitcoin::address_serde")] change_address: bitcoin::Address, diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index c8e85841aa..6cd0a0cc35 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -274,8 +274,8 @@ pub struct State1 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, - tx_partial_refund_fee: bitcoin::Amount, - tx_refund_amnesty_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -460,7 +460,6 @@ pub struct State3 { S_b_monero: monero::PublicKey, S_b_bitcoin: swap_core::bitcoin::PublicKey, pub v: monero::PrivateViewKey, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc: bitcoin::Amount, pub xmr: monero::Amount, pub btc_amnesty_amount: bitcoin::Amount, @@ -486,15 +485,11 @@ pub struct State3 { /// to wait for the timelock to expire. #[serde(default)] tx_early_refund_sig_bob: Option, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_punish_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] - pub tx_partial_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] + pub tx_partial_refund_fee: Option, + pub tx_refund_amnesty_fee: Option, pub tx_cancel_fee: bitcoin::Amount, } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index eb3c589548..2ecdaa75f6 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -26,7 +26,6 @@ use uuid::Uuid; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub enum BobState { Started { - #[serde(with = "::bitcoin::amount::serde::as_sat")] btc_amount: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, #[serde(with = "address_serde")] @@ -436,14 +435,12 @@ pub struct State2 { /// This signature is voluntarily revealed by alice. tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_punish_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, } impl State2 { @@ -534,11 +531,10 @@ pub struct State3 { /// This signature is voluntarily revealed by alice. tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -681,11 +677,10 @@ pub struct State4 { tx_refund_amnesty_sig: Option, monero_wallet_restore_blockheight: BlockHeight, lock_transfer_proof: TransferProof, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_redeem_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -861,10 +856,10 @@ pub struct State6 { /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. tx_refund_amnesty_sig: Option, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, } impl State6 { diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 05e1a99c4a..07f61002e3 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -35,13 +35,9 @@ pub struct Message0 { pub v_b: monero::PrivateViewKey, #[serde(with = "swap_serde::bitcoin::address_serde")] pub refund_address: bitcoin::Address, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_partial_refund_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_amnesty_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, } @@ -57,11 +53,8 @@ pub struct Message1 { pub redeem_address: bitcoin::Address, #[serde(with = "swap_serde::bitcoin::address_serde")] pub punish_address: bitcoin::Address, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_redeem_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_punish_fee: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] /// The amount of Bitcoin that Bob not get refunded unless Alice decides so. /// Introduced in [#675](https://github.com/eigenwallet/core/pull/675) to combat spam. pub amnesty_amount: bitcoin::Amount, diff --git a/swap-p2p/src/protocols/quote.rs b/swap-p2p/src/protocols/quote.rs index a7fe31f84b..7e126a87b9 100644 --- a/swap-p2p/src/protocols/quote.rs +++ b/swap-p2p/src/protocols/quote.rs @@ -27,16 +27,13 @@ impl AsRef for BidQuoteProtocol { #[typeshare] pub struct BidQuote { /// The price at which the maker is willing to buy at. - #[serde(with = "::bitcoin::amount::serde::as_sat")] #[typeshare(serialized_as = "number")] pub price: bitcoin::Amount, /// The minimum quantity the maker is willing to buy. /// #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] #[typeshare(serialized_as = "number")] pub min_quantity: bitcoin::Amount, /// The maximum quantity the maker is willing to buy. - #[serde(with = "::bitcoin::amount::serde::as_sat")] #[typeshare(serialized_as = "number")] pub max_quantity: bitcoin::Amount, } diff --git a/swap-p2p/src/protocols/swap_setup.rs b/swap-p2p/src/protocols/swap_setup.rs index 60f50ceb1b..33b654781e 100644 --- a/swap-p2p/src/protocols/swap_setup.rs +++ b/swap-p2p/src/protocols/swap_setup.rs @@ -43,7 +43,6 @@ pub struct BlockchainNetwork { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SpotPriceRequest { - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc: bitcoin::Amount, pub blockchain_network: BlockchainNetwork, } @@ -58,19 +57,14 @@ pub enum SpotPriceResponse { pub enum SpotPriceError { NoSwapsAccepted, AmountBelowMinimum { - #[serde(with = "::bitcoin::amount::serde::as_sat")] min: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] buy: bitcoin::Amount, }, AmountAboveMaximum { - #[serde(with = "::bitcoin::amount::serde::as_sat")] max: bitcoin::Amount, - #[serde(with = "::bitcoin::amount::serde::as_sat")] buy: bitcoin::Amount, }, BalanceTooLow { - #[serde(with = "::bitcoin::amount::serde::as_sat")] buy: bitcoin::Amount, }, BlockchainNetworkMismatch { diff --git a/swap/src/cli/api/request.rs b/swap/src/cli/api/request.rs index 95f92cbf3f..49b6f877b7 100644 --- a/swap/src/cli/api/request.rs +++ b/swap/src/cli/api/request.rs @@ -160,7 +160,7 @@ impl Request for MoneroRecoveryArgs { #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct WithdrawBtcArgs { #[typeshare(serialized_as = "number")] - #[serde(default, with = "::bitcoin::amount::serde::as_sat::opt")] + #[serde(default)] pub amount: Option, #[typeshare(serialized_as = "string")] #[serde(with = "swap_serde::bitcoin::address_serde")] @@ -171,7 +171,6 @@ pub struct WithdrawBtcArgs { #[derive(Serialize, Deserialize, Debug)] pub struct WithdrawBtcResponse { #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub amount: bitcoin::Amount, pub txid: String, } @@ -229,18 +228,14 @@ pub struct GetSwapInfoResponse { #[typeshare(serialized_as = "number")] pub xmr_amount: monero::Amount, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc_amount: bitcoin::Amount, #[typeshare(serialized_as = "string")] pub tx_lock_id: Txid, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_cancel_fee: bitcoin::Amount, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_refund_fee: bitcoin::Amount, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub tx_lock_fee: bitcoin::Amount, pub btc_refund_address: String, pub cancel_timelock: CancelTimelock, @@ -291,7 +286,6 @@ pub struct BalanceArgs { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct BalanceResponse { #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub balance: bitcoin::Amount, } diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index c9cc2ad69a..22283c3438 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -61,10 +61,8 @@ pub struct ContextStatus { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct LockBitcoinDetails { #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc_lock_amount: bitcoin::Amount, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc_network_fee: bitcoin::Amount, #[typeshare(serialized_as = "number")] pub xmr_receive_amount: monero::Amount, @@ -79,7 +77,6 @@ pub struct SelectMakerDetails { #[typeshare(serialized_as = "string")] pub swap_id: Uuid, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] pub btc_amount_to_swap: bitcoin::Amount, pub maker: QuoteWithAddress, } @@ -888,16 +885,13 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "string")] deposit_address: bitcoin::Address, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] max_giveable: bitcoin::Amount, #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] min_bitcoin_lock_tx_fee: bitcoin::Amount, known_quotes: Vec, }, SwapSetupInflight { #[typeshare(serialized_as = "number")] - #[serde(with = "::bitcoin::amount::serde::as_sat")] btc_lock_amount: bitcoin::Amount, }, RetrievingMoneroBlockheight, From 2bc6b837f472914683c1e10b423be44fc965fda5 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 15:50:07 +0100 Subject: [PATCH 017/146] add tx_partial_refund_fee and tx_refund_amnesty_fee to all bob and alice states + make them optional for db compatibility --- swap-machine/src/alice/mod.rs | 9 +- swap-machine/src/bob/mod.rs | 125 ++++++++++++++++------- swap-machine/src/common/mod.rs | 6 +- swap-p2p/src/protocols/swap_setup.rs | 2 +- swap-p2p/src/protocols/swap_setup/bob.rs | 26 +++-- swap/src/protocol/bob/swap.rs | 15 +-- 6 files changed, 123 insertions(+), 60 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 6cd0a0cc35..6a35ababba 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -242,8 +242,8 @@ impl State0 { tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: msg.tx_refund_fee, - tx_partial_refund_fee: msg.tx_partial_refund_fee, - tx_refund_amnesty_fee: msg.tx_refund_amnesty_fee, + tx_partial_refund_fee: Some(msg.tx_partial_refund_fee), + tx_refund_amnesty_fee: Some(msg.tx_refund_amnesty_fee), tx_cancel_fee: msg.tx_cancel_fee, }, )) @@ -347,8 +347,8 @@ pub struct State2 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, - tx_partial_refund_fee: bitcoin::Amount, - tx_refund_amnesty_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -446,6 +446,7 @@ impl State2 { tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, }) } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 2ecdaa75f6..cee14ffe57 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -1,11 +1,11 @@ #![allow(non_snake_case)] -use crate::common::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM}; -use anyhow::{anyhow, bail, Context, Result}; +use crate::common::{CROSS_CURVE_PROOF_SYSTEM, Message0, Message1, Message2, Message3, Message4}; +use anyhow::{Context, Result, anyhow, bail}; use bitcoin_wallet::primitives::Subscription; +use ecdsa_fun::Signature; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::nonce::Deterministic; -use ecdsa_fun::Signature; use monero::BlockHeight; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; @@ -14,11 +14,11 @@ use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ - self, current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, - TxLock, Txid, + self, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxLock, Txid, + current_epoch, }; -use swap_core::monero::primitives::WatchRequest; use swap_core::monero::ScalarExt; +use swap_core::monero::primitives::WatchRequest; use swap_core::monero::{self, TransferProof}; use swap_serde::bitcoin::address_serde; use uuid::Uuid; @@ -83,14 +83,14 @@ pub enum BobRefundType { tx_full_refund_encsig: bitcoin::EncryptedSignature, }, /// Alice has only signed the full refund transaction. - /// This is only used to maintain backwards compatibility for older swaps + /// This is only used to maintain backwards compatibility for older swaps /// from before the partial refund protocol change. /// See [#675](https://github.com/eigenwallet/core/pull/675). Legacy { // Serde raname keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. #[serde(rename = "tx_refund_encsig")] tx_full_refund_encsig: bitcoin::EncryptedSignature, - } + }, } impl fmt::Display for BobState { @@ -181,8 +181,8 @@ pub struct State0 { punish_timelock: PunishTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u64, - tx_partial_refund_fee: bitcoin::Amount, - tx_refund_amnesty_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -228,16 +228,16 @@ impl State0 { punish_timelock, refund_address, min_monero_confirmations, - tx_partial_refund_fee, - tx_refund_amnesty_fee, + tx_partial_refund_fee: Some(tx_partial_refund_fee), + tx_refund_amnesty_fee: Some(tx_refund_amnesty_fee), tx_refund_fee, tx_cancel_fee, tx_lock_fee, } } - pub fn next_message(&self) -> Message0 { - Message0 { + pub fn next_message(&self) -> Result { + Ok(Message0 { swap_id: self.swap_id, B: self.b.public(), S_b_monero: self.S_b_monero, @@ -246,10 +246,14 @@ impl State0 { v_b: self.v_b, refund_address: self.refund_address.clone(), tx_refund_fee: self.tx_refund_fee, - tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_partial_refund_fee: self + .tx_partial_refund_fee + .context("tx_partial_refund_fee missing but required to setup swap")?, + tx_refund_amnesty_fee: self + .tx_refund_amnesty_fee + .context("tx_refund_amnesty_fee missing but required to setup swap")?, tx_cancel_fee: self.tx_cancel_fee, - } + }) } pub async fn receive( @@ -327,8 +331,8 @@ pub struct State1 { punish_address: bitcoin::Address, tx_lock: bitcoin::TxLock, min_monero_confirmations: u64, - tx_partial_refund_fee: bitcoin::Amount, - tx_refund_amnesty_fee: bitcoin::Amount, + tx_partial_refund_fee: Option, + tx_refund_amnesty_fee: Option, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -351,8 +355,15 @@ impl State1 { self.tx_cancel_fee, )?; - let tx_partial_refund = - bitcoin::TxPartialRefund::new(&tx_cancel, &self.refund_address, self.A, self.b.public(), self.btc_amnesty_amount, self.tx_partial_refund_fee)?; + let tx_partial_refund = bitcoin::TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + self.btc_amnesty_amount, + self.tx_partial_refund_fee + .context("tx_partial_refund_fee missing but required to setup swap")?, + )?; bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_encsig( @@ -364,7 +375,8 @@ impl State1 { // Verify the full refund signature if it is present if let Some(tx_full_refund_encsig) = &msg.tx_full_refund_encsig { - let tx_full_refund = bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + let tx_full_refund = + bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); bitcoin::verify_encsig( self.A, bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), @@ -375,11 +387,19 @@ impl State1 { // Verify the refund amnesty signature if it is present if let Some(tx_refund_amnesty_sig) = &msg.tx_refund_amnesty_sig { - let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new(&tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee); + let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("tx_refund_amnesty_fee missing but required to setup swap")?, + ); bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig)?; } - let bob_refund_type = BobRefundType::from_possibly_full_refund_sig(msg.tx_partial_refund_encsig, msg.tx_full_refund_encsig); + let bob_refund_type = BobRefundType::from_possibly_full_refund_sig( + msg.tx_partial_refund_encsig, + msg.tx_full_refund_encsig, + ); Ok(State2 { A: self.A, b: self.b, @@ -400,6 +420,8 @@ impl State1 { min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_punish_fee: self.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -497,6 +519,8 @@ impl State2 { min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, }, self.tx_lock, @@ -582,6 +606,8 @@ impl State3 { tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, } } @@ -601,6 +627,8 @@ impl State3 { tx_refund_amnesty_sig: self.tx_refund_amnesty_sig.clone(), tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, xmr: self.xmr, } } @@ -783,6 +811,8 @@ impl State4 { tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, } } @@ -945,15 +975,16 @@ impl State6 { } pub fn signed_full_refund_transaction(&self) -> Result { - let tx_full_refund_encsig = self.bob_refund_type.tx_full_refund_encsig().context("Can't sign full refund transaction because we don't have the necessary signature")?; - + let tx_full_refund_encsig = self.bob_refund_type.tx_full_refund_encsig().context( + "Can't sign full refund transaction because we don't have the necessary signature", + )?; + let tx_refund = self.construct_tx_refund()?; let adaptor = Adaptor::, Deterministic>::default(); let sig_b = self.b.sign(tx_refund.digest()); - let sig_a = - adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), tx_full_refund_encsig); + let sig_a = adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), tx_full_refund_encsig); let signed_tx_refund = tx_refund.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?; @@ -1003,30 +1034,50 @@ impl State6 { } impl BobRefundType { - pub fn from_possibly_full_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option) -> Self { + pub fn from_possibly_full_refund_sig( + partial_refund_encsig: bitcoin::EncryptedSignature, + full_refund_encsig: Option, + ) -> Self { if let Some(full_refund_encsig) = full_refund_encsig { - Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_full_refund_encsig: full_refund_encsig } + Self::Full { + tx_partial_refund_encsig: partial_refund_encsig, + tx_full_refund_encsig: full_refund_encsig, + } } else { - Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } + Self::Partial { + tx_partial_refund_encsig: partial_refund_encsig, + } } } - + pub fn from_partial_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { - Self::Partial { tx_partial_refund_encsig: partial_refund_encsig } + Self::Partial { + tx_partial_refund_encsig: partial_refund_encsig, + } } pub fn tx_full_refund_encsig(&self) -> Option { match self { BobRefundType::Partial { .. } => None, - BobRefundType::Full { tx_full_refund_encsig, .. } => Some(tx_full_refund_encsig.clone()), - BobRefundType::Legacy { tx_full_refund_encsig } => Some(tx_full_refund_encsig.clone()), + BobRefundType::Full { + tx_full_refund_encsig, + .. + } => Some(tx_full_refund_encsig.clone()), + BobRefundType::Legacy { + tx_full_refund_encsig, + } => Some(tx_full_refund_encsig.clone()), } } pub fn tx_partial_refund_encsig(&self) -> Option { match self { - BobRefundType::Partial { tx_partial_refund_encsig } => Some(tx_partial_refund_encsig.clone()), - BobRefundType::Full { tx_partial_refund_encsig, .. } => Some(tx_partial_refund_encsig.clone()), + BobRefundType::Partial { + tx_partial_refund_encsig, + } => Some(tx_partial_refund_encsig.clone()), + BobRefundType::Full { + tx_partial_refund_encsig, + .. + } => Some(tx_partial_refund_encsig.clone()), BobRefundType::Legacy { .. } => None, } } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 07f61002e3..0c0f316945 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -1,15 +1,15 @@ -use crate::alice::is_complete as alice_is_complete; use crate::alice::AliceState; -use crate::bob::is_complete as bob_is_complete; +use crate::alice::is_complete as alice_is_complete; use crate::bob::BobState; +use crate::bob::is_complete as bob_is_complete; use anyhow::Result; use async_trait::async_trait; use conquer_once::Lazy; use libp2p::{Multiaddr, PeerId}; use serde::{Deserialize, Serialize}; use sha2::Sha256; -use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof}; use sigma_fun::HashTranscript; +use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof}; use std::convert::TryInto; use swap_core::bitcoin; use swap_core::monero::{self, MoneroAddressPool}; diff --git a/swap-p2p/src/protocols/swap_setup.rs b/swap-p2p/src/protocols/swap_setup.rs index 33b654781e..09bb31984b 100644 --- a/swap-p2p/src/protocols/swap_setup.rs +++ b/swap-p2p/src/protocols/swap_setup.rs @@ -18,7 +18,7 @@ pub mod protocol { use libp2p::swarm::Stream; use void::Void; - use super::vendor_from_fn::{from_fn, FromFnUpgrade}; + use super::vendor_from_fn::{FromFnUpgrade, from_fn}; pub fn new() -> SwapSetup { from_fn( diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index ca1541a90c..474c5a97c1 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -1,12 +1,12 @@ use crate::out_event; use crate::protocols::swap_setup::{ - protocol, BlockchainNetwork, SpotPriceError, SpotPriceResponse, + BlockchainNetwork, SpotPriceError, SpotPriceResponse, protocol, }; use anyhow::{Context, Result}; use bitcoin_wallet::BitcoinWallet; -use futures::future::{BoxFuture, OptionFuture}; use futures::AsyncWriteExt; use futures::FutureExt; +use futures::future::{BoxFuture, OptionFuture}; use libp2p::core::upgrade; use libp2p::swarm::behaviour::ConnectionEstablished; use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; @@ -26,7 +26,7 @@ use swap_machine::bob::{State0, State2}; use swap_machine::common::{Message1, Message3}; use uuid::Uuid; -use super::{read_cbor_message, write_cbor_message, SpotPriceRequest}; +use super::{SpotPriceRequest, read_cbor_message, write_cbor_message}; #[allow(missing_debug_implementations)] pub struct Behaviour { @@ -537,7 +537,6 @@ async fn run_swap_setup( new_swap_request.tx_refund_fee, new_swap_request.tx_cancel_fee, new_swap_request.tx_lock_fee, - ); tracing::trace!( @@ -545,9 +544,14 @@ async fn run_swap_setup( "Transitioned into state0 during swap setup", ); - write_cbor_message(&mut substream, state0.next_message()) - .await - .context("Failed to send state0 message to Alice")?; + write_cbor_message( + &mut substream, + state0 + .next_message() + .context("Couldn't generate Message0")?, + ) + .await + .context("Failed to send state0 message to Alice")?; let message1 = read_cbor_message::(&mut substream) .await .context("Failed to read message1 from Alice")?; @@ -620,10 +624,14 @@ pub enum Error { max: bitcoin::Amount, buy: bitcoin::Amount, }, - #[error("Seller's XMR balance is currently too low to fulfill the swap request to buy {buy}, please try again later")] + #[error( + "Seller's XMR balance is currently too low to fulfill the swap request to buy {buy}, please try again later" + )] BalanceTooLow { buy: bitcoin::Amount }, - #[error("Seller blockchain network {asb:?} setup did not match your blockchain network setup {cli:?}")] + #[error( + "Seller blockchain network {asb:?} setup did not match your blockchain network setup {cli:?}" + )] BlockchainNetworkMismatch { cli: BlockchainNetwork, asb: BlockchainNetwork, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index f968506a35..86c3cbb88a 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -11,7 +11,9 @@ use crate::protocol::{bob, Database}; use anyhow::{Context as AnyContext, Result}; use std::sync::Arc; use std::time::Duration; -use swap_core::bitcoin::{ExpiredTimelocks, TxCancel, TxFullRefund}; +use swap_core::bitcoin::{ + ExpiredTimelocks, TxCancel, TxFullRefund, TxPartialRefund, TxRefundAmnesty, +}; use swap_core::monero::TxHash; use swap_env::env; use swap_machine::bob::State5; @@ -112,17 +114,18 @@ async fn next_state( let tx_refund_fee = bitcoin_wallet .estimate_fee(TxFullRefund::weight(), Some(btc_amount)) .await?; - - // At this point we don't know how high btc_amnesty_amount is. + + // At this point we don't know how high btc_amnesty_amount is. // This means we don't know how large the amount of the partial refund and amnesty transactions will be. // We therefore specify the same upper limit on tx fees as for the other transactions, even though // the maximum fee percentage might be higher due to that. - let tx_partial_refund_fee = bitcoin_wallet. - estimate_fee(TxPartialRefund::weight(), Some(btc_amount)).await?; + let tx_partial_refund_fee = bitcoin_wallet + .estimate_fee(TxPartialRefund::weight(), Some(btc_amount)) + .await?; let tx_refund_amnesty_fee = bitcoin_wallet .estimate_fee(TxRefundAmnesty::weight(), Some(btc_amount)) .await?; - + // Emit an event to tauri that we are negotiating with the maker to lock the Bitcoin event_emitter.emit_swap_progress_event( swap_id, From 4f73fba0494d072f5c52e51a94505685ed6eedf8 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 16:09:45 +0100 Subject: [PATCH 018/146] fix merge conflict --- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index cb29ef6ffe..7fb8594fdd 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -247,11 +247,7 @@ export default function SwapStatusAlert({ swap: GetSwapInfoResponseExt | null; onlyShowIfUnusualAmountOfTimeHasPassed?: boolean; }) { -<<<<<<< HEAD const swapId = swap?.swap_id ?? null; -======= - const swapId = swap?.swap_id ?? ""; ->>>>>>> b539b31b (fix react bug nullish check) const timelock = useAppSelector(selectSwapTimelock(swapId)); const isRunning = useIsSpecificSwapRunning(swapId); @@ -296,14 +292,11 @@ export default function SwapStatusAlert({ ) ) : ( <> -<<<<<<< HEAD Swap {swap.swap_id} is not running -======= - Swap {swapId} is not running ->>>>>>> b539b31b (fix react bug nullish check) - )} - + ) + } + {timelock && } - + ); } From e809b42aba514a6ed145bc6975ccbceb4aa4b290 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 16:27:14 +0100 Subject: [PATCH 019/146] add PartiallyRefunded, AmnestyPublished, AmnestyConfirmed states for Bob --- swap-db/src/bob.rs | 13 +++++++++++++ swap-machine/src/bob/mod.rs | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index cbb79974bb..4742b754d5 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -44,6 +44,8 @@ pub enum Bob { BtcCancelled(bob::State6), BtcRefundPublished(bob::State6), BtcEarlyRefundPublished(bob::State6), + BtcPartiallyRefunded(bob::State6), + BtcAmnestyPublished(bob::State6), Done(BobEndState), } @@ -53,6 +55,7 @@ pub enum BobEndState { XmrRedeemed { tx_lock_id: bitcoin::Txid }, BtcRefunded(Box), BtcEarlyRefunded(Box), + BtcAmnestyConfirmed(Box), } impl From for Bob { @@ -108,6 +111,11 @@ impl From for Bob { BobState::BtcEarlyRefunded(state6) => { Bob::Done(BobEndState::BtcEarlyRefunded(Box::new(state6))) } + BobState::BtcPartiallyRefunded(state6) => Bob::BtcPartiallyRefunded(state6), + BobState::BtcAmnestyPublished(state6) => Bob::BtcAmnestyPublished(state6), + BobState::BtcAmnestyConfirmed(state6) => { + Bob::Done(BobEndState::BtcAmnestyConfirmed(Box::new(state6))) + } BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted), } } @@ -157,6 +165,8 @@ impl From for BobState { Bob::CancelTimelockExpired(state6) => BobState::CancelTimelockExpired(state6), Bob::BtcCancelled(state6) => BobState::BtcCancelled(state6), Bob::BtcRefundPublished(state6) => BobState::BtcRefundPublished(state6), + Bob::BtcPartiallyRefunded(state6) => BobState::BtcPartiallyRefunded(state6), + Bob::BtcAmnestyPublished(state6) => BobState::BtcAmnestyPublished(state6), Bob::BtcEarlyRefundPublished(state6) => BobState::BtcEarlyRefundPublished(state6), Bob::BtcPunished { state, tx_lock_id } => BobState::BtcPunished { state, tx_lock_id }, Bob::Done(end_state) => match end_state { @@ -164,6 +174,7 @@ impl From for BobState { BobEndState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id }, BobEndState::BtcRefunded(state6) => BobState::BtcRefunded(*state6), BobEndState::BtcEarlyRefunded(state6) => BobState::BtcEarlyRefunded(*state6), + BobEndState::BtcAmnestyConfirmed(state6) => BobState::BtcAmnestyConfirmed(*state6), }, } } @@ -188,6 +199,8 @@ impl fmt::Display for Bob { Bob::Done(end_state) => write!(f, "Done: {}", end_state), Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"), Bob::BtcPunished { .. } => f.write_str("Bitcoin punished"), + Bob::BtcPartiallyRefunded { .. } => f.write_str("Bitcoin partially refunded"), + Bob::BtcAmnestyPublished { .. } => f.write_str("Bitcoin amnesty published"), } } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index cee14ffe57..7c7d72af75 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -55,6 +55,9 @@ pub enum BobState { BtcEarlyRefundPublished(State6), BtcRefunded(State6), BtcEarlyRefunded(State6), + BtcPartiallyRefunded(State6), + BtcAmnestyPublished(State6), + BtcAmnestyConfirmed(State6), XmrRedeemed { tx_lock_id: bitcoin::Txid, }, @@ -116,6 +119,9 @@ impl fmt::Display for BobState { BobState::XmrRedeemed { .. } => write!(f, "xmr is redeemed"), BobState::BtcPunished { .. } => write!(f, "btc is punished"), BobState::BtcEarlyRefunded { .. } => write!(f, "btc is early refunded"), + BobState::BtcPartiallyRefunded { .. } => write!(f, "btc is partially refunded"), + BobState::BtcAmnestyPublished { .. } => write!(f, "btc amnesty is published"), + BobState::BtcAmnestyConfirmed { .. } => write!(f, "btc amnesty is confirmed"), BobState::SafelyAborted => write!(f, "safely aborted"), } } @@ -143,7 +149,10 @@ impl BobState { BobState::CancelTimelockExpired(state) | BobState::BtcCancelled(state) | BobState::BtcRefundPublished(state) - | BobState::BtcEarlyRefundPublished(state) => { + | BobState::BtcEarlyRefundPublished(state) + | BobState::BtcPartiallyRefunded(state) + | BobState::BtcAmnestyPublished(state) + | BobState::BtcAmnestyConfirmed(state) => { Some(state.expired_timelock(bitcoin_wallet.as_ref()).await?) } BobState::BtcPunished { .. } => Some(ExpiredTimelocks::Punish), From 9851f357cce2b446b3505e76ca81cde0a89d3054 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 16:32:20 +0100 Subject: [PATCH 020/146] add Bob::BtcPartialRefundPublished state --- swap-db/src/bob.rs | 6 ++++++ swap-machine/src/bob/mod.rs | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 4742b754d5..71cfac23ca 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -44,6 +44,7 @@ pub enum Bob { BtcCancelled(bob::State6), BtcRefundPublished(bob::State6), BtcEarlyRefundPublished(bob::State6), + BtcPartialRefundPublished(bob::State6), BtcPartiallyRefunded(bob::State6), BtcAmnestyPublished(bob::State6), Done(BobEndState), @@ -103,6 +104,7 @@ impl From for Bob { BobState::BtcCancelled(state6) => Bob::BtcCancelled(state6), BobState::BtcRefundPublished(state6) => Bob::BtcRefundPublished(state6), BobState::BtcEarlyRefundPublished(state6) => Bob::BtcEarlyRefundPublished(state6), + BobState::BtcPartialRefundPublished(state6) => Bob::BtcPartialRefundPublished(state6), BobState::BtcPunished { state, tx_lock_id } => Bob::BtcPunished { state, tx_lock_id }, BobState::BtcRefunded(state6) => Bob::Done(BobEndState::BtcRefunded(Box::new(state6))), BobState::XmrRedeemed { tx_lock_id } => { @@ -165,6 +167,7 @@ impl From for BobState { Bob::CancelTimelockExpired(state6) => BobState::CancelTimelockExpired(state6), Bob::BtcCancelled(state6) => BobState::BtcCancelled(state6), Bob::BtcRefundPublished(state6) => BobState::BtcRefundPublished(state6), + Bob::BtcPartialRefundPublished(state6) => BobState::BtcPartialRefundPublished(state6), Bob::BtcPartiallyRefunded(state6) => BobState::BtcPartiallyRefunded(state6), Bob::BtcAmnestyPublished(state6) => BobState::BtcAmnestyPublished(state6), Bob::BtcEarlyRefundPublished(state6) => BobState::BtcEarlyRefundPublished(state6), @@ -195,6 +198,9 @@ impl fmt::Display for Bob { Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"), Bob::BtcRefundPublished { .. } => f.write_str("Bitcoin refund published"), Bob::BtcEarlyRefundPublished { .. } => f.write_str("Bitcoin early refund published"), + Bob::BtcPartialRefundPublished { .. } => { + f.write_str("Bitcoin partially refund published") + } Bob::BtcRedeemed(_) => f.write_str("Monero redeemable"), Bob::Done(end_state) => write!(f, "Done: {}", end_state), Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"), diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 7c7d72af75..6d4fb3c383 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -53,6 +53,7 @@ pub enum BobState { BtcCancelled(State6), BtcRefundPublished(State6), BtcEarlyRefundPublished(State6), + BtcPartialRefundPublished(State6), BtcRefunded(State6), BtcEarlyRefunded(State6), BtcPartiallyRefunded(State6), @@ -115,6 +116,9 @@ impl fmt::Display for BobState { BobState::BtcCancelled(..) => write!(f, "btc is cancelled"), BobState::BtcRefundPublished { .. } => write!(f, "btc refund is published"), BobState::BtcEarlyRefundPublished { .. } => write!(f, "btc early refund is published"), + BobState::BtcPartialRefundPublished { .. } => { + write!(f, "btc partially refund is published") + } BobState::BtcRefunded(..) => write!(f, "btc is refunded"), BobState::XmrRedeemed { .. } => write!(f, "xmr is redeemed"), BobState::BtcPunished { .. } => write!(f, "btc is punished"), @@ -150,6 +154,7 @@ impl BobState { | BobState::BtcCancelled(state) | BobState::BtcRefundPublished(state) | BobState::BtcEarlyRefundPublished(state) + | BobState::BtcPartialRefundPublished(state) | BobState::BtcPartiallyRefunded(state) | BobState::BtcAmnestyPublished(state) | BobState::BtcAmnestyConfirmed(state) => { From 2b6b05b3ed2ba0fd34f4a09ea91d35073876b285 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 17:05:18 +0100 Subject: [PATCH 021/146] add new states to match arms --- swap/src/cli/cancel_and_refund.rs | 8 ++++++++ swap/src/protocol/bob/swap.rs | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 3bd008f258..3d41a7c7e3 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -67,6 +67,10 @@ pub async fn cancel( BobState::BtcCancelled(state6) => state6, BobState::BtcRefundPublished(state6) => state6, BobState::BtcEarlyRefundPublished(state6) => state6, + BobState::BtcPartialRefundPublished(state6) => state6, + BobState::BtcPartiallyRefunded(state6) => state6, + BobState::BtcAmnestyConfirmed(state6) => state6, + BobState::BtcAmnestyPublished(state6) => state6, BobState::Started { .. } | BobState::BtcRedeemed(_) @@ -170,6 +174,10 @@ pub async fn refund( BobState::BtcRefunded(state6) => state6, BobState::BtcRefundPublished(state6) => state6, BobState::BtcEarlyRefundPublished(state6) => state6, + BobState::BtcPartialRefundPublished(state6) => state6, + BobState::BtcPartiallyRefunded(state6) => state6, + BobState::BtcAmnestyPublished(state6) => state6, + BobState::BtcAmnestyConfirmed(state6) => state6, BobState::Started { .. } | BobState::SwapSetupCompleted(_) | BobState::BtcRedeemed(_) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 86c3cbb88a..c65bf71f82 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1052,6 +1052,10 @@ async fn next_state( } // TODO: Emit a Tauri event here BobState::BtcEarlyRefunded(state) => BobState::BtcEarlyRefunded(state), + BobState::BtcPartialRefundPublished(state) + | BobState::BtcPartiallyRefunded(state) + | BobState::BtcAmnestyPublished(state) + | BobState::BtcAmnestyConfirmed(state) => todo!(), BobState::SafelyAborted => BobState::SafelyAborted, BobState::XmrRedeemed { tx_lock_id } => { event_emitter.emit_swap_progress_event( From b70275d2bc9ed66b304394a70f2b3f89f3566614 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 3 Dec 2025 17:09:51 +0100 Subject: [PATCH 022/146] fix compilation errors in tests --- swap/src/bitcoin/wallet.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 07bb0fb269..1d8d8abafc 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3773,7 +3773,7 @@ mod swap_core_bitcoin_tests { tx_lock_fee, ); - let message0 = bob_state0.next_message(); + let message0 = bob_state0.next_message().unwrap(); let (_, alice_state1) = alice_state0.receive(message0).unwrap(); let alice_message1 = alice_state1.next_message(); @@ -3814,7 +3814,11 @@ mod swap_core_bitcoin_tests { assert_weight(redeem_transaction, TxRedeem::weight().to_wu(), "TxRedeem"); assert_weight(cancel_transaction, TxCancel::weight().to_wu(), "TxCancel"); assert_weight(punish_transaction, TxPunish::weight().to_wu(), "TxPunish"); - assert_weight(refund_transaction, TxFullRefund::weight().to_wu(), "TxRefund"); + assert_weight( + refund_transaction, + TxFullRefund::weight().to_wu(), + "TxRefund", + ); // Test TxEarlyRefund transaction let early_refund_transaction = alice_state3 @@ -3883,7 +3887,7 @@ mod swap_core_bitcoin_tests { ); // Complete the state machine up to State3 - let message0 = bob_state0.next_message(); + let message0 = bob_state0.next_message().unwrap(); let (_, alice_state1) = alice_state0.receive(message0).unwrap(); let alice_message1 = alice_state1.next_message(); @@ -3940,7 +3944,10 @@ mod swap_core_bitcoin_tests { // It should be the same as TxRedeem and TxRefund weights since they have similar structure assert_eq!(TxEarlyRefund::weight() as u64, TxRedeem::weight().to_wu()); - assert_eq!(TxEarlyRefund::weight() as u64, TxFullRefund::weight().to_wu()); + assert_eq!( + TxEarlyRefund::weight() as u64, + TxFullRefund::weight().to_wu() + ); } // Weights fluctuate because of the length of the signatures. Valid ecdsa From c6e1385dfce13482f5a4fab97121c04c7d437101 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 6 Dec 2025 11:42:42 +0100 Subject: [PATCH 023/146] add btc_amnesty_amount (optional) to all Bob states --- swap-machine/src/bob/mod.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 6d4fb3c383..39e835f1f5 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -309,7 +309,7 @@ impl State0 { S_a_bitcoin: msg.S_a_bitcoin, v, xmr: self.xmr, - btc_amnesty_amount: msg.amnesty_amount, + btc_amnesty_amount: Some(msg.amnesty_amount), cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -337,7 +337,7 @@ pub struct State1 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, xmr: monero::Amount, - btc_amnesty_amount: bitcoin::Amount, + btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -374,7 +374,8 @@ impl State1 { &self.refund_address, self.A, self.b.public(), - self.btc_amnesty_amount, + self.btc_amnesty_amount + .context("btc_amnesty_amount is missing but required to create TxPartialRefund")?, self.tx_partial_refund_fee .context("tx_partial_refund_fee missing but required to setup swap")?, )?; @@ -422,6 +423,7 @@ impl State1 { S_a_bitcoin: self.S_a_bitcoin, v: self.v, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -452,6 +454,7 @@ pub struct State2 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, pub xmr: monero::Amount, + btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, #[serde(with = "address_serde")] @@ -522,6 +525,7 @@ impl State2 { S_a_bitcoin: self.S_a_bitcoin, v: self.v, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -552,6 +556,7 @@ pub struct State3 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, xmr: monero::Amount, + btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, #[serde(with = "address_serde")] @@ -607,6 +612,7 @@ impl State3 { S_a_bitcoin: self.S_a_bitcoin, v: self.v, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, refund_address: self.refund_address, @@ -644,6 +650,7 @@ impl State3 { tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, xmr: self.xmr, + btc_ammesty_amount: self.btc_amnesty_amount, } } @@ -701,6 +708,7 @@ pub struct State4 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, xmr: monero::Amount, + btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, #[serde(with = "address_serde")] @@ -750,6 +758,7 @@ impl State4 { s_b: self.s_b, v: self.v, xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, tx_lock: self.tx_lock.clone(), monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, lock_transfer_proof: self.lock_transfer_proof.clone(), @@ -825,6 +834,7 @@ impl State4 { tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, + btc_ammesty_amount: self.btc_amnesty_amount, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, } @@ -842,6 +852,7 @@ pub struct State5 { s_b: monero::Scalar, v: monero::PrivateViewKey, xmr: monero::Amount, + btc_amnesty_amount: Option, tx_lock: bitcoin::TxLock, pub monero_wallet_restore_blockheight: BlockHeight, pub lock_transfer_proof: TransferProof, @@ -885,6 +896,7 @@ pub struct State6 { s_b: monero::Scalar, v: monero::PrivateViewKey, pub xmr: monero::Amount, + btc_ammesty_amount: Option, pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, @@ -1026,6 +1038,7 @@ impl State6 { s_b: self.s_b, v: self.v, xmr: self.xmr, + btc_amnesty_amount: self.btc_ammesty_amount, tx_lock: self.tx_lock.clone(), monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, lock_transfer_proof, From 2b6e81acd5d304e1e28cd0def7a28caeef8e88ad Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 6 Dec 2025 11:43:18 +0100 Subject: [PATCH 024/146] add construct_tx_partial_refund and signed_partial_refund_transaction to Bob's State6 --- swap-machine/src/bob/mod.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 39e835f1f5..81bfecd8ca 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -1018,6 +1018,41 @@ impl State6 { Ok(signed_tx_refund) } + pub fn construct_tx_partial_refund(&self) -> Result { + let tx_cancel = self.construct_tx_cancel()?; + bitcoin::TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + self.btc_ammesty_amount + .context("Can't construct TxPartialRefund because btc_amnesty_amount is missing")?, + self.tx_partial_refund_fee.context( + "Can't construct TxPartialRefund because tx_partial_refund_fee is missing", + )?, + ) + } + + pub fn signed_partial_refund_transaction(&self) -> Result { + let tx_partial_refund_encsig = self + .bob_refund_type + .tx_partial_refund_encsig() + .context("Can't finalize TxPartialRefund because Alice's encsig is missing")?; + + let tx_partial_refund = self.construct_tx_partial_refund()?; + + let adaptor = Adaptor::, Deterministic>::default(); + + let sig_b = self.b.sign(tx_partial_refund.digest()); + let sig_a = + adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), tx_partial_refund_encsig); + + let signed_tx_partial_refund = + tx_partial_refund.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?; + + Ok(signed_tx_partial_refund) + } + pub fn construct_tx_early_refund(&self) -> bitcoin::TxEarlyRefund { bitcoin::TxEarlyRefund::new(&self.tx_lock, &self.refund_address, self.tx_refund_fee) } From 55f413f2f2883a82fdbeefcb2217f4c823310b63 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 6 Dec 2025 14:19:15 +0100 Subject: [PATCH 025/146] alice: actually send TxPartialRefund encsig --- swap-machine/src/alice/mod.rs | 39 +++++++++++++--------- swap-p2p/src/protocols/swap_setup/alice.rs | 22 +++++++----- swap/src/bitcoin/wallet.rs | 4 +-- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 6a35ababba..6c94fbec5d 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -1,19 +1,19 @@ #![allow(non_snake_case)] -use crate::common::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM}; -use anyhow::{anyhow, bail, Context, Result}; +use crate::common::{CROSS_CURVE_PROOF_SYSTEM, Message0, Message1, Message2, Message3, Message4}; +use anyhow::{Context, Result, anyhow, bail}; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ - current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, - TxEarlyRefund, TxPunish, TxRedeem, TxFullRefund, Txid, + CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxEarlyRefund, + TxFullRefund, TxPunish, TxRedeem, Txid, current_epoch, }; use swap_core::monero; -use swap_core::monero::primitives::{BlockHeight, TransferProof, TransferRequest, WatchRequest}; use swap_core::monero::ScalarExt; +use swap_core::monero::primitives::{BlockHeight, TransferProof, TransferRequest, WatchRequest}; use swap_env::env::Config; use uuid::Uuid; @@ -353,7 +353,7 @@ pub struct State2 { } impl State2 { - pub fn next_message(&self) -> Message3 { + pub fn next_message(&self) -> Result { let tx_cancel = swap_core::bitcoin::TxCancel::new( &self.tx_lock, self.cancel_timelock, @@ -363,23 +363,32 @@ impl State2 { ) .expect("valid cancel tx"); - let tx_refund = - swap_core::bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); - // Alice encsigns the refund transaction(bitcoin) digest with Bob's monero - // pubkey(S_b). The refund transaction spends the output of - // tx_lock_bitcoin to Bob's refund address. + let tx_partial_refund = swap_core::bitcoin::TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.a.public(), + self.B, + self.btc_amnesty_amount, + self.tx_refund_fee, + )?; + // Alice encsigns the partial refund transaction(bitcoin) digest with Bob's monero + // pubkey(S_b). The partial refund transaction spends the output of + // tx_lock_bitcoin to Bob's refund address (except for the amnesty output). // recover(encsign(a, S_b, d), sign(a, d), S_b) = s_b where d is a digest, (a, // A) is alice's keypair and (s_b, S_b) is bob's keypair. - let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest()); + let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); let tx_cancel_sig = self.a.sign(tx_cancel.digest()); - let (tx_full_refund_encsig, tx_refund_amnesty_sig) = todo!("TODO: Implement system for Alice to decide commiting to full refund"); - Message3 { + // TODO: When to send these? + let tx_full_refund_encsig = None; + let tx_refund_amnesty_sig = None; + + Ok(Message3 { tx_cancel_sig, tx_partial_refund_encsig: tx_refund_encsig, tx_full_refund_encsig, tx_refund_amnesty_sig, - } + }) } pub fn receive(self, msg: Message4) -> Result { diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 7bbb39d583..7fd57d14a9 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -1,12 +1,12 @@ use crate::out_event; use crate::protocols::swap_setup; use crate::protocols::swap_setup::{ - protocol, BlockchainNetwork, SpotPriceError, SpotPriceRequest, SpotPriceResponse, + BlockchainNetwork, SpotPriceError, SpotPriceRequest, SpotPriceResponse, protocol, }; -use anyhow::{anyhow, Context, Result}; -use futures::future::{BoxFuture, OptionFuture}; +use anyhow::{Context, Result, anyhow}; use futures::AsyncWriteExt; use futures::FutureExt; +use futures::future::{BoxFuture, OptionFuture}; use libp2p::core::upgrade; use libp2p::swarm::handler::ConnectionEvent; use libp2p::swarm::{ConnectionHandler, ConnectionId}; @@ -320,7 +320,9 @@ where env_config, min_buy, max_buy, - latest_rate.map_err(|error| Box::new(error) as Box), + latest_rate.map_err(|error| { + Box::new(error) as Box + }), ), ); @@ -503,8 +505,7 @@ async fn run_swap_setup( }); } - let rate = - latest_rate.map_err(Error::LatestRateFetchFailed)?; + let rate = latest_rate.map_err(Error::LatestRateFetchFailed)?; let xmr = rate .sell_quote(btc) .map_err(Error::SellQuoteCalculationFailed)?; @@ -572,9 +573,12 @@ async fn run_swap_setup( .receive(message2) .context("Failed to transition state1 -> state2 using message2")?; - swap_setup::write_cbor_message(&mut substream, state2.next_message()) - .await - .context("Failed to send message3")?; + swap_setup::write_cbor_message( + &mut substream, + state2.next_message().context("Couldn't produce Message3")?, + ) + .await + .context("Failed to send message3")?; let message4 = swap_setup::read_cbor_message::(&mut substream) .await diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 1d8d8abafc..a64c097db4 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -3785,7 +3785,7 @@ mod swap_core_bitcoin_tests { let bob_message2 = bob_state1.next_message(); let alice_state2 = alice_state1.receive(bob_message2).unwrap(); - let alice_message3 = alice_state2.next_message(); + let alice_message3 = alice_state2.next_message().unwrap(); let bob_state2 = bob_state1.receive(alice_message3).unwrap(); let bob_message4 = bob_state2.next_message(); @@ -3898,7 +3898,7 @@ mod swap_core_bitcoin_tests { let bob_message2 = bob_state1.next_message(); let alice_state2 = alice_state1.receive(bob_message2).unwrap(); - let alice_message3 = alice_state2.next_message(); + let alice_message3 = alice_state2.next_message().unwrap(); let bob_state2 = bob_state1.receive(alice_message3).unwrap(); let bob_message4 = bob_state2.next_message(); From c3c000c4d1f0280fd0c285bfaf3ffe553ad18505 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 10:57:49 +0100 Subject: [PATCH 026/146] add ensure_broadcasted function to BitcoinWallet trait --- bitcoin-wallet/src/lib.rs | 6 +++++ bitcoin-wallet/src/primitives.rs | 16 +++++++++++- swap/src/bitcoin/wallet.rs | 44 +++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/bitcoin-wallet/src/lib.rs b/bitcoin-wallet/src/lib.rs index b98be65a19..a5ffbe8ff7 100644 --- a/bitcoin-wallet/src/lib.rs +++ b/bitcoin-wallet/src/lib.rs @@ -41,6 +41,12 @@ pub trait BitcoinWallet: Send + Sync { kind: &str, ) -> Result<(Txid, Subscription)>; + async fn ensure_broadcasted( + &self, + transaction: bitcoin::Transaction, + kind: &str, + ) -> Result<(Txid, Subscription)>; + async fn sync(&self) -> Result<()>; async fn subscribe_to(&self, tx: Box) -> Subscription; diff --git a/bitcoin-wallet/src/primitives.rs b/bitcoin-wallet/src/primitives.rs index 4755c1369c..2a84cd1008 100644 --- a/bitcoin-wallet/src/primitives.rs +++ b/bitcoin-wallet/src/primitives.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use bitcoin::{FeeRate, ScriptBuf, Txid}; +use bitcoin::{FeeRate, ScriptBuf, Transaction, Txid}; /// An object that can estimate fee rates and minimum relay fees. pub trait EstimateFeeRate { @@ -192,6 +192,20 @@ impl Watchable for (Txid, ScriptBuf) { } } +// Watching a transaction by watching it's first output +// (because Electrum expects a script hash). This works +// because all outputs of a transaction have the same status. +impl Watchable for Transaction { + fn id(&self) -> Txid { + self.compute_txid() + } + + fn script(&self) -> ScriptBuf { + debug_assert!(!self.output.is_empty(), "Transaction has no outputs"); + self.output[0].script_pubkey.clone() + } +} + impl Watchable for &dyn Watchable { fn id(&self) -> Txid { (*self).id() diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index a64c097db4..4da262c4db 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -668,12 +668,7 @@ impl Wallet { let txid = transaction.compute_txid(); // to watch for confirmations, watching a single output is enough - let subscription = self - .subscribe_to(Box::new(( - txid, - transaction.output[0].script_pubkey.clone(), - ))) - .await; + let subscription = self.subscribe_to(Box::new(transaction.clone())).await; let client = self.electrum_client.lock().await; let broadcast_results = client @@ -736,6 +731,27 @@ impl Wallet { Ok((txid, subscription)) } + /// Check if a [`Transaction`] has been broadcasted and if not, broadcast it. + pub async fn ensure_broadcasted( + &self, + transaction: bitcoin::Transaction, + kind: &str, + ) -> Result<(Txid, Subscription)> { + let tx_status = self.status_of_script(&transaction).await?; + + // If it's already been broadcasted, return a subscription to it + if matches!( + tx_status, + ScriptStatus::InMempool | ScriptStatus::Confirmed(_) + ) { + let subscription = self.subscribe_to(Box::new(transaction.clone())).await; + return Ok((transaction.compute_txid(), subscription)); + } + + // Otherwise broadcast it + self.broadcast(transaction, kind).await + } + pub async fn get_raw_transaction(&self, txid: Txid) -> Result>> { self.get_tx(txid) .await @@ -2116,6 +2132,14 @@ impl bitcoin_wallet::BitcoinWallet for Wallet { Wallet::broadcast(self, transaction, kind).await } + async fn ensure_broadcasted( + &self, + transaction: bitcoin::Transaction, + kind: &str, + ) -> Result<(Txid, Subscription)> { + Wallet::ensure_broadcasted(self, transaction, kind).await + } + async fn sync(&self) -> Result<()> { Wallet::sync(self).await } @@ -2947,6 +2971,14 @@ mod tests { unimplemented!("stub method called erroneously") } + async fn ensure_broadcasted( + &self, + transaction: bitcoin::Transaction, + kind: &str, + ) -> Result<(Txid, Subscription)> { + unimplemented!("stub method called erroneously") + } + async fn sync(&self) -> Result<()> { unimplemented!("stub method called erroneously") } From 1f83ff7c8f139f50bddea6d4c639920543c34725 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 11:44:10 +0100 Subject: [PATCH 027/146] bob state machine: publish best bitcoin refund transaction depending on which signatures we have --- swap-machine/src/bob/mod.rs | 51 +++++++++++++++++++++++++------ swap/src/cli/cancel_and_refund.rs | 5 ++- swap/src/protocol/bob/swap.rs | 17 ++++++++--- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 81bfecd8ca..39ec933efc 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -69,9 +69,14 @@ pub enum BobState { SafelyAborted, } -/// !IMPORTANT: This enum must be #[untagged] and maintain the field names in order to be backwards compatible +/// An enum abstracting over the different combination of +/// refund signatures Alice could have sent us. +/// Maintains backward compatibility with old swaps (which only had the full refund signature). +/// +/// # IMPORTANT +/// This enum must be `#[untagged]` and maintain the field names in order to be backwards compatible /// with the database. -/// Changing any of that is a breaking change +/// Changing any of that is a breaking change. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(untagged)] pub enum BobRefundType { @@ -907,7 +912,7 @@ pub struct State6 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - bob_refund_type: BobRefundType, + pub bob_refund_type: BobRefundType, /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. @@ -980,15 +985,43 @@ impl State6 { Ok((tx_id, subscription)) } - pub async fn publish_refund_btc( + /// Publish the best refund transaction based on the refund signatures Alice has sent us. + /// This is either `TxFullRefund` or `TxPartialRefund`. + /// Returns the corresponding state (`BtcRefundPublished`/`PartialRefundPublished`) on success. + pub async fn publish_best_btc_refund_tx( &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, - ) -> Result { - let signed_tx_refund = self.signed_full_refund_transaction()?; - let signed_tx_refund_txid = signed_tx_refund.compute_txid(); - bitcoin_wallet.broadcast(signed_tx_refund, "refund").await?; + ) -> Result<(Txid, BobState)> { + if self.bob_refund_type.tx_full_refund_encsig().is_some() { + tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); + let tx_full_refund = self + .signed_full_refund_transaction() + .context("Couldn't construct TxFullRefund")?; + let (txid, _) = bitcoin_wallet + .ensure_broadcasted(tx_full_refund, "full refund") + .await + .context("Couldn't ensure broadcast of TxFullRefund")?; + + return Ok((txid, BobState::BtcRefundPublished(self.clone()))); + } + + if self.bob_refund_type.tx_partial_refund_encsig().is_some() { + tracing::info!( + "Don't have the full refund signature, attempting partial Bitcoin refund" + ); + + let tx_partial_refund = self + .signed_partial_refund_transaction() + .context("Couldn't construct TxPartialRefund")?; + let (txid, _) = bitcoin_wallet + .ensure_broadcasted(tx_partial_refund, "partial refund") + .await + .context("Couldn't ensure broadcast of TxPartialRefund")?; + + return Ok((txid, BobState::BtcPartialRefundPublished(self.clone()))); + } - Ok(signed_tx_refund_txid) + unreachable!("We always have either the partial or full refund encsig"); } pub fn construct_tx_refund(&self) -> Result { diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 3d41a7c7e3..be7c8391ca 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -194,7 +194,10 @@ pub async fn refund( tracing::info!(%swap_id, "Attempting to manually refund swap"); // Attempt to just publish the refund transaction - match state6.publish_refund_btc(bitcoin_wallet.as_ref()).await { + match state6 + .publish_best_btc_refund_tx(bitcoin_wallet.as_ref()) + .await + { Ok(_) => { let state = BobState::BtcRefunded(state6); db.insert_latest_state(swap_id, state.clone().into()) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index c65bf71f82..07f92eb7b7 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -772,6 +772,7 @@ async fn next_state( let bitcoin_wallet_for_retry = bitcoin_wallet.clone(); let state_for_retry = state.clone(); + retry( "Check timelocks and try to refund", || { @@ -785,11 +786,19 @@ async fn next_state( ))) } ExpiredTimelocks::Cancel { .. } => { - let btc_refund_txid = state.publish_refund_btc(&*bitcoin_wallet).await.context("Failed to publish refund transaction after ensuring cancel timelock has expired and refund timelock has not expired").map_err(backoff::Error::transient)?; - - tracing::info!(%btc_refund_txid, "Refunded our Bitcoin"); + // Publish the best Bitcoin refund transaction we can sign: + // - either full refund, if alice sent use that signature (prioritized) + // - or just partial refund. + // `publish_best_btc_refund_tx` returns the appropriate state depending on which + // one was published. It also logs the refund type. + let (txid, next_state) = state.publish_best_btc_refund_tx(&*bitcoin_wallet) + .await + .context("Couldn't publish Bitcoin refund tx") + .map_err(backoff::Error::transient)?; - Ok(BobState::BtcRefundPublished(state.clone())) + tracing::info!(%txid, "Published Bitcoin refund transaction"); + + Ok(next_state) } ExpiredTimelocks::Punish => { let tx_lock_id = state.tx_lock_id(); From e0341e973d7e1cee377799af47195cae13487a16 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 11:56:35 +0100 Subject: [PATCH 028/146] inline publish_best_btc_refund_tx --- swap/src/protocol/bob/swap.rs | 38 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 07f92eb7b7..8d8a69be96 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -789,16 +789,36 @@ async fn next_state( // Publish the best Bitcoin refund transaction we can sign: // - either full refund, if alice sent use that signature (prioritized) // - or just partial refund. - // `publish_best_btc_refund_tx` returns the appropriate state depending on which - // one was published. It also logs the refund type. - let (txid, next_state) = state.publish_best_btc_refund_tx(&*bitcoin_wallet) - .await - .context("Couldn't publish Bitcoin refund tx") - .map_err(backoff::Error::transient)?; - tracing::info!(%txid, "Published Bitcoin refund transaction"); - - Ok(next_state) + if state.bob_refund_type.tx_full_refund_encsig().is_some() { + tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); + let tx_full_refund = state + .signed_full_refund_transaction() + .context("Couldn't construct TxFullRefund")?; + let (txid, _) = bitcoin_wallet + .ensure_broadcasted(tx_full_refund, "full refund") + .await + .context("Couldn't ensure broadcast of TxFullRefund")?; + tracing::info!(%txid, "Successfully published full bitcoin refund transaction"); + return Ok(BobState::BtcRefundPublished(state.clone())); + } + + if state.bob_refund_type.tx_partial_refund_encsig().is_some() { + tracing::info!( + "Don't have the full refund signature, attempting partial Bitcoin refund" + ); + let tx_partial_refund = state + .signed_partial_refund_transaction() + .context("Couldn't construct TxPartialRefund")?; + let (txid, _) = bitcoin_wallet + .ensure_broadcasted(tx_partial_refund, "partial refund") + .await + .context("Couldn't ensure broadcast of TxPartialRefund")?; + tracing::info!(%txid, "Successfully published partial bitcoin refund transaction"); + return Ok(BobState::BtcPartialRefundPublished(state.clone())); + } + + unreachable!("We always have either the partial or full refund encsig"); } ExpiredTimelocks::Punish => { let tx_lock_id = state.tx_lock_id(); From 651a5fab2200fff08fce43481f301911d9636151 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 12:00:26 +0100 Subject: [PATCH 029/146] rename BobRefundType to RefundSignatures --- swap-machine/src/bob/mod.rs | 46 ++++++++++++++++++----------------- swap/src/protocol/bob/swap.rs | 4 +-- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 39ec933efc..5238cbed17 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -79,7 +79,7 @@ pub enum BobState { /// Changing any of that is a breaking change. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(untagged)] -pub enum BobRefundType { +pub enum RefundSignatures { /// Alice has only signed the partial refund transaction (most cases). Partial { tx_partial_refund_encsig: bitcoin::EncryptedSignature, @@ -416,7 +416,7 @@ impl State1 { bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig)?; } - let bob_refund_type = BobRefundType::from_possibly_full_refund_sig( + let refund_signatures = RefundSignatures::from_possibly_full_refund_sig( msg.tx_partial_refund_encsig, msg.tx_full_refund_encsig, ); @@ -436,7 +436,7 @@ impl State1 { punish_address: self.punish_address, tx_lock: self.tx_lock, tx_cancel_sig_a: msg.tx_cancel_sig, - bob_refund_type, + refund_signatures, tx_refund_amnesty_sig: msg.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, @@ -473,7 +473,7 @@ pub struct State2 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - bob_refund_type: BobRefundType, + refund_signatures: RefundSignatures, /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. @@ -537,7 +537,7 @@ impl State2 { redeem_address: self.redeem_address, tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a, - bob_refund_type: self.bob_refund_type, + refund_signatures: self.refund_signatures, tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, @@ -570,10 +570,12 @@ pub struct State3 { redeem_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, tx_cancel_sig_a: Signature, + /// The (encrypted) signatures Alice sent us for the Bitcoin refund transaction(s). + /// /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - bob_refund_type: BobRefundType, + refund_signatures: RefundSignatures, /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. @@ -624,7 +626,7 @@ impl State3 { redeem_address: self.redeem_address, tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, - bob_refund_type: self.bob_refund_type, + refund_signatures: self.refund_signatures, tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, monero_wallet_restore_blockheight, lock_transfer_proof, @@ -648,7 +650,7 @@ impl State3 { refund_address: self.refund_address.clone(), tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), - bob_refund_type: self.bob_refund_type.clone(), + refund_signatures: self.refund_signatures.clone(), tx_refund_amnesty_sig: self.tx_refund_amnesty_sig.clone(), tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, @@ -725,7 +727,7 @@ pub struct State4 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - bob_refund_type: BobRefundType, + refund_signatures: RefundSignatures, /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. @@ -834,7 +836,7 @@ impl State4 { refund_address: self.refund_address, tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, - bob_refund_type: self.bob_refund_type, + refund_signatures: self.refund_signatures, tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, @@ -912,7 +914,7 @@ pub struct State6 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - pub bob_refund_type: BobRefundType, + pub refund_signatures: RefundSignatures, /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. @@ -992,7 +994,7 @@ impl State6 { &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, ) -> Result<(Txid, BobState)> { - if self.bob_refund_type.tx_full_refund_encsig().is_some() { + if self.refund_signatures.tx_full_refund_encsig().is_some() { tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); let tx_full_refund = self .signed_full_refund_transaction() @@ -1005,7 +1007,7 @@ impl State6 { return Ok((txid, BobState::BtcRefundPublished(self.clone()))); } - if self.bob_refund_type.tx_partial_refund_encsig().is_some() { + if self.refund_signatures.tx_partial_refund_encsig().is_some() { tracing::info!( "Don't have the full refund signature, attempting partial Bitcoin refund" ); @@ -1034,7 +1036,7 @@ impl State6 { } pub fn signed_full_refund_transaction(&self) -> Result { - let tx_full_refund_encsig = self.bob_refund_type.tx_full_refund_encsig().context( + let tx_full_refund_encsig = self.refund_signatures.tx_full_refund_encsig().context( "Can't sign full refund transaction because we don't have the necessary signature", )?; @@ -1068,7 +1070,7 @@ impl State6 { pub fn signed_partial_refund_transaction(&self) -> Result { let tx_partial_refund_encsig = self - .bob_refund_type + .refund_signatures .tx_partial_refund_encsig() .context("Can't finalize TxPartialRefund because Alice's encsig is missing")?; @@ -1128,7 +1130,7 @@ impl State6 { } } -impl BobRefundType { +impl RefundSignatures { pub fn from_possibly_full_refund_sig( partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option, @@ -1153,12 +1155,12 @@ impl BobRefundType { pub fn tx_full_refund_encsig(&self) -> Option { match self { - BobRefundType::Partial { .. } => None, - BobRefundType::Full { + RefundSignatures::Partial { .. } => None, + RefundSignatures::Full { tx_full_refund_encsig, .. } => Some(tx_full_refund_encsig.clone()), - BobRefundType::Legacy { + RefundSignatures::Legacy { tx_full_refund_encsig, } => Some(tx_full_refund_encsig.clone()), } @@ -1166,14 +1168,14 @@ impl BobRefundType { pub fn tx_partial_refund_encsig(&self) -> Option { match self { - BobRefundType::Partial { + RefundSignatures::Partial { tx_partial_refund_encsig, } => Some(tx_partial_refund_encsig.clone()), - BobRefundType::Full { + RefundSignatures::Full { tx_partial_refund_encsig, .. } => Some(tx_partial_refund_encsig.clone()), - BobRefundType::Legacy { .. } => None, + RefundSignatures::Legacy { .. } => None, } } } diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 8d8a69be96..a4f92da284 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -790,7 +790,7 @@ async fn next_state( // - either full refund, if alice sent use that signature (prioritized) // - or just partial refund. - if state.bob_refund_type.tx_full_refund_encsig().is_some() { + if state.refund_signatures.tx_full_refund_encsig().is_some() { tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); let tx_full_refund = state .signed_full_refund_transaction() @@ -803,7 +803,7 @@ async fn next_state( return Ok(BobState::BtcRefundPublished(state.clone())); } - if state.bob_refund_type.tx_partial_refund_encsig().is_some() { + if state.refund_signatures.tx_partial_refund_encsig().is_some() { tracing::info!( "Don't have the full refund signature, attempting partial Bitcoin refund" ); From 4542b6df853d368025e682c1f7eba5b8e99df713 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 12:01:41 +0100 Subject: [PATCH 030/146] fix btc_amnesty_amount type --- swap-machine/src/bob/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 5238cbed17..5f66318e26 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -657,7 +657,7 @@ impl State3 { tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, xmr: self.xmr, - btc_ammesty_amount: self.btc_amnesty_amount, + btc_amnesty_amount: self.btc_amnesty_amount, } } @@ -841,7 +841,7 @@ impl State4 { tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, - btc_ammesty_amount: self.btc_amnesty_amount, + btc_amnesty_amount: self.btc_amnesty_amount, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, } @@ -903,7 +903,7 @@ pub struct State6 { s_b: monero::Scalar, v: monero::PrivateViewKey, pub xmr: monero::Amount, - btc_ammesty_amount: Option, + btc_amnesty_amount: Option, pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, @@ -1060,7 +1060,7 @@ impl State6 { &self.refund_address, self.A, self.b.public(), - self.btc_ammesty_amount + self.btc_amnesty_amount .context("Can't construct TxPartialRefund because btc_amnesty_amount is missing")?, self.tx_partial_refund_fee.context( "Can't construct TxPartialRefund because tx_partial_refund_fee is missing", @@ -1108,7 +1108,7 @@ impl State6 { s_b: self.s_b, v: self.v, xmr: self.xmr, - btc_amnesty_amount: self.btc_ammesty_amount, + btc_amnesty_amount: self.btc_amnesty_amount, tx_lock: self.tx_lock.clone(), monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, lock_transfer_proof, From 2fef464517fe956315be743b6fd58cc79851f464 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 12:37:50 +0100 Subject: [PATCH 031/146] bob: refactor btc refund publish logic --- swap-machine/src/bob/mod.rs | 63 +++++++++++++++++++++---------- swap/src/bitcoin/wallet.rs | 3 ++ swap/src/cli/cancel_and_refund.rs | 15 ++++++-- swap/src/protocol/bob/swap.rs | 49 +++++++++++------------- 4 files changed, 79 insertions(+), 51 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 5f66318e26..6426d61673 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -102,6 +102,15 @@ pub enum RefundSignatures { }, } +/// Either a full refund or a partial refund +pub enum RefundType { + Full, + Partial { + total_swap_amount: bitcoin::Amount, + btc_amnesty_amount: bitcoin::Amount, + }, +} + impl fmt::Display for BobState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -136,6 +145,15 @@ impl fmt::Display for BobState { } } +impl fmt::Display for RefundType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RefundType::Full => write!(f, "full btc refund"), + RefundType::Partial { .. } => write!(f, "partial btc refund"), + } + } +} + impl BobState { /// Fetch the expired timelocks for the swap. /// Depending on the State, there are no locks to expire. @@ -987,40 +1005,37 @@ impl State6 { Ok((tx_id, subscription)) } - /// Publish the best refund transaction based on the refund signatures Alice has sent us. + /// Construct the best refund transaction based on the refund signatures Alice has sent us. /// This is either `TxFullRefund` or `TxPartialRefund`. - /// Returns the corresponding state (`BtcRefundPublished`/`PartialRefundPublished`) on success. - pub async fn publish_best_btc_refund_tx( - &self, - bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, - ) -> Result<(Txid, BobState)> { + /// Returns the fully constructed and signed transaction along with the refund type. + pub async fn construct_best_bitcoin_refund_tx(&self) -> Result<(Transaction, RefundType)> { if self.refund_signatures.tx_full_refund_encsig().is_some() { - tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); + tracing::debug!("Have the full refund signature, constructing full Bitcoin refund"); let tx_full_refund = self .signed_full_refund_transaction() .context("Couldn't construct TxFullRefund")?; - let (txid, _) = bitcoin_wallet - .ensure_broadcasted(tx_full_refund, "full refund") - .await - .context("Couldn't ensure broadcast of TxFullRefund")?; - return Ok((txid, BobState::BtcRefundPublished(self.clone()))); + return Ok((tx_full_refund, RefundType::Full)); } if self.refund_signatures.tx_partial_refund_encsig().is_some() { - tracing::info!( - "Don't have the full refund signature, attempting partial Bitcoin refund" + tracing::debug!( + "Don't have the full refund signature, constructing partial Bitcoin refund" ); let tx_partial_refund = self .signed_partial_refund_transaction() .context("Couldn't construct TxPartialRefund")?; - let (txid, _) = bitcoin_wallet - .ensure_broadcasted(tx_partial_refund, "partial refund") - .await - .context("Couldn't ensure broadcast of TxPartialRefund")?; - - return Ok((txid, BobState::BtcPartialRefundPublished(self.clone()))); + let total_swap_amount = self.tx_lock.lock_amount(); + let btc_amnesty_amount = self.btc_amnesty_amount.context("Missing Bitcoin amnesty amount even though we don't have the full refund signature")?; + + return Ok(( + tx_partial_refund, + RefundType::Partial { + total_swap_amount, + btc_amnesty_amount, + }, + )); } unreachable!("We always have either the partial or full refund encsig"); @@ -1178,4 +1193,12 @@ impl RefundSignatures { RefundSignatures::Legacy { .. } => None, } } + + pub fn has_full_refund_encsig(&self) -> bool { + self.tx_full_refund_encsig().is_some() + } + + pub fn has_partial_refund_encsig(&self) -> bool { + self.tx_partial_refund_encsig().is_some() + } } diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 4da262c4db..96e8e125a8 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -737,6 +737,7 @@ impl Wallet { transaction: bitcoin::Transaction, kind: &str, ) -> Result<(Txid, Subscription)> { + let txid = transaction.compute_txid(); let tx_status = self.status_of_script(&transaction).await?; // If it's already been broadcasted, return a subscription to it @@ -744,11 +745,13 @@ impl Wallet { tx_status, ScriptStatus::InMempool | ScriptStatus::Confirmed(_) ) { + tracing::debug!(%txid, %tx_status, "Bitcoin transaction already published, not publishing again"); let subscription = self.subscribe_to(Box::new(transaction.clone())).await; return Ok((transaction.compute_txid(), subscription)); } // Otherwise broadcast it + tracing::debug!(%txid, %tx_status, "Bitcoin transaction not yet published, publishing"); self.broadcast(transaction, kind).await } diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index be7c8391ca..15f84eaaee 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -6,6 +6,7 @@ use bitcoin::Txid; use bitcoin_wallet::BitcoinWallet; use std::sync::Arc; use swap_core::bitcoin::ExpiredTimelocks; +use swap_machine::bob::RefundType; use uuid::Uuid; pub async fn cancel_and_refund( @@ -193,13 +194,21 @@ pub async fn refund( tracing::info!(%swap_id, "Attempting to manually refund swap"); + let (refund_tx, refund_type) = state6.construct_best_bitcoin_refund_tx().await?; + + tracing::info!("Attempting to publish Bitcoin refund transaction. Refund type: {refund_type}"); + // Attempt to just publish the refund transaction - match state6 - .publish_best_btc_refund_tx(bitcoin_wallet.as_ref()) + match bitcoin_wallet + .ensure_broadcasted(refund_tx, &refund_type.to_string()) .await { Ok(_) => { - let state = BobState::BtcRefunded(state6); + let state = match refund_type { + RefundType::Full => BobState::BtcRefundPublished(state6), + RefundType::Partial { .. } => BobState::BtcPartialRefundPublished(state6), + }; + db.insert_latest_state(swap_id, state.clone().into()) .await?; diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index a4f92da284..9b07c7ecf7 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -8,7 +8,7 @@ use crate::network::cooperative_xmr_redeem_after_punish::Response::{Fullfilled, use crate::network::swap_setup::bob::NewSwap; use crate::protocol::bob::*; use crate::protocol::{bob, Database}; -use anyhow::{Context as AnyContext, Result}; +use anyhow::{Context as AnyContext, Result, anyhow}; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin::{ @@ -789,36 +789,29 @@ async fn next_state( // Publish the best Bitcoin refund transaction we can sign: // - either full refund, if alice sent use that signature (prioritized) // - or just partial refund. - - if state.refund_signatures.tx_full_refund_encsig().is_some() { - tracing::info!("Have the full refund signature, attempting full Bitcoin refund"); - let tx_full_refund = state - .signed_full_refund_transaction() - .context("Couldn't construct TxFullRefund")?; - let (txid, _) = bitcoin_wallet - .ensure_broadcasted(tx_full_refund, "full refund") + tracing::debug!("Attempting to refund Bitcoin"); + + if state.refund_signatures.has_full_refund_encsig() { + let full_refund_tx = state.signed_full_refund_transaction().context("Couldn't construct full refund Bitcoin transaction")?; + tracing::debug!("Have full refund signature, attempting full refund"); + bitcoin_wallet.ensure_broadcasted(full_refund_tx, "full refund") .await - .context("Couldn't ensure broadcast of TxFullRefund")?; - tracing::info!(%txid, "Successfully published full bitcoin refund transaction"); - return Ok(BobState::BtcRefundPublished(state.clone())); - } - - if state.refund_signatures.tx_partial_refund_encsig().is_some() { - tracing::info!( - "Don't have the full refund signature, attempting partial Bitcoin refund" - ); - let tx_partial_refund = state - .signed_partial_refund_transaction() - .context("Couldn't construct TxPartialRefund")?; - let (txid, _) = bitcoin_wallet - .ensure_broadcasted(tx_partial_refund, "partial refund") + .context("Couldn't ensure broadcast of Bitcoin full refund transaction") + .map_err(backoff::Error::transient)?; + + Ok(BobState::BtcRefundPublished(state.clone())) + } else if state.refund_signatures.has_partial_refund_encsig() { + let partial_refund_tx = state.signed_partial_refund_transaction().context("Couldn't construct partial refund Bitcoin transaction")?; + tracing::debug!("Don't have full refund signature, attempting partial refund"); + bitcoin_wallet.ensure_broadcasted(partial_refund_tx, "partial refund") .await - .context("Couldn't ensure broadcast of TxPartialRefund")?; - tracing::info!(%txid, "Successfully published partial bitcoin refund transaction"); - return Ok(BobState::BtcPartialRefundPublished(state.clone())); + .context("Couldn't ensure broadcast of Bitcoin partial refund transaction") + .map_err(backoff::Error::transient)?; + + Ok(BobState::BtcPartialRefundPublished(state.clone())) + } else { + Err(backoff::Error::permanent(anyhow!("Unreachable - We have neither partial nor full refund signatures"))) } - - unreachable!("We always have either the partial or full refund encsig"); } ExpiredTimelocks::Punish => { let tx_lock_id = state.tx_lock_id(); From 56d4fb31976a6727f56aa99bdcdb1f38de04f177 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 12:46:49 +0100 Subject: [PATCH 032/146] add PartialRefund and Amnesty events to SwapProgressEvent --- swap/src/cli/api/tauri_bindings.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 22283c3438..c5a5f46cf5 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -943,6 +943,20 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "string")] btc_refund_txid: Txid, }, + BtcPartialRefundPublished { + #[typeshare(serialized_as = "string")] + btc_partial_refund_txid: Txid, + /// Whether we have Alice's signature on the amnesty transaction + /// such that we will be able to refund the rest of the locked Bitcoin + /// after the partial refund went through. + has_amnesty_signature: bool, + }, + // BtcAmnesty was published but not yet confirmed. + // Requires BtcPartialRefund to be published first. + BtcAmnestyPublished { + #[typeshare(serialized_as = "string")] + btc_amnesty_txid: Txid, + }, // tx_early_refund has been confirmed BtcEarlyRefunded { #[typeshare(serialized_as = "string")] @@ -953,6 +967,20 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "string")] btc_refund_txid: Txid, }, + // We got partially refunded. Might still be able to get amnesty. + BtcPartiallyRefunded { + #[typeshare(serialized_as = "string")] + btc_partial_refund_txid: Txid, + /// Whether we have Alice's signature on the amnesty transaction + /// such that we will be able to refund the rest of the locked Bitcoin + /// after the partial refund went through. + has_amnesty_signature: bool, + }, + // BtcAmnesty was published but not yet confirmed. + BtcAmnestyReceived { + #[typeshare(serialized_as = "string")] + btc_amnesty_txid: Txid, + }, BtcPunished, AttemptingCooperativeRedeem, CooperativeRedeemAccepted, From 2a6c01f2dd3674c19ccc087cf4072a8c1fbaeb66 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 13:11:42 +0100 Subject: [PATCH 033/146] bob: handle BtcPartialRefundPublished --- swap-machine/src/bob/mod.rs | 4 +++- swap/src/protocol/bob/swap.rs | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 6426d61673..fe0100df8b 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -921,6 +921,8 @@ pub struct State6 { s_b: monero::Scalar, v: monero::PrivateViewKey, pub xmr: monero::Amount, + /// How much of the locked Bitcoin will stay locked in case of a partial refund. + /// May still be retrieve by publishing the `TxAmnesty` transaction. btc_amnesty_amount: Option, pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, @@ -936,7 +938,7 @@ pub struct State6 { /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). /// It allows Bob to retrieve the refund fee introduced in the PR. /// This signature is voluntarily revealed by alice. - tx_refund_amnesty_sig: Option, + pub tx_refund_amnesty_sig: Option, pub tx_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, tx_partial_refund_fee: Option, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 9b07c7ecf7..2eaf5ea7ad 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -927,6 +927,38 @@ async fn next_state( }, } } + BobState::BtcPartialRefundPublished(state)=> { + // 1. Emit a Tauri event + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcPartialRefundPublished { + btc_partial_refund_txid: state.construct_tx_partial_refund()?.txid(), + has_amnesty_signature: state.tx_refund_amnesty_sig.is_some(), + }, + ); + + // TxEarlyRefund might still get published+confirmed before the PartialRefund gets confirmed + // 2. Wait for either refund transaction to be confirmed + + let tx_partial_refund = state.construct_tx_partial_refund()?; + let tx_early_refund = state.construct_tx_early_refund(); + + let (tx_partial_refund_status, tx_early_refund_status) = tokio::join!( + bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund.clone())), + bitcoin_wallet.subscribe_to(Box::new(tx_early_refund.clone())), + ); + + select!{ + _ = tx_partial_refund_status.wait_until_final() => { + tracing::info!("TxPartialRefund has been confirmed"); + BobState::BtcPartiallyRefunded(state) + } + _ = tx_early_refund_status.wait_until_final() => { + tracing::info!("TxEarlyRefund has been confirmed"); + BobState::BtcEarlyRefunded(state) + } + } + } BobState::BtcRefunded(state) => { event_emitter.emit_swap_progress_event( swap_id, @@ -1074,8 +1106,7 @@ async fn next_state( } // TODO: Emit a Tauri event here BobState::BtcEarlyRefunded(state) => BobState::BtcEarlyRefunded(state), - BobState::BtcPartialRefundPublished(state) - | BobState::BtcPartiallyRefunded(state) + BobState::BtcPartiallyRefunded(state) | BobState::BtcAmnestyPublished(state) | BobState::BtcAmnestyConfirmed(state) => todo!(), BobState::SafelyAborted => BobState::SafelyAborted, From 3018ddefe6c2519706feb6cbdc8f13fd120be1a5 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 15:20:55 +0100 Subject: [PATCH 034/146] bob: publish TxRefundAmnesty if we have the key or wait for Alice to do it --- swap-machine/src/bob/mod.rs | 26 ++++++++++++++++++ swap/src/protocol/bob/swap.rs | 52 ++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index fe0100df8b..259868ea91 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -1105,6 +1105,32 @@ impl State6 { Ok(signed_tx_partial_refund) } + pub fn signed_amnesty_transaction(&self) -> Result { + let tx_amnesty = self.construct_tx_amnesty()?; + + let sig_a = self.tx_refund_amnesty_sig.clone().context( + "Can't sign amnesty transaction because Alice's amnesty signature is missing", + )?; + let sig_b = self.b.sign(tx_amnesty.digest()); + + let signed_tx_amnesty = + tx_amnesty.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?; + + Ok(signed_tx_amnesty) + } + + pub fn construct_tx_amnesty(&self) -> Result { + let tx_partial_refund = self.construct_tx_partial_refund()?; + + Ok(bitcoin::TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee.context( + "Can't construct TxRefundAmnesty because tx_refund_amnesty_fee is missing", + )?, + )) + } + pub fn construct_tx_early_refund(&self) -> bitcoin::TxEarlyRefund { bitcoin::TxEarlyRefund::new(&self.tx_lock, &self.refund_address, self.tx_refund_fee) } diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 2eaf5ea7ad..77e517493b 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -8,7 +8,7 @@ use crate::network::cooperative_xmr_redeem_after_punish::Response::{Fullfilled, use crate::network::swap_setup::bob::NewSwap; use crate::protocol::bob::*; use crate::protocol::{bob, Database}; -use anyhow::{Context as AnyContext, Result, anyhow}; +use anyhow::{Context as AnyContext, Result, anyhow, bail}; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin::{ @@ -959,6 +959,56 @@ async fn next_state( } } } + BobState::BtcPartiallyRefunded(state) => { + let has_amnesty_signature = state.tx_refund_amnesty_sig.is_some(); + + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcPartiallyRefunded { + btc_partial_refund_txid: state.construct_tx_partial_refund()?.txid(), + has_amnesty_signature, + }, + ); + + // If we have the amnesty signature, we publish the transaction ourselves. + // This also succeeds if the transaction is published by Alice. + if has_amnesty_signature { + retry("Refund amnesty transaction", || async { + let state = state.clone(); + let transaction = state.signed_amnesty_transaction().context("Couldn't construct Bitcoin amnesty transaction").map_err(backoff::Error::permanent)?; + bitcoin_wallet.ensure_broadcasted(transaction, "Bitcoin amnesty transaction") + .await + .context("Couldn't ensure broadcast of Bitcoin amnesty transaction") + .map_err(backoff::Error::transient)?; + Ok(()) + }, + None, + None + ) + .await + .context("Couldn't publish Bitcoin amnesty transaction")?; + + return Ok(BobState::BtcAmnestyPublished(state)) + } + + // If we don't have the amnesty signature, we have to wait for Alice to publish it. + // TODO: Would a timeout make sense here? Maybe once concurrent swap support landed. + + let tx_amnesty = state.construct_tx_amnesty().context("Couldn't construct Bitcoin amnesty transaction")?; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_amnesty.clone())).await; + + retry("Waiting for Bitcoin amnesty transaction to be published by Alice", || async { + subscription.clone() + .wait_until_seen() + .await + .context("Failed to wait for Bitcoin amnesty transaction to be published by Alice") + .map_err(backoff::Error::transient)?; + + Ok(BobState::BtcAmnestyPublished(state.clone())) + }, None, None) + .await + .context("Failed to wait for Bitcoin amnesty transaction to be published by Alice")? + } BobState::BtcRefunded(state) => { event_emitter.emit_swap_progress_event( swap_id, From 23391f893cd7eca825cb1f1849e0cbf81346193b Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 8 Dec 2025 16:05:36 +0100 Subject: [PATCH 035/146] bob: handle BtcAmnestyPublished and BtcAmestyConfirmed --- swap-machine/src/bob/mod.rs | 1 + swap/src/protocol/bob/swap.rs | 51 ++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 259868ea91..89cb5eb9ea 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -197,6 +197,7 @@ pub fn is_complete(state: &BobState) -> bool { state, BobState::BtcRefunded(..) | BobState::BtcEarlyRefunded { .. } + | BobState::BtcAmnestyConfirmed { .. } | BobState::XmrRedeemed { .. } | BobState::SafelyAborted ) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 77e517493b..8f2a84bbb6 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1003,7 +1003,7 @@ async fn next_state( .await .context("Failed to wait for Bitcoin amnesty transaction to be published by Alice") .map_err(backoff::Error::transient)?; - + Ok(BobState::BtcAmnestyPublished(state.clone())) }, None, None) .await @@ -1019,6 +1019,38 @@ async fn next_state( BobState::BtcRefunded(state) } + BobState::BtcAmnestyPublished(state) => { + // Here we just wait for the amnesty transaction to be confirmed + let tx_amnesty = state.construct_tx_amnesty().context("Couldn't construct Bitcoin amnesty transaction")?; + + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcAmnestyPublished { + btc_amnesty_txid: tx_amnesty.txid(), + }, + ); + + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_amnesty.clone())).await; + + retry("Waiting for Bitcoin amnesty transaction to be published by Alice", || async { + subscription.clone() + .wait_until_final() + .await + .context("Failed to wait for Bitcoin amnesty transaction to be confirmed") + .map_err(backoff::Error::transient)?; + + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcAmnestyReceived { + btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), + }, + ); + + Ok(BobState::BtcAmnestyConfirmed(state.clone())) + }, None, None) + .await + .context("Failed to wait for Bitcoin amnesty transaction to be confirmed")? + } BobState::BtcPunished { state, tx_lock_id } => { tracing::info!("You have been punished for not refunding in time"); event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcPunished); @@ -1154,11 +1186,18 @@ async fn next_state( } }; } - // TODO: Emit a Tauri event here - BobState::BtcEarlyRefunded(state) => BobState::BtcEarlyRefunded(state), - BobState::BtcPartiallyRefunded(state) - | BobState::BtcAmnestyPublished(state) - | BobState::BtcAmnestyConfirmed(state) => todo!(), + BobState::BtcEarlyRefunded(state) => { + event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcEarlyRefunded { + btc_early_refund_txid: state.construct_tx_early_refund().txid(), + }); + BobState::BtcEarlyRefunded(state) + }, + BobState::BtcAmnestyConfirmed(state) => { + event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcAmnestyReceived { + btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), + }); + BobState::BtcAmnestyConfirmed(state) + }, BobState::SafelyAborted => BobState::SafelyAborted, BobState::XmrRedeemed { tx_lock_id } => { event_emitter.emit_swap_progress_event( From cc7b64e3b094e33d2d0ffedcc242ddef08778674 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 11:38:44 +0100 Subject: [PATCH 036/146] asb: add refund_policy to Config, apply it in event loop --- swap-asb/src/main.rs | 1 + swap-controller/src/main.rs | 2 +- swap-env/src/config.rs | 39 ++++++++++++++++++---- swap-env/src/defaults.rs | 5 +++ swap-orchestrator/src/main.rs | 5 +-- swap-p2p/src/out_event/alice.rs | 14 +++++--- swap-p2p/src/protocols/swap_setup/alice.rs | 22 ++++++------ swap/src/asb/event_loop.rs | 37 +++++++++++++++++++- 8 files changed, 100 insertions(+), 25 deletions(-) diff --git a/swap-asb/src/main.rs b/swap-asb/src/main.rs index ab3ad20c7d..bb0feba121 100644 --- a/swap-asb/src/main.rs +++ b/swap-asb/src/main.rs @@ -314,6 +314,7 @@ pub async fn main() -> Result<()> { config.maker.max_buy_btc, config.maker.external_bitcoin_redeem_address, tip_config, + config.maker.refund_policy, ) .unwrap(); diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index 6c0361bd8e..cc03eaf3b9 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -95,7 +95,7 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { println!("No rendezvous points configured"); } else { for item in response.registrations { - let address = item.address.as_deref().unwrap_or("?"); + let address = item.address.as_ref().map(String::as_str).unwrap_or("?"); println!( "Connection status to rendezvous point at \"{}\" is \"{:?}\". Registration status is \"{:?}\"", address, item.connection, item.registration diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index 9544b7e288..b1696fcd8e 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -1,14 +1,14 @@ use crate::defaults::{ - GetDefaults, BITFINEX_PRICE_TICKER_WS_URL, KRAKEN_PRICE_TICKER_WS_URL, + BITFINEX_PRICE_TICKER_WS_URL, GetDefaults, KRAKEN_PRICE_TICKER_WS_URL, KUCOIN_PRICE_TICKER_REST_URL, }; use crate::env::{Mainnet, Testnet}; use crate::prompt; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use config::ConfigError; use libp2p::core::Multiaddr; use rust_decimal::Decimal; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, de}; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; @@ -101,23 +101,39 @@ pub struct Maker { #[serde(with = "::bitcoin::amount::serde::as_btc")] pub max_buy_btc: bitcoin::Amount, pub ask_spread: Decimal, + /// What refund conditions to give to takers. + #[serde(default)] + pub refund_policy: RefundPolicy, #[serde(default = "default_price_ticker_ws_url_kraken")] pub price_ticker_ws_url_kraken: Url, #[serde(default = "default_price_ticker_ws_url_bitfinex")] pub price_ticker_ws_url_bitfinex: Url, #[serde(default = "default_price_ticker_rest_url_kucoin")] pub price_ticker_rest_url_kucoin: Url, + /// If specified, Bitcoin received from successful swaps will be sent to this address. #[serde(default, with = "swap_serde::bitcoin::address_serde::option")] pub external_bitcoin_redeem_address: Option, /// Percentage (between 0.0 and 1.0) of the swap amount - // that will be donated to the project as part of the Monero lock transaction + /// that will be donated to the devepment fund as part of the Monero lock transaction. #[serde(default = "default_developer_tip")] pub developer_tip: Decimal, } -fn default_developer_tip() -> Decimal { - // By default, we do not tip - Decimal::ZERO +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct RefundPolicy { + /// Takers will only receive this percentage of their Bitcoin back by default. + /// Maker can still issue "amnesty" to refund the rest. + /// This protects the maker against griefing attacks. + #[serde(default = "default_taker_refund_ratio")] + pub taker_refund_ratio: Decimal, +} + +impl Default for RefundPolicy { + fn default() -> Self { + Self { + taker_refund_ratio: default_taker_refund_ratio(), + } + } } fn default_price_ticker_ws_url_kraken() -> Url { @@ -132,6 +148,14 @@ fn default_price_ticker_rest_url_kucoin() -> Url { Url::parse(KUCOIN_PRICE_TICKER_REST_URL).expect("default kucoin rest url to be valid") } +fn default_developer_tip() -> Decimal { + Decimal::ZERO +} + +fn default_taker_refund_ratio() -> Decimal { + Decimal::ONE +} + impl Config { pub fn read(config_file: D) -> Result where @@ -249,6 +273,7 @@ pub fn query_user_for_initial_config_with_network( price_ticker_rest_url_kucoin: defaults.price_ticker_rest_url_kucoin, external_bitcoin_redeem_address: None, developer_tip, + refund_policy: defaults.refund_policy, }, }) } diff --git a/swap-env/src/defaults.rs b/swap-env/src/defaults.rs index ce94dc97a4..5effa77619 100644 --- a/swap-env/src/defaults.rs +++ b/swap-env/src/defaults.rs @@ -1,7 +1,9 @@ +use crate::config::RefundPolicy; use crate::env::{Mainnet, Testnet}; use anyhow::{Context, Result}; use libp2p::Multiaddr; use rust_decimal::Decimal; +use std::cell::Ref; use std::path::{Path, PathBuf}; use std::str::FromStr; use swap_fs::{system_config_dir, system_data_dir}; @@ -116,6 +118,7 @@ pub struct Defaults { pub bitcoin_confirmation_target: u16, pub use_mempool_space_fee_estimation: bool, pub developer_tip: Decimal, + pub refund_policy: RefundPolicy, } impl GetDefaults for Mainnet { @@ -133,6 +136,7 @@ impl GetDefaults for Mainnet { bitcoin_confirmation_target: 1, use_mempool_space_fee_estimation: true, developer_tip: Decimal::ZERO, + refund_policy: RefundPolicy::default(), }; Ok(defaults) @@ -154,6 +158,7 @@ impl GetDefaults for Testnet { bitcoin_confirmation_target: 1, use_mempool_space_fee_estimation: true, developer_tip: Decimal::ZERO, + refund_policy: RefundPolicy::default(), }; Ok(defaults) diff --git a/swap-orchestrator/src/main.rs b/swap-orchestrator/src/main.rs index 450dd173cf..8e4f27715c 100644 --- a/swap-orchestrator/src/main.rs +++ b/swap-orchestrator/src/main.rs @@ -4,8 +4,8 @@ mod images; mod prompt; use crate::compose::{ - IntoSpec, OrchestratorDirectories, OrchestratorImage, OrchestratorImages, OrchestratorInput, - OrchestratorNetworks, ASB_DATA_DIR, DOCKER_COMPOSE_FILE, + ASB_DATA_DIR, DOCKER_COMPOSE_FILE, IntoSpec, OrchestratorDirectories, OrchestratorImage, + OrchestratorImages, OrchestratorInput, OrchestratorNetworks, }; use std::path::PathBuf; use swap_env::config::{ @@ -193,6 +193,7 @@ fn main() { price_ticker_ws_url_bitfinex: defaults.price_ticker_ws_url_bitfinex, price_ticker_rest_url_kucoin: defaults.price_ticker_rest_url_kucoin, external_bitcoin_redeem_address: None, + refund_policy: defaults.refund_policy, developer_tip, }, }; diff --git a/swap-p2p/src/out_event/alice.rs b/swap-p2p/src/out_event/alice.rs index ada6c61189..8f769f8775 100644 --- a/swap-p2p/src/out_event/alice.rs +++ b/swap-p2p/src/out_event/alice.rs @@ -1,10 +1,10 @@ -use libp2p::{identify, ping}; use libp2p::{ + PeerId, request_response::{ InboundFailure, InboundRequestId, OutboundFailure, OutboundRequestId, ResponseChannel, }, - PeerId, }; +use libp2p::{identify, ping}; use uuid::Uuid; use crate::protocols::rendezvous; @@ -16,8 +16,14 @@ use crate::protocols::{ #[derive(Debug)] pub enum OutEvent { SwapSetupInitiated { - send_wallet_snapshot: - bmrng::RequestReceiver, + // run_swap_setup in connection handler sends us the amount of + // Bitcoin Bob wants to send. + // We respond with a snapshot of our wallets and how much of that + // should go into the amnesty output + send_wallet_snapshot: bmrng::RequestReceiver< + bitcoin::Amount, + (swap_setup::alice::WalletSnapshot, bitcoin::Amount), + >, }, SwapSetupCompleted { peer_id: PeerId, diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 594b3c1a65..a96a8b8555 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -7,7 +7,7 @@ use anyhow::{Context, Result, anyhow}; use futures::AsyncWriteExt; use futures::FutureExt; use futures::StreamExt; -use futures::future::{BoxFuture, OptionFuture}; +use futures::future::BoxFuture; use futures::stream::FuturesUnordered; use libp2p::core::upgrade; use libp2p::swarm::handler::ConnectionEvent; @@ -29,7 +29,8 @@ use uuid::Uuid; #[allow(clippy::large_enum_variant)] pub enum OutEvent { Initiated { - send_wallet_snapshot: bmrng::RequestReceiver, + send_wallet_snapshot: + bmrng::RequestReceiver, }, Completed { peer_id: PeerId, @@ -259,7 +260,7 @@ impl Handler { #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum HandlerOutEvent { - Initiated(bmrng::RequestReceiver), + Initiated(bmrng::RequestReceiver), Completed(Result<(Uuid, State3)>), } @@ -292,11 +293,12 @@ where ConnectionEvent::FullyNegotiatedInbound(substream) => { let substream = substream.protocol; - let (sender, receiver) = - bmrng::channel_with_timeout::( - 1, - crate::defaults::SWAP_SETUP_CHANNEL_TIMEOUT, - ); + let (sender, receiver) = bmrng::channel_with_timeout::< + bitcoin::Amount, + (WalletSnapshot, bitcoin::Amount), + >( + 1, crate::defaults::SWAP_SETUP_CHANNEL_TIMEOUT + ); let resume_only = self.resume_only; let min_buy = self.min_buy; @@ -442,7 +444,7 @@ impl Error { async fn run_swap_setup( mut substream: libp2p::swarm::Stream, - sender: bmrng::RequestSender, + sender: bmrng::RequestSender, resume_only: bool, env_config: env::Config, min_buy: bitcoin::Amount, @@ -453,7 +455,7 @@ async fn run_swap_setup( .await .context("Failed to read spot price request")?; - let wallet_snapshot = sender + let (wallet_snapshot, btc_amnesty_amount) = sender .send_receive(request.btc) .await .context("Failed to receive wallet snapshot")?; diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 99cfa390c1..e71fdcb226 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -21,6 +21,7 @@ use libp2p::request_response::{OutboundFailure, OutboundRequestId, ResponseChann use libp2p::swarm::SwarmEvent; use libp2p::{PeerId, Swarm}; use moka::future::Cache; +use rust_decimal::prelude::FromPrimitive; use rust_decimal::Decimal; use std::collections::HashMap; use std::convert::TryInto; @@ -29,6 +30,7 @@ use std::io::Write; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin; +use swap_env::config::{Config, RefundPolicy}; use swap_env::env; use swap_feed::LatestRate; use tokio::sync::{mpsc, oneshot}; @@ -51,6 +53,7 @@ where max_buy: bitcoin::Amount, external_redeem_address: Option, developer_tip: TipConfig, + refund_policy: RefundPolicy, /// Cache for quotes quote_cache: Cache, Arc>>, @@ -142,6 +145,7 @@ where max_buy: bitcoin::Amount, external_redeem_address: Option, developer_tip: TipConfig, + refund_policy: RefundPolicy, ) -> Result<(Self, mpsc::Receiver, EventLoopService)> { let swap_channel = MpscChannels::default(); let (outgoing_transfer_proofs_sender, outgoing_transfer_proofs_requests) = @@ -162,6 +166,7 @@ where max_buy, external_redeem_address, developer_tip, + refund_policy, quote_cache, recv_encrypted_signature: Default::default(), inflight_encrypted_signatures: Default::default(), @@ -247,6 +252,14 @@ where } }; + // TODO: propagate error to the swap_setup routine instead of swallowing it + let btc_amnesty_amount = match apply_bitcoin_amnesty_policy(btc, &self.refund_policy) { + Ok(amount) => amount, + Err(error) => { + tracing::error!("Swap request will be ignored because we were unable to create wallet snapshot for swap: {:#}", error); + continue; + } + }; let wallet_snapshot = match capture_wallet_snapshot(self.bitcoin_wallet.clone(), &self.monero_wallet, &self.external_redeem_address, btc).await { Ok(wallet_snapshot) => wallet_snapshot, Err(error) => { @@ -256,7 +269,7 @@ where }; // Ignore result, we should never hit this because the receiver will alive as long as the connection is. - let _ = responder.respond(wallet_snapshot); + let _ = responder.respond((wallet_snapshot, btc_amnesty_amount)); } SwarmEvent::Behaviour(OutEvent::SwapSetupCompleted{peer_id, swap_id, state3}) => { if let Err(error) = self.handle_execution_setup_done(peer_id, swap_id, state3).await { @@ -817,6 +830,28 @@ impl EventLoopHandle { } } +/// For a new swap of `swap_amount`, this function calculates how much +/// Bitcoin should go into the amnesty-lock incase of a refund. +fn apply_bitcoin_amnesty_policy( + swap_amount: bitcoin::Amount, + refund_policy: &RefundPolicy, +) -> Result { + let amount_sats = swap_amount.to_sat(); + let btc_amnesty_ratio = Decimal::ONE + .checked_sub(refund_policy.taker_refund_ratio) + .context("can't have refund ration > 1")?; + + let btc_amnesty_sats = Decimal::from_u64(amount_sats) + .context("Decimal overflowed by Bitcoin sats")? + .checked_mul(btc_amnesty_ratio) + .context("Decimal overflow when computing amnesty amount in sats")? + .floor() + .try_into() + .context("Couldn't convert Decimal to u64")?; + + Ok(bitcoin::Amount::from_sat(btc_amnesty_sats)) +} + async fn capture_wallet_snapshot( bitcoin_wallet: Arc, monero_wallet: &monero::Wallets, From cf5fce9a4d83859f65b9f2a2a3aea2a669150ca0 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 11:39:42 +0100 Subject: [PATCH 037/146] update tests to have refund policy --- ..._refund_using_cancel_and_refund_command.rs | 2 +- ...and_refund_command_timelock_not_expired.rs | 2 +- ...refund_using_cancel_then_refund_command.rs | 2 +- ...llet_rpc_after_started_btc_early_refund.rs | 2 +- ..._balance_after_started_btc_early_refund.rs | 2 +- .../alice_manually_punishes_after_bob_dead.rs | 2 +- ...punishes_after_bob_dead_and_bob_cancels.rs | 2 +- ..._manually_redeems_after_enc_sig_learned.rs | 2 +- .../alice_punishes_after_restart_bob_dead.rs | 2 +- ...lice_refunds_after_restart_bob_refunded.rs | 2 +- ...ncurrent_bobs_after_xmr_lock_proof_sent.rs | 2 +- ...current_bobs_before_xmr_lock_proof_sent.rs | 2 +- swap/tests/ensure_same_swap_id.rs | 2 +- swap/tests/happy_path.rs | 2 +- swap/tests/happy_path_alice_developer_tip.rs | 1 + ...ppy_path_alice_developer_tip_subaddress.rs | 1 + ...ath_bob_offline_while_alice_redeems_btc.rs | 69 ++++++++++--------- ...ppy_path_restart_alice_after_xmr_locked.rs | 2 +- ...happy_path_restart_bob_after_xmr_locked.rs | 2 +- ...appy_path_restart_bob_before_xmr_locked.rs | 2 +- swap/tests/harness/mod.rs | 8 +++ swap/tests/punish.rs | 2 +- 22 files changed, 65 insertions(+), 50 deletions(-) diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs index 01991be165..edb0b2880d 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs @@ -11,7 +11,7 @@ use swap::{asb, cli}; #[tokio::test] async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() { - harness::setup_test(FastCancelConfig, None, |mut ctx| async move { + harness::setup_test(FastCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_timelock_not_expired.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_timelock_not_expired.rs index ddda32680a..89433e5c0a 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_timelock_not_expired.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_timelock_not_expired.rs @@ -12,7 +12,7 @@ use swap::{asb, cli}; #[tokio::test] async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_and_bob_refund_using_cancel_then_refund_command.rs b/swap/tests/alice_and_bob_refund_using_cancel_then_refund_command.rs index 62c339bc1d..8936568c53 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_then_refund_command.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_then_refund_command.rs @@ -11,7 +11,7 @@ use swap::{asb, cli}; #[tokio::test] async fn given_alice_and_bob_manually_cancel_and_refund_after_funds_locked_both_refund() { - harness::setup_test(FastCancelConfig, None, |mut ctx| async move { + harness::setup_test(FastCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_broken_wallet_rpc_after_started_btc_early_refund.rs b/swap/tests/alice_broken_wallet_rpc_after_started_btc_early_refund.rs index 1102516589..4a8a4a16ec 100644 --- a/swap/tests/alice_broken_wallet_rpc_after_started_btc_early_refund.rs +++ b/swap/tests/alice_broken_wallet_rpc_after_started_btc_early_refund.rs @@ -10,7 +10,7 @@ use crate::harness::SlowCancelConfig; #[tokio::test] async fn alice_zero_xmr_refunds_bitcoin() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_handle) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_empty_balance_after_started_btc_early_refund.rs b/swap/tests/alice_empty_balance_after_started_btc_early_refund.rs index 61d412414f..c63988260f 100644 --- a/swap/tests/alice_empty_balance_after_started_btc_early_refund.rs +++ b/swap/tests/alice_empty_balance_after_started_btc_early_refund.rs @@ -10,7 +10,7 @@ use crate::harness::SlowCancelConfig; #[tokio::test] async fn alice_zero_xmr_refunds_bitcoin() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_handle) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_manually_punishes_after_bob_dead.rs b/swap/tests/alice_manually_punishes_after_bob_dead.rs index 9cd9f4474d..f29fc0fdf3 100644 --- a/swap/tests/alice_manually_punishes_after_bob_dead.rs +++ b/swap/tests/alice_manually_punishes_after_bob_dead.rs @@ -14,7 +14,7 @@ use swap::protocol::{alice, bob}; /// punish command. Bob then cooperates with Alice and redeems XMR with her key. #[tokio::test] async fn alice_manually_punishes_after_bob_dead() { - harness::setup_test(FastPunishConfig, None, |mut ctx| async move { + harness::setup_test(FastPunishConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs b/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs index 21d1cb1025..03bfaa1188 100644 --- a/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs +++ b/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs @@ -14,7 +14,7 @@ use swap::protocol::{alice, bob}; /// punish command. Then Bob tries to refund. #[tokio::test] async fn alice_manually_punishes_after_bob_dead_and_bob_cancels() { - harness::setup_test(FastPunishConfig, None, |mut ctx| async move { + harness::setup_test(FastPunishConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_manually_redeems_after_enc_sig_learned.rs b/swap/tests/alice_manually_redeems_after_enc_sig_learned.rs index ad2e97f596..bcb24c7560 100644 --- a/swap/tests/alice_manually_redeems_after_enc_sig_learned.rs +++ b/swap/tests/alice_manually_redeems_after_enc_sig_learned.rs @@ -11,7 +11,7 @@ use swap::protocol::{alice, bob}; /// after learning encsig from Bob #[tokio::test] async fn alice_manually_redeems_after_enc_sig_learned() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/alice_punishes_after_restart_bob_dead.rs b/swap/tests/alice_punishes_after_restart_bob_dead.rs index cabf76a0b3..91518e2d7a 100644 --- a/swap/tests/alice_punishes_after_restart_bob_dead.rs +++ b/swap/tests/alice_punishes_after_restart_bob_dead.rs @@ -12,7 +12,7 @@ use swap::protocol::{alice, bob}; /// the encsig and fail to refund or redeem. Alice cancels and punishes. Bob then cooperates with Alice and redeems XMR with her key. #[tokio::test] async fn alice_punishes_after_restart_if_bob_dead() { - harness::setup_test(FastPunishConfig, None, |mut ctx| async move { + harness::setup_test(FastPunishConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); diff --git a/swap/tests/alice_refunds_after_restart_bob_refunded.rs b/swap/tests/alice_refunds_after_restart_bob_refunded.rs index b79f52a2ad..7b3dd89832 100644 --- a/swap/tests/alice_refunds_after_restart_bob_refunded.rs +++ b/swap/tests/alice_refunds_after_restart_bob_refunded.rs @@ -10,7 +10,7 @@ use swap::protocol::{alice, bob}; /// Eventually Alice comes back online and refunds as well. #[tokio::test] async fn alice_refunds_after_restart_if_bob_already_refunded() { - harness::setup_test(FastCancelConfig, None, |mut ctx| async move { + harness::setup_test(FastCancelConfig, None, None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/concurrent_bobs_after_xmr_lock_proof_sent.rs b/swap/tests/concurrent_bobs_after_xmr_lock_proof_sent.rs index e48683afe6..ec3053b4cc 100644 --- a/swap/tests/concurrent_bobs_after_xmr_lock_proof_sent.rs +++ b/swap/tests/concurrent_bobs_after_xmr_lock_proof_sent.rs @@ -9,7 +9,7 @@ use swap::protocol::{alice, bob}; #[tokio::test] async fn concurrent_bobs_after_xmr_lock_proof_sent() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap_1, bob_join_handle_1) = ctx.bob_swap().await; let swap_id = bob_swap_1.id; diff --git a/swap/tests/concurrent_bobs_before_xmr_lock_proof_sent.rs b/swap/tests/concurrent_bobs_before_xmr_lock_proof_sent.rs index 775a1e2a35..a255c5ea31 100644 --- a/swap/tests/concurrent_bobs_before_xmr_lock_proof_sent.rs +++ b/swap/tests/concurrent_bobs_before_xmr_lock_proof_sent.rs @@ -9,7 +9,7 @@ use swap::protocol::{alice, bob}; #[tokio::test] async fn concurrent_bobs_before_xmr_lock_proof_sent() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap_1, bob_join_handle_1) = ctx.bob_swap().await; let swap_id = bob_swap_1.id; diff --git a/swap/tests/ensure_same_swap_id.rs b/swap/tests/ensure_same_swap_id.rs index 8deb1428cc..309f89904a 100644 --- a/swap/tests/ensure_same_swap_id.rs +++ b/swap/tests/ensure_same_swap_id.rs @@ -5,7 +5,7 @@ use swap::protocol::bob; #[tokio::test] async fn ensure_same_swap_id_for_alice_and_bob() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path.rs b/swap/tests/happy_path.rs index da0ee150bc..bb0b983c98 100644 --- a/swap/tests/happy_path.rs +++ b/swap/tests/happy_path.rs @@ -7,7 +7,7 @@ use tokio::join; #[tokio::test] async fn happy_path() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path_alice_developer_tip.rs b/swap/tests/happy_path_alice_developer_tip.rs index eba9df567e..cc2be6b664 100644 --- a/swap/tests/happy_path_alice_developer_tip.rs +++ b/swap/tests/happy_path_alice_developer_tip.rs @@ -11,6 +11,7 @@ async fn happy_path_alice_developer_tip() { harness::setup_test( SlowCancelConfig, Some((Decimal::from_f32_retain(0.1).unwrap(), false)), + None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path_alice_developer_tip_subaddress.rs b/swap/tests/happy_path_alice_developer_tip_subaddress.rs index df34d3c6d5..2589279b2d 100644 --- a/swap/tests/happy_path_alice_developer_tip_subaddress.rs +++ b/swap/tests/happy_path_alice_developer_tip_subaddress.rs @@ -11,6 +11,7 @@ async fn happy_path_alice_developer_tip_subaddress() { harness::setup_test( SlowCancelConfig, Some((Decimal::from_f32_retain(0.1).unwrap(), true)), + None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs b/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs index 1b4774acef..0b97a659bf 100644 --- a/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs +++ b/swap/tests/happy_path_bob_offline_while_alice_redeems_btc.rs @@ -8,37 +8,42 @@ use tokio::join; #[tokio::test] async fn given_bob_restarts_while_alice_redeems_btc() { - harness::setup_test(harness::SlowCancelConfig, None, |mut ctx| async move { - let (bob_swap, bob_handle) = ctx.bob_swap().await; - let swap_id = bob_swap.id; - - let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_encsig_sent)); - - let alice_swap = ctx.alice_next_swap().await; - let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); - - let (bob_state, alice_state) = join!(bob_swap, alice_swap); - ctx.assert_alice_redeemed(alice_state??).await; - assert!(matches!(bob_state??, BobState::EncSigSent { .. })); - - let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_handle, swap_id).await; - - if let BobState::EncSigSent(state4) = bob_swap.state.clone() { - bob_swap - .bitcoin_wallet - .subscribe_to(Box::new(state4.tx_lock)) - .await - .wait_until_confirmed_with(state4.cancel_timelock) - .await?; - } else { - panic!("Bob in unexpected state {}", bob_swap.state); - } - - // Restart Bob - let bob_state = bob::run(bob_swap).await?; - ctx.assert_bob_redeemed(bob_state).await; - - Ok(()) - }) + harness::setup_test( + harness::SlowCancelConfig, + None, + None, + |mut ctx| async move { + let (bob_swap, bob_handle) = ctx.bob_swap().await; + let swap_id = bob_swap.id; + + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_encsig_sent)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + let (bob_state, alice_state) = join!(bob_swap, alice_swap); + ctx.assert_alice_redeemed(alice_state??).await; + assert!(matches!(bob_state??, BobState::EncSigSent { .. })); + + let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_handle, swap_id).await; + + if let BobState::EncSigSent(state4) = bob_swap.state.clone() { + bob_swap + .bitcoin_wallet + .subscribe_to(Box::new(state4.tx_lock)) + .await + .wait_until_confirmed_with(state4.cancel_timelock) + .await?; + } else { + panic!("Bob in unexpected state {}", bob_swap.state); + } + + // Restart Bob + let bob_state = bob::run(bob_swap).await?; + ctx.assert_bob_redeemed(bob_state).await; + + Ok(()) + }, + ) .await; } diff --git a/swap/tests/happy_path_restart_alice_after_xmr_locked.rs b/swap/tests/happy_path_restart_alice_after_xmr_locked.rs index 1461947c60..6ab91c02e2 100644 --- a/swap/tests/happy_path_restart_alice_after_xmr_locked.rs +++ b/swap/tests/happy_path_restart_alice_after_xmr_locked.rs @@ -8,7 +8,7 @@ use swap::protocol::{alice, bob}; #[tokio::test] async fn given_alice_restarts_after_xmr_is_locked_resume_swap() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path_restart_bob_after_xmr_locked.rs b/swap/tests/happy_path_restart_bob_after_xmr_locked.rs index 07b44ebc7e..c35b8e065f 100644 --- a/swap/tests/happy_path_restart_bob_after_xmr_locked.rs +++ b/swap/tests/happy_path_restart_bob_after_xmr_locked.rs @@ -8,7 +8,7 @@ use swap::protocol::{alice, bob}; #[tokio::test] async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_xmr_locked)); diff --git a/swap/tests/happy_path_restart_bob_before_xmr_locked.rs b/swap/tests/happy_path_restart_bob_before_xmr_locked.rs index 07b44ebc7e..c35b8e065f 100644 --- a/swap/tests/happy_path_restart_bob_before_xmr_locked.rs +++ b/swap/tests/happy_path_restart_bob_before_xmr_locked.rs @@ -8,7 +8,7 @@ use swap::protocol::{alice, bob}; #[tokio::test] async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { - harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { + harness::setup_test(SlowCancelConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_xmr_locked)); diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 5241ee6a5c..5703511d22 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -13,6 +13,7 @@ use rust_decimal::Decimal; use std::cmp::Ordering; use std::fmt; use std::path::PathBuf; +use swap_env::config::RefundPolicy; use std::str::FromStr; use std::sync::Arc; @@ -50,6 +51,7 @@ use uuid::Uuid; pub async fn setup_test( _config: C, developer_tip_ratio: Option<(Decimal, bool)>, + refund_policy: Option, testfn: T, ) where T: Fn(TestContext) -> F, @@ -158,6 +160,7 @@ pub async fn setup_test( alice_bitcoin_wallet.clone(), alice_monero_wallet.clone(), developer_tip.clone(), + refund_policy.clone().unwrap_or_default(), ) .await; @@ -207,6 +210,7 @@ pub async fn setup_test( bob_monero_wallet, developer_tip_monero_wallet, developer_tip, + refund_policy: refund_policy.unwrap_or_default(), monerod_container_id: containers._monerod_container.id().to_string(), }; @@ -298,6 +302,7 @@ async fn start_alice( bitcoin_wallet: Arc, monero_wallet: Arc, developer_tip: TipConfig, + refund_policy: RefundPolicy, ) -> (AliceApplicationHandle, Receiver) { if let Some(parent_dir) = db_path.parent() { ensure_directory_exists(parent_dir).unwrap(); @@ -343,6 +348,7 @@ async fn start_alice( max_buy, None, developer_tip, + refund_policy, ) .unwrap(); @@ -668,6 +674,7 @@ pub struct TestContext { btc_amount: bitcoin::Amount, xmr_amount: monero::Amount, developer_tip: TipConfig, + refund_policy: RefundPolicy, alice_seed: Seed, alice_db_path: PathBuf, @@ -713,6 +720,7 @@ impl TestContext { self.alice_bitcoin_wallet.clone(), self.alice_monero_wallet.clone(), self.developer_tip.clone(), + self.refund_policy.clone(), ) .await; diff --git a/swap/tests/punish.rs b/swap/tests/punish.rs index 4829c7ebec..0d5d2d47db 100644 --- a/swap/tests/punish.rs +++ b/swap/tests/punish.rs @@ -10,7 +10,7 @@ use swap::protocol::{alice, bob}; /// the encsig and fail to refund or redeem. Alice punishes. Bob then cooperates with Alice and redeems XMR with her key. #[tokio::test] async fn alice_punishes_if_bob_never_acts_after_fund() { - harness::setup_test(FastPunishConfig, None, |mut ctx| async move { + harness::setup_test(FastPunishConfig, None, None, |mut ctx| async move { let (bob_swap, bob_join_handle) = ctx.bob_swap().await; let bob_swap_id = bob_swap.id; let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); From fe944161789011caae47f0ddcc9fb12c329329ed Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 11:44:15 +0100 Subject: [PATCH 038/146] alice: actually use btc_amnesty_amount in run_swap_setup --- swap-p2p/src/protocols/swap_setup/alice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index a96a8b8555..57070a9c04 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -536,7 +536,7 @@ async fn run_swap_setup( let state0 = State0::new( request.btc, xmr, - todo!("TODO: Implement system for alice to decide amnesty amount"), + btc_amnesty_amount, env_config, wallet_snapshot.redeem_address, wallet_snapshot.punish_address, From 3863fc1804cf9620764caeebf9f262a1a623cb9b Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 12:55:56 +0100 Subject: [PATCH 039/146] tracing: force ansi output for terminal layer. if anything breaks with docker or something this is the fault --- swap/src/common/tracing_util.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/swap/src/common/tracing_util.rs b/swap/src/common/tracing_util.rs index 9a72d89b8a..0f8ab69ac0 100644 --- a/swap/src/common/tracing_util.rs +++ b/swap/src/common/tracing_util.rs @@ -110,10 +110,9 @@ pub fn init( ); // Layer for writing to the terminal - let is_terminal = std::io::stderr().is_terminal(); let terminal_layer = fmt::layer() .with_writer(std::io::stderr) - .with_ansi(is_terminal) + .with_ansi(true) .with_timer(UtcTime::rfc_3339()) .with_target(true) .with_file(true) From ceac03aa4f2c3b316a7b69e0cfb0c58d713fc708 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 12:57:09 +0100 Subject: [PATCH 040/146] remove yarn@4 from package.json as package manager --- src-gui/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src-gui/package.json b/src-gui/package.json index c65eb0d919..1a8f2f617c 100644 --- a/src-gui/package.json +++ b/src-gui/package.json @@ -78,6 +78,5 @@ "vite-plugin-watch": "^0.3.1", "vite-tsconfig-paths": "^4.3.2", "vitest": "^2.1.1" - }, - "packageManager": "yarn@4.12.0" + } } From 53f9aaf8cc43d3aaf97cc38767a5664fd2593ba0 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 15:21:02 +0100 Subject: [PATCH 041/146] remove unnecessary env var from just asb-testnet command --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index f77297e6c7..f3ba6bad62 100644 --- a/justfile +++ b/justfile @@ -83,7 +83,7 @@ swap: # Run the asb on testnet asb-testnet: - ASB_DEV_ADDR_OUTPUT_PATH="$PWD/src-gui/.env.development" cargo run -p swap-asb --bin asb -- --testnet --trace start --rpc-bind-port 9944 --rpc-bind-host 0.0.0.0 + cargo run -p swap-asb --bin asb -- --testnet --trace start --rpc-bind-port 9944 --rpc-bind-host 0.0.0.0 # Launch the ASB controller REPL against a local testnet ASB instance asb-testnet-controller: From cb9bec0da0b74ee27fcd6c3571e8b4d3128da4ac Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 15:22:23 +0100 Subject: [PATCH 042/146] state-machine(alice): make btc_amnesty_amount optional --- swap-machine/src/alice/mod.rs | 23 ++++++++++++---------- swap-machine/src/bob/mod.rs | 2 +- swap-machine/src/lib.rs | 4 ++-- swap-p2p/src/protocols/swap_setup/alice.rs | 11 ++++++++--- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 6c94fbec5d..017db7f1d4 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -148,7 +148,7 @@ pub struct State0 { dleq_proof_s_a: CrossCurveDLEQProof, btc: bitcoin::Amount, xmr: monero::Amount, - btc_amnesty_amount: bitcoin::Amount, + btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, redeem_address: bitcoin::Address, @@ -188,7 +188,7 @@ impl State0 { point: S_a_monero.compress(), }, dleq_proof_s_a, - btc_amnesty_amount, + btc_amnesty_amount: Some(btc_amnesty_amount), redeem_address, punish_address, btc, @@ -265,7 +265,7 @@ pub struct State1 { dleq_proof_s_a: CrossCurveDLEQProof, btc: bitcoin::Amount, xmr: monero::Amount, - btc_amnesty_amount: bitcoin::Amount, + btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -280,8 +280,8 @@ pub struct State1 { } impl State1 { - pub fn next_message(&self) -> Message1 { - Message1 { + pub fn next_message(&self) -> Result { + Ok(Message1 { A: self.a.public(), S_a_monero: self.S_a_monero, S_a_bitcoin: self.S_a_bitcoin, @@ -291,8 +291,10 @@ impl State1 { punish_address: self.punish_address.clone(), tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, - amnesty_amount: self.btc_amnesty_amount, - } + amnesty_amount: self + .btc_amnesty_amount + .context("Missing btc_amesty_amount for new swap that should have it")?, + }) } pub fn receive(self, msg: Message2) -> Result { @@ -337,7 +339,7 @@ pub struct State2 { v: monero::PrivateViewKey, btc: bitcoin::Amount, xmr: monero::Amount, - btc_amnesty_amount: bitcoin::Amount, + btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, refund_address: bitcoin::Address, @@ -368,7 +370,8 @@ impl State2 { &self.refund_address, self.a.public(), self.B, - self.btc_amnesty_amount, + self.btc_amnesty_amount + .context("Missing btc_amnesty_amount for new swap that should have it")?, self.tx_refund_fee, )?; // Alice encsigns the partial refund transaction(bitcoin) digest with Bob's monero @@ -472,7 +475,7 @@ pub struct State3 { pub v: monero::PrivateViewKey, pub btc: bitcoin::Amount, pub xmr: monero::Amount, - pub btc_amnesty_amount: bitcoin::Amount, + pub btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, #[serde(with = "swap_serde::bitcoin::address_serde")] diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 89cb5eb9ea..fa7ac5d3fe 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -478,7 +478,7 @@ pub struct State2 { S_a_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, pub xmr: monero::Amount, - btc_amnesty_amount: Option, + pub btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, #[serde(with = "address_serde")] diff --git a/swap-machine/src/lib.rs b/swap-machine/src/lib.rs index c36dea0945..8ac33b2b10 100644 --- a/swap-machine/src/lib.rs +++ b/swap-machine/src/lib.rs @@ -77,7 +77,7 @@ mod tests { let message0 = bob_state0.next_message().unwrap(); let (_, alice_state1) = alice_state0.receive(message0).unwrap(); - let alice_message1 = alice_state1.next_message(); + let alice_message1 = alice_state1.next_message().unwrap(); let bob_state1 = bob_state0 .receive(&bob_wallet, alice_message1) @@ -190,7 +190,7 @@ mod tests { // Complete the state machine up to State3 let message0 = bob_state0.next_message().unwrap(); let (_, alice_state1) = alice_state0.receive(message0).unwrap(); - let alice_message1 = alice_state1.next_message(); + let alice_message1 = alice_state1.next_message().unwrap(); let bob_state1 = bob_state0 .receive(&bob_wallet, alice_message1) diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 57070a9c04..9ff5de2d21 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -552,9 +552,14 @@ async fn run_swap_setup( .receive(message0) .context("Failed to transition state0 -> state1 using message0")?; - swap_setup::write_cbor_message(&mut substream, state1.next_message()) - .await - .context("Failed to send message1")?; + swap_setup::write_cbor_message( + &mut substream, + state1 + .next_message() + .context("Couldn't construct Mesage1")?, + ) + .await + .context("Failed to send message1")?; let message2 = swap_setup::read_cbor_message::(&mut substream) .await From 3a7035ba07f73bf44dba6f114c1d77a271121af4 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 15:23:19 +0100 Subject: [PATCH 043/146] gui: show bitcoin amnesty in SwapSetupInflight page --- .../in_progress/SwapSetupInflightPage.tsx | 133 ++++++++++-------- swap/src/asb/event_loop.rs | 11 +- swap/src/cli/api/tauri_bindings.rs | 3 + swap/src/protocol/bob/swap.rs | 2 + 4 files changed, 84 insertions(+), 65 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx index 01ee48ae0d..02e2c66e3f 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx @@ -75,7 +75,7 @@ export default function SwapSetupInflightPage({ ); } - const { btc_network_fee, monero_receive_pool, xmr_receive_amount } = + const { btc_network_fee, monero_receive_pool, xmr_receive_amount, btc_amnesty_amount } = request.request.content; return ( @@ -104,6 +104,7 @@ export default function SwapSetupInflightPage({ @@ -187,78 +188,88 @@ export default function SwapSetupInflightPage({ interface BitcoinSendSectionProps { btc_lock_amount: number; btc_network_fee: number; + btc_amnesty_amount: number; } -const BitcoinMainBox = ({ +function BitcoinMainBox ({ btc_lock_amount, btc_network_fee, -}: { - btc_lock_amount: number; - btc_network_fee: number; -}) => ( - + btc_amnesty_amount +}: BitcoinSendSectionProps) { + const guaranteedRefundPercentage: number = (btc_lock_amount - btc_amnesty_amount) / btc_lock_amount * 100; + return ( theme.palette.warning.light + "10", - background: (theme) => - `linear-gradient(135deg, ${theme.palette.warning.light}20, ${theme.palette.warning.light}05)`, + flexDirection: "column", + gap: 1, }} > - ({ - color: theme.palette.text.primary, - })} - > - You send - - ({ - fontWeight: "bold", - color: theme.palette.warning.dark, - textShadow: "0 1px 2px rgba(0,0,0,0.1)", - })} + theme.palette.warning.light + "10", + background: (theme) => + `linear-gradient(135deg, ${theme.palette.warning.light}20, ${theme.palette.warning.light}05)`, + }} > - - - + ({ + color: theme.palette.text.primary, + })} + > + You send + + ({ + fontWeight: "bold", + color: theme.palette.warning.dark, + textShadow: "0 1px 2px rgba(0,0,0,0.1)", + })} + > + + + ({ + color: theme.palette.text.primary, + })} + > + ({guaranteedRefundPercentage}% refund guaranteed) + + - {/* Network fee box attached to the bottom */} - theme.palette.warning.main, - color: (theme) => theme.palette.warning.contrastText, - borderRadius: "4px", - fontSize: "0.75rem", - fontWeight: 600, - boxShadow: "0 2px 4px rgba(0,0,0,0.1)", - whiteSpace: "nowrap", - zIndex: 1, - }} - > - Network fee: + {/* Network fee box attached to the bottom */} + theme.palette.warning.main, + color: (theme) => theme.palette.warning.contrastText, + borderRadius: "4px", + fontSize: "0.75rem", + fontWeight: 600, + boxShadow: "0 2px 4px rgba(0,0,0,0.1)", + whiteSpace: "nowrap", + zIndex: 1, + }} + > + Network fee: + - -); + ) +}; interface PoolBreakdownProps { monero_receive_pool: Array<{ diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index e71fdcb226..6e7261cae5 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -836,16 +836,19 @@ fn apply_bitcoin_amnesty_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, ) -> Result { - let amount_sats = swap_amount.to_sat(); let btc_amnesty_ratio = Decimal::ONE .checked_sub(refund_policy.taker_refund_ratio) .context("can't have refund ration > 1")?; - let btc_amnesty_sats = Decimal::from_u64(amount_sats) - .context("Decimal overflowed by Bitcoin sats")? + let amount_sats = swap_amount.to_sat(); + let amount_decimal = + Decimal::from_u64(amount_sats).context("Decimal overflowed by Bitcoin sats")?; + + let btc_amnesty_decimal = amount_decimal .checked_mul(btc_amnesty_ratio) .context("Decimal overflow when computing amnesty amount in sats")? - .floor() + .floor(); + let btc_amnesty_sats = btc_amnesty_decimal .try_into() .context("Couldn't convert Decimal to u64")?; diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index acbed85733..fa9e2451d0 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -95,6 +95,9 @@ pub struct LockBitcoinDetails { pub monero_receive_pool: MoneroAddressPool, #[typeshare(serialized_as = "string")] pub swap_id: Uuid, + /// The amount of Bitcoin the taker will only be able to refund with cooperation from the maker + #[typeshare(serialized_as = "number")] + pub btc_amnesty_amount: bitcoin::Amount, } #[typeshare] diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 8f2a84bbb6..9e320291f9 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -154,6 +154,7 @@ async fn next_state( BobState::SwapSetupCompleted(state2) => { // Alice and Bob have exchanged all necessary signatures let xmr_receive_amount = state2.xmr; + let btc_amnesty_amount = state2.btc_amnesty_amount.context("btc_amnesty_amount missing")?; // Sign the Bitcoin lock transaction let (state3, tx_lock) = state2.lock_btc().await?; @@ -172,6 +173,7 @@ async fn next_state( let details = LockBitcoinDetails { btc_lock_amount, btc_network_fee, + btc_amnesty_amount, xmr_receive_amount, monero_receive_pool, swap_id, From da31dcc0756f9c0fd8a0c82c0b52e3c596f3bb46 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 10 Dec 2025 16:25:46 +0100 Subject: [PATCH 044/146] state-machine(alice): wait for either TxFullRefund or TxPartialRefund --- swap-asb/src/main.rs | 3 ++- swap-machine/src/alice/mod.rs | 35 +++++++++++++++++++++++++++++++-- swap/src/protocol/alice/swap.rs | 17 +++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/swap-asb/src/main.rs b/swap-asb/src/main.rs index bb0feba121..fb829eaddf 100644 --- a/swap-asb/src/main.rs +++ b/swap-asb/src/main.rs @@ -543,7 +543,8 @@ pub async fn main() -> Result<()> { .next() .context("Couldn't find state Started for this swap")?; - let secret_spend_key = match state3.watch_for_btc_tx_refund(&bitcoin_wallet).await { + let secret_spend_key = match state3.watch_for_btc_tx_full_refund(&bitcoin_wallet).await + { Ok(secret) => secret, Err(error) => { tracing::error!( diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 017db7f1d4..5bc115609d 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -9,7 +9,7 @@ use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxEarlyRefund, - TxFullRefund, TxPunish, TxRedeem, Txid, current_epoch, + TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, Txid, current_epoch, }; use swap_core::monero; use swap_core::monero::ScalarExt; @@ -575,6 +575,19 @@ impl State3 { ) } + pub fn tx_partial_refund(&self) -> Result { + swap_core::bitcoin::TxPartialRefund::new( + &self.tx_cancel(), + &self.refund_address, + self.a.public(), + self.B, + self.btc_amnesty_amount + .context("Missing btc_amnesty_amount")?, + self.tx_partial_refund_fee + .context("Missing tx_partial_refund_fee")?, + ) + } + pub fn tx_redeem(&self) -> TxRedeem { TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee) } @@ -711,7 +724,7 @@ impl State3 { } } - pub async fn watch_for_btc_tx_refund( + pub async fn watch_for_btc_tx_full_refund( &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, ) -> Result { @@ -728,6 +741,24 @@ impl State3 { "Bitcoin refund transaction not found even though we saw it in the mempool previously", ) } + + pub async fn watch_for_btc_tx_partial_refund( + &self, + bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, + ) -> Result { + let tx_refund_status = bitcoin_wallet + .subscribe_to(Box::new(self.tx_partial_refund()?)) + .await; + + tx_refund_status + .wait_until_seen() + .await + .context("Failed to monitor refund transaction")?; + + self.refund_btc(bitcoin_wallet).await?.context( + "Bitcoin refund transaction not found even though we saw it in the mempool previously", + ) + } } pub trait ReservesMonero { diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index dd11741079..73fdb990cb 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -607,8 +607,23 @@ where .subscribe_to(Box::new(state3.tx_cancel())) .await; + // We wait for either TxFullRefund or TxPartialRefund to be published + // - both allow us to extract the Monero refund key. + // Otherwise we punish, once that timelock expired. + + // TODO: should we retry here? select! { - spend_key = state3.watch_for_btc_tx_refund(&*bitcoin_wallet) => { + spend_key = state3.watch_for_btc_tx_full_refund(&*bitcoin_wallet) => { + let spend_key = spend_key?; + + AliceState::BtcRefunded { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, + } + } + spend_key = state3.watch_for_btc_tx_partial_refund(&*bitcoin_wallet) => { let spend_key = spend_key?; AliceState::BtcRefunded { From 478b9507fa502c143440bb8c4e9199f3cd8c5cd2 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 12:02:13 +0100 Subject: [PATCH 045/146] implement BitcoinWallet::ensure_broadcasted --- bitcoin-wallet/src/wallet.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index 40014d6598..5808ffd266 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -760,6 +760,25 @@ impl Wallet { Ok((txid, subscription)) } + /// Broadcast a transaction, but only if it's not already in the mempool/blockchain. + /// Return txid and a subcription to it's status in either case. + pub async fn ensure_broadcasted( + &self, + tx: Transaction, + kind: &str, + ) -> Result<(Txid, Subscription)> { + let txid = tx.compute_txid(); + + let status = self.status_of_script(&tx).await?; + + if matches!(status, ScriptStatus::InMempool | ScriptStatus::Confirmed(_)) { + let subscription = self.subscribe_to(Box::new(tx)).await; + return Ok((txid, subscription)); + } + + self.broadcast(tx, kind).await + } + pub async fn get_raw_transaction(&self, txid: Txid) -> Result>> { self.get_tx(txid) .await From aadffaaa0ebfa7bcac14bd00a4f9709d34849132 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 12:24:02 +0100 Subject: [PATCH 046/146] state-machine(alice): add BtcPartiallyRefunded and XmrRefundable states --- swap-db/src/alice.rs | 30 +++++++++++++++++++++++++++ swap-machine/src/alice/mod.rs | 16 +++++++++++++- swap/src/asb/recovery/cancel.rs | 2 ++ swap/src/asb/recovery/punish.rs | 2 ++ swap/src/asb/recovery/refund.rs | 2 ++ swap/src/asb/recovery/safely_abort.rs | 2 ++ swap/src/protocol/alice/swap.rs | 22 ++++++++++++++++++++ 7 files changed, 75 insertions(+), 1 deletion(-) diff --git a/swap-db/src/alice.rs b/swap-db/src/alice.rs index 187a1b7a29..001ae7c553 100644 --- a/swap-db/src/alice.rs +++ b/swap-db/src/alice.rs @@ -75,6 +75,13 @@ pub enum Alice { #[serde(with = "swap_serde::monero::private_key")] spend_key: monero::PrivateKey, }, + BtcPartiallyRefunded { + monero_wallet_restore_blockheight: BlockHeight, + transfer_proof: TransferProof, + state3: alice::State3, + #[serde(with = "swap_serde::monero::private_key")] + spend_key: monero::PrivateKey, + }, Done(AliceEndState), } @@ -170,6 +177,17 @@ impl From for Alice { spend_key, state3: state3.as_ref().clone(), }, + AliceState::BtcPartiallyRefunded { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, + } => Alice::BtcPartiallyRefunded { + monero_wallet_restore_blockheight, + transfer_proof, + state3: *state3, + spend_key, + }, AliceState::BtcEarlyRefundable { state3 } => Alice::BtcEarlyRefundable { state3: state3.as_ref().clone(), }, @@ -320,6 +338,17 @@ impl From for AliceState { spend_key, state3: Box::new(state3), }, + Alice::BtcPartiallyRefunded { + monero_wallet_restore_blockheight, + transfer_proof, + state3, + spend_key, + } => AliceState::BtcPartiallyRefunded { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3: Box::new(state3), + }, Alice::BtcEarlyRefundable { state3 } => AliceState::BtcEarlyRefundable { state3: Box::new(state3), }, @@ -366,6 +395,7 @@ impl fmt::Display for Alice { Alice::BtcCancelled { .. } => f.write_str("Bitcoin cancel transaction published"), Alice::BtcPunishable { .. } => f.write_str("Bitcoin punishable"), Alice::BtcRefunded { .. } => f.write_str("Monero refundable"), + Alice::BtcPartiallyRefunded { .. } => f.write_str("Monero refundable"), Alice::BtcEarlyRefundable { .. } => f.write_str("Bitcoin early refundable"), Alice::Done(end_state) => write!(f, "Done: {}", end_state), } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 5bc115609d..25e422249e 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -69,11 +69,19 @@ pub enum AliceState { spend_key: monero::PrivateKey, state3: Box, }, - BtcPunishable { + BtcPartiallyRefunded { + monero_wallet_restore_blockheight: BlockHeight, + transfer_proof: TransferProof, + spend_key: monero::PrivateKey, + state3: Box, + }, + XmrRefundable { monero_wallet_restore_blockheight: BlockHeight, transfer_proof: TransferProof, + spend_key: monero::PrivateKey, state3: Box, }, + // TODO: save redeem transaction id XmrRefunded, WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight: BlockHeight, @@ -85,6 +93,11 @@ pub enum AliceState { transfer_proof: TransferProof, state3: Box, }, + BtcPunishable { + monero_wallet_restore_blockheight: BlockHeight, + transfer_proof: TransferProof, + state3: Box, + }, BtcPunished { state3: Box, transfer_proof: TransferProof, @@ -133,6 +146,7 @@ impl fmt::Display for AliceState { AliceState::CancelTimelockExpired { .. } => write!(f, "cancel timelock is expired"), AliceState::BtcEarlyRefundable { .. } => write!(f, "btc is early refundable"), AliceState::BtcEarlyRefunded(_) => write!(f, "btc is early refunded"), + AliceState::BtcPartiallyRefunded { .. } => write!(f, "btc is partially refunded"), } } } diff --git a/swap/src/asb/recovery/cancel.rs b/swap/src/asb/recovery/cancel.rs index 6f8dc51000..7e58193c82 100644 --- a/swap/src/asb/recovery/cancel.rs +++ b/swap/src/asb/recovery/cancel.rs @@ -30,6 +30,8 @@ pub async fn cancel( | AliceState::CancelTimelockExpired { monero_wallet_restore_blockheight, transfer_proof, state3} | AliceState::BtcCancelled { monero_wallet_restore_blockheight, transfer_proof, state3 } | AliceState::BtcRefunded { monero_wallet_restore_blockheight, transfer_proof, state3 ,.. } + | AliceState::BtcPartiallyRefunded { monero_wallet_restore_blockheight, transfer_proof, state3 ,.. } + | AliceState::XmrRefundable { monero_wallet_restore_blockheight, transfer_proof, state3 ,.. } | AliceState::BtcPunishable { monero_wallet_restore_blockheight, transfer_proof, state3 } => { (monero_wallet_restore_blockheight, transfer_proof, state3) } diff --git a/swap/src/asb/recovery/punish.rs b/swap/src/asb/recovery/punish.rs index a71a1b58a3..76b09a882d 100644 --- a/swap/src/asb/recovery/punish.rs +++ b/swap/src/asb/recovery/punish.rs @@ -34,6 +34,8 @@ pub async fn punish( // The state machine is in a state where punish is theoretically impossible but we try and punish anyway as this is what the user wants | AliceState::BtcRedeemTransactionPublished { state3, transfer_proof, .. } | AliceState::BtcRefunded { state3, transfer_proof,.. } => { (state3, transfer_proof) } + | AliceState::BtcPartiallyRefunded { state3, transfer_proof,.. } => { (state3, transfer_proof) } + | AliceState::XmrRefundable { state3, transfer_proof,.. } => { (state3, transfer_proof) } // Alice already in final state or at the start of the swap so we can't punish | AliceState::Started { .. } diff --git a/swap/src/asb/recovery/refund.rs b/swap/src/asb/recovery/refund.rs index b747af5bc7..79aab3b3ce 100644 --- a/swap/src/asb/recovery/refund.rs +++ b/swap/src/asb/recovery/refund.rs @@ -51,6 +51,8 @@ pub async fn refund( // Refund possible due to cancel transaction already being published | AliceState::BtcCancelled { transfer_proof, state3, .. } | AliceState::BtcRefunded { transfer_proof, state3, .. } + | AliceState::BtcPartiallyRefunded { transfer_proof, state3, .. } + | AliceState::XmrRefundable { transfer_proof, state3, .. } | AliceState::BtcPunishable { transfer_proof, state3, .. } => { (transfer_proof, state3) } diff --git a/swap/src/asb/recovery/safely_abort.rs b/swap/src/asb/recovery/safely_abort.rs index f9e5812a34..f5382d3cc5 100644 --- a/swap/src/asb/recovery/safely_abort.rs +++ b/swap/src/asb/recovery/safely_abort.rs @@ -29,6 +29,8 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc) -> Result AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, + }, + AliceState::BtcPartiallyRefunded { + transfer_proof, + spend_key, + state3, + monero_wallet_restore_blockheight, + } => AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, + }, + AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, } => { retry( "Refund Monero", From de920474c025db7852cfa9df3b725321e44cf36d Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 15:21:20 +0100 Subject: [PATCH 047/146] add justfile aliases for gui linting --- justfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/justfile b/justfile index f3ba6bad62..198b5e0eb9 100644 --- a/justfile +++ b/justfile @@ -108,10 +108,14 @@ fmt: generate-sqlx-cache: ./dev-scripts/regenerate_sqlx_cache.sh + +alias eslint := check_gui_eslint # Run eslint for the GUI frontend check_gui_eslint: cd src-gui && yarn run eslint +alias tsc := check_gui_tsc + # Run the typescript type checker for the GUI frontend check_gui_tsc: cd src-gui && yarn run tsc --noEmit From dd433d4ba3c6d546c7bca542548bae46a565757e Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 15:22:14 +0100 Subject: [PATCH 048/146] state-machine(alice): add XmrRefundable state --- swap-db/src/alice.rs | 30 ++++++++++++++++++++++++++++++ swap-machine/src/alice/mod.rs | 1 + swap/src/asb/recovery/redeem.rs | 2 ++ swap/src/protocol/alice/swap.rs | 21 ++++++++++++++------- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/swap-db/src/alice.rs b/swap-db/src/alice.rs index 001ae7c553..4d3c6cb57f 100644 --- a/swap-db/src/alice.rs +++ b/swap-db/src/alice.rs @@ -82,6 +82,13 @@ pub enum Alice { #[serde(with = "swap_serde::monero::private_key")] spend_key: monero::PrivateKey, }, + XmrRefundable { + monero_wallet_restore_blockheight: BlockHeight, + transfer_proof: TransferProof, + state3: alice::State3, + #[serde(with = "swap_serde::monero::private_key")] + spend_key: monero::PrivateKey, + }, Done(AliceEndState), } @@ -188,6 +195,17 @@ impl From for Alice { state3: *state3, spend_key, }, + AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + state3, + spend_key, + } => Alice::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + state3: *state3, + spend_key, + }, AliceState::BtcEarlyRefundable { state3 } => Alice::BtcEarlyRefundable { state3: state3.as_ref().clone(), }, @@ -352,6 +370,17 @@ impl From for AliceState { Alice::BtcEarlyRefundable { state3 } => AliceState::BtcEarlyRefundable { state3: Box::new(state3), }, + Alice::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + state3, + spend_key, + } => AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3: Box::new(state3), + }, Alice::Done(end_state) => match end_state { AliceEndState::SafelyAborted => AliceState::SafelyAborted, AliceEndState::BtcRedeemed => AliceState::BtcRedeemed, @@ -397,6 +426,7 @@ impl fmt::Display for Alice { Alice::BtcRefunded { .. } => f.write_str("Monero refundable"), Alice::BtcPartiallyRefunded { .. } => f.write_str("Monero refundable"), Alice::BtcEarlyRefundable { .. } => f.write_str("Bitcoin early refundable"), + Alice::XmrRefundable { .. } => f.write_str("Bitcoin early refundable"), Alice::Done(end_state) => write!(f, "Done: {}", end_state), } } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 25e422249e..4f849017a5 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -147,6 +147,7 @@ impl fmt::Display for AliceState { AliceState::BtcEarlyRefundable { .. } => write!(f, "btc is early refundable"), AliceState::BtcEarlyRefunded(_) => write!(f, "btc is early refunded"), AliceState::BtcPartiallyRefunded { .. } => write!(f, "btc is partially refunded"), + AliceState::XmrRefundable { .. } => write!(f, "xmr is refundable"), } } } diff --git a/swap/src/asb/recovery/redeem.rs b/swap/src/asb/recovery/redeem.rs index 586463bbee..9024450a2a 100644 --- a/swap/src/asb/recovery/redeem.rs +++ b/swap/src/asb/recovery/redeem.rs @@ -87,9 +87,11 @@ pub async fn redeem( | AliceState::CancelTimelockExpired { .. } | AliceState::BtcCancelled { .. } | AliceState::BtcRefunded { .. } + | AliceState::BtcPartiallyRefunded { .. } | AliceState::BtcPunishable { .. } | AliceState::BtcRedeemed | AliceState::XmrRefunded + | AliceState::XmrRefundable { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) | AliceState::BtcPunished { .. } diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 2fe001db30..29a981d9d1 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -1,5 +1,6 @@ //! Run an XMR/BTC swap in the role of Alice. //! Alice holds XMR and wishes receive BTC. +use std::any::Any; use std::sync::Arc; use std::time::Duration; @@ -648,7 +649,7 @@ where transfer_proof, spend_key, state3, - .. + monero_wallet_restore_blockheight, } => AliceState::XmrRefundable { monero_wallet_restore_blockheight, transfer_proof, @@ -660,12 +661,18 @@ where spend_key, state3, monero_wallet_restore_blockheight, - } => AliceState::XmrRefundable { - monero_wallet_restore_blockheight, - transfer_proof, - spend_key, - state3, - }, + } => { + let should_grant_amnesty = true; + + // TODO: Publish amnesty transaction/send amnesty tx sig / decide against it + + AliceState::XmrRefundable { + monero_wallet_restore_blockheight, + transfer_proof, + spend_key, + state3, + } + } AliceState::XmrRefundable { monero_wallet_restore_blockheight, transfer_proof, From fdaa70d954504d0e0b7966277c1dafbfb2476ac5 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 15:22:28 +0100 Subject: [PATCH 049/146] tiny gui fixes --- src-gui/src/renderer/components/other/MonospaceTextBox.tsx | 6 +++--- .../components/pages/monero/SendTransactionModal.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src-gui/src/renderer/components/other/MonospaceTextBox.tsx b/src-gui/src/renderer/components/other/MonospaceTextBox.tsx index bce732a0e8..739fb67258 100644 --- a/src-gui/src/renderer/components/other/MonospaceTextBox.tsx +++ b/src-gui/src/renderer/components/other/MonospaceTextBox.tsx @@ -17,9 +17,9 @@ export default function MonospaceTextBox({ display: "flex", alignItems: "center", justifyContent: "space-between", - backgroundColor: light ? "transparent" : theme.palette.grey[900], - borderRadius: 2, - border: light ? `1px solid ${theme.palette.grey[800]}` : "none", + backgroundColor: theme.palette.action.hover, + borderRadius: theme.shape.borderRadius, + border: "none", padding: theme.spacing(1), gap: 1, })} diff --git a/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx b/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx index e25aae0110..f589569b6f 100644 --- a/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx +++ b/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx @@ -27,7 +27,7 @@ export default function SendTransactionModal({ const showSuccess = successResponse !== null; - const handleClose = (event: unknown, reason: string) => { + const handleClose = (_: any, reason: string) => { // We want the user to explicitly close the dialog. // We do not close the dialog upon a backdrop click. if (reason === "backdropClick") { @@ -60,7 +60,7 @@ export default function SendTransactionModal({ )} {showSuccess && ( )} From 1f913b2b22bd200a9cb17041163ad18a0524111a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 11 Dec 2025 16:27:58 +0100 Subject: [PATCH 050/146] gui: update types to reflect new states --- src-gui/src/models/tauriModelExt.ts | 19 ++++++++++++++++ .../pages/swap/swap/SwapStatePage.tsx | 14 +++++++++++- .../swap/swap/done/BitcoinRefundedPage.tsx | 22 +++++++++++++++++++ swap-machine/src/bob/mod.rs | 2 +- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src-gui/src/models/tauriModelExt.ts b/src-gui/src/models/tauriModelExt.ts index 2023d94e05..69d112ef2a 100644 --- a/src-gui/src/models/tauriModelExt.ts +++ b/src-gui/src/models/tauriModelExt.ts @@ -50,9 +50,13 @@ export enum BobStateName { CancelTimelockExpired = "cancel timelock is expired", BtcCancelled = "btc is cancelled", BtcRefundPublished = "btc refund is published", + BtcPartialRefundPublished = "btc partial refund is published", BtcEarlyRefundPublished = "btc early refund is published", BtcRefunded = "btc is refunded", BtcEarlyRefunded = "btc is early refunded", + BtcPartiallyRefunded = "btc is partially refunded", + BtcAmnestyPublished = "btc amnesty is published", + BtcAmnestyReceived = "btc amnesty is confirmed", XmrRedeemed = "xmr is redeemed", BtcPunished = "btc is punished", SafelyAborted = "safely aborted", @@ -84,10 +88,18 @@ export function bobStateNameToHumanReadable(stateName: BobStateName): string { return "Bitcoin refund published"; case BobStateName.BtcEarlyRefundPublished: return "Bitcoin early refund published"; + case BobStateName.BtcPartialRefundPublished: + return "Bitcoin partial refund published"; + case BobStateName.BtcAmnestyPublished: + return "Bitcoin amnesty was granted"; case BobStateName.BtcRefunded: return "Bitcoin refunded"; case BobStateName.BtcEarlyRefunded: return "Bitcoin early refunded"; + case BobStateName.BtcPartiallyRefunded: + return "Bitcoin partially refunded"; + case BobStateName.BtcAmnestyReceived: + return "Bitcoin amnesty was received"; case BobStateName.XmrRedeemed: return "Monero redeemed"; case BobStateName.BtcPunished: @@ -133,6 +145,10 @@ export type BobStateNameRunningSwap = Exclude< | BobStateName.Started | BobStateName.SwapSetupCompleted | BobStateName.BtcRefunded + | BobStateName.BtcPartiallyRefunded + | BobStateName.BtcAmnestyPublished + | BobStateName.BtcAmnestyReceived + | BobStateName.BtcRefunded | BobStateName.BtcEarlyRefunded | BobStateName.BtcPunished | BobStateName.SafelyAborted @@ -151,6 +167,9 @@ export function isBobStateNameRunningSwap( BobStateName.SwapSetupCompleted, BobStateName.BtcRefunded, BobStateName.BtcEarlyRefunded, + BobStateName.BtcPartiallyRefunded, + BobStateName.BtcAmnestyPublished, + BobStateName.BtcAmnestyReceived, BobStateName.BtcPunished, BobStateName.SafelyAborted, BobStateName.XmrRedeemed, diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index 455e4c210c..dc78f3a5a5 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -7,6 +7,10 @@ import { BitcoinEarlyRefundedPage, BitcoinEarlyRefundPublishedPage, BitcoinRefundPublishedPage, + BitcoinPartialRefundPublished, + BitcoinPartiallyRefunded, + BitcoinAmnestyPublished, + BitcoinAmnestyReceived } from "./done/BitcoinRefundedPage"; import XmrRedeemInMempoolPage from "./done/XmrRedeemInMempoolPage"; import ProcessExitedPage from "./exited/ProcessExitedPage"; @@ -88,7 +92,7 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { case "BtcCancelled": return ; - //// 4 different types of Bitcoin refund states we can be in + //// 8 different types of Bitcoin refund states we can be in case "BtcRefundPublished": // tx_refund has been published but has not been confirmed yet if (state.curr.type === "BtcRefundPublished") { return ; @@ -109,6 +113,14 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { return ; } break; + case "BtcPartialRefundPublished": + return ; + case "BtcPartiallyRefunded": + return ; + case "BtcAmnestyPublished": + return ; + case "BtcAmnestyReceived": + return ; //// 4 different types of Bitcoin punished states we can be in case "BtcPunished": diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx index 866a6fcc41..5c56cd939f 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx @@ -91,3 +91,25 @@ function MultiBitcoinRefundedPage({ ); } + +export function BitcoinPartialRefundPublished() { + return ( + <>TxPartialRefund published + ) +} + +export function BitcoinPartiallyRefunded() { + return ( + <>Bitcoin partially refunded + ) +} +export function BitcoinAmnestyPublished() { + return ( + <>TxAmnesty published + ) +} +export function BitcoinAmnestyReceived() { + return ( + <>Bitcoin amnesty received + ) +} diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index fa7ac5d3fe..c4a1a2983c 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -131,7 +131,7 @@ impl fmt::Display for BobState { BobState::BtcRefundPublished { .. } => write!(f, "btc refund is published"), BobState::BtcEarlyRefundPublished { .. } => write!(f, "btc early refund is published"), BobState::BtcPartialRefundPublished { .. } => { - write!(f, "btc partially refund is published") + write!(f, "btc partial refund is published") } BobState::BtcRefunded(..) => write!(f, "btc is refunded"), BobState::XmrRedeemed { .. } => write!(f, "xmr is redeemed"), From a621ccffdb0a0034e6402cca9b13d7c15cf95b6a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 12 Dec 2025 12:59:40 +0100 Subject: [PATCH 051/146] bob: send sig for TxRefundAmnesty, alice: publish it --- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 1 + swap-core/src/bitcoin/refund_amnesty.rs | 35 +++++++--- swap-machine/src/alice/mod.rs | 69 +++++++++++++++++-- swap-machine/src/bob/mod.rs | 32 +++++++-- swap-machine/src/common/mod.rs | 5 +- swap-machine/src/lib.rs | 4 +- swap-p2p/src/protocols/swap_setup/bob.rs | 11 ++- swap/src/protocol/alice/swap.rs | 10 ++- 8 files changed, 138 insertions(+), 29 deletions(-) diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 7fb8594fdd..f83da10481 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -194,6 +194,7 @@ export function StateAlert({ case BobStateName.CancelTimelockExpired: case BobStateName.BtcCancelled: case BobStateName.BtcRefundPublished: // Even if the transactions have been published, it cannot be + case BobStateName.BtcPartialRefundPublished: // Even if the transactions have been published, it cannot be case BobStateName.BtcEarlyRefundPublished: // guaranteed that they will be confirmed in time if (timelock != null) { switch (timelock.type) { diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/refund_amnesty.rs index 3ffc3c04ea..0acb6c290e 100644 --- a/swap-core/src/bitcoin/refund_amnesty.rs +++ b/swap-core/src/bitcoin/refund_amnesty.rs @@ -1,11 +1,9 @@ use crate::bitcoin::partial_refund::TxPartialRefund; -use crate::bitcoin::{ - Address, Amount, PublicKey, Transaction, -}; +use crate::bitcoin::{self, Address, Amount, PublicKey, Transaction}; use ::bitcoin::sighash::SighashCache; -use ::bitcoin::{secp256k1, ScriptBuf, Weight}; -use ::bitcoin::{sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, Txid}; -use anyhow::Result; +use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; +use ::bitcoin::{ScriptBuf, Weight, secp256k1}; +use anyhow::{Context, Result}; use bdk_wallet::miniscript::Descriptor; use bitcoin_wallet::primitives::Watchable; use ecdsa_fun::Signature; @@ -20,8 +18,13 @@ pub struct TxRefundAmnesty { } impl TxRefundAmnesty { - pub fn new(tx_refund: &TxPartialRefund, refund_address: &Address, spending_fee: Amount) -> Self { - let tx_refund_amnesty = tx_refund.build_amnesty_spend_transaction(refund_address, spending_fee); + pub fn new( + tx_refund: &TxPartialRefund, + refund_address: &Address, + spending_fee: Amount, + ) -> Self { + let tx_refund_amnesty = + tx_refund.build_amnesty_spend_transaction(refund_address, spending_fee); let digest = SighashCache::new(&tx_refund_amnesty) .p2wsh_signature_hash( @@ -51,6 +54,20 @@ impl TxRefundAmnesty { self.digest } + pub fn complete_as_alice( + &self, + s_a: bitcoin::SecretKey, + B: bitcoin::PublicKey, + sig_b: Signature, + ) -> Result { + let digest = self.digest(); + let sig_a = s_a.sign(digest); + + self.clone() + .add_signatures((s_a.public(), sig_a), (B, sig_b)) + .context("Couldn't add signatures to transaction") + } + pub fn add_signatures( self, (A, sig_a): (PublicKey, Signature), @@ -70,7 +87,7 @@ impl TxRefundAmnesty { let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; - + // The order in which these are inserted doesn't matter satisfier.insert( A, diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 4f849017a5..19e2cef4c8 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -5,11 +5,11 @@ use anyhow::{Context, Result, anyhow, bail}; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; -use std::fmt; +use std::fmt::{self, Debug}; use std::sync::Arc; use swap_core::bitcoin::{ CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxEarlyRefund, - TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, Txid, current_epoch, + TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, TxRefundAmnesty, Txid, current_epoch, }; use swap_core::monero; use swap_core::monero::ScalarExt; @@ -63,6 +63,9 @@ pub enum AliceState { state3: Box, }, BtcEarlyRefunded(Box), + // We enter the refund states regardless of whether or not the refund + // transaction was confirmed because we do not care. We can extract the key + // we need to refund ourself regardless. BtcRefunded { monero_wallet_restore_blockheight: BlockHeight, transfer_proof: TransferProof, @@ -313,9 +316,13 @@ impl State1 { } pub fn receive(self, msg: Message2) -> Result { - let tx_lock = - swap_core::bitcoin::TxLock::from_psbt(msg.psbt, self.a.public(), self.B, self.btc) - .context("Failed to re-construct TxLock from received PSBT")?; + let tx_lock = swap_core::bitcoin::TxLock::from_psbt( + msg.tx_lock_psbt, + self.a.public(), + self.B, + self.btc, + ) + .context("Failed to re-construct TxLock from received PSBT")?; Ok(State2 { a: self.a, @@ -450,6 +457,33 @@ impl State2 { ) .context("Failed to verify early refund transaction")?; + // Create TxRefundAmnesty ourself + let tx_partial_refund = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.a.public(), + self.B, + self.btc_amnesty_amount + .context("missing btc_amnesty_amount")?, + self.tx_partial_refund_fee + .context("missing tx_partial_refund_fee")?, + ) + .context("Couldn't construct TxPartialRefund")?; + let tx_refund_amnesty = TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("missing tx_refund_amnesty_fee")?, + ); + + // Check if the provided signature by Bob is valid for the transaction + swap_core::bitcoin::verify_sig( + &self.B, + &tx_refund_amnesty.digest(), + &msg.tx_refund_amnesty_sig, + ) + .context("Failed to verify refund amnesty transaction")?; + Ok(State3 { a: self.a, B: self.B, @@ -469,6 +503,7 @@ impl State2 { tx_punish_sig_bob: msg.tx_punish_sig, tx_cancel_sig_bob: msg.tx_cancel_sig, tx_early_refund_sig_bob: msg.tx_early_refund_sig.into(), + tx_refund_amnesty_sig_bob: msg.tx_refund_amnesty_sig.into(), tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, @@ -513,6 +548,12 @@ pub struct State3 { /// to wait for the timelock to expire. #[serde(default)] tx_early_refund_sig_bob: Option, + /// This field was added in PR [#675](https://github.com/eigenwallet/core/pull/344). + /// It is optional to maintain backwards compatibility with old swaps in the database. + /// Bob must send this to us during swap setup, in order for us to publish TxRefundAmnesty + /// in case of a refund. Otherwise Bob will only be partially refunded. + #[serde(default)] + tx_refund_amnesty_sig_bob: Option, tx_redeem_fee: bitcoin::Amount, pub tx_punish_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, @@ -664,6 +705,24 @@ impl State3 { Ok(tx_id) } + pub fn signed_bitcoin_amnesty_transaction(&self) -> Result { + let tx_partial_refund = self.tx_partial_refund()?; + let tx_amnesty = TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("Missing tx_refund_amnesty_fee")?, + ); + + tx_amnesty.complete_as_alice( + self.a.clone(), + self.B, + self.tx_refund_amnesty_sig_bob + .clone() + .context("missing Bob's signature for TxRefundAmnesty")?, + ) + } + pub async fn punish_btc( &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index c4a1a2983c..627509fb66 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -14,8 +14,8 @@ use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ - self, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxLock, Txid, - current_epoch, + self, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxLock, + TxPartialRefund, TxRefundAmnesty, Txid, current_epoch, }; use swap_core::monero::ScalarExt; use swap_core::monero::primitives::WatchRequest; @@ -380,7 +380,7 @@ pub struct State1 { impl State1 { pub fn next_message(&self) -> Message2 { Message2 { - psbt: self.tx_lock.clone().into(), + tx_lock_psbt: self.tx_lock.clone().into(), } } @@ -507,7 +507,7 @@ pub struct State2 { } impl State2 { - pub fn next_message(&self) -> Message4 { + pub fn next_message(&self) -> Result { let tx_cancel = TxCancel::new( &self.tx_lock, self.cancel_timelock, @@ -532,11 +532,31 @@ impl State2 { let tx_early_refund_sig = self.b.sign(tx_early_refund.digest()); - Message4 { + let tx_partial_refund = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + self.btc_amnesty_amount + .context("missing btc_amnesty_amount")?, + self.tx_partial_refund_fee + .context("missing tx_partial_refund_fee")?, + ) + .context("Couldn't construct TxPartialRefund")?; + let tx_refund_amnesty = TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("Missing tx_refund_amnesty_fee")?, + ); + let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); + + Ok(Message4 { tx_punish_sig, tx_cancel_sig, tx_early_refund_sig, - } + tx_refund_amnesty_sig, + }) } pub async fn lock_btc(self) -> Result<(State3, TxLock)> { diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 78ffcffbbc..86273769e7 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -63,7 +63,7 @@ pub struct Message1 { #[allow(non_snake_case)] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Message2 { - pub psbt: bitcoin::PartiallySignedTransaction, + pub tx_lock_psbt: bitcoin::PartiallySignedTransaction, } #[allow(non_snake_case)] @@ -71,7 +71,7 @@ pub struct Message2 { pub struct Message3 { pub tx_cancel_sig: bitcoin::Signature, /// The following fields were reworked in [#675](https://github.com/eigenwallet/core/pull/675). - /// Alice _may_ choose to commit to a full refund during the swap setup already, but doesn't + /// Alice _may_ choose to commit to a full refund for bob during the swap setup already, but doesn't /// have to. pub tx_partial_refund_encsig: bitcoin::EncryptedSignature, pub tx_full_refund_encsig: Option, @@ -84,6 +84,7 @@ pub struct Message4 { pub tx_punish_sig: bitcoin::Signature, pub tx_cancel_sig: bitcoin::Signature, pub tx_early_refund_sig: bitcoin::Signature, + pub tx_refund_amnesty_sig: bitcoin::Signature, } #[allow(clippy::large_enum_variant)] diff --git a/swap-machine/src/lib.rs b/swap-machine/src/lib.rs index 8ac33b2b10..f00aad1399 100644 --- a/swap-machine/src/lib.rs +++ b/swap-machine/src/lib.rs @@ -89,7 +89,7 @@ mod tests { let alice_message3 = alice_state2.next_message().unwrap(); let bob_state2 = bob_state1.receive(alice_message3).unwrap(); - let bob_message4 = bob_state2.next_message(); + let bob_message4 = bob_state2.next_message().unwrap(); let alice_state3 = alice_state2.receive(bob_message4).unwrap(); @@ -202,7 +202,7 @@ mod tests { let alice_message3 = alice_state2.next_message().unwrap(); let bob_state2 = bob_state1.receive(alice_message3).unwrap(); - let bob_message4 = bob_state2.next_message(); + let bob_message4 = bob_state2.next_message().unwrap(); let alice_state3 = alice_state2.receive(bob_message4).unwrap(); diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 66bfbcbd71..d5cc2558d0 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -623,9 +623,14 @@ async fn run_swap_setup( "Transitioned into state2 during swap setup", ); - write_cbor_message(&mut substream, state2.next_message()) - .await - .context("Failed to send state2 message")?; + write_cbor_message( + &mut substream, + state2 + .next_message() + .context("Couldn't construct Message4")?, + ) + .await + .context("Failed to send state2 message")?; substream .flush() diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 29a981d9d1..9f33771c3f 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -662,9 +662,15 @@ where state3, monero_wallet_restore_blockheight, } => { - let should_grant_amnesty = true; - // TODO: Publish amnesty transaction/send amnesty tx sig / decide against it + // TODO: retry, maybe in background? we don't want this to block us from refunding the Monero though + let tx_refund_amnesty = state3 + .signed_bitcoin_amnesty_transaction() + .context("Couldn't construct Bitcoin refund amnesty transaction")?; + + bitcoin_wallet + .ensure_broadcasted(tx_refund_amnesty, "refund amnesty") + .await?; AliceState::XmrRefundable { monero_wallet_restore_blockheight, From 0780e535705bb4554a2e5de511c6090e268ddafa Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 12 Dec 2025 13:21:29 +0100 Subject: [PATCH 052/146] alice: extract monero private key from partial_refund also --- swap-core/src/bitcoin/partial_refund.rs | 19 ++++++++------- swap-machine/src/alice/mod.rs | 32 +++++++++++++++++++++---- swap/src/asb/recovery/refund.rs | 2 +- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 50d93e9554..954a4cdf22 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -2,13 +2,13 @@ use crate::bitcoin; use crate::bitcoin::{ - build_shared_output_descriptor, verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, - NotThreeWitnesses, PublicKey, TooManyInputs, Transaction, TxCancel, + Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, TooManyInputs, + Transaction, TxCancel, build_shared_output_descriptor, verify_sig, }; use ::bitcoin::sighash::SighashCache; -use ::bitcoin::{secp256k1, ScriptBuf, Weight}; -use ::bitcoin::{sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, Txid}; -use anyhow::{bail, Context, Result}; +use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; +use ::bitcoin::{ScriptBuf, Weight, secp256k1}; +use anyhow::{Context, Result, bail}; use bdk_wallet::miniscript::Descriptor; use bitcoin_wallet::primitives::Watchable; use curve25519_dalek::scalar::Scalar; @@ -88,7 +88,10 @@ impl TxPartialRefund { refund_address: &Address, spending_fee: Amount, ) -> Transaction { - use ::bitcoin::{transaction::Version, locktime::absolute::LockTime as PackedLockTime, Sequence, TxIn, TxOut}; + use ::bitcoin::{ + Sequence, TxIn, TxOut, locktime::absolute::LockTime as PackedLockTime, + transaction::Version, + }; let tx_in = TxIn { previous_output: self.amnesty_outpoint(), @@ -129,7 +132,7 @@ impl TxPartialRefund { let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; - + // The order in which these are inserted doesn't matter satisfier.insert( A, @@ -165,7 +168,7 @@ impl TxPartialRefund { ) -> Result { let tx_refund_sig = self .extract_signature_by_key(signed_refund_tx, a.public()) - .context("Failed to extract signature from Bitcoin refund tx")?; + .context("Failed to extract signature from Bitcoin partial refund tx")?; let tx_refund_encsig = a.encsign(S_b_bitcoin, self.digest()); let s_b = bitcoin::recover(S_b_bitcoin, tx_refund_sig, tx_refund_encsig) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 19e2cef4c8..71dddde03c 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -656,7 +656,7 @@ impl State3 { ) } - pub fn extract_monero_private_key( + pub fn extract_monero_private_key_from_refund( &self, signed_refund_tx: Arc, ) -> Result { @@ -670,6 +670,20 @@ impl State3 { )) } + pub fn extract_monero_private_key_from_partial_refund( + &self, + signed_partial_refund_tx: Arc, + ) -> Result { + Ok(monero::PrivateKey::from_scalar( + self.tx_partial_refund()?.extract_monero_private_key( + signed_partial_refund_tx, + self.s_a, + self.a.clone(), + self.S_b_bitcoin, + )?, + )) + } + pub async fn check_for_tx_cancel( &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, @@ -788,13 +802,21 @@ impl State3 { let refund_tx = bitcoin_wallet .get_raw_transaction(self.tx_refund().txid()) .await?; + let partial_refund_tx = bitcoin_wallet + .get_raw_transaction(self.tx_partial_refund()?.txid()) + .await?; - match refund_tx { - Some(refund_tx) => { - let spend_key = self.extract_monero_private_key(refund_tx)?; + match (refund_tx, partial_refund_tx) { + (Some(refund_tx), _) => { + let spend_key = self.extract_monero_private_key_from_refund(refund_tx)?; + Ok(Some(spend_key)) + } + (_, Some(partial_refund_tx)) => { + let spend_key = + self.extract_monero_private_key_from_partial_refund(partial_refund_tx)?; Ok(Some(spend_key)) } - None => Ok(None), + (None, None) => Ok(None), } } diff --git a/swap/src/asb/recovery/refund.rs b/swap/src/asb/recovery/refund.rs index 79aab3b3ce..c79d6a41ab 100644 --- a/swap/src/asb/recovery/refund.rs +++ b/swap/src/asb/recovery/refund.rs @@ -73,7 +73,7 @@ pub async fn refund( state3.fetch_tx_refund(bitcoin_wallet.as_ref()).await? { tracing::debug!(%swap_id, "Bitcoin refund transaction found, extracting key to refund Monero"); - state3.extract_monero_private_key(published_refund_tx)? + state3.extract_monero_private_key_from_refund(published_refund_tx)? } else { let bob_peer_id = db.get_peer_id(swap_id).await?; bail!(Error::RefundTransactionNotPublishedYet(bob_peer_id),); From 87b3e9624b21a8ddf891079d5b0d9ac8bef96f45 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 12 Dec 2025 13:57:13 +0100 Subject: [PATCH 053/146] switch all uses of BitcoinWallet::broadcast to BitcoinWallet::ensure_broadcasted --- bitcoin-wallet/src/lib.rs | 6 ------ bitcoin-wallet/src/wallet.rs | 16 ---------------- swap-machine/src/alice/mod.rs | 8 ++++++-- swap-machine/src/bob/mod.rs | 4 +++- swap/src/asb/recovery/redeem.rs | 4 +++- swap/src/protocol/alice/swap.rs | 4 ++-- swap/src/protocol/bob/swap.rs | 2 +- 7 files changed, 15 insertions(+), 29 deletions(-) diff --git a/bitcoin-wallet/src/lib.rs b/bitcoin-wallet/src/lib.rs index 4cbc937a81..69959ae161 100644 --- a/bitcoin-wallet/src/lib.rs +++ b/bitcoin-wallet/src/lib.rs @@ -41,12 +41,6 @@ pub trait BitcoinWallet: Send + Sync { async fn sign_and_finalize(&self, psbt: bitcoin::psbt::Psbt) -> Result; - async fn broadcast( - &self, - transaction: bitcoin::Transaction, - kind: &str, - ) -> Result<(Txid, Subscription)>; - async fn ensure_broadcasted( &self, transaction: bitcoin::Transaction, diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index 5808ffd266..43b675cc82 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -2141,14 +2141,6 @@ impl BitcoinWallet for Wallet { Wallet::sign_and_finalize(self, psbt).await } - async fn broadcast( - &self, - transaction: bitcoin::Transaction, - kind: &str, - ) -> Result<(Txid, Subscription)> { - Wallet::broadcast(self, transaction, kind).await - } - async fn ensure_broadcasted( &self, tx: bitcoin::Transaction, @@ -2967,14 +2959,6 @@ impl BitcoinWallet for Wallet { unimplemented!("stub method called erroneously") } - async fn broadcast( - &self, - transaction: bitcoin::Transaction, - kind: &str, - ) -> Result<(Txid, Subscription)> { - unimplemented!("stub method called erroneously") - } - async fn sync(&self) -> Result<()> { unimplemented!("stub method called erroneously") } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 71dddde03c..f28e27231e 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -715,7 +715,9 @@ impl State3 { bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, ) -> Result { let transaction = self.signed_cancel_transaction()?; - let (tx_id, _) = bitcoin_wallet.broadcast(transaction, "cancel").await?; + let (tx_id, _) = bitcoin_wallet + .ensure_broadcasted(transaction, "cancel") + .await?; Ok(tx_id) } @@ -743,7 +745,9 @@ impl State3 { ) -> Result { let signed_tx_punish = self.signed_punish_transaction()?; - let (txid, subscription) = bitcoin_wallet.broadcast(signed_tx_punish, "punish").await?; + let (txid, subscription) = bitcoin_wallet + .ensure_broadcasted(signed_tx_punish, "punish") + .await?; subscription.wait_until_final().await?; Ok(txid) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 627509fb66..f48147afcf 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -1023,7 +1023,9 @@ impl State6 { .complete_as_bob(self.A, self.b.clone(), self.tx_cancel_sig_a.clone()) .context("Failed to complete Bitcoin cancel transaction")?; - let (tx_id, subscription) = bitcoin_wallet.broadcast(transaction, "cancel").await?; + let (tx_id, subscription) = bitcoin_wallet + .ensure_broadcasted(transaction, "cancel") + .await?; Ok((tx_id, subscription)) } diff --git a/swap/src/asb/recovery/redeem.rs b/swap/src/asb/recovery/redeem.rs index 9024450a2a..c5bed032c9 100644 --- a/swap/src/asb/recovery/redeem.rs +++ b/swap/src/asb/recovery/redeem.rs @@ -40,7 +40,9 @@ pub async fn redeem( tracing::info!(%swap_id, "Trying to redeem swap"); let redeem_tx = state3.signed_redeem_transaction(*encrypted_signature)?; - let (txid, subscription) = bitcoin_wallet.broadcast(redeem_tx, "redeem").await?; + let (txid, subscription) = bitcoin_wallet + .ensure_broadcasted(redeem_tx, "redeem") + .await?; subscription.wait_until_seen().await?; diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 9f33771c3f..16483a720e 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -270,7 +270,7 @@ where // Retry repeatedly to broadcast tx_early_refund result = async { backoff::future::retry_notify(backoff, || async { - bitcoin_wallet.broadcast(tx_early_refund.clone(), "early_refund").await.map_err(backoff::Error::transient) + bitcoin_wallet.ensure_broadcasted(tx_early_refund.clone(), "early_refund").await.map_err(backoff::Error::transient) }, |e, wait_time: Duration| { tracing::warn!( %tx_early_refund_txid, @@ -475,7 +475,7 @@ where } bitcoin_wallet - .broadcast(tx_redeem.clone(), "redeem") + .ensure_broadcasted(tx_redeem.clone(), "redeem") .await .map(Some) .map_err(backoff::Error::transient) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 9e320291f9..3414b46af4 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -255,7 +255,7 @@ async fn next_state( tracing::info!(txid = %state3.tx_lock_id(), "Bitcoin lock transaction already published, skipping publish"); } else { // Publish the signed Bitcoin lock transaction - let (..) = bitcoin_wallet.broadcast(btc_lock_tx_signed, "lock").await?; + let (..) = bitcoin_wallet.ensure_broadcasted(btc_lock_tx_signed, "lock").await?; } BobState::BtcLocked { From db83f79f1c59a49c2512022f5c2c72b37e92a174 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 16 Dec 2025 14:06:28 +0100 Subject: [PATCH 054/146] add remaining_refund_timelock --- swap-core/src/bitcoin.rs | 24 ++++++------- swap-core/src/bitcoin/partial_refund.rs | 4 ++- swap-core/src/bitcoin/refund_amnesty.rs | 10 ++++-- swap-core/src/bitcoin/timelocks.rs | 46 ++++++++++++++++++++++++ swap-env/src/env.rs | 4 +++ swap-machine/src/alice/mod.rs | 17 +++++++-- swap-machine/src/bob/mod.rs | 25 +++++++++++-- swap-p2p/src/protocols/swap_setup/bob.rs | 1 + 8 files changed, 112 insertions(+), 19 deletions(-) diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 7606c752c9..08b2d5170b 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -2,42 +2,42 @@ mod cancel; mod early_refund; +mod full_refund; mod lock; +mod partial_refund; mod punish; mod redeem; -mod full_refund; -mod partial_refund; mod refund_amnesty; mod timelocks; pub use crate::bitcoin::cancel::TxCancel; pub use crate::bitcoin::early_refund::TxEarlyRefund; -pub use crate::bitcoin::partial_refund::TxPartialRefund; +pub use crate::bitcoin::full_refund::TxFullRefund; pub use crate::bitcoin::lock::TxLock; +pub use crate::bitcoin::partial_refund::TxPartialRefund; pub use crate::bitcoin::punish::TxPunish; pub use crate::bitcoin::redeem::TxRedeem; -pub use crate::bitcoin::full_refund::TxFullRefund; pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; -pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock}; +pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock, RemainingRefundTimelock}; pub use ::bitcoin::amount::Amount; pub use ::bitcoin::psbt::Psbt as PartiallySignedTransaction; pub use ::bitcoin::{Address, AddressType, Network, Transaction, Txid}; +pub use ecdsa_fun::Signature; pub use ecdsa_fun::adaptor::EncryptedSignature; pub use ecdsa_fun::fun::Scalar; -pub use ecdsa_fun::Signature; use ::bitcoin::hashes::Hash; use ::bitcoin::secp256k1::ecdsa; use ::bitcoin::sighash::SegwitV0Sighash as Sighash; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use bdk_wallet::miniscript::descriptor::Wsh; use bdk_wallet::miniscript::{Descriptor, Segwitv0}; use bitcoin_wallet::primitives::ScriptStatus; +use ecdsa_fun::ECDSA; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::fun::Point; use ecdsa_fun::nonce::Deterministic; -use ecdsa_fun::ECDSA; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sha2::Sha256; @@ -561,8 +561,8 @@ mod tests { /// subscriptions to the transaction are on index `0` when broadcasting the /// transaction. #[tokio::test] - async fn given_amounts_with_change_outputs_when_signing_tx_then_output_index_0_is_ensured_for_script( - ) { + async fn given_amounts_with_change_outputs_when_signing_tx_then_output_index_0_is_ensured_for_script() + { // This value is somewhat arbitrary but the indexation problem usually occurred // on the first or second value (i.e. 547, 548) We keep the test // iterations relatively low because these tests are expensive. @@ -704,9 +704,9 @@ TRACE swap::bitcoin::wallet: Bitcoin transaction status changed txid=00000000000 mod cached_fee_estimator_tests { use super::*; - use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; - use tokio::time::{sleep, Duration}; + use std::sync::atomic::{AtomicU32, Ordering}; + use tokio::time::{Duration, sleep}; /// Mock fee estimator that tracks how many times methods are called #[derive(Clone)] diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 954a4cdf22..67c5d6f3c2 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; use std::sync::Arc; use super::extract_ecdsa_sig; +use super::timelocks::RemainingRefundTimelock; #[derive(Debug, Clone)] pub struct TxPartialRefund { @@ -87,6 +88,7 @@ impl TxPartialRefund { &self, refund_address: &Address, spending_fee: Amount, + remaining_refund_timelock: RemainingRefundTimelock, ) -> Transaction { use ::bitcoin::{ Sequence, TxIn, TxOut, locktime::absolute::LockTime as PackedLockTime, @@ -96,7 +98,7 @@ impl TxPartialRefund { let tx_in = TxIn { previous_output: self.amnesty_outpoint(), script_sig: Default::default(), - sequence: Sequence(0xFFFF_FFFF), + sequence: Sequence(remaining_refund_timelock.0), witness: Default::default(), }; diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/refund_amnesty.rs index 0acb6c290e..6fb130476e 100644 --- a/swap-core/src/bitcoin/refund_amnesty.rs +++ b/swap-core/src/bitcoin/refund_amnesty.rs @@ -9,6 +9,8 @@ use bitcoin_wallet::primitives::Watchable; use ecdsa_fun::Signature; use std::collections::HashMap; +use super::timelocks::RemainingRefundTimelock; + #[derive(Debug, Clone)] pub struct TxRefundAmnesty { inner: Transaction, @@ -22,9 +24,13 @@ impl TxRefundAmnesty { tx_refund: &TxPartialRefund, refund_address: &Address, spending_fee: Amount, + remaining_refund_timelock: RemainingRefundTimelock, ) -> Self { - let tx_refund_amnesty = - tx_refund.build_amnesty_spend_transaction(refund_address, spending_fee); + let tx_refund_amnesty = tx_refund.build_amnesty_spend_transaction( + refund_address, + spending_fee, + remaining_refund_timelock, + ); let digest = SighashCache::new(&tx_refund_amnesty) .p2wsh_signature_hash( diff --git a/swap-core/src/bitcoin/timelocks.rs b/swap-core/src/bitcoin/timelocks.rs index fc7b3d870d..204e565573 100644 --- a/swap-core/src/bitcoin/timelocks.rs +++ b/swap-core/src/bitcoin/timelocks.rs @@ -106,12 +106,58 @@ impl PartialEq for u32 { } } +/// How long a taker has to wait to refund the remaining Bitcoin after publishing +/// TxPartialRefund. +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(transparent)] +#[typeshare] +pub struct RemainingRefundTimelock(pub u32); + +impl From for u32 { + fn from(remainin_refund_timelock: RemainingRefundTimelock) -> Self { + remainin_refund_timelock.0 + } +} + +impl From for RemainingRefundTimelock { + fn from(number_of_blocks: u32) -> Self { + Self(number_of_blocks) + } +} + +impl RemainingRefundTimelock { + pub const fn new(number_of_blocks: u32) -> Self { + Self(number_of_blocks) + } +} + +impl Add for BlockHeight { + type Output = BlockHeight; + + fn add(self, rhs: RemainingRefundTimelock) -> Self::Output { + self + rhs.0 + } +} + +impl PartialOrd for u32 { + fn partial_cmp(&self, other: &RemainingRefundTimelock) -> Option { + self.partial_cmp(&other.0) + } +} + +impl PartialEq for u32 { + fn eq(&self, other: &RemainingRefundTimelock) -> bool { + self.eq(&other.0) + } +} + #[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] #[serde(tag = "type", content = "content")] pub enum ExpiredTimelocks { None { blocks_left: u32 }, Cancel { blocks_left: u32 }, + RemainingRefund { block_left: u32 }, Punish, } diff --git a/swap-env/src/env.rs b/swap-env/src/env.rs index 61e0bc9d7c..9014d93c1c 100644 --- a/swap-env/src/env.rs +++ b/swap-env/src/env.rs @@ -15,6 +15,7 @@ pub struct Config { pub bitcoin_avg_block_time: Duration, pub bitcoin_cancel_timelock: u32, pub bitcoin_punish_timelock: u32, + pub bitcoin_remaining_refund_timelock: u32, pub bitcoin_network: bitcoin::Network, pub monero_avg_block_time: Duration, pub monero_finality_confirmations: u64, @@ -61,6 +62,7 @@ impl GetConfig for Mainnet { bitcoin_avg_block_time: 10.std_minutes(), bitcoin_cancel_timelock: 72, bitcoin_punish_timelock: 144, + bitcoin_remaining_refund_timelock: 2, bitcoin_network: bitcoin::Network::Bitcoin, monero_avg_block_time: 2.std_minutes(), // If Alice cannot lock her Monero within this timeout, @@ -83,6 +85,7 @@ impl GetConfig for Testnet { bitcoin_avg_block_time: 10.std_minutes(), bitcoin_cancel_timelock: 12 * 3, bitcoin_punish_timelock: 24 * 3, + bitcoin_remaining_refund_timelock: 2, bitcoin_network: bitcoin::Network::Testnet, monero_avg_block_time: 2.std_minutes(), monero_lock_retry_timeout: 10.std_minutes(), @@ -103,6 +106,7 @@ impl GetConfig for Regtest { bitcoin_avg_block_time: 5.std_seconds(), bitcoin_cancel_timelock: 100, bitcoin_punish_timelock: 50, + bitcoin_remaining_refund_timelock: 5, bitcoin_network: bitcoin::Network::Regtest, monero_avg_block_time: 1.std_seconds(), monero_lock_retry_timeout: 1.std_minutes(), diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index f28e27231e..8bbd2fc00c 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -8,8 +8,9 @@ use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; use std::fmt::{self, Debug}; use std::sync::Arc; use swap_core::bitcoin::{ - CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxEarlyRefund, - TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, TxRefundAmnesty, Txid, current_epoch, + CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, + TxCancel, TxEarlyRefund, TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, TxRefundAmnesty, + Txid, current_epoch, }; use swap_core::monero; use swap_core::monero::ScalarExt; @@ -169,6 +170,7 @@ pub struct State0 { btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, tx_redeem_fee: bitcoin::Amount, @@ -213,6 +215,7 @@ impl State0 { xmr, cancel_timelock: env_config.bitcoin_cancel_timelock.into(), punish_timelock: env_config.bitcoin_punish_timelock.into(), + remaining_refund_timelock: Some(env_config.bitcoin_remaining_refund_timelock.into()), tx_redeem_fee, tx_punish_fee, } @@ -254,6 +257,7 @@ impl State0 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: msg.refund_address, redeem_address: self.redeem_address, punish_address: self.punish_address, @@ -286,6 +290,7 @@ pub struct State1 { btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -336,6 +341,7 @@ impl State1 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: self.redeem_address, punish_address: self.punish_address, @@ -364,6 +370,7 @@ pub struct State2 { btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -474,6 +481,8 @@ impl State2 { &self.refund_address, self.tx_refund_amnesty_fee .context("missing tx_refund_amnesty_fee")?, + self.remaining_refund_timelock + .context("missing remaining_refund_timelock")?, ); // Check if the provided signature by Bob is valid for the transaction @@ -496,6 +505,7 @@ impl State2 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: self.redeem_address, punish_address: self.punish_address, @@ -528,6 +538,7 @@ pub struct State3 { pub btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, #[serde(with = "swap_serde::bitcoin::address_serde")] refund_address: bitcoin::Address, #[serde(with = "swap_serde::bitcoin::address_serde")] @@ -728,6 +739,8 @@ impl State3 { &self.refund_address, self.tx_refund_amnesty_fee .context("Missing tx_refund_amnesty_fee")?, + self.remaining_refund_timelock + .context("Missing remaining_refund_timelock")?, ); tx_amnesty.complete_as_alice( diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index f48147afcf..4ab0a4e6cb 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -14,8 +14,8 @@ use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ - self, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel, TxLock, - TxPartialRefund, TxRefundAmnesty, Txid, current_epoch, + self, CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, + TxCancel, TxLock, TxPartialRefund, TxRefundAmnesty, Txid, current_epoch, }; use swap_core::monero::ScalarExt; use swap_core::monero::primitives::WatchRequest; @@ -217,6 +217,7 @@ pub struct State0 { xmr: monero::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: Option, @@ -235,6 +236,7 @@ impl State0 { xmr: monero::Amount, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: RemainingRefundTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, @@ -264,6 +266,7 @@ impl State0 { dleq_proof_s_b, cancel_timelock, punish_timelock, + remaining_refund_timelock: Some(remaining_refund_timelock), refund_address, min_monero_confirmations, tx_partial_refund_fee: Some(tx_partial_refund_fee), @@ -336,6 +339,7 @@ impl State0 { btc_amnesty_amount: Some(msg.amnesty_amount), cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: msg.redeem_address, punish_address: msg.punish_address, @@ -364,6 +368,7 @@ pub struct State1 { btc_amnesty_amount: Option, cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -431,6 +436,8 @@ impl State1 { &self.refund_address, self.tx_refund_amnesty_fee .context("tx_refund_amnesty_fee missing but required to setup swap")?, + self.remaining_refund_timelock + .context("remaining_refund_timelock missing but required to setup swap")?, ); bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig)?; } @@ -450,6 +457,7 @@ impl State1 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: self.redeem_address, punish_address: self.punish_address, @@ -481,6 +489,7 @@ pub struct State2 { pub btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, #[serde(with = "address_serde")] pub refund_address: bitcoin::Address, #[serde(with = "address_serde")] @@ -548,6 +557,8 @@ impl State2 { &self.refund_address, self.tx_refund_amnesty_fee .context("Missing tx_refund_amnesty_fee")?, + self.remaining_refund_timelock + .context("missing remaining_refund_timelock")?, ); let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); @@ -572,6 +583,7 @@ impl State2 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: self.redeem_address, tx_lock: self.tx_lock.clone(), @@ -603,6 +615,7 @@ pub struct State3 { btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, #[serde(with = "address_serde")] refund_address: bitcoin::Address, #[serde(with = "address_serde")] @@ -661,6 +674,7 @@ impl State3 { btc_amnesty_amount: self.btc_amnesty_amount, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, redeem_address: self.redeem_address, tx_lock: self.tx_lock, @@ -686,6 +700,7 @@ impl State3 { monero_wallet_restore_blockheight, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address.clone(), tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), @@ -757,6 +772,7 @@ pub struct State4 { btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, #[serde(with = "address_serde")] refund_address: bitcoin::Address, #[serde(with = "address_serde")] @@ -872,6 +888,7 @@ impl State4 { monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, cancel_timelock: self.cancel_timelock, punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, refund_address: self.refund_address, tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, @@ -948,6 +965,7 @@ pub struct State6 { pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, #[serde(with = "address_serde")] refund_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, @@ -1151,6 +1169,9 @@ impl State6 { self.tx_refund_amnesty_fee.context( "Can't construct TxRefundAmnesty because tx_refund_amnesty_fee is missing", )?, + self.remaining_refund_timelock.context( + "Can't construct TxRefundAmnesty because remaining_refund_timelock is missing", + )?, )) } diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index d5cc2558d0..e35b27fe3a 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -573,6 +573,7 @@ async fn run_swap_setup( xmr, env_config.bitcoin_cancel_timelock.into(), env_config.bitcoin_punish_timelock.into(), + env_config.bitcoin_remaining_refund_timelock.into(), new_swap_request.bitcoin_refund_address.clone(), env_config.monero_finality_confirmations, new_swap_request.tx_partial_refund_fee, From 0d2cfe6db238dc5d5626f6937dfd9b191879647e Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 11:38:53 +0100 Subject: [PATCH 055/146] add RemainingRefundTimelock to ExpiredTimelocks --- swap-core/src/bitcoin.rs | 19 +++++++++++- swap-core/src/bitcoin/timelocks.rs | 48 +++++++++++++++++++++++++++++- swap-machine/src/alice/mod.rs | 11 +++++++ swap-machine/src/bob/mod.rs | 47 +++++++++++++++++++++++++++++ swap/src/cli/cancel_and_refund.rs | 23 ++++++++++++++ swap/src/cli/watcher.rs | 2 +- swap/src/protocol/bob/swap.rs | 16 ++++++++++ 7 files changed, 163 insertions(+), 3 deletions(-) diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 08b2d5170b..007f04566d 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -20,6 +20,7 @@ pub use crate::bitcoin::redeem::TxRedeem; pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock, RemainingRefundTimelock}; +pub use bitcoin_wallet::ScriptStatus; pub use ::bitcoin::amount::Amount; pub use ::bitcoin::psbt::Psbt as PartiallySignedTransaction; pub use ::bitcoin::{Address, AddressType, Network, Transaction, Txid}; @@ -33,7 +34,6 @@ use ::bitcoin::sighash::SegwitV0Sighash as Sighash; use anyhow::{Context, Result, bail}; use bdk_wallet::miniscript::descriptor::Wsh; use bdk_wallet::miniscript::{Descriptor, Segwitv0}; -use bitcoin_wallet::primitives::ScriptStatus; use ecdsa_fun::ECDSA; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::fun::Point; @@ -246,13 +246,30 @@ pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Resu pub fn current_epoch( cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, + remaining_refund_timelock: Option, tx_lock_status: ScriptStatus, tx_cancel_status: ScriptStatus, + tx_partial_refund_status: Option, ) -> ExpiredTimelocks { if tx_cancel_status.is_confirmed_with(punish_timelock) { return ExpiredTimelocks::Punish; } + // Check if TxPartialRefund is confirmed and handle remaining refund timelock + // For old swaps, these will be None and we skip the partial refund checks + if let (Some(remaining_refund_timelock), Some(tx_partial_refund_status)) = + (remaining_refund_timelock, tx_partial_refund_status) + { + if tx_partial_refund_status.is_confirmed_with(remaining_refund_timelock) { + return ExpiredTimelocks::RemainingRefund; + } + if tx_partial_refund_status.is_confirmed() { + return ExpiredTimelocks::WaitingForRemainingRefund { + blocks_left: tx_partial_refund_status.blocks_left_until(remaining_refund_timelock), + }; + } + } + if tx_lock_status.is_confirmed_with(cancel_timelock) { return ExpiredTimelocks::Cancel { blocks_left: tx_cancel_status.blocks_left_until(punish_timelock), diff --git a/swap-core/src/bitcoin/timelocks.rs b/swap-core/src/bitcoin/timelocks.rs index 204e565573..2b8d777916 100644 --- a/swap-core/src/bitcoin/timelocks.rs +++ b/swap-core/src/bitcoin/timelocks.rs @@ -157,7 +157,8 @@ impl PartialEq for u32 { pub enum ExpiredTimelocks { None { blocks_left: u32 }, Cancel { blocks_left: u32 }, - RemainingRefund { block_left: u32 }, + WaitingForRemainingRefund { blocks_left: u32 }, + RemainingRefund, Punish, } @@ -188,8 +189,10 @@ mod tests { let expired_timelock = current_epoch( CancelTimelock::new(5), PunishTimelock::new(5), + None, tx_lock_status, tx_cancel_status, + None, ); assert!(matches!(expired_timelock, ExpiredTimelocks::None { .. })); @@ -203,8 +206,10 @@ mod tests { let expired_timelock = current_epoch( CancelTimelock::new(5), PunishTimelock::new(5), + None, tx_lock_status, tx_cancel_status, + None, ); assert!(matches!(expired_timelock, ExpiredTimelocks::Cancel { .. })); @@ -218,13 +223,54 @@ mod tests { let expired_timelock = current_epoch( CancelTimelock::new(5), PunishTimelock::new(5), + None, tx_lock_status, tx_cancel_status, + None, ); assert_eq!(expired_timelock, ExpiredTimelocks::Punish) } + #[test] + fn partial_refund_confirmed_waiting_for_remaining_refund_timelock() { + let tx_lock_status = ScriptStatus::from_confirmations(10); + let tx_cancel_status = ScriptStatus::from_confirmations(5); + let tx_partial_refund_status = ScriptStatus::from_confirmations(2); + + let expired_timelock = current_epoch( + CancelTimelock::new(5), + PunishTimelock::new(10), + Some(RemainingRefundTimelock::new(5)), + tx_lock_status, + tx_cancel_status, + Some(tx_partial_refund_status), + ); + + assert!(matches!( + expired_timelock, + ExpiredTimelocks::WaitingForRemainingRefund { .. } + )); + } + + #[test] + fn partial_refund_remaining_timelock_expired() { + let tx_lock_status = ScriptStatus::from_confirmations(10); + let tx_cancel_status = ScriptStatus::from_confirmations(5); + let tx_partial_refund_status = ScriptStatus::from_confirmations(5); + + let expired_timelock = current_epoch( + CancelTimelock::new(5), + PunishTimelock::new(10), + Some(RemainingRefundTimelock::new(5)), + tx_lock_status, + tx_cancel_status, + Some(tx_partial_refund_status), + ); + + assert_eq!(expired_timelock, ExpiredTimelocks::RemainingRefund); + } + #[test] fn tx_early_refund_has_correct_weight() { // TxEarlyRefund should have the same weight as other similar transactions diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 8bbd2fc00c..d9142e8ce8 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -582,12 +582,23 @@ impl State3 { let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; + // Only check partial refund status if we have the data to construct it + // (old swaps won't have these fields) + let tx_partial_refund_status = + if let (Some(_), Some(_)) = (self.btc_amnesty_amount, self.tx_partial_refund_fee) { + let tx = self.tx_partial_refund()?; + Some(bitcoin_wallet.status_of_script(&tx).await?) + } else { + None + }; Ok(current_epoch( self.cancel_timelock, self.punish_timelock, + self.remaining_refund_timelock, tx_lock_status, tx_cancel_status, + tx_partial_refund_status, )) } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 4ab0a4e6cb..6db55cb0b5 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -733,12 +733,30 @@ impl State3 { let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; + let tx_partial_refund_status = + if let (Some(btc_amnesty_amount), Some(tx_partial_refund_fee)) = + (self.btc_amnesty_amount, self.tx_partial_refund_fee) + { + let tx = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + btc_amnesty_amount, + tx_partial_refund_fee, + )?; + Some(bitcoin_wallet.status_of_script(&tx).await?) + } else { + None + }; Ok(current_epoch( self.cancel_timelock, self.punish_timelock, + self.remaining_refund_timelock, tx_lock_status, tx_cancel_status, + tx_partial_refund_status, )) } @@ -870,12 +888,30 @@ impl State4 { let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; + let tx_partial_refund_status = + if let (Some(btc_amnesty_amount), Some(tx_partial_refund_fee)) = + (self.btc_amnesty_amount, self.tx_partial_refund_fee) + { + let tx = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + btc_amnesty_amount, + tx_partial_refund_fee, + )?; + Some(bitcoin_wallet.status_of_script(&tx).await?) + } else { + None + }; Ok(current_epoch( self.cancel_timelock, self.punish_timelock, + self.remaining_refund_timelock, tx_lock_status, tx_cancel_status, + tx_partial_refund_status, )) } @@ -999,12 +1035,23 @@ impl State6 { let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?; let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?; + // Only check partial refund status if we have the data to construct it + // (old swaps won't have these fields) + let tx_partial_refund_status = + if let (Some(_), Some(_)) = (self.btc_amnesty_amount, self.tx_partial_refund_fee) { + let tx = self.construct_tx_partial_refund()?; + Some(bitcoin_wallet.status_of_script(&tx).await?) + } else { + None + }; Ok(current_epoch( self.cancel_timelock, self.punish_timelock, + self.remaining_refund_timelock, tx_lock_status, tx_cancel_status, + tx_partial_refund_status, )) } diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 15f84eaaee..530ea8d282 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -136,6 +136,17 @@ pub async fn cancel( Ok(ExpiredTimelocks::Cancel { .. }) => { bail!(err.context("Failed to cancel swap even though cancel timelock has expired. This is unexpected.")); } + Ok(ExpiredTimelocks::WaitingForRemainingRefund { blocks_left }) => { + bail!(err.context( + format!( + "Cannot cancel swap because partial refund is already in progress. Waiting {} blocks for amnesty timelock.", + blocks_left + ) + )); + } + Ok(ExpiredTimelocks::RemainingRefund) => { + bail!(err.context("Cannot cancel swap because we are in the partial refund phase. TxRefundAmnesty can be published.")); + } Err(timelock_err) => { bail!(err .context(timelock_err) @@ -243,6 +254,18 @@ pub async fn refund( Ok(ExpiredTimelocks::Cancel { .. }) => { bail!(bitcoin_publication_err.context("Failed to refund swap even though cancel timelock has expired. This is unexpected.")); } + Ok(ExpiredTimelocks::WaitingForRemainingRefund { blocks_left }) => { + bail!( + bitcoin_publication_err.context(format!( + "Cannot refund swap yet. Partial refund was published but waiting {} blocks for amnesty timelock to expire.", + blocks_left + )) + ); + } + Ok(ExpiredTimelocks::RemainingRefund) => { + // TODO: Try to publish TxRefundAmnesty here instead of just reporting the state + bail!(bitcoin_publication_err.context("Amnesty timelock has expired. TxRefundAmnesty can be published.")); + } Err(e) => { bail!(bitcoin_publication_err .context(e) diff --git a/swap/src/cli/watcher.rs b/swap/src/cli/watcher.rs index 299f30b2f4..7dc542f3b4 100644 --- a/swap/src/cli/watcher.rs +++ b/swap/src/cli/watcher.rs @@ -107,7 +107,7 @@ impl Watcher { self.cached_timelocks.insert(swap_id, new_timelock_status); // If the swap has to be refunded, do it in the background - if let Some(ExpiredTimelocks::Cancel { .. }) = new_timelock_status { + if matches!(new_timelock_status, Some(ExpiredTimelocks::Cancel { .. }) | Some(ExpiredTimelocks::RemainingRefund)) { // If the swap is already refunded, we can skip the refund if matches!(state, BobState::BtcRefunded(_)) { continue; diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 3414b46af4..dcf1293755 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -822,6 +822,22 @@ async fn next_state( state, }) } + ExpiredTimelocks::WaitingForRemainingRefund { blocks_left } => { + // TxPartialRefund has been published, waiting for remaining_refund_timelock + // This is unusual from BtcCancelled state - means we published partial refund but crashed + // Retry until timelock expires + tracing::debug!("Partial refund published, waiting {} blocks for amnesty timelock", blocks_left); + Err(backoff::Error::transient(anyhow::anyhow!( + "Waiting for remaining refund timelock to expire. Blocks left: {}", + blocks_left + ))) + } + ExpiredTimelocks::RemainingRefund => { + // TxPartialRefund was published and timelock expired - publish TxRefundAmnesty + // Transition to BtcPartiallyRefunded which handles amnesty publication + tracing::info!("Remaining refund timelock expired, can publish amnesty transaction"); + Ok(BobState::BtcPartiallyRefunded(state)) + } } } }, From 9de25bc236b8686647620fd772f3e655ca141427 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 12:39:37 +0100 Subject: [PATCH 056/146] fix warnings --- bitcoin-wallet/src/wallet.rs | 4 +--- monero-tests/src/lib.rs | 8 ++++++++ swap-env/src/config.rs | 2 +- swap-env/src/defaults.rs | 1 - swap-orchestrator/src/lib.rs | 6 ++++++ swap-orchestrator/src/main.rs | 2 ++ swap-p2p/src/observe.rs | 2 +- swap-p2p/src/protocols/swap_setup/bob.rs | 2 -- swap/src/asb/event_loop.rs | 4 ++-- swap/src/cli/api/tauri_bindings.rs | 2 +- swap/src/cli/command.rs | 1 - swap/src/common/tracing_util.rs | 2 +- swap/src/protocol/alice/swap.rs | 3 +-- swap/src/protocol/bob/swap.rs | 2 +- 14 files changed, 25 insertions(+), 16 deletions(-) diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index 43b675cc82..72aa6a37ed 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -13,8 +13,6 @@ use bdk_wallet::template::{Bip84, DescriptorTemplate}; use bdk_wallet::KeychainKind; use bdk_wallet::WalletPersister; use bdk_wallet::{Balance, PersistedWallet}; -#[allow(deprecated)] -use bitcoin::bip32::ExtendedPrivKey; use bitcoin::bip32::Xpriv; use bitcoin::{psbt::Psbt as PartiallySignedTransaction, Address, Amount, Transaction, Txid}; use bitcoin::{Psbt, ScriptBuf, Weight}; @@ -69,7 +67,7 @@ pub trait BitcoinTauriBackgroundTask: Send + Sync { } pub trait BitcoinWalletSeed { - fn derive_extended_private_key(&self, network: bitcoin::Network) -> Result; + fn derive_extended_private_key(&self, network: bitcoin::Network) -> Result; /// Same as `derive_extended_private_key`, but using the legacy BDK API. /// diff --git a/monero-tests/src/lib.rs b/monero-tests/src/lib.rs index 2235e70956..2807718fee 100644 --- a/monero-tests/src/lib.rs +++ b/monero-tests/src/lib.rs @@ -1 +1,9 @@ // Empty but necessary for cargo +use anyhow as _; +use monero as _; +use monero_harness as _; +use monero_sys as _; +use testcontainers as _; +use tokio as _; +use tracing as _; +use tracing_subscriber as _; diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index b1696fcd8e..8a26691342 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -8,7 +8,7 @@ use anyhow::{Context, Result, bail}; use config::ConfigError; use libp2p::core::Multiaddr; use rust_decimal::Decimal; -use serde::{Deserialize, Serialize, de}; +use serde::{Deserialize, Serialize}; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; diff --git a/swap-env/src/defaults.rs b/swap-env/src/defaults.rs index 5effa77619..28f412efaa 100644 --- a/swap-env/src/defaults.rs +++ b/swap-env/src/defaults.rs @@ -3,7 +3,6 @@ use crate::env::{Mainnet, Testnet}; use anyhow::{Context, Result}; use libp2p::Multiaddr; use rust_decimal::Decimal; -use std::cell::Ref; use std::path::{Path, PathBuf}; use std::str::FromStr; use swap_fs::{system_config_dir, system_data_dir}; diff --git a/swap-orchestrator/src/lib.rs b/swap-orchestrator/src/lib.rs index 8b20132996..719099c42a 100644 --- a/swap-orchestrator/src/lib.rs +++ b/swap-orchestrator/src/lib.rs @@ -1,3 +1,9 @@ pub mod compose; pub mod containers; pub mod images; + +use anyhow as _; +use dialoguer as _; +use swap_env as _; +use toml as _; +use url as _; diff --git a/swap-orchestrator/src/main.rs b/swap-orchestrator/src/main.rs index 8e4f27715c..230e019998 100644 --- a/swap-orchestrator/src/main.rs +++ b/swap-orchestrator/src/main.rs @@ -3,6 +3,8 @@ mod containers; mod images; mod prompt; +use swap_orchestrator as _; + use crate::compose::{ ASB_DATA_DIR, DOCKER_COMPOSE_FILE, IntoSpec, OrchestratorDirectories, OrchestratorImage, OrchestratorImages, OrchestratorInput, OrchestratorNetworks, diff --git a/swap-p2p/src/observe.rs b/swap-p2p/src/observe.rs index f42f55cac7..6d1c48dda7 100644 --- a/swap-p2p/src/observe.rs +++ b/swap-p2p/src/observe.rs @@ -126,7 +126,7 @@ impl NetworkBehaviour for Behaviour { fn poll( &mut self, - cx: &mut std::task::Context<'_>, + _cx: &mut std::task::Context<'_>, ) -> Poll>> { if let Some(event) = self.to_swarm.pop_front() { return Poll::Ready(ToSwarm::GenerateEvent(event)); diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index e35b27fe3a..dba374fd0c 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -6,8 +6,6 @@ use crate::protocols::swap_setup::{ use anyhow::{Context, Result}; use bitcoin_wallet::BitcoinWallet; use futures::AsyncWriteExt; -use futures::FutureExt; -use futures::future::{BoxFuture, OptionFuture}; use libp2p::core::upgrade; use libp2p::swarm::behaviour::ConnectionEstablished; use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 6e7261cae5..106d6d367d 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -6,7 +6,7 @@ use crate::asb::{Behaviour, OutEvent}; use crate::monero; use crate::network::cooperative_xmr_redeem_after_punish::CooperativeXmrRedeemRejectReason; use crate::network::cooperative_xmr_redeem_after_punish::Response::{Fullfilled, Rejected}; -use crate::network::quote::{BidQuote, ReserveProofWithAddress}; +use crate::network::quote::BidQuote; use crate::network::swap_setup::alice::WalletSnapshot; use crate::network::transfer_proof; use crate::protocol::alice::swap::has_already_processed_enc_sig; @@ -30,7 +30,7 @@ use std::io::Write; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin; -use swap_env::config::{Config, RefundPolicy}; +use swap_env::config::RefundPolicy; use swap_env::env; use swap_feed::LatestRate; use tokio::sync::{mpsc, oneshot}; diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index fa9e2451d0..e9513e4519 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -8,7 +8,7 @@ use crate::{monero, network::quote::BidQuote}; use anyhow::{anyhow, bail, Context, Result}; use async_trait::async_trait; use bitcoin::Txid; -use libp2p::{Multiaddr, PeerId}; +use libp2p::PeerId; use monero_rpc_pool::pool::PoolStatus; use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 39673c55a8..213ef06e38 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -3,7 +3,6 @@ use crate::cli::api::request::{ MoneroRecoveryArgs, Request, ResumeSwapArgs, WithdrawBtcArgs, }; use crate::cli::api::Context; -use crate::monero::{self, MoneroAddressPool}; use anyhow::Result; use bitcoin::address::NetworkUnchecked; use bitcoin_wallet::{bitcoin_address, Amount}; diff --git a/swap/src/common/tracing_util.rs b/swap/src/common/tracing_util.rs index 0f8ab69ac0..6231032f07 100644 --- a/swap/src/common/tracing_util.rs +++ b/swap/src/common/tracing_util.rs @@ -1,4 +1,4 @@ -use std::io::{self, IsTerminal}; +use std::io; use std::path::Path; use std::str::FromStr; diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 16483a720e..ca5acc6124 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -1,6 +1,5 @@ //! Run an XMR/BTC swap in the role of Alice. //! Alice holds XMR and wishes receive BTC. -use std::any::Any; use std::sync::Arc; use std::time::Duration; @@ -680,7 +679,7 @@ where } } AliceState::XmrRefundable { - monero_wallet_restore_blockheight, + monero_wallet_restore_blockheight: _, transfer_proof, spend_key, state3, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index dcf1293755..1371be45fd 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -8,7 +8,7 @@ use crate::network::cooperative_xmr_redeem_after_punish::Response::{Fullfilled, use crate::network::swap_setup::bob::NewSwap; use crate::protocol::bob::*; use crate::protocol::{bob, Database}; -use anyhow::{Context as AnyContext, Result, anyhow, bail}; +use anyhow::{Context as AnyContext, Result, anyhow}; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin::{ From 8c972914a0465d3dacd8b26b19f0dd98adf2671a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 12:55:23 +0100 Subject: [PATCH 057/146] add TxRefundBurn (see comment on #675 for explanation) --- swap-core/src/bitcoin.rs | 2 + swap-core/src/bitcoin/partial_refund.rs | 41 +++++ swap-core/src/bitcoin/refund_burn.rs | 205 ++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 swap-core/src/bitcoin/refund_burn.rs diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 007f04566d..8c95e72f37 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -8,6 +8,7 @@ mod partial_refund; mod punish; mod redeem; mod refund_amnesty; +mod refund_burn; mod timelocks; pub use crate::bitcoin::cancel::TxCancel; @@ -18,6 +19,7 @@ pub use crate::bitcoin::partial_refund::TxPartialRefund; pub use crate::bitcoin::punish::TxPunish; pub use crate::bitcoin::redeem::TxRedeem; pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; +pub use crate::bitcoin::refund_burn::TxRefundBurn; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock, RemainingRefundTimelock}; pub use bitcoin_wallet::ScriptStatus; diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 67c5d6f3c2..80ffe2806c 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -115,6 +115,47 @@ impl TxPartialRefund { } } + /// Build a transaction that spends the amnesty output to a new 2-of-2 multisig (burn output). + /// This is used by TxRefundBurn to "burn" the amnesty by moving it to another multisig. + /// Unlike `build_amnesty_spend_transaction`, this has no timelock. + pub fn build_burn_spend_transaction( + &self, + burn_output_descriptor: &Descriptor<::bitcoin::PublicKey>, + spending_fee: Amount, + ) -> Transaction { + use ::bitcoin::{ + Sequence, TxIn, TxOut, locktime::absolute::LockTime as PackedLockTime, + transaction::Version, + }; + + // TODO: Handle case where fee >= amnesty_amount more gracefully + assert!( + self.amnesty_amount() > spending_fee, + "Burn spend fee ({}) must be less than amnesty amount ({})", + spending_fee, + self.amnesty_amount() + ); + + let tx_in = TxIn { + previous_output: self.amnesty_outpoint(), + script_sig: Default::default(), + sequence: Sequence(0xFFFF_FFFF), // No timelock + witness: Default::default(), + }; + + let tx_out = TxOut { + value: self.amnesty_amount() - spending_fee, + script_pubkey: burn_output_descriptor.script_pubkey(), + }; + + Transaction { + version: Version(2), + lock_time: PackedLockTime::from_height(0).expect("0 to be below lock time threshold"), + input: vec![tx_in], + output: vec![tx_out], + } + } + pub fn add_signatures( self, (A, sig_a): (PublicKey, Signature), diff --git a/swap-core/src/bitcoin/refund_burn.rs b/swap-core/src/bitcoin/refund_burn.rs new file mode 100644 index 0000000000..844dbb0434 --- /dev/null +++ b/swap-core/src/bitcoin/refund_burn.rs @@ -0,0 +1,205 @@ +#![allow(non_snake_case)] + +use crate::bitcoin::partial_refund::TxPartialRefund; +use crate::bitcoin::{self, build_shared_output_descriptor, Address, Amount, PublicKey, Transaction}; +use ::bitcoin::sighash::SighashCache; +use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; +use ::bitcoin::{OutPoint, ScriptBuf, Weight, secp256k1}; +use anyhow::{Context, Result}; +use bdk_wallet::miniscript::Descriptor; +use bitcoin_wallet::primitives::Watchable; +use ecdsa_fun::Signature; +use std::collections::HashMap; + +/// TxRefundBurn spends the amnesty output of TxPartialRefund and sends it to +/// a new 2-of-2 multisig. This allows Alice to "burn" the amnesty (prevent Bob +/// from claiming it via TxRefundAmnesty) while still allowing a later refund +/// via TxFinalAmnesty if Alice cooperates. +/// +/// Unlike TxRefundAmnesty, this transaction has no timelock - Alice can publish +/// it immediately after TxPartialRefund is confirmed. +#[derive(Debug, Clone)] +pub struct TxRefundBurn { + inner: Transaction, + digest: Sighash, + amnesty_output_descriptor: Descriptor<::bitcoin::PublicKey>, + pub(in crate::bitcoin) burn_output_descriptor: Descriptor<::bitcoin::PublicKey>, + watch_script: ScriptBuf, +} + +impl TxRefundBurn { + pub fn new( + tx_partial_refund: &TxPartialRefund, + A: PublicKey, + B: PublicKey, + spending_fee: Amount, + ) -> Result { + // TODO: Handle case where fee >= amnesty_amount more gracefully + // For now, assert to catch this during development + assert!( + tx_partial_refund.amnesty_amount() > spending_fee, + "TxRefundBurn fee ({}) must be less than amnesty amount ({})", + spending_fee, + tx_partial_refund.amnesty_amount() + ); + + let burn_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; + + let tx_refund_burn = tx_partial_refund.build_burn_spend_transaction( + &burn_output_descriptor, + spending_fee, + ); + + let digest = SighashCache::new(&tx_refund_burn) + .p2wsh_signature_hash( + 0, // Only one input: amnesty output from tx_partial_refund + &tx_partial_refund + .amnesty_output_descriptor + .script_code() + .expect("scriptcode"), + tx_partial_refund.amnesty_amount(), + EcdsaSighashType::All, + ) + .expect("sighash"); + + let watch_script = burn_output_descriptor.script_pubkey(); + + Ok(Self { + inner: tx_refund_burn, + digest, + amnesty_output_descriptor: tx_partial_refund.amnesty_output_descriptor.clone(), + burn_output_descriptor, + watch_script, + }) + } + + pub fn txid(&self) -> Txid { + self.inner.compute_txid() + } + + pub fn digest(&self) -> Sighash { + self.digest + } + + pub fn amount(&self) -> Amount { + self.inner.output[0].value + } + + pub fn as_outpoint(&self) -> OutPoint { + OutPoint::new(self.txid(), 0) + } + + pub fn complete_as_alice( + &self, + a: bitcoin::SecretKey, + B: bitcoin::PublicKey, + sig_b: Signature, + ) -> Result { + let sig_a = a.sign(self.digest()); + + self.clone() + .add_signatures((a.public(), sig_a), (B, sig_b)) + .context("Couldn't add signatures to transaction") + } + + pub fn add_signatures( + self, + (A, sig_a): (PublicKey, Signature), + (B, sig_b): (PublicKey, Signature), + ) -> Result { + let satisfier = { + let mut satisfier = HashMap::with_capacity(2); + + let A = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, + }; + let B = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, + }; + + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; + + // The order in which these are inserted doesn't matter + satisfier.insert( + A, + ::bitcoin::ecdsa::Signature { + signature: sig_a, + sighash_type: EcdsaSighashType::All, + }, + ); + satisfier.insert( + B, + ::bitcoin::ecdsa::Signature { + signature: sig_b, + sighash_type: EcdsaSighashType::All, + }, + ); + + satisfier + }; + + let mut tx = self.inner; + self.amnesty_output_descriptor + .satisfy(&mut tx.input[0], satisfier)?; + + Ok(tx) + } + + /// Build a transaction that spends the burn output to a destination address. + /// Used by TxFinalAmnesty to send the funds back to Bob's refund address. + pub fn build_spend_transaction( + &self, + destination: &Address, + spending_fee: Amount, + ) -> Transaction { + use ::bitcoin::{ + Sequence, TxIn, TxOut, locktime::absolute::LockTime as PackedLockTime, + transaction::Version, + }; + + // TODO: Handle case where fee >= burn amount more gracefully + // For now, assert to catch this during development + assert!( + self.amount() > spending_fee, + "TxFinalAmnesty fee ({}) must be less than burn amount ({})", + spending_fee, + self.amount() + ); + + let tx_in = TxIn { + previous_output: self.as_outpoint(), + script_sig: Default::default(), + sequence: Sequence(0xFFFF_FFFF), // No timelock + witness: Default::default(), + }; + + let tx_out = TxOut { + value: self.amount() - spending_fee, + script_pubkey: destination.script_pubkey(), + }; + + Transaction { + version: Version(2), + lock_time: PackedLockTime::from_height(0).expect("0 to be below lock time threshold"), + input: vec![tx_in], + output: vec![tx_out], + } + } + + pub fn weight() -> Weight { + Weight::from_wu(548) + } +} + +impl Watchable for TxRefundBurn { + fn id(&self) -> Txid { + self.txid() + } + + fn script(&self) -> ScriptBuf { + self.watch_script.clone() + } +} From 95f86a0513b6d296f106d1145a07dd559b5f3c8f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 13:32:53 +0100 Subject: [PATCH 058/146] add TxFinalAmnesty --- swap-core/src/bitcoin.rs | 2 + swap-core/src/bitcoin/final_amnesty.rs | 148 +++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 swap-core/src/bitcoin/final_amnesty.rs diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 8c95e72f37..2940d11fe7 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -2,6 +2,7 @@ mod cancel; mod early_refund; +mod final_amnesty; mod full_refund; mod lock; mod partial_refund; @@ -13,6 +14,7 @@ mod timelocks; pub use crate::bitcoin::cancel::TxCancel; pub use crate::bitcoin::early_refund::TxEarlyRefund; +pub use crate::bitcoin::final_amnesty::TxFinalAmnesty; pub use crate::bitcoin::full_refund::TxFullRefund; pub use crate::bitcoin::lock::TxLock; pub use crate::bitcoin::partial_refund::TxPartialRefund; diff --git a/swap-core/src/bitcoin/final_amnesty.rs b/swap-core/src/bitcoin/final_amnesty.rs new file mode 100644 index 0000000000..dc6f3e1734 --- /dev/null +++ b/swap-core/src/bitcoin/final_amnesty.rs @@ -0,0 +1,148 @@ +#![allow(non_snake_case)] + +use crate::bitcoin::refund_burn::TxRefundBurn; +use crate::bitcoin::{self, Address, Amount, PublicKey, Transaction}; +use ::bitcoin::sighash::SighashCache; +use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; +use ::bitcoin::{ScriptBuf, Weight, secp256k1}; +use anyhow::{Context, Result}; +use bdk_wallet::miniscript::Descriptor; +use bitcoin_wallet::primitives::Watchable; +use ecdsa_fun::Signature; +use std::collections::HashMap; + +/// TxFinalAmnesty spends the burn output of TxRefundBurn and sends it to +/// Bob's refund address. This allows Alice to voluntarily refund Bob even +/// after she has "burnt" the amnesty output. +/// +/// This transaction is presigned by Bob during swap setup, but Alice keeps +/// her signature private until she decides to cooperate (e.g., if Bob contacts +/// her to request the refund). +#[derive(Debug, Clone)] +pub struct TxFinalAmnesty { + inner: Transaction, + digest: Sighash, + burn_output_descriptor: Descriptor<::bitcoin::PublicKey>, + watch_script: ScriptBuf, +} + +impl TxFinalAmnesty { + pub fn new( + tx_refund_burn: &TxRefundBurn, + refund_address: &Address, + spending_fee: Amount, + ) -> Self { + // TODO: Handle case where fee >= burn amount more gracefully + assert!( + tx_refund_burn.amount() > spending_fee, + "TxFinalAmnesty fee ({}) must be less than burn amount ({})", + spending_fee, + tx_refund_burn.amount() + ); + + let tx_final_amnesty = tx_refund_burn.build_spend_transaction( + refund_address, + spending_fee, + ); + + let digest = SighashCache::new(&tx_final_amnesty) + .p2wsh_signature_hash( + 0, // Only one input: burn output from tx_refund_burn + &tx_refund_burn + .burn_output_descriptor + .script_code() + .expect("scriptcode"), + tx_refund_burn.amount(), + EcdsaSighashType::All, + ) + .expect("sighash"); + + Self { + inner: tx_final_amnesty, + digest, + burn_output_descriptor: tx_refund_burn.burn_output_descriptor.clone(), + watch_script: refund_address.script_pubkey(), + } + } + + pub fn txid(&self) -> Txid { + self.inner.compute_txid() + } + + pub fn digest(&self) -> Sighash { + self.digest + } + + pub fn complete_as_alice( + &self, + a: bitcoin::SecretKey, + B: bitcoin::PublicKey, + sig_b: Signature, + ) -> Result { + let sig_a = a.sign(self.digest()); + + self.clone() + .add_signatures((a.public(), sig_a), (B, sig_b)) + .context("Couldn't add signatures to transaction") + } + + pub fn add_signatures( + self, + (A, sig_a): (PublicKey, Signature), + (B, sig_b): (PublicKey, Signature), + ) -> Result { + let satisfier = { + let mut satisfier = HashMap::with_capacity(2); + + let A = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&A.0.to_bytes())?, + }; + let B = ::bitcoin::PublicKey { + compressed: true, + inner: secp256k1::PublicKey::from_slice(&B.0.to_bytes())?, + }; + + let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?; + let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?; + + // The order in which these are inserted doesn't matter + satisfier.insert( + A, + ::bitcoin::ecdsa::Signature { + signature: sig_a, + sighash_type: EcdsaSighashType::All, + }, + ); + satisfier.insert( + B, + ::bitcoin::ecdsa::Signature { + signature: sig_b, + sighash_type: EcdsaSighashType::All, + }, + ); + + satisfier + }; + + let mut tx = self.inner; + self.burn_output_descriptor + .satisfy(&mut tx.input[0], satisfier)?; + + Ok(tx) + } + + pub fn weight() -> Weight { + Weight::from_wu(548) + } +} + +impl Watchable for TxFinalAmnesty { + fn id(&self) -> Txid { + self.txid() + } + + fn script(&self) -> ScriptBuf { + self.watch_script.clone() + } +} From d39305690b470a855b0b5fb0a0d7a62597f3b715 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 13:34:12 +0100 Subject: [PATCH 059/146] state-machine(bob): add new states (WaitingForRemainingRefundTimelockExpiration, RemainingRefundTimelockExpired, BtcRefundBurnPublished, BtcRefundBurnt, BtcFinalAmnestyPublished, BtcFinalAmnstyReceived) --- swap-db/src/bob.rs | 39 +++++++++++++++++++++++++++++++ swap-machine/src/bob/mod.rs | 36 +++++++++++++++++++++++++++- swap/src/cli/cancel_and_refund.rs | 12 ++++++++++ swap/src/protocol/bob/swap.rs | 34 ++++++++++++++++++++++++++- 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 71cfac23ca..66ff5f1038 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -47,6 +47,11 @@ pub enum Bob { BtcPartialRefundPublished(bob::State6), BtcPartiallyRefunded(bob::State6), BtcAmnestyPublished(bob::State6), + WaitingForRemainingRefundTimelockExpiration(bob::State6), + RemainingRefundTimelockExpired(bob::State6), + BtcRefundBurnPublished(bob::State6), + BtcRefundBurnt(bob::State6), + BtcFinalAmnestyPublished(bob::State6), Done(BobEndState), } @@ -57,6 +62,7 @@ pub enum BobEndState { BtcRefunded(Box), BtcEarlyRefunded(Box), BtcAmnestyConfirmed(Box), + BtcFinalAmnestyConfirmed(Box), } impl From for Bob { @@ -118,6 +124,18 @@ impl From for Bob { BobState::BtcAmnestyConfirmed(state6) => { Bob::Done(BobEndState::BtcAmnestyConfirmed(Box::new(state6))) } + BobState::WaitingForRemainingRefundTimelockExpiration(state6) => { + Bob::WaitingForRemainingRefundTimelockExpiration(state6) + } + BobState::RemainingRefundTimelockExpired(state6) => { + Bob::RemainingRefundTimelockExpired(state6) + } + BobState::BtcRefundBurnPublished(state6) => Bob::BtcRefundBurnPublished(state6), + BobState::BtcRefundBurnt(state6) => Bob::BtcRefundBurnt(state6), + BobState::BtcFinalAmnestyPublished(state6) => Bob::BtcFinalAmnestyPublished(state6), + BobState::BtcFinalAmnestyConfirmed(state6) => { + Bob::Done(BobEndState::BtcFinalAmnestyConfirmed(Box::new(state6))) + } BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted), } } @@ -172,12 +190,24 @@ impl From for BobState { Bob::BtcAmnestyPublished(state6) => BobState::BtcAmnestyPublished(state6), Bob::BtcEarlyRefundPublished(state6) => BobState::BtcEarlyRefundPublished(state6), Bob::BtcPunished { state, tx_lock_id } => BobState::BtcPunished { state, tx_lock_id }, + Bob::WaitingForRemainingRefundTimelockExpiration(state6) => { + BobState::WaitingForRemainingRefundTimelockExpiration(state6) + } + Bob::RemainingRefundTimelockExpired(state6) => { + BobState::RemainingRefundTimelockExpired(state6) + } + Bob::BtcRefundBurnPublished(state6) => BobState::BtcRefundBurnPublished(state6), + Bob::BtcRefundBurnt(state6) => BobState::BtcRefundBurnt(state6), + Bob::BtcFinalAmnestyPublished(state6) => BobState::BtcFinalAmnestyPublished(state6), Bob::Done(end_state) => match end_state { BobEndState::SafelyAborted => BobState::SafelyAborted, BobEndState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id }, BobEndState::BtcRefunded(state6) => BobState::BtcRefunded(*state6), BobEndState::BtcEarlyRefunded(state6) => BobState::BtcEarlyRefunded(*state6), BobEndState::BtcAmnestyConfirmed(state6) => BobState::BtcAmnestyConfirmed(*state6), + BobEndState::BtcFinalAmnestyConfirmed(state6) => { + BobState::BtcFinalAmnestyConfirmed(*state6) + } }, } } @@ -207,6 +237,15 @@ impl fmt::Display for Bob { Bob::BtcPunished { .. } => f.write_str("Bitcoin punished"), Bob::BtcPartiallyRefunded { .. } => f.write_str("Bitcoin partially refunded"), Bob::BtcAmnestyPublished { .. } => f.write_str("Bitcoin amnesty published"), + Bob::WaitingForRemainingRefundTimelockExpiration { .. } => { + f.write_str("Waiting for remaining refund timelock to expire") + } + Bob::RemainingRefundTimelockExpired { .. } => { + f.write_str("Remaining refund timelock expired") + } + Bob::BtcRefundBurnPublished { .. } => f.write_str("Bitcoin refund burn published"), + Bob::BtcRefundBurnt { .. } => f.write_str("Bitcoin refund burnt"), + Bob::BtcFinalAmnestyPublished { .. } => f.write_str("Bitcoin final amnesty published"), } } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 6db55cb0b5..c549ea229a 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -59,6 +59,19 @@ pub enum BobState { BtcPartiallyRefunded(State6), BtcAmnestyPublished(State6), BtcAmnestyConfirmed(State6), + /// Waiting for RemainingRefundTimelock to expire after partial refund confirmed. + /// During this time, Alice may publish TxRefundBurn. + WaitingForRemainingRefundTimelockExpiration(State6), + /// RemainingRefundTimelock has expired, we can now publish TxRefundAmnesty. + RemainingRefundTimelockExpired(State6), + /// Alice published TxRefundBurn before we could publish TxRefundAmnesty. + BtcRefundBurnPublished(State6), + /// TxRefundBurn has been confirmed. The amnesty output is now burnt. + BtcRefundBurnt(State6), + /// Alice published TxFinalAmnesty (using our presigned signature) to refund us. + BtcFinalAmnestyPublished(State6), + /// TxFinalAmnesty has been confirmed. We received the burnt funds back. + BtcFinalAmnestyConfirmed(State6), XmrRedeemed { tx_lock_id: bitcoin::Txid, }, @@ -140,6 +153,20 @@ impl fmt::Display for BobState { BobState::BtcPartiallyRefunded { .. } => write!(f, "btc is partially refunded"), BobState::BtcAmnestyPublished { .. } => write!(f, "btc amnesty is published"), BobState::BtcAmnestyConfirmed { .. } => write!(f, "btc amnesty is confirmed"), + BobState::WaitingForRemainingRefundTimelockExpiration { .. } => { + write!(f, "waiting for remaining refund timelock to expire") + } + BobState::RemainingRefundTimelockExpired { .. } => { + write!(f, "remaining refund timelock expired") + } + BobState::BtcRefundBurnPublished { .. } => write!(f, "btc refund burn is published"), + BobState::BtcRefundBurnt { .. } => write!(f, "btc refund is burnt"), + BobState::BtcFinalAmnestyPublished { .. } => { + write!(f, "btc final amnesty is published") + } + BobState::BtcFinalAmnestyConfirmed { .. } => { + write!(f, "btc final amnesty is confirmed") + } BobState::SafelyAborted => write!(f, "safely aborted"), } } @@ -180,10 +207,16 @@ impl BobState { | BobState::BtcPartialRefundPublished(state) | BobState::BtcPartiallyRefunded(state) | BobState::BtcAmnestyPublished(state) - | BobState::BtcAmnestyConfirmed(state) => { + | BobState::BtcAmnestyConfirmed(state) + | BobState::WaitingForRemainingRefundTimelockExpiration(state) + | BobState::RemainingRefundTimelockExpired(state) + | BobState::BtcRefundBurnPublished(state) + | BobState::BtcRefundBurnt(state) + | BobState::BtcFinalAmnestyPublished(state) => { Some(state.expired_timelock(bitcoin_wallet.as_ref()).await?) } BobState::BtcPunished { .. } => Some(ExpiredTimelocks::Punish), + BobState::BtcFinalAmnestyConfirmed(_) => Some(ExpiredTimelocks::RemainingRefund), BobState::BtcRefunded(_) | BobState::BtcEarlyRefunded { .. } | BobState::BtcRedeemed(_) @@ -198,6 +231,7 @@ pub fn is_complete(state: &BobState) -> bool { BobState::BtcRefunded(..) | BobState::BtcEarlyRefunded { .. } | BobState::BtcAmnestyConfirmed { .. } + | BobState::BtcFinalAmnestyConfirmed { .. } | BobState::XmrRedeemed { .. } | BobState::SafelyAborted ) diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 530ea8d282..5c5f624524 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -72,12 +72,18 @@ pub async fn cancel( BobState::BtcPartiallyRefunded(state6) => state6, BobState::BtcAmnestyConfirmed(state6) => state6, BobState::BtcAmnestyPublished(state6) => state6, + BobState::WaitingForRemainingRefundTimelockExpiration(state6) => state6, + BobState::RemainingRefundTimelockExpired(state6) => state6, + BobState::BtcRefundBurnPublished(state6) => state6, + BobState::BtcFinalAmnestyPublished(state6) => state6, BobState::Started { .. } | BobState::BtcRedeemed(_) | BobState::XmrRedeemed { .. } | BobState::BtcPunished { .. } | BobState::BtcEarlyRefunded { .. } + | BobState::BtcRefundBurnt { .. } + | BobState::BtcFinalAmnestyConfirmed { .. } | BobState::SafelyAborted => bail!( "Cannot cancel swap {} because it is in state {} which is not cancellable.", swap_id, @@ -190,12 +196,18 @@ pub async fn refund( BobState::BtcPartiallyRefunded(state6) => state6, BobState::BtcAmnestyPublished(state6) => state6, BobState::BtcAmnestyConfirmed(state6) => state6, + BobState::WaitingForRemainingRefundTimelockExpiration(state6) => state6, + BobState::RemainingRefundTimelockExpired(state6) => state6, + BobState::BtcRefundBurnPublished(state6) => state6, + BobState::BtcFinalAmnestyPublished(state6) => state6, BobState::Started { .. } | BobState::SwapSetupCompleted(_) | BobState::BtcRedeemed(_) | BobState::BtcEarlyRefunded { .. } | BobState::XmrRedeemed { .. } | BobState::BtcPunished { .. } + | BobState::BtcRefundBurnt { .. } + | BobState::BtcFinalAmnestyConfirmed { .. } | BobState::SafelyAborted => bail!( "Cannot refund swap {} because it is in state {} which is not refundable.", swap_id, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 1371be45fd..e7fa04596b 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1214,8 +1214,40 @@ async fn next_state( event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcAmnestyReceived { btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), }); - BobState::BtcAmnestyConfirmed(state) + BobState::BtcAmnestyConfirmed(state) }, + BobState::WaitingForRemainingRefundTimelockExpiration(_state) => { + // TODO: Wait for timelock expiry while watching for TxRefundBurn + // If timelock expires -> RemainingRefundTimelockExpired + // If TxRefundBurn seen -> BtcRefundBurnPublished + todo!("WaitingForRemainingRefundTimelockExpiration state transition not yet implemented") + } + BobState::RemainingRefundTimelockExpired(_state) => { + // TODO: Check if TxRefundBurn was published/confirmed first + // If TxRefundBurn confirmed -> BtcRefundBurnt + // If TxRefundBurn published -> BtcRefundBurnPublished + // Otherwise publish TxRefundAmnesty -> BtcAmnestyPublished + todo!("RemainingRefundTimelockExpired state transition not yet implemented") + } + BobState::BtcRefundBurnPublished(_state) => { + // TODO: Wait for TxRefundBurn confirmation + // Then -> BtcRefundBurnt + todo!("BtcRefundBurnPublished state transition not yet implemented") + } + BobState::BtcRefundBurnt(state) => { + // Terminal state - Alice needs to manually publish TxFinalAmnesty + // Similar to BtcPunished, we stop here + BobState::BtcRefundBurnt(state) + } + BobState::BtcFinalAmnestyPublished(_state) => { + // TODO: Wait for TxFinalAmnesty confirmation + // Then -> BtcFinalAmnestyConfirmed + todo!("BtcFinalAmnestyPublished state transition not yet implemented") + } + BobState::BtcFinalAmnestyConfirmed(state) => { + // Terminal state - we received the burnt funds back + BobState::BtcFinalAmnestyConfirmed(state) + } BobState::SafelyAborted => BobState::SafelyAborted, BobState::XmrRedeemed { tx_lock_id } => { event_emitter.emit_swap_progress_event( From 310acc1f60f585c4fc51f1246f6522a027b8bdb9 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 15:32:57 +0100 Subject: [PATCH 060/146] swap-setup: exchange signatures and fees for TxRefundBurn and TxFinalAmnesty --- swap-machine/src/alice/mod.rs | 51 +++++++++++++++++++++- swap-machine/src/bob/mod.rs | 36 ++++++++++++++- swap-machine/src/common/mod.rs | 4 ++ swap-p2p/src/protocols/swap_setup/alice.rs | 4 ++ swap-p2p/src/protocols/swap_setup/bob.rs | 2 + swap/src/asb/event_loop.rs | 4 ++ swap/src/protocol/bob/swap.rs | 6 ++- 7 files changed, 103 insertions(+), 4 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index d9142e8ce8..d2d6696e50 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -9,8 +9,8 @@ use std::fmt::{self, Debug}; use std::sync::Arc; use swap_core::bitcoin::{ CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, - TxCancel, TxEarlyRefund, TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, TxRefundAmnesty, - Txid, current_epoch, + TxCancel, TxEarlyRefund, TxFinalAmnesty, TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, + TxRefundAmnesty, TxRefundBurn, Txid, current_epoch, }; use swap_core::monero; use swap_core::monero::ScalarExt; @@ -175,6 +175,7 @@ pub struct State0 { punish_address: bitcoin::Address, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, + tx_refund_burn_fee: Option, } impl State0 { @@ -188,6 +189,7 @@ impl State0 { punish_address: bitcoin::Address, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, + tx_refund_burn_fee: bitcoin::Amount, rng: &mut R, ) -> Self where @@ -218,6 +220,7 @@ impl State0 { remaining_refund_timelock: Some(env_config.bitcoin_remaining_refund_timelock.into()), tx_redeem_fee, tx_punish_fee, + tx_refund_burn_fee: Some(tx_refund_burn_fee), } } @@ -266,6 +269,8 @@ impl State0 { tx_refund_fee: msg.tx_refund_fee, tx_partial_refund_fee: Some(msg.tx_partial_refund_fee), tx_refund_amnesty_fee: Some(msg.tx_refund_amnesty_fee), + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: Some(msg.tx_final_amnesty_fee), tx_cancel_fee: msg.tx_cancel_fee, }, )) @@ -299,6 +304,8 @@ pub struct State1 { tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -317,6 +324,9 @@ impl State1 { amnesty_amount: self .btc_amnesty_amount .context("Missing btc_amesty_amount for new swap that should have it")?, + tx_refund_burn_fee: self + .tx_refund_burn_fee + .context("Missing tx_refund_burn_fee for new swap that should have it")?, }) } @@ -351,6 +361,8 @@ impl State1 { tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -380,6 +392,8 @@ pub struct State2 { tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -493,6 +507,39 @@ impl State2 { ) .context("Failed to verify refund amnesty transaction")?; + // Create TxRefundBurn ourself + let tx_refund_burn = TxRefundBurn::new( + &tx_partial_refund, + self.a.public(), + self.B, + self.tx_refund_burn_fee + .context("missing tx_refund_burn_fee")?, + )?; + + // Check if the provided signature by Bob is valid for the transaction + swap_core::bitcoin::verify_sig( + &self.B, + &tx_refund_burn.digest(), + &msg.tx_refund_burn_sig, + ) + .context("Failed to verify refund burn transaction")?; + + // Create TxFinalAmnesty ourself + let tx_final_amnesty = TxFinalAmnesty::new( + &tx_refund_burn, + &self.refund_address, + self.tx_final_amnesty_fee + .context("missing tx_final_amnesty_fee")?, + ); + + // Check if the provided signature by Bob is valid for the transaction + swap_core::bitcoin::verify_sig( + &self.B, + &tx_final_amnesty.digest(), + &msg.tx_final_amnesty_sig, + ) + .context("Failed to verify final amnesty transaction")?; + Ok(State3 { a: self.a, B: self.B, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index c549ea229a..edf1c67e92 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -15,7 +15,8 @@ use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ self, CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, - TxCancel, TxLock, TxPartialRefund, TxRefundAmnesty, Txid, current_epoch, + TxCancel, TxFinalAmnesty, TxLock, TxPartialRefund, TxRefundAmnesty, TxRefundBurn, Txid, + current_epoch, }; use swap_core::monero::ScalarExt; use swap_core::monero::primitives::WatchRequest; @@ -256,6 +257,7 @@ pub struct State0 { min_monero_confirmations: u64, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_final_amnesty_fee: Option, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -275,6 +277,7 @@ impl State0 { min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, tx_refund_amnesty_fee: bitcoin::Amount, + tx_final_amnesty_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -305,6 +308,7 @@ impl State0 { min_monero_confirmations, tx_partial_refund_fee: Some(tx_partial_refund_fee), tx_refund_amnesty_fee: Some(tx_refund_amnesty_fee), + tx_final_amnesty_fee: Some(tx_final_amnesty_fee), tx_refund_fee, tx_cancel_fee, tx_lock_fee, @@ -327,6 +331,9 @@ impl State0 { tx_refund_amnesty_fee: self .tx_refund_amnesty_fee .context("tx_refund_amnesty_fee missing but required to setup swap")?, + tx_final_amnesty_fee: self + .tx_final_amnesty_fee + .context("tx_final_amnesty_fee missing but required to setup swap")?, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -383,6 +390,8 @@ impl State0 { tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: Some(msg.tx_refund_burn_fee), + tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_punish_fee: msg.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -410,6 +419,8 @@ pub struct State1 { min_monero_confirmations: u64, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -504,6 +515,8 @@ impl State1 { tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_punish_fee: self.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -547,6 +560,8 @@ pub struct State2 { pub tx_cancel_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, } impl State2 { @@ -596,11 +611,30 @@ impl State2 { ); let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); + let tx_refund_burn = TxRefundBurn::new( + &tx_partial_refund, + self.A, + self.b.public(), + self.tx_refund_burn_fee + .context("Missing tx_refund_burn_fee")?, + )?; + let tx_refund_burn_sig = self.b.sign(tx_refund_burn.digest()); + + let tx_final_amnesty = TxFinalAmnesty::new( + &tx_refund_burn, + &self.refund_address, + self.tx_final_amnesty_fee + .context("Missing tx_final_amnesty_fee")?, + ); + let tx_final_amnesty_sig = self.b.sign(tx_final_amnesty.digest()); + Ok(Message4 { tx_punish_sig, tx_cancel_sig, tx_early_refund_sig, tx_refund_amnesty_sig, + tx_refund_burn_sig, + tx_final_amnesty_sig, }) } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 86273769e7..75754a3db3 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -39,6 +39,7 @@ pub struct Message0 { pub tx_partial_refund_fee: bitcoin::Amount, pub tx_refund_amnesty_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, + pub tx_final_amnesty_fee: bitcoin::Amount, } #[allow(non_snake_case)] @@ -58,6 +59,7 @@ pub struct Message1 { /// The amount of Bitcoin that Bob not get refunded unless Alice decides so. /// Introduced in [#675](https://github.com/eigenwallet/core/pull/675) to combat spam. pub amnesty_amount: bitcoin::Amount, + pub tx_refund_burn_fee: bitcoin::Amount, } #[allow(non_snake_case)] @@ -85,6 +87,8 @@ pub struct Message4 { pub tx_cancel_sig: bitcoin::Signature, pub tx_early_refund_sig: bitcoin::Signature, pub tx_refund_amnesty_sig: bitcoin::Signature, + pub tx_refund_burn_sig: bitcoin::Signature, + pub tx_final_amnesty_sig: bitcoin::Signature, } #[allow(clippy::large_enum_variant)] diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 9ff5de2d21..159d0e958e 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -55,6 +55,7 @@ pub struct WalletSnapshot { redeem_fee: bitcoin::Amount, punish_fee: bitcoin::Amount, + refund_burn_fee: bitcoin::Amount, } impl WalletSnapshot { @@ -64,6 +65,7 @@ impl WalletSnapshot { punish_address: bitcoin::Address, redeem_fee: bitcoin::Amount, punish_fee: bitcoin::Amount, + refund_burn_fee: bitcoin::Amount, ) -> Self { Self { unlocked_balance, @@ -72,6 +74,7 @@ impl WalletSnapshot { punish_address, redeem_fee, punish_fee, + refund_burn_fee, } } } @@ -542,6 +545,7 @@ async fn run_swap_setup( wallet_snapshot.punish_address, wallet_snapshot.redeem_fee, wallet_snapshot.punish_fee, + wallet_snapshot.refund_burn_fee, &mut rand::thread_rng(), ); diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index dba374fd0c..245d11bb22 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -331,6 +331,7 @@ pub struct NewSwap { pub tx_refund_fee: bitcoin::Amount, pub tx_partial_refund_fee: bitcoin::Amount, pub tx_refund_amnesty_fee: bitcoin::Amount, + pub tx_final_amnesty_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, pub bitcoin_refund_address: bitcoin::Address, } @@ -576,6 +577,7 @@ async fn run_swap_setup( env_config.monero_finality_confirmations, new_swap_request.tx_partial_refund_fee, new_swap_request.tx_refund_amnesty_fee, + new_swap_request.tx_final_amnesty_fee, new_swap_request.tx_refund_fee, new_swap_request.tx_cancel_fee, new_swap_request.tx_lock_fee, diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 106d6d367d..c4de258e37 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -879,6 +879,9 @@ async fn capture_wallet_snapshot( let punish_fee = bitcoin_wallet .estimate_fee(bitcoin::TxPunish::weight(), Some(transfer_amount)) .await?; + let refund_burn_fee = bitcoin_wallet + .estimate_fee(bitcoin::TxRefundBurn::weight(), Some(transfer_amount)) + .await?; Ok(WalletSnapshot::new( unlocked_balance.into(), @@ -886,6 +889,7 @@ async fn capture_wallet_snapshot( punish_address, redeem_fee, punish_fee, + refund_burn_fee, )) } diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index e7fa04596b..c888e12817 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -12,7 +12,7 @@ use anyhow::{Context as AnyContext, Result, anyhow}; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin::{ - ExpiredTimelocks, TxCancel, TxFullRefund, TxPartialRefund, TxRefundAmnesty, + ExpiredTimelocks, TxCancel, TxFinalAmnesty, TxFullRefund, TxPartialRefund, TxRefundAmnesty, }; use swap_core::monero::TxHash; use swap_env::env; @@ -125,6 +125,9 @@ async fn next_state( let tx_refund_amnesty_fee = bitcoin_wallet .estimate_fee(TxRefundAmnesty::weight(), Some(btc_amount)) .await?; + let tx_final_amnesty_fee = bitcoin_wallet + .estimate_fee(TxFinalAmnesty::weight(), Some(btc_amount)) + .await?; // Emit an event to tauri that we are negotiating with the maker to lock the Bitcoin event_emitter.emit_swap_progress_event( @@ -142,6 +145,7 @@ async fn next_state( tx_refund_fee, tx_partial_refund_fee, tx_refund_amnesty_fee, + tx_final_amnesty_fee, tx_cancel_fee, bitcoin_refund_address: change_address, }) From 7afbde5712956785887db0fa2fa4e9697368e531 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 16:29:55 +0100 Subject: [PATCH 061/146] state-machine(bob): add tx_final_amnesty_fee and tx_refund_burn_fee to all bob states and implement new state transitions --- swap-machine/src/bob/mod.rs | 39 ++++++++++- swap/src/protocol/bob/swap.rs | 126 ++++++++++++++++++---------------- 2 files changed, 106 insertions(+), 59 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index edf1c67e92..412f959b72 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -663,6 +663,8 @@ impl State2 { tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, }, self.tx_lock, @@ -705,6 +707,8 @@ pub struct State3 { tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -756,6 +760,8 @@ impl State3 { tx_cancel_fee: self.tx_cancel_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, } } @@ -778,6 +784,8 @@ impl State3 { tx_cancel_fee: self.tx_cancel_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, xmr: self.xmr, btc_amnesty_amount: self.btc_amnesty_amount, } @@ -879,6 +887,8 @@ pub struct State4 { tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -1004,6 +1014,8 @@ impl State4 { btc_amnesty_amount: self.btc_amnesty_amount, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, } } @@ -1069,7 +1081,7 @@ pub struct State6 { pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, - remaining_refund_timelock: Option, + pub remaining_refund_timelock: Option, #[serde(with = "address_serde")] refund_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, @@ -1086,6 +1098,8 @@ pub struct State6 { pub tx_cancel_fee: bitcoin::Amount, tx_partial_refund_fee: Option, tx_refund_amnesty_fee: Option, + tx_refund_burn_fee: Option, + tx_final_amnesty_fee: Option, } impl State6 { @@ -1290,6 +1304,29 @@ impl State6 { )) } + pub fn construct_tx_refund_burn(&self) -> Result { + let tx_partial_refund = self.construct_tx_partial_refund()?; + bitcoin::TxRefundBurn::new( + &tx_partial_refund, + self.A, + self.b.public(), + self.tx_refund_burn_fee.context( + "Can't construct TxRefundBurn because tx_refund_burn_fee is missing", + )?, + ) + } + + pub fn construct_tx_final_amnesty(&self) -> Result { + let tx_refund_burn = self.construct_tx_refund_burn()?; + Ok(bitcoin::TxFinalAmnesty::new( + &tx_refund_burn, + &self.refund_address, + self.tx_final_amnesty_fee.context( + "Can't construct TxFinalAmnesty because tx_final_amnesty_fee is missing", + )?, + )) + } + pub fn construct_tx_early_refund(&self) -> bitcoin::TxEarlyRefund { bitcoin::TxEarlyRefund::new(&self.tx_lock, &self.refund_address, self.tx_refund_fee) } diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index c888e12817..22f740c3f3 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -983,7 +983,7 @@ async fn next_state( } BobState::BtcPartiallyRefunded(state) => { let has_amnesty_signature = state.tx_refund_amnesty_sig.is_some(); - + event_emitter.emit_swap_progress_event( swap_id, TauriSwapProgressEvent::BtcPartiallyRefunded { @@ -992,44 +992,9 @@ async fn next_state( }, ); - // If we have the amnesty signature, we publish the transaction ourselves. - // This also succeeds if the transaction is published by Alice. - if has_amnesty_signature { - retry("Refund amnesty transaction", || async { - let state = state.clone(); - let transaction = state.signed_amnesty_transaction().context("Couldn't construct Bitcoin amnesty transaction").map_err(backoff::Error::permanent)?; - bitcoin_wallet.ensure_broadcasted(transaction, "Bitcoin amnesty transaction") - .await - .context("Couldn't ensure broadcast of Bitcoin amnesty transaction") - .map_err(backoff::Error::transient)?; - Ok(()) - }, - None, - None - ) - .await - .context("Couldn't publish Bitcoin amnesty transaction")?; - - return Ok(BobState::BtcAmnestyPublished(state)) - } - - // If we don't have the amnesty signature, we have to wait for Alice to publish it. - // TODO: Would a timeout make sense here? Maybe once concurrent swap support landed. - - let tx_amnesty = state.construct_tx_amnesty().context("Couldn't construct Bitcoin amnesty transaction")?; - let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_amnesty.clone())).await; - - retry("Waiting for Bitcoin amnesty transaction to be published by Alice", || async { - subscription.clone() - .wait_until_seen() - .await - .context("Failed to wait for Bitcoin amnesty transaction to be published by Alice") - .map_err(backoff::Error::transient)?; - - Ok(BobState::BtcAmnestyPublished(state.clone())) - }, None, None) - .await - .context("Failed to wait for Bitcoin amnesty transaction to be published by Alice")? + // Transition to waiting state where we race remaining_refund_timelock + // against Alice potentially publishing TxRefundBurn + BobState::WaitingForRemainingRefundTimelockExpiration(state) } BobState::BtcRefunded(state) => { event_emitter.emit_swap_progress_event( @@ -1220,33 +1185,78 @@ async fn next_state( }); BobState::BtcAmnestyConfirmed(state) }, - BobState::WaitingForRemainingRefundTimelockExpiration(_state) => { - // TODO: Wait for timelock expiry while watching for TxRefundBurn - // If timelock expires -> RemainingRefundTimelockExpired - // If TxRefundBurn seen -> BtcRefundBurnPublished - todo!("WaitingForRemainingRefundTimelockExpiration state transition not yet implemented") + BobState::WaitingForRemainingRefundTimelockExpiration(state) => { + // Race between: + // - Remaining refund timelock expiring (so we can publish TxRefundAmnesty) + // - Alice publishing TxRefundBurn (burns the amnesty output) + let tx_partial_refund = state.construct_tx_partial_refund()?; + let tx_refund_burn = state.construct_tx_refund_burn()?; + + let remaining_refund_timelock = state.remaining_refund_timelock.context( + "Can't wait for remaining refund timelock because remaining_refund_timelock is missing", + )?; + + let (tx_partial_refund_status, tx_refund_burn_status) = tokio::join!( + bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund)), + bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)), + ); + + select! { + // Wait for remaining_refund_timelock confirmations on tx_partial_refund + result = tx_partial_refund_status.wait_until_confirmed_with(remaining_refund_timelock) => { + result?; + tracing::info!("Remaining refund timelock expired, can now publish TxRefundAmnesty"); + BobState::RemainingRefundTimelockExpired(state) + } + // Watch for Alice publishing TxRefundBurn + _ = tx_refund_burn_status.wait_until_seen() => { + tracing::info!("Alice published TxRefundBurn, amnesty output is being burnt"); + BobState::BtcRefundBurnPublished(state) + } + } } - BobState::RemainingRefundTimelockExpired(_state) => { - // TODO: Check if TxRefundBurn was published/confirmed first - // If TxRefundBurn confirmed -> BtcRefundBurnt - // If TxRefundBurn published -> BtcRefundBurnPublished - // Otherwise publish TxRefundAmnesty -> BtcAmnestyPublished - todo!("RemainingRefundTimelockExpired state transition not yet implemented") + BobState::RemainingRefundTimelockExpired(state) => { + // TODO: We should retry this and the check + // First check if TxRefundBurn was seen (we may have missed it while offline) + let tx_refund_burn = state.construct_tx_refund_burn()?; + let tx_refund_burn_status = bitcoin_wallet.status_of_script(&tx_refund_burn).await?; + + if tx_refund_burn_status.has_been_seen() { + tracing::info!("TxRefundBurn was already published, transitioning to BtcRefundBurnPublished"); + return Ok(BobState::BtcRefundBurnPublished(state)); + } + + // TxRefundBurn not published, we can publish TxRefundAmnesty + // Alice always sends the amnesty signature in swap setup + let transaction = state.signed_amnesty_transaction() + .context("Couldn't construct Bitcoin amnesty transaction")?; + bitcoin_wallet.ensure_broadcasted(transaction, "amnesty") + .await + .context("Couldn't ensure broadcast of Bitcoin amnesty transaction")?; + BobState::BtcAmnestyPublished(state) } - BobState::BtcRefundBurnPublished(_state) => { - // TODO: Wait for TxRefundBurn confirmation - // Then -> BtcRefundBurnt - todo!("BtcRefundBurnPublished state transition not yet implemented") + BobState::BtcRefundBurnPublished(state) => { + // Wait for TxRefundBurn confirmation + let tx_refund_burn = state.construct_tx_refund_burn()?; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; + + subscription.wait_until_final().await?; + tracing::info!("TxRefundBurn confirmed, amnesty output is burnt"); + BobState::BtcRefundBurnt(state) } BobState::BtcRefundBurnt(state) => { // Terminal state - Alice needs to manually publish TxFinalAmnesty // Similar to BtcPunished, we stop here BobState::BtcRefundBurnt(state) } - BobState::BtcFinalAmnestyPublished(_state) => { - // TODO: Wait for TxFinalAmnesty confirmation - // Then -> BtcFinalAmnestyConfirmed - todo!("BtcFinalAmnestyPublished state transition not yet implemented") + BobState::BtcFinalAmnestyPublished(state) => { + // Wait for TxFinalAmnesty confirmation + let tx_final_amnesty = state.construct_tx_final_amnesty()?; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_final_amnesty)).await; + + subscription.wait_until_final().await?; + tracing::info!("TxFinalAmnesty confirmed, received burnt funds back"); + BobState::BtcFinalAmnestyConfirmed(state) } BobState::BtcFinalAmnestyConfirmed(state) => { // Terminal state - we received the burnt funds back From 37c6635af3778be81886584025eb1e2c15a258a1 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 17:08:32 +0100 Subject: [PATCH 062/146] swap-setup/state-machine(bob): make alice's sig on TxRefundAmnesty non-optional --- swap-machine/src/alice/mod.rs | 15 ++++++- swap-machine/src/bob/mod.rs | 78 ++++++++++++++++------------------ swap-machine/src/common/mod.rs | 3 +- swap/src/protocol/bob/swap.rs | 4 +- 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index d2d6696e50..c801b7e910 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -425,9 +425,20 @@ impl State2 { let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); let tx_cancel_sig = self.a.sign(tx_cancel.digest()); - // TODO: When to send these? + + // Construct and sign TxRefundAmnesty + let tx_refund_amnesty = swap_core::bitcoin::TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("Missing tx_refund_amnesty_fee for new swap")?, + self.remaining_refund_timelock + .context("Missing remaining_refund_timelock for new swap")?, + ); + let tx_refund_amnesty_sig = self.a.sign(tx_refund_amnesty.digest()); + + // TODO: When to send full refund encsig? let tx_full_refund_encsig = None; - let tx_refund_amnesty_sig = None; Ok(Message3 { tx_cancel_sig, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 412f959b72..44dfe2f916 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -95,22 +95,26 @@ pub enum BobState { #[serde(untagged)] pub enum RefundSignatures { /// Alice has only signed the partial refund transaction (most cases). + /// Includes the amnesty signature which is always provided in new swaps. Partial { tx_partial_refund_encsig: bitcoin::EncryptedSignature, + tx_refund_amnesty_sig: bitcoin::Signature, }, /// Alice has signed both the partial and full refund transactions. + /// Includes the amnesty signature which is always provided in new swaps. Full { tx_partial_refund_encsig: bitcoin::EncryptedSignature, // Serde rename keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. #[serde(rename = "tx_refund_encsig")] tx_full_refund_encsig: bitcoin::EncryptedSignature, + tx_refund_amnesty_sig: bitcoin::Signature, }, /// Alice has only signed the full refund transaction. /// This is only used to maintain backwards compatibility for older swaps /// from before the partial refund protocol change. /// See [#675](https://github.com/eigenwallet/core/pull/675). Legacy { - // Serde raname keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. + // Serde rename keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. #[serde(rename = "tx_refund_encsig")] tx_full_refund_encsig: bitcoin::EncryptedSignature, }, @@ -474,22 +478,21 @@ impl State1 { )?; } - // Verify the refund amnesty signature if it is present - if let Some(tx_refund_amnesty_sig) = &msg.tx_refund_amnesty_sig { - let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new( - &tx_partial_refund, - &self.refund_address, - self.tx_refund_amnesty_fee - .context("tx_refund_amnesty_fee missing but required to setup swap")?, - self.remaining_refund_timelock - .context("remaining_refund_timelock missing but required to setup swap")?, - ); - bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig)?; - } + // Verify the refund amnesty signature (always provided in new swaps) + let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("tx_refund_amnesty_fee missing but required to setup swap")?, + self.remaining_refund_timelock + .context("remaining_refund_timelock missing but required to setup swap")?, + ); + bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), &msg.tx_refund_amnesty_sig)?; let refund_signatures = RefundSignatures::from_possibly_full_refund_sig( msg.tx_partial_refund_encsig, msg.tx_full_refund_encsig, + msg.tx_refund_amnesty_sig, ); Ok(State2 { A: self.A, @@ -509,7 +512,6 @@ impl State1 { tx_lock: self.tx_lock, tx_cancel_sig_a: msg.tx_cancel_sig, refund_signatures, - tx_refund_amnesty_sig: msg.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, @@ -549,10 +551,6 @@ pub struct State2 { /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] refund_signatures: RefundSignatures, - /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). - /// It allows Bob to retrieve the refund fee introduced in the PR. - /// This signature is voluntarily revealed by alice. - tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -657,7 +655,6 @@ impl State2 { tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a, refund_signatures: self.refund_signatures, - tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, min_monero_confirmations: self.min_monero_confirmations, tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, @@ -698,10 +695,6 @@ pub struct State3 { /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] refund_signatures: RefundSignatures, - /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). - /// It allows Bob to retrieve the refund fee introduced in the PR. - /// This signature is voluntarily revealed by alice. - tx_refund_amnesty_sig: Option, min_monero_confirmations: u64, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, @@ -752,7 +745,6 @@ impl State3 { tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, refund_signatures: self.refund_signatures, - tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, monero_wallet_restore_blockheight, lock_transfer_proof, tx_redeem_fee: self.tx_redeem_fee, @@ -779,7 +771,6 @@ impl State3 { tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), refund_signatures: self.refund_signatures.clone(), - tx_refund_amnesty_sig: self.tx_refund_amnesty_sig.clone(), tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, @@ -877,10 +868,6 @@ pub struct State4 { /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] refund_signatures: RefundSignatures, - /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). - /// It allows Bob to retrieve the refund fee introduced in the PR. - /// This signature is voluntarily revealed by alice. - tx_refund_amnesty_sig: Option, monero_wallet_restore_blockheight: BlockHeight, lock_transfer_proof: TransferProof, tx_redeem_fee: bitcoin::Amount, @@ -1007,7 +994,6 @@ impl State4 { tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, refund_signatures: self.refund_signatures, - tx_refund_amnesty_sig: self.tx_refund_amnesty_sig, tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, xmr: self.xmr, @@ -1090,10 +1076,6 @@ pub struct State6 { /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] pub refund_signatures: RefundSignatures, - /// This field was added in [#675](https://github.com/eigenwallet/core/pull/675). - /// It allows Bob to retrieve the refund fee introduced in the PR. - /// This signature is voluntarily revealed by alice. - pub tx_refund_amnesty_sig: Option, pub tx_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, tx_partial_refund_fee: Option, @@ -1278,7 +1260,7 @@ impl State6 { pub fn signed_amnesty_transaction(&self) -> Result { let tx_amnesty = self.construct_tx_amnesty()?; - let sig_a = self.tx_refund_amnesty_sig.clone().context( + let sig_a = self.refund_signatures.tx_refund_amnesty_sig().context( "Can't sign amnesty transaction because Alice's amnesty signature is missing", )?; let sig_b = self.b.sign(tx_amnesty.digest()); @@ -1373,25 +1355,22 @@ impl RefundSignatures { pub fn from_possibly_full_refund_sig( partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option, + refund_amnesty_sig: bitcoin::Signature, ) -> Self { if let Some(full_refund_encsig) = full_refund_encsig { Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_full_refund_encsig: full_refund_encsig, + tx_refund_amnesty_sig: refund_amnesty_sig, } } else { Self::Partial { tx_partial_refund_encsig: partial_refund_encsig, + tx_refund_amnesty_sig: refund_amnesty_sig, } } } - pub fn from_partial_refund_sig(partial_refund_encsig: bitcoin::EncryptedSignature) -> Self { - Self::Partial { - tx_partial_refund_encsig: partial_refund_encsig, - } - } - pub fn tx_full_refund_encsig(&self) -> Option { match self { RefundSignatures::Partial { .. } => None, @@ -1409,6 +1388,7 @@ impl RefundSignatures { match self { RefundSignatures::Partial { tx_partial_refund_encsig, + .. } => Some(tx_partial_refund_encsig.clone()), RefundSignatures::Full { tx_partial_refund_encsig, @@ -1418,6 +1398,22 @@ impl RefundSignatures { } } + /// Returns Alice's signature for the amnesty transaction. + /// Only available for new swaps (Partial/Full variants), not Legacy swaps. + pub fn tx_refund_amnesty_sig(&self) -> Option { + match self { + RefundSignatures::Partial { + tx_refund_amnesty_sig, + .. + } => Some(tx_refund_amnesty_sig.clone()), + RefundSignatures::Full { + tx_refund_amnesty_sig, + .. + } => Some(tx_refund_amnesty_sig.clone()), + RefundSignatures::Legacy { .. } => None, + } + } + pub fn has_full_refund_encsig(&self) -> bool { self.tx_full_refund_encsig().is_some() } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 75754a3db3..68c596555f 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -77,7 +77,8 @@ pub struct Message3 { /// have to. pub tx_partial_refund_encsig: bitcoin::EncryptedSignature, pub tx_full_refund_encsig: Option, - pub tx_refund_amnesty_sig: Option, + /// Alice's signature for the amnesty transaction - always provided. + pub tx_refund_amnesty_sig: bitcoin::Signature, } #[allow(non_snake_case)] diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 22f740c3f3..1f66f22292 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -955,7 +955,7 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcPartialRefundPublished { btc_partial_refund_txid: state.construct_tx_partial_refund()?.txid(), - has_amnesty_signature: state.tx_refund_amnesty_sig.is_some(), + has_amnesty_signature: state.refund_signatures.tx_refund_amnesty_sig().is_some(), }, ); @@ -982,7 +982,7 @@ async fn next_state( } } BobState::BtcPartiallyRefunded(state) => { - let has_amnesty_signature = state.tx_refund_amnesty_sig.is_some(); + let has_amnesty_signature = state.refund_signatures.tx_refund_amnesty_sig().is_some(); event_emitter.emit_swap_progress_event( swap_id, From 2e6175f714a4848af836e176b58bfc76bff56add Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 17:37:24 +0100 Subject: [PATCH 063/146] fix tests: pass remaining_refund_timelock --- swap-machine/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/swap-machine/src/lib.rs b/swap-machine/src/lib.rs index f00aad1399..ceea4c2a49 100644 --- a/swap-machine/src/lib.rs +++ b/swap-machine/src/lib.rs @@ -55,6 +55,7 @@ mod tests { punish_address, tx_redeem_fee, tx_punish_fee, + spending_fee, &mut OsRng, ); @@ -65,12 +66,14 @@ mod tests { xmr_amount, CancelTimelock::new(config.bitcoin_cancel_timelock), PunishTimelock::new(config.bitcoin_punish_timelock), + RemainingRefundTimelock::new(config.bitcoin_remaining_refund_timelock), bob_wallet.new_address().await.unwrap(), config.monero_finality_confirmations, spending_fee, spending_fee, spending_fee, spending_fee, + spending_fee, tx_lock_fee, ); @@ -168,6 +171,7 @@ mod tests { punish_address, tx_redeem_fee, tx_punish_fee, + spending_fee, &mut OsRng, ); @@ -178,6 +182,7 @@ mod tests { xmr_amount, CancelTimelock::new(config.bitcoin_cancel_timelock), PunishTimelock::new(config.bitcoin_punish_timelock), + RemainingRefundTimelock::new(config.bitcoin_remaining_refund_timelock), bob_wallet.new_address().await.unwrap(), config.monero_finality_confirmations, spending_fee, @@ -185,6 +190,7 @@ mod tests { spending_fee, spending_fee, spending_fee, + spending_fee, ); // Complete the state machine up to State3 From 06478ebdf9e1c3841c0386b2a52d615515cfa0bd Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 20:30:20 +0100 Subject: [PATCH 064/146] alice: sent encsig for TxFullRefund during swap setup when btc_amnesty_amount == 0 --- swap-machine/src/alice/mod.rs | 10 ++++++++-- swap/src/asb/event_loop.rs | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 4c674d316b..a734dc23d8 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -439,8 +439,14 @@ impl State2 { ); let tx_refund_amnesty_sig = self.a.sign(tx_refund_amnesty.digest()); - // TODO: When to send full refund encsig? - let tx_full_refund_encsig = None; + // Send full refund encsig when btc_amnesty_amount is None or ZERO (ratio = 1.0) + let tx_full_refund = TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + let tx_full_refund_encsig = + if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { + Some(self.a.encsign(self.S_b_bitcoin, tx_full_refund.digest())) + } else { + None + }; Ok(Message3 { tx_cancel_sig, diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index c4de258e37..058099f05f 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -832,10 +832,16 @@ impl EventLoopHandle { /// For a new swap of `swap_amount`, this function calculates how much /// Bitcoin should go into the amnesty-lock incase of a refund. +/// Returns ZERO when taker_refund_ratio is 1.0 (100%), indicating full refund. fn apply_bitcoin_amnesty_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, ) -> Result { + // When ratio is 1.0, no amnesty - use full refund path + if refund_policy.taker_refund_ratio == Decimal::ONE { + return Ok(bitcoin::Amount::ZERO); + } + let btc_amnesty_ratio = Decimal::ONE .checked_sub(refund_policy.taker_refund_ratio) .context("can't have refund ration > 1")?; From 6cfe0092aab28543d00cbf619c7b2a5690a963e2 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 20:30:54 +0100 Subject: [PATCH 065/146] bob: make fee fiels in state puiblic --- swap-machine/src/bob/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index bdc3a8aba2..a5a8745a5f 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -1084,7 +1084,7 @@ pub struct State6 { pub xmr: monero::Amount, /// How much of the locked Bitcoin will stay locked in case of a partial refund. /// May still be retrieve by publishing the `TxAmnesty` transaction. - btc_amnesty_amount: Option, + pub btc_amnesty_amount: Option, pub monero_wallet_restore_blockheight: BlockHeight, pub cancel_timelock: CancelTimelock, punish_timelock: PunishTimelock, @@ -1099,10 +1099,10 @@ pub struct State6 { pub refund_signatures: RefundSignatures, pub tx_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, - tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + pub tx_partial_refund_fee: Option, + pub tx_refund_amnesty_fee: Option, + pub tx_refund_burn_fee: Option, + pub tx_final_amnesty_fee: Option, } impl State6 { From 0276e8c96319abe8e6213b97d781a848bbda4df7 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 20:31:55 +0100 Subject: [PATCH 066/146] tests: add integration test for partial refund + amnesty : --- swap/tests/harness/mod.rs | 155 ++++++++++++++++++ .../partial_refund_bob_claims_amnesty.rs | 53 ++++++ 2 files changed, 208 insertions(+) create mode 100644 swap/tests/partial_refund_bob_claims_amnesty.rs diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 288ecd3965..f5171906e0 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -904,6 +904,121 @@ impl TestContext { .unwrap(); } + pub async fn assert_bob_partially_refunded(&self, state: BobState) { + self.bob_bitcoin_wallet.sync().await.unwrap(); + + let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_amount) = match state { + BobState::BtcPartiallyRefunded(state6) => ( + state6.tx_lock_id(), + state6.tx_cancel_fee, + state6.tx_partial_refund_fee.expect("partial refund fee"), + state6.btc_amnesty_amount.expect("amnesty amount"), + ), + _ => panic!("Bob is not in btc partially refunded state: {:?}", state), + }; + let lock_tx_bitcoin_fee = self + .bob_bitcoin_wallet + .transaction_fee(lock_tx_id) + .await + .unwrap(); + + let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); + let expected_balance = self.bob_starting_balances.btc + - lock_tx_bitcoin_fee + - cancel_fee + - partial_refund_fee + - amnesty_amount; + + assert_eq!(btc_balance_after_swap, expected_balance); + } + + pub async fn assert_bob_amnesty_received(&self, state: BobState) { + self.bob_bitcoin_wallet.sync().await.unwrap(); + + let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_fee) = match state { + BobState::BtcAmnestyConfirmed(state6) => ( + state6.tx_lock_id(), + state6.tx_cancel_fee, + state6.tx_partial_refund_fee.expect("partial refund fee"), + state6.tx_refund_amnesty_fee.expect("amnesty fee"), + ), + _ => panic!("Bob is not in btc amnesty confirmed state: {:?}", state), + }; + let lock_tx_bitcoin_fee = self + .bob_bitcoin_wallet + .transaction_fee(lock_tx_id) + .await + .unwrap(); + + let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); + // Bob gets full amount back minus all the fees + let expected_balance = self.bob_starting_balances.btc + - lock_tx_bitcoin_fee + - cancel_fee + - partial_refund_fee + - amnesty_fee; + + assert_eq!(btc_balance_after_swap, expected_balance); + } + + pub async fn assert_bob_refund_burnt(&self, state: BobState) { + self.bob_bitcoin_wallet.sync().await.unwrap(); + + let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_amount) = match state { + BobState::BtcRefundBurnt(state6) => ( + state6.tx_lock_id(), + state6.tx_cancel_fee, + state6.tx_partial_refund_fee.expect("partial refund fee"), + state6.btc_amnesty_amount.expect("amnesty amount"), + ), + _ => panic!("Bob is not in btc refund burnt state: {:?}", state), + }; + let lock_tx_bitcoin_fee = self + .bob_bitcoin_wallet + .transaction_fee(lock_tx_id) + .await + .unwrap(); + + let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); + // Bob lost the amnesty amount (it was burnt) + let expected_balance = self.bob_starting_balances.btc + - lock_tx_bitcoin_fee + - cancel_fee + - partial_refund_fee + - amnesty_amount; + + assert_eq!(btc_balance_after_swap, expected_balance); + } + + pub async fn assert_bob_final_amnesty_received(&self, state: BobState) { + self.bob_bitcoin_wallet.sync().await.unwrap(); + + let (lock_tx_id, cancel_fee, partial_refund_fee, final_amnesty_fee) = match state { + BobState::BtcFinalAmnestyConfirmed(state6) => ( + state6.tx_lock_id(), + state6.tx_cancel_fee, + state6.tx_partial_refund_fee.expect("partial refund fee"), + state6.tx_final_amnesty_fee.expect("final amnesty fee"), + ), + _ => panic!("Bob is not in btc final amnesty confirmed state: {:?}", state), + }; + let lock_tx_bitcoin_fee = self + .bob_bitcoin_wallet + .transaction_fee(lock_tx_id) + .await + .unwrap(); + + let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); + // Bob gets full amount back via final amnesty + let expected_balance = self.bob_starting_balances.btc + - lock_tx_bitcoin_fee + - cancel_fee + - partial_refund_fee + - final_amnesty_fee; + + assert_eq!(btc_balance_after_swap, expected_balance); + } + fn alice_redeemed_xmr_balance(&self) -> monero::Amount { self.alice_starting_balances.xmr - self.xmr_amount } @@ -1218,6 +1333,10 @@ pub mod alice_run_until { pub fn is_btc_redeemed(state: &AliceState) -> bool { matches!(state, AliceState::BtcRedeemed { .. }) } + + pub fn is_btc_partially_refunded(state: &AliceState) -> bool { + matches!(state, AliceState::BtcPartiallyRefunded { .. }) + } } pub mod bob_run_until { @@ -1238,6 +1357,30 @@ pub mod bob_run_until { pub fn is_encsig_sent(state: &BobState) -> bool { matches!(state, BobState::EncSigSent(..)) } + + pub fn is_btc_partially_refunded(state: &BobState) -> bool { + matches!(state, BobState::BtcPartiallyRefunded(..)) + } + + pub fn is_waiting_for_remaining_refund_timelock(state: &BobState) -> bool { + matches!(state, BobState::WaitingForRemainingRefundTimelockExpiration(..)) + } + + pub fn is_remaining_refund_timelock_expired(state: &BobState) -> bool { + matches!(state, BobState::RemainingRefundTimelockExpired(..)) + } + + pub fn is_btc_amnesty_confirmed(state: &BobState) -> bool { + matches!(state, BobState::BtcAmnestyConfirmed(..)) + } + + pub fn is_btc_refund_burnt(state: &BobState) -> bool { + matches!(state, BobState::BtcRefundBurnt(..)) + } + + pub fn is_btc_final_amnesty_confirmed(state: &BobState) -> bool { + matches!(state, BobState::BtcFinalAmnestyConfirmed(..)) + } } pub struct SlowCancelConfig; @@ -1273,3 +1416,15 @@ impl GetConfig for FastPunishConfig { } } } + +pub struct FastAmnestyConfig; + +impl GetConfig for FastAmnestyConfig { + fn get_config() -> Config { + Config { + bitcoin_cancel_timelock: CancelTimelock::new(10).into(), + bitcoin_remaining_refund_timelock: 3, + ..env::Regtest::get_config() + } + } +} diff --git a/swap/tests/partial_refund_bob_claims_amnesty.rs b/swap/tests/partial_refund_bob_claims_amnesty.rs new file mode 100644 index 0000000000..4c1c0c7c83 --- /dev/null +++ b/swap/tests/partial_refund_bob_claims_amnesty.rs @@ -0,0 +1,53 @@ +pub mod harness; + +use harness::alice_run_until::is_xmr_lock_transaction_sent; +use harness::FastAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::{alice, bob}; +use swap_env::config::RefundPolicy; + +/// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial +/// refund, waits for the remaining refund timelock, and then claims the amnesty. +#[tokio::test] +async fn given_partial_refund_bob_claims_amnesty_after_timelock() { + // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty + let refund_policy = Some(RefundPolicy { + taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% + }); + + harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { + let (bob_swap, _) = ctx.bob_swap().await; + let bob_swap = tokio::spawn(bob::run(bob_swap)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + // Alice finishes first (just sends XMR lock and stops) + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::XmrLockTransactionSent { .. } + )); + + // Bob takes longer: cancel timelock -> partial refund -> remaining refund timelock -> amnesty + let bob_state = bob_swap.await??; + ctx.assert_bob_amnesty_received(bob_state).await; + + // Restart Alice so she can refund her XMR + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + let alice_state = alice_swap.await??; + ctx.assert_alice_refunded(alice_state).await; + + Ok(()) + }) + .await; +} From 92c7ee37a7a7a1d4a75bfdc632d2b10a8536f949 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 20:38:27 +0100 Subject: [PATCH 067/146] alice: don't try to publish TxRefundAmnesty --- swap/src/protocol/alice/swap.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 2185471ac0..37a26839c2 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -667,16 +667,9 @@ where state3, monero_wallet_restore_blockheight, } => { - // TODO: Publish amnesty transaction/send amnesty tx sig / decide against it - // TODO: retry, maybe in background? we don't want this to block us from refunding the Monero though - let tx_refund_amnesty = state3 - .signed_bitcoin_amnesty_transaction() - .context("Couldn't construct Bitcoin refund amnesty transaction")?; - - bitcoin_wallet - .ensure_broadcasted(tx_refund_amnesty, "refund amnesty") - .await?; - + // Bob has the pre-signed TxRefundAmnesty from swap setup and can + // publish it himself after the remaining refund timelock expires. + // TODO: implement system for publishing TxRefundBurn at this point AliceState::XmrRefundable { monero_wallet_restore_blockheight, transfer_proof, From 840d029879a816a94461c248df2ccbe2a1c9bc52 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 17 Dec 2025 20:43:40 +0100 Subject: [PATCH 068/146] add new integration test to ci --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97649afc23..82a97c4e40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,8 @@ jobs: test_name: alice_broken_wallet_rpc_after_started_btc_early_refund - package: swap test_name: happy_path_alice_does_not_send_transfer_proof + - package: swap + test_name: partial_refund_bob_claims_amnesty - package: monero-tests test_name: reserve_proof - package: monero-tests From a91ac5f2a5d62012fc0752552634c90aec4525cc Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 18 Dec 2025 08:09:25 +0100 Subject: [PATCH 069/146] fmt --- swap-machine/src/alice/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index a734dc23d8..30291b18de 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -440,7 +440,8 @@ impl State2 { let tx_refund_amnesty_sig = self.a.sign(tx_refund_amnesty.digest()); // Send full refund encsig when btc_amnesty_amount is None or ZERO (ratio = 1.0) - let tx_full_refund = TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + let tx_full_refund = + TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); let tx_full_refund_encsig = if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { Some(self.a.encsign(self.S_b_bitcoin, tx_full_refund.digest())) @@ -536,12 +537,8 @@ impl State2 { )?; // Check if the provided signature by Bob is valid for the transaction - swap_core::bitcoin::verify_sig( - &self.B, - &tx_refund_burn.digest(), - &msg.tx_refund_burn_sig, - ) - .context("Failed to verify refund burn transaction")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_refund_burn.digest(), &msg.tx_refund_burn_sig) + .context("Failed to verify refund burn transaction")?; // Create TxFinalAmnesty ourself let tx_final_amnesty = TxFinalAmnesty::new( From 15ed6905e73445870a90696402525d8098a4be4d Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 18 Dec 2025 08:59:29 +0100 Subject: [PATCH 070/146] controller: output table when running get-swaps --- Cargo.lock | 1 + swap-controller/Cargo.toml | 1 + swap-controller/src/main.rs | 16 +++++++++----- swap-controller/src/util.rs | 43 +++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 swap-controller/src/util.rs diff --git a/Cargo.lock b/Cargo.lock index ac7415cbd1..b7cffb695e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10744,6 +10744,7 @@ version = "3.6.1" dependencies = [ "anyhow", "clap 4.5.53", + "comfy-table", "jsonrpsee", "monero", "rustyline", diff --git a/swap-controller/Cargo.toml b/swap-controller/Cargo.toml index ef6397c4f1..c3ad61cdf4 100644 --- a/swap-controller/Cargo.toml +++ b/swap-controller/Cargo.toml @@ -10,6 +10,7 @@ path = "src/main.rs" [dependencies] anyhow = { workspace = true } clap = { version = "4", features = ["derive"] } +comfy-table = "7.2.1" jsonrpsee = { workspace = true, features = ["client-core", "http-client"] } monero = { workspace = true } rustyline = "17.0.0" diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index cc03eaf3b9..9f697acfcb 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -1,9 +1,11 @@ mod cli; mod repl; +mod util; use clap::Parser; use cli::{Cli, Cmd}; use swap_controller_api::{AsbApiClient, MoneroSeedResponse}; +use util::ToTable; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -76,13 +78,17 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { } Cmd::GetSwaps => { let swaps = client.get_swaps().await?; + + // Create a table containing the swap id and state + let mut table = swaps.iter().map(|swap| (&swap.id, &swap.state)).to_table(); + if swaps.is_empty() { - println!("No swaps found"); - } else { - for swap in swaps { - println!("{}: {}", swap.id, swap.state); - } + table.add_row(["No swaps found"]); } + + table.set_header(["ID", "State"]); + + println!("{table}"); } Cmd::BitcoinSeed => { let response = client.bitcoin_seed().await?; diff --git a/swap-controller/src/util.rs b/swap-controller/src/util.rs new file mode 100644 index 0000000000..c7838ee157 --- /dev/null +++ b/swap-controller/src/util.rs @@ -0,0 +1,43 @@ +//! Utilities for easily generating tables. + +use comfy_table::Table; +use std::fmt::Display; + +pub trait ToTable { + fn to_table(self) -> Table; +} + +trait TupleToRow { + fn to_row(self) -> Vec; +} + +impl TupleToRow for (A,) { + fn to_row(self) -> Vec { + vec![self.0.to_string()] + } +} + +impl TupleToRow for (A, B) { + fn to_row(self) -> Vec { + vec![self.0.to_string(), self.1.to_string()] + } +} + +impl TupleToRow for (A, B, C) { + fn to_row(self) -> Vec { + vec![self.0.to_string(), self.1.to_string(), self.2.to_string()] + } +} + +impl ToTable for I +where + I: IntoIterator, +{ + fn to_table(self) -> Table { + let mut table = Table::new(); + for item in self { + table.add_row(item.to_row()); + } + table + } +} From 8a4ac957f58c5e361ea836d9dedb1312b662439b Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 18 Dec 2025 16:47:50 +0100 Subject: [PATCH 071/146] controller: display more information about swaps --- justfile | 2 +- swap-controller-api/src/lib.rs | 14 +++++- swap-controller/src/main.rs | 33 ++++++++++--- swap-controller/src/util.rs | 43 ---------------- swap-core/src/bitcoin/cancel.rs | 7 +-- swap-core/src/bitcoin/final_amnesty.rs | 6 +-- swap-core/src/bitcoin/refund_burn.rs | 11 +++-- swap-machine/src/alice/mod.rs | 3 ++ swap-machine/src/common/mod.rs | 20 ++++++++ swap/src/asb/rpc/server.rs | 68 +++++++++++++++++++------- swap/src/database/sqlite.rs | 27 +++++++--- 11 files changed, 146 insertions(+), 88 deletions(-) delete mode 100644 swap-controller/src/util.rs diff --git a/justfile b/justfile index 198b5e0eb9..8621457913 100644 --- a/justfile +++ b/justfile @@ -62,7 +62,7 @@ tests: # Run docker tests (e.g., "just docker_test happy_path_alice_developer_tip") docker_test test_name: - cargo test --package swap --test {{test_name}} -- --nocapture + RUST_BACKTRACE=1 cargo test --package swap --test {{test_name}} -- --nocapture docker_test_happy_path: just docker_test happy_path diff --git a/swap-controller-api/src/lib.rs b/swap-controller-api/src/lib.rs index 6790dec75d..afc1f4de28 100644 --- a/swap-controller-api/src/lib.rs +++ b/swap-controller-api/src/lib.rs @@ -64,10 +64,22 @@ pub struct RegistrationStatusResponse { pub registrations: Vec, } +// TODO: we should not need both this and asb::SwapDetails #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Swap { - pub id: String, + pub swap_id: String, + pub start_date: String, pub state: String, + pub btc_lock_txid: String, + #[serde(with = "bitcoin::amount::serde::as_sat")] + pub btc_amount: bitcoin::Amount, + /// Monero amount in piconero + pub xmr_amount: u64, + /// Exchange rate: BTC per XMR (amount of BTC needed to buy 1 XMR) + #[serde(with = "bitcoin::amount::serde::as_sat")] + pub exchange_rate: bitcoin::Amount, + pub peer_id: String, + pub completed: bool, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index 9f697acfcb..042b0b6b9e 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -1,11 +1,9 @@ mod cli; mod repl; -mod util; use clap::Parser; use cli::{Cli, Cmd}; use swap_controller_api::{AsbApiClient, MoneroSeedResponse}; -use util::ToTable; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -79,15 +77,38 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { Cmd::GetSwaps => { let swaps = client.get_swaps().await?; - // Create a table containing the swap id and state - let mut table = swaps.iter().map(|swap| (&swap.id, &swap.state)).to_table(); + let mut table = comfy_table::Table::new(); + table.set_header([ + "ID", + "Started", + "State", + "BTC Lock TxID", + "BTC", + "XMR", + "Rate (BTC/XMR)", + "Peer ID", + "Completed", + ]); if swaps.is_empty() { table.add_row(["No swaps found"]); + } else { + for swap in &swaps { + let xmr = monero::Amount::from_pico(swap.xmr_amount); + table.add_row([ + &swap.swap_id, + &swap.start_date, + &swap.state, + &swap.btc_lock_txid, + &swap.btc_amount.to_string(), + &format!("{:.12} XMR", xmr.as_xmr()), + &swap.exchange_rate.to_string(), + &swap.peer_id, + &swap.completed.to_string(), + ]); + } } - table.set_header(["ID", "State"]); - println!("{table}"); } Cmd::BitcoinSeed => { diff --git a/swap-controller/src/util.rs b/swap-controller/src/util.rs deleted file mode 100644 index c7838ee157..0000000000 --- a/swap-controller/src/util.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Utilities for easily generating tables. - -use comfy_table::Table; -use std::fmt::Display; - -pub trait ToTable { - fn to_table(self) -> Table; -} - -trait TupleToRow { - fn to_row(self) -> Vec; -} - -impl TupleToRow for (A,) { - fn to_row(self) -> Vec { - vec![self.0.to_string()] - } -} - -impl TupleToRow for (A, B) { - fn to_row(self) -> Vec { - vec![self.0.to_string(), self.1.to_string()] - } -} - -impl TupleToRow for (A, B, C) { - fn to_row(self) -> Vec { - vec![self.0.to_string(), self.1.to_string(), self.2.to_string()] - } -} - -impl ToTable for I -where - I: IntoIterator, -{ - fn to_table(self) -> Table { - let mut table = Table::new(); - for item in self { - table.add_row(item.to_row()); - } - table - } -} diff --git a/swap-core/src/bitcoin/cancel.rs b/swap-core/src/bitcoin/cancel.rs index 3dbb892c31..a84d8e65e7 100644 --- a/swap-core/src/bitcoin/cancel.rs +++ b/swap-core/src/bitcoin/cancel.rs @@ -2,14 +2,14 @@ use crate::bitcoin::{self, CancelTimelock, PunishTimelock}; use crate::bitcoin::{ - build_shared_output_descriptor, Address, Amount, PublicKey, Transaction, TxLock, + Address, Amount, PublicKey, Transaction, TxLock, build_shared_output_descriptor, }; +use ::bitcoin::Weight; use ::bitcoin::sighash::SighashCache; use ::bitcoin::transaction::Version; -use ::bitcoin::Weight; use ::bitcoin::{ - locktime::absolute::LockTime as PackedLockTime, secp256k1, sighash::SegwitV0Sighash as Sighash, EcdsaSighashType, OutPoint, ScriptBuf, Sequence, TxIn, TxOut, Txid, + locktime::absolute::LockTime as PackedLockTime, secp256k1, sighash::SegwitV0Sighash as Sighash, }; use anyhow::Result; use bdk_wallet::miniscript::Descriptor; @@ -209,6 +209,7 @@ impl TxCancel { witness: Default::default(), }; + assert!(self.amount() > (amnesty_amount + spending_fee)); let refund_amount = self.amount() - amnesty_amount - spending_fee; let tx_out_refund = TxOut { diff --git a/swap-core/src/bitcoin/final_amnesty.rs b/swap-core/src/bitcoin/final_amnesty.rs index dc6f3e1734..98b99674d7 100644 --- a/swap-core/src/bitcoin/final_amnesty.rs +++ b/swap-core/src/bitcoin/final_amnesty.rs @@ -40,10 +40,7 @@ impl TxFinalAmnesty { tx_refund_burn.amount() ); - let tx_final_amnesty = tx_refund_burn.build_spend_transaction( - refund_address, - spending_fee, - ); + let tx_final_amnesty = tx_refund_burn.build_spend_transaction(refund_address, spending_fee); let digest = SighashCache::new(&tx_final_amnesty) .p2wsh_signature_hash( @@ -132,6 +129,7 @@ impl TxFinalAmnesty { Ok(tx) } + // TODO: calculate actual weight pub fn weight() -> Weight { Weight::from_wu(548) } diff --git a/swap-core/src/bitcoin/refund_burn.rs b/swap-core/src/bitcoin/refund_burn.rs index 844dbb0434..bcc577ad63 100644 --- a/swap-core/src/bitcoin/refund_burn.rs +++ b/swap-core/src/bitcoin/refund_burn.rs @@ -1,7 +1,9 @@ #![allow(non_snake_case)] use crate::bitcoin::partial_refund::TxPartialRefund; -use crate::bitcoin::{self, build_shared_output_descriptor, Address, Amount, PublicKey, Transaction}; +use crate::bitcoin::{ + self, Address, Amount, PublicKey, Transaction, build_shared_output_descriptor, +}; use ::bitcoin::sighash::SighashCache; use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; use ::bitcoin::{OutPoint, ScriptBuf, Weight, secp256k1}; @@ -45,10 +47,8 @@ impl TxRefundBurn { let burn_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; - let tx_refund_burn = tx_partial_refund.build_burn_spend_transaction( - &burn_output_descriptor, - spending_fee, - ); + let tx_refund_burn = + tx_partial_refund.build_burn_spend_transaction(&burn_output_descriptor, spending_fee); let digest = SighashCache::new(&tx_refund_burn) .p2wsh_signature_hash( @@ -189,6 +189,7 @@ impl TxRefundBurn { } } + // TODO: calculate actual weight pub fn weight() -> Weight { Weight::from_wu(548) } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 30291b18de..8e6894d9c6 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -601,6 +601,7 @@ pub struct State3 { pub btc_amnesty_amount: Option, pub cancel_timelock: CancelTimelock, pub punish_timelock: PunishTimelock, + #[serde(default)] remaining_refund_timelock: Option, #[serde(with = "swap_serde::bitcoin::address_serde")] refund_address: bitcoin::Address, @@ -631,7 +632,9 @@ pub struct State3 { tx_redeem_fee: bitcoin::Amount, pub tx_punish_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, + #[serde(default)] pub tx_partial_refund_fee: Option, + #[serde(default)] pub tx_refund_amnesty_fee: Option, pub tx_cancel_fee: bitcoin::Amount, } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 6ced6bd2d0..094112dc6a 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -169,6 +169,26 @@ pub trait Database { async fn get_state(&self, swap_id: Uuid) -> Result; async fn get_states(&self, swap_id: Uuid) -> Result>; async fn all(&self) -> Result>; + + /// Returns the current (latest) state and the starting state for a swap. + async fn get_current_and_starting_state(&self, swap_id: Uuid) -> Result<(State, State)> { + use anyhow::Context; + + let states = self + .get_states(swap_id) + .await + .context("Error fetching all states of swap from database")?; + let starting = states.first().cloned().context("No states found")?; + let current = states.last().cloned().context("No states found")?; + + // Sanity check: both states must be from the same role + match (¤t, &starting) { + (State::Alice(_), State::Alice(_)) | (State::Bob(_), State::Bob(_)) => {} + _ => anyhow::bail!("Current and starting states have mismatched roles"), + } + + Ok((current, starting)) + } async fn insert_buffered_transfer_proof( &self, swap_id: Uuid, diff --git a/swap/src/asb/rpc/server.rs b/swap/src/asb/rpc/server.rs index 31cf5b5a45..402ff7f58c 100644 --- a/swap/src/asb/rpc/server.rs +++ b/swap/src/asb/rpc/server.rs @@ -154,24 +154,58 @@ impl AsbApiServer for RpcImpl { } async fn get_swaps(&self) -> Result, ErrorObjectOwned> { - let swaps = self.db.all().await.into_json_rpc_result()?; + use crate::protocol::alice::{is_complete, AliceState}; + use crate::protocol::State; - let swaps = swaps - .into_iter() - .map(|(swap_id, state)| { - let state_str = match state { - crate::protocol::State::Alice(state) => format!("{state}"), - crate::protocol::State::Bob(state) => format!("{state}"), - }; - - Swap { - id: swap_id.to_string(), - state: state_str, - } - }) - .collect(); - - Ok(swaps) + let swaps = self + .db + .all() + .await + .context("Error fetching all swap's from database") + .into_json_rpc_result()?; + let mut results = Vec::with_capacity(swaps.len()); + + for (swap_id, _) in swaps { + let (current, starting) = self + .db + .get_current_and_starting_state(swap_id) + .await + .context("Error fetching current and first state from database") + .into_json_rpc_result()?; + + let (State::Alice(current_alice), State::Alice(AliceState::Started { state3 })) = + (current, starting) + else { + continue; // Skip non-Alice swaps + }; + + let start_date = self + .db + .get_swap_start_date(swap_id) + .await + .into_json_rpc_result()?; + let peer_id = self.db.get_peer_id(swap_id).await.into_json_rpc_result()?; + + // Exchange rate: BTC per XMR (amount of BTC needed to buy 1 XMR) + let rate_btc_per_xmr = state3.btc.to_btc() / state3.xmr.as_xmr(); + let exchange_rate = bitcoin::Amount::from_btc(rate_btc_per_xmr) + .context("exchange rate should be valid") + .into_json_rpc_result()?; + + results.push(Swap { + swap_id: swap_id.to_string(), + start_date, + state: current_alice.to_string(), + btc_lock_txid: state3.tx_lock.txid().to_string(), + btc_amount: state3.btc, + xmr_amount: state3.xmr.as_piconero(), + exchange_rate, + peer_id: peer_id.to_string(), + completed: is_complete(¤t_alice), + }); + } + + Ok(results) } async fn registration_status(&self) -> Result { diff --git a/swap/src/database/sqlite.rs b/swap/src/database/sqlite.rs index 421863349f..28a4f2f26d 100644 --- a/swap/src/database/sqlite.rs +++ b/swap/src/database/sqlite.rs @@ -411,18 +411,29 @@ impl Database for SqliteDatabase { let result = rows .iter() - .map(|row| { + .filter_map(|row| { let state_str: &str = &row.state; - let state = match serde_json::from_str::(state_str) { - Ok(a) => Ok(State::from(a)), - Err(e) => Err(e), - }?; - Ok(state) + match serde_json::from_str::(state_str) { + Ok(a) => { + // debugging + if swap_id.to_string().as_str() == "ef5435d3-bb7d-4b3a-a83b-42f2b9f7ca4b" { + tracing::info!("Managed to deserialize swap: {a}") + } + Some(State::from(a)) + } + Err(e) => { + // debugging + if swap_id.to_string().as_str() == "ef5435d3-bb7d-4b3a-a83b-42f2b9f7ca4b" { + tracing::error!(error=%e, "Failed to deserialize swap") + } + None + } + } }) - .collect::>>(); + .collect::>(); - result + Ok(result) } async fn insert_buffered_transfer_proof( From db2343f9a8e23dd719a6adbb1275156294b2e5e2 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 19 Dec 2025 13:08:32 +0100 Subject: [PATCH 072/146] swap-setup(alice+bob): only construct TxRefundAmnesty/TxRefundBurn/TxFinalAmnesty when the amnsty output is greater than zero --- swap-core/src/bitcoin/partial_refund.rs | 12 +- swap-core/src/bitcoin/refund_amnesty.rs | 18 ++- swap-machine/src/alice/mod.rs | 125 +++++++++++---- swap-machine/src/bob/mod.rs | 199 ++++++++++++++---------- swap-machine/src/common/mod.rs | 17 +- 5 files changed, 232 insertions(+), 139 deletions(-) diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 80ffe2806c..40406ee776 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -89,7 +89,7 @@ impl TxPartialRefund { refund_address: &Address, spending_fee: Amount, remaining_refund_timelock: RemainingRefundTimelock, - ) -> Transaction { + ) -> Result { use ::bitcoin::{ Sequence, TxIn, TxOut, locktime::absolute::LockTime as PackedLockTime, transaction::Version, @@ -103,16 +103,19 @@ impl TxPartialRefund { }; let tx_out = TxOut { - value: self.amnesty_amount() - spending_fee, + value: self + .amnesty_amount() + .checked_sub(spending_fee) + .context("btc amnesty amount is less than spending fee")?, script_pubkey: refund_address.script_pubkey(), }; - Transaction { + Ok(Transaction { version: Version(2), lock_time: PackedLockTime::from_height(0).expect("0 to be below lock time threshold"), input: vec![tx_in], output: vec![tx_out], - } + }) } /// Build a transaction that spends the amnesty output to a new 2-of-2 multisig (burn output). @@ -252,6 +255,7 @@ impl TxPartialRefund { Ok(sig) } + // TODO: calculate actual weight pub fn weight() -> Weight { Weight::from_wu(548) } diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/refund_amnesty.rs index 6fb130476e..c6e726ecfa 100644 --- a/swap-core/src/bitcoin/refund_amnesty.rs +++ b/swap-core/src/bitcoin/refund_amnesty.rs @@ -25,12 +25,14 @@ impl TxRefundAmnesty { refund_address: &Address, spending_fee: Amount, remaining_refund_timelock: RemainingRefundTimelock, - ) -> Self { - let tx_refund_amnesty = tx_refund.build_amnesty_spend_transaction( - refund_address, - spending_fee, - remaining_refund_timelock, - ); + ) -> Result { + let tx_refund_amnesty = tx_refund + .build_amnesty_spend_transaction( + refund_address, + spending_fee, + remaining_refund_timelock, + ) + .context("Couldn't build tx refund amnesty")?; let digest = SighashCache::new(&tx_refund_amnesty) .p2wsh_signature_hash( @@ -44,12 +46,12 @@ impl TxRefundAmnesty { ) .expect("sighash"); - Self { + Ok(Self { inner: tx_refund_amnesty, digest, amensty_output_descriptor: tx_refund.amnesty_output_descriptor.clone(), watch_script: refund_address.script_pubkey(), - } + }) } pub fn txid(&self) -> Txid { diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 8e6894d9c6..a4c8b6df22 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -410,6 +410,24 @@ impl State2 { ) .expect("valid cancel tx"); + let tx_cancel_sig = self.a.sign(tx_cancel.digest()); + + // When the amnesty output is zero, we can't construct the tx partial refund transaction + // due to an integer underflow. + // We only send the cancel and full refund signatures. + if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { + let tx_full_refund = + TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_full_refund.digest()); + + return Ok(Message3 { + tx_cancel_sig, + tx_partial_refund_encsig: None, + tx_full_refund_encsig: Some(tx_refund_encsig), + tx_refund_amnesty_sig: None, + }); + } + let tx_partial_refund = swap_core::bitcoin::TxPartialRefund::new( &tx_cancel, &self.refund_address, @@ -424,9 +442,7 @@ impl State2 { // tx_lock_bitcoin to Bob's refund address (except for the amnesty output). // recover(encsign(a, S_b, d), sign(a, d), S_b) = s_b where d is a digest, (a, // A) is alice's keypair and (s_b, S_b) is bob's keypair. - let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); - - let tx_cancel_sig = self.a.sign(tx_cancel.digest()); + let tx_partial_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); // Construct and sign TxRefundAmnesty let tx_refund_amnesty = swap_core::bitcoin::TxRefundAmnesty::new( @@ -436,24 +452,14 @@ impl State2 { .context("Missing tx_refund_amnesty_fee for new swap")?, self.remaining_refund_timelock .context("Missing remaining_refund_timelock for new swap")?, - ); + )?; let tx_refund_amnesty_sig = self.a.sign(tx_refund_amnesty.digest()); - // Send full refund encsig when btc_amnesty_amount is None or ZERO (ratio = 1.0) - let tx_full_refund = - TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); - let tx_full_refund_encsig = - if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { - Some(self.a.encsign(self.S_b_bitcoin, tx_full_refund.digest())) - } else { - None - }; - Ok(Message3 { tx_cancel_sig, - tx_partial_refund_encsig: tx_refund_encsig, - tx_full_refund_encsig, - tx_refund_amnesty_sig, + tx_partial_refund_encsig: Some(tx_partial_refund_encsig), + tx_refund_amnesty_sig: Some(tx_refund_amnesty_sig), + tx_full_refund_encsig: None, }) } @@ -498,6 +504,45 @@ impl State2 { ) .context("Failed to verify early refund transaction")?; + // When the bitcoin amnesty amount is zero, we can't construct the transactions for the partial refund path. + // We sent Bob the encsig for the full refund path already, so we don't + // care about the partial refund path signatures of Bob anyway. + // We just save `None`. + if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { + return Ok(State3 { + a: self.a, + B: self.B, + s_a: self.s_a, + S_b_monero: self.S_b_monero, + S_b_bitcoin: self.S_b_bitcoin, + v: self.v, + btc: self.btc, + xmr: self.xmr, + btc_amnesty_amount: self.btc_amnesty_amount, + cancel_timelock: self.cancel_timelock, + punish_timelock: self.punish_timelock, + remaining_refund_timelock: self.remaining_refund_timelock, + refund_address: self.refund_address, + redeem_address: self.redeem_address, + punish_address: self.punish_address, + tx_lock: self.tx_lock, + tx_punish_sig_bob: msg.tx_punish_sig, + tx_cancel_sig_bob: msg.tx_cancel_sig, + tx_early_refund_sig_bob: msg.tx_early_refund_sig.into(), + tx_refund_amnesty_sig_bob: None, + tx_redeem_fee: self.tx_redeem_fee, + tx_punish_fee: self.tx_punish_fee, + tx_refund_fee: self.tx_refund_fee, + tx_partial_refund_fee: self.tx_partial_refund_fee, + tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_cancel_fee: self.tx_cancel_fee, + tx_refund_burn_sig_bob: None, + tx_final_amnesty_sig_bob: None, + }); + } + // Create TxRefundAmnesty ourself let tx_partial_refund = TxPartialRefund::new( &tx_cancel, @@ -517,15 +562,15 @@ impl State2 { .context("missing tx_refund_amnesty_fee")?, self.remaining_refund_timelock .context("missing remaining_refund_timelock")?, - ); + )?; // Check if the provided signature by Bob is valid for the transaction - swap_core::bitcoin::verify_sig( - &self.B, - &tx_refund_amnesty.digest(), - &msg.tx_refund_amnesty_sig, - ) - .context("Failed to verify refund amnesty transaction")?; + let tx_refund_amnesty_sig = msg + .tx_refund_amnesty_sig + .as_ref() + .context("Missing tx_refund_amnesty_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig) + .context("Failed to verify refund amnesty transaction")?; // Create TxRefundBurn ourself let tx_refund_burn = TxRefundBurn::new( @@ -537,7 +582,11 @@ impl State2 { )?; // Check if the provided signature by Bob is valid for the transaction - swap_core::bitcoin::verify_sig(&self.B, &tx_refund_burn.digest(), &msg.tx_refund_burn_sig) + let tx_refund_burn_sig = msg + .tx_refund_burn_sig + .as_ref() + .context("Missing tx_refund_burn_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_refund_burn.digest(), tx_refund_burn_sig) .context("Failed to verify refund burn transaction")?; // Create TxFinalAmnesty ourself @@ -549,12 +598,12 @@ impl State2 { ); // Check if the provided signature by Bob is valid for the transaction - swap_core::bitcoin::verify_sig( - &self.B, - &tx_final_amnesty.digest(), - &msg.tx_final_amnesty_sig, - ) - .context("Failed to verify final amnesty transaction")?; + let tx_final_amnesty_sig = msg + .tx_final_amnesty_sig + .as_ref() + .context("Missing tx_final_amnesty_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_final_amnesty.digest(), tx_final_amnesty_sig) + .context("Failed to verify final amnesty transaction")?; Ok(State3 { a: self.a, @@ -582,7 +631,11 @@ impl State2 { tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, + tx_refund_burn_fee: self.tx_refund_burn_fee, + tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, + tx_refund_burn_sig_bob: msg.tx_refund_burn_sig, + tx_final_amnesty_sig_bob: msg.tx_final_amnesty_sig, }) } } @@ -636,7 +689,15 @@ pub struct State3 { pub tx_partial_refund_fee: Option, #[serde(default)] pub tx_refund_amnesty_fee: Option, + #[serde(default)] + pub tx_refund_burn_fee: Option, + #[serde(default)] + pub tx_final_amnesty_fee: Option, pub tx_cancel_fee: bitcoin::Amount, + #[serde(default)] + tx_refund_burn_sig_bob: Option, + #[serde(default)] + tx_final_amnesty_sig_bob: Option, } impl State3 { @@ -805,7 +866,7 @@ impl State3 { .context("Missing tx_refund_amnesty_fee")?, self.remaining_refund_timelock .context("Missing remaining_refund_timelock")?, - ); + )?; tx_amnesty.complete_as_alice( self.a.clone(), diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index a5a8745a5f..1496a14487 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -15,8 +15,8 @@ use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ self, CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, - TxCancel, TxFinalAmnesty, TxLock, TxPartialRefund, TxRefundAmnesty, TxRefundBurn, Txid, - current_epoch, + TxCancel, TxFinalAmnesty, TxFullRefund, TxLock, TxPartialRefund, TxRefundAmnesty, TxRefundBurn, + Txid, current_epoch, }; use swap_core::compat::IntoDalekNg; use swap_core::monero; @@ -477,53 +477,67 @@ impl State1 { self.tx_cancel_fee, )?; - let tx_partial_refund = bitcoin::TxPartialRefund::new( - &tx_cancel, - &self.refund_address, - self.A, - self.b.public(), - self.btc_amnesty_amount - .context("btc_amnesty_amount is missing but required to create TxPartialRefund")?, - self.tx_partial_refund_fee - .context("tx_partial_refund_fee missing but required to setup swap")?, - )?; - - bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; - bitcoin::verify_encsig( - self.A, - bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), - &tx_partial_refund.digest(), - &msg.tx_partial_refund_encsig, - )?; + // Depending on which signatures we get, verify and store them + let refund_signatures = match ( + msg.tx_full_refund_encsig, + msg.tx_partial_refund_encsig, + msg.tx_refund_amnesty_sig, + ) { + // We got the encrypted signature for the full refund - awesome + (Some(tx_full_refund_encsig), _, _) => { + let tx_full_refund = + TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); + bitcoin::verify_encsig( + self.A, + bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), + &tx_full_refund.digest(), + &tx_full_refund_encsig, + ) + .context("Couldn't verify Alice's signature on TxFullRefund")?; + + RefundSignatures::Legacy { + tx_full_refund_encsig, + } + } + // We got the encrypted signatures for the partial refund path. + (None, Some(tx_partial_refund_encsig), Some(tx_refund_amnesty_sig)) => { + let tx_partial_refund = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + self.btc_amnesty_amount + .context("Missing btc_amnesty_amount")?, + self.tx_partial_refund_fee + .context("Missing tx_partial_refund_fee")?, + )?; + bitcoin::verify_encsig( + self.A, + bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), + &tx_partial_refund.digest(), + &tx_partial_refund_encsig, + )?; - // Verify the full refund signature if it is present - if let Some(tx_full_refund_encsig) = &msg.tx_full_refund_encsig { - let tx_full_refund = - bitcoin::TxFullRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee); - bitcoin::verify_encsig( - self.A, - bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()), - &tx_full_refund.digest(), - tx_full_refund_encsig, - )?; - } + let tx_refund_amnesty = TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("missing tx_refund_amnesty_fee")?, + self.remaining_refund_timelock + .context("missing remaining_refund_timelock")?, + )?; + bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), &tx_refund_amnesty_sig)?; - // Verify the refund amnesty signature (always provided in new swaps) - let tx_refund_amnesty = bitcoin::TxRefundAmnesty::new( - &tx_partial_refund, - &self.refund_address, - self.tx_refund_amnesty_fee - .context("tx_refund_amnesty_fee missing but required to setup swap")?, - self.remaining_refund_timelock - .context("remaining_refund_timelock missing but required to setup swap")?, - ); - bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), &msg.tx_refund_amnesty_sig)?; + RefundSignatures::Partial { + tx_partial_refund_encsig, + tx_refund_amnesty_sig, + } + } + (_, _, _) => anyhow::bail!( + "Alice sent us neither TxFullRefund encsig nor signatures for the partial refund path" + ), + }; - let refund_signatures = RefundSignatures::from_possibly_full_refund_sig( - msg.tx_partial_refund_encsig, - msg.tx_full_refund_encsig, - msg.tx_refund_amnesty_sig, - ); Ok(State2 { A: self.A, b: self.b, @@ -618,43 +632,57 @@ impl State2 { let tx_early_refund_sig = self.b.sign(tx_early_refund.digest()); - let tx_partial_refund = TxPartialRefund::new( - &tx_cancel, - &self.refund_address, - self.A, - self.b.public(), - self.btc_amnesty_amount - .context("missing btc_amnesty_amount")?, - self.tx_partial_refund_fee - .context("missing tx_partial_refund_fee")?, - ) - .context("Couldn't construct TxPartialRefund")?; - let tx_refund_amnesty = TxRefundAmnesty::new( - &tx_partial_refund, - &self.refund_address, - self.tx_refund_amnesty_fee - .context("Missing tx_refund_amnesty_fee")?, - self.remaining_refund_timelock - .context("missing remaining_refund_timelock")?, - ); - let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); + // We can only construct a valid TxRefundAmnesty/TxRefundBurn/TxFinalAmnesty when the amnesty amount + // is greater than zero. Thus we only send our signatures for them if that is the case. + // Alice accepts this because she sent us her signature for TxFullRefund already anyway. + let (tx_refund_amnesty_sig, tx_refund_burn_sig, tx_final_amnesty_sig) = + if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { + (None, None, None) + } else { + let tx_partial_refund = TxPartialRefund::new( + &tx_cancel, + &self.refund_address, + self.A, + self.b.public(), + self.btc_amnesty_amount + .context("missing btc_amnesty_amount")?, + self.tx_partial_refund_fee + .context("missing tx_partial_refund_fee")?, + ) + .context("Couldn't construct TxPartialRefund")?; + let tx_refund_amnesty = TxRefundAmnesty::new( + &tx_partial_refund, + &self.refund_address, + self.tx_refund_amnesty_fee + .context("Missing tx_refund_amnesty_fee")?, + self.remaining_refund_timelock + .context("missing remaining_refund_timelock")?, + )?; + let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); - let tx_refund_burn = TxRefundBurn::new( - &tx_partial_refund, - self.A, - self.b.public(), - self.tx_refund_burn_fee - .context("Missing tx_refund_burn_fee")?, - )?; - let tx_refund_burn_sig = self.b.sign(tx_refund_burn.digest()); + let tx_refund_burn = TxRefundBurn::new( + &tx_partial_refund, + self.A, + self.b.public(), + self.tx_refund_burn_fee + .context("Missing tx_refund_burn_fee")?, + )?; + let tx_refund_burn_sig = self.b.sign(tx_refund_burn.digest()); - let tx_final_amnesty = TxFinalAmnesty::new( - &tx_refund_burn, - &self.refund_address, - self.tx_final_amnesty_fee - .context("Missing tx_final_amnesty_fee")?, - ); - let tx_final_amnesty_sig = self.b.sign(tx_final_amnesty.digest()); + let tx_final_amnesty = TxFinalAmnesty::new( + &tx_refund_burn, + &self.refund_address, + self.tx_final_amnesty_fee + .context("Missing tx_final_amnesty_fee")?, + ); + let tx_final_amnesty_sig = self.b.sign(tx_final_amnesty.digest()); + + ( + Some(tx_refund_amnesty_sig), + Some(tx_refund_burn_sig), + Some(tx_final_amnesty_sig), + ) + }; Ok(Message4 { tx_punish_sig, @@ -1295,7 +1323,7 @@ impl State6 { pub fn construct_tx_amnesty(&self) -> Result { let tx_partial_refund = self.construct_tx_partial_refund()?; - Ok(bitcoin::TxRefundAmnesty::new( + bitcoin::TxRefundAmnesty::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee.context( @@ -1304,7 +1332,7 @@ impl State6 { self.remaining_refund_timelock.context( "Can't construct TxRefundAmnesty because remaining_refund_timelock is missing", )?, - )) + ) } pub fn construct_tx_refund_burn(&self) -> Result { @@ -1313,9 +1341,8 @@ impl State6 { &tx_partial_refund, self.A, self.b.public(), - self.tx_refund_burn_fee.context( - "Can't construct TxRefundBurn because tx_refund_burn_fee is missing", - )?, + self.tx_refund_burn_fee + .context("Can't construct TxRefundBurn because tx_refund_burn_fee is missing")?, ) } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 094112dc6a..be359dc835 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -72,13 +72,12 @@ pub struct Message2 { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Message3 { pub tx_cancel_sig: bitcoin::Signature, - /// The following fields were reworked in [#675](https://github.com/eigenwallet/core/pull/675). - /// Alice _may_ choose to commit to a full refund for bob during the swap setup already, but doesn't - /// have to. - pub tx_partial_refund_encsig: bitcoin::EncryptedSignature, + // The following fields were reworked in [#675](https://github.com/eigenwallet/core/pull/675). + // Alice will send either the full refund encsig or signatures for both partial refund + // and tx refund amnesty. pub tx_full_refund_encsig: Option, - /// Alice's signature for the amnesty transaction - always provided. - pub tx_refund_amnesty_sig: bitcoin::Signature, + pub tx_partial_refund_encsig: Option, + pub tx_refund_amnesty_sig: Option, } #[allow(non_snake_case)] @@ -87,9 +86,9 @@ pub struct Message4 { pub tx_punish_sig: bitcoin::Signature, pub tx_cancel_sig: bitcoin::Signature, pub tx_early_refund_sig: bitcoin::Signature, - pub tx_refund_amnesty_sig: bitcoin::Signature, - pub tx_refund_burn_sig: bitcoin::Signature, - pub tx_final_amnesty_sig: bitcoin::Signature, + pub tx_refund_amnesty_sig: Option, + pub tx_refund_burn_sig: Option, + pub tx_final_amnesty_sig: Option, } #[allow(clippy::large_enum_variant)] From 5c2261d8e93c1ef4f43a316ccb68765508d35914 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 19 Dec 2025 13:39:18 +0100 Subject: [PATCH 073/146] just command for listing docker tests --- justfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/justfile b/justfile index 8621457913..e9f7279a79 100644 --- a/justfile +++ b/justfile @@ -60,6 +60,10 @@ build-gui-windows: tests: cargo nextest run +# List all available docker integration tests +list-docker-tests: + @find swap/tests -maxdepth 1 -type f -name "*.rs" | xargs -n1 basename | sed 's/\.rs$//' | sort + # Run docker tests (e.g., "just docker_test happy_path_alice_developer_tip") docker_test test_name: RUST_BACKTRACE=1 cargo test --package swap --test {{test_name}} -- --nocapture From cdd260ec6768a53aefe7abbe105a7e62ef21e05f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 26 Dec 2025 17:44:29 +0100 Subject: [PATCH 074/146] store should_publish_tx_refund_burn in alice states --- swap-machine/src/alice/mod.rs | 15 +++++++++++++++ swap-machine/src/lib.rs | 4 ++++ swap-p2p/src/out_event/alice.rs | 2 +- swap-p2p/src/protocols/swap_setup/alice.rs | 20 ++++++++++---------- swap/src/asb/event_loop.rs | 19 ++++++++++++++----- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index a4c8b6df22..872f76c2aa 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -177,6 +177,7 @@ pub struct State0 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_burn_fee: Option, + should_publish_tx_refund_burn: Option, } impl State0 { @@ -191,6 +192,7 @@ impl State0 { tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, tx_refund_burn_fee: bitcoin::Amount, + should_publish_tx_refund_burn: bool, rng: &mut R, ) -> Self where @@ -223,6 +225,7 @@ impl State0 { tx_redeem_fee, tx_punish_fee, tx_refund_burn_fee: Some(tx_refund_burn_fee), + should_publish_tx_refund_burn: Some(should_publish_tx_refund_burn), } } @@ -274,6 +277,7 @@ impl State0 { tx_refund_burn_fee: self.tx_refund_burn_fee, tx_final_amnesty_fee: Some(msg.tx_final_amnesty_fee), tx_cancel_fee: msg.tx_cancel_fee, + should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, }, )) } @@ -309,6 +313,7 @@ pub struct State1 { tx_refund_burn_fee: Option, tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, + should_publish_tx_refund_burn: Option, } impl State1 { @@ -366,6 +371,7 @@ impl State1 { tx_refund_burn_fee: self.tx_refund_burn_fee, tx_final_amnesty_fee: self.tx_final_amnesty_fee, tx_cancel_fee: self.tx_cancel_fee, + should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, }) } } @@ -397,6 +403,7 @@ pub struct State2 { tx_refund_burn_fee: Option, tx_final_amnesty_fee: Option, tx_cancel_fee: bitcoin::Amount, + should_publish_tx_refund_burn: Option, } impl State2 { @@ -540,6 +547,7 @@ impl State2 { tx_cancel_fee: self.tx_cancel_fee, tx_refund_burn_sig_bob: None, tx_final_amnesty_sig_bob: None, + should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, }); } @@ -636,6 +644,7 @@ impl State2 { tx_cancel_fee: self.tx_cancel_fee, tx_refund_burn_sig_bob: msg.tx_refund_burn_sig, tx_final_amnesty_sig_bob: msg.tx_final_amnesty_sig, + should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, }) } } @@ -698,6 +707,12 @@ pub struct State3 { tx_refund_burn_sig_bob: Option, #[serde(default)] tx_final_amnesty_sig_bob: Option, + /// Whether Alice should publish TxRefundBurn to deny Bob's amnesty. + /// None = no decision yet (legacy swaps or awaiting controller input) + /// Some(false) = don't burn (default for new swaps) + /// Some(true) = burn the amnesty output + #[serde(default)] + pub should_publish_tx_refund_burn: Option, } impl State3 { diff --git a/swap-machine/src/lib.rs b/swap-machine/src/lib.rs index 64cf053733..484fa2dda1 100644 --- a/swap-machine/src/lib.rs +++ b/swap-machine/src/lib.rs @@ -28,6 +28,7 @@ mod tests { let spending_fee = Amount::from_sat(1_000); let btc_amount = Amount::from_sat(500_000); let btc_amnesty_amount = Amount::from_sat(100_000); + let should_publish_tx_refund = false; let xmr_amount = swap_core::monero::primitives::Amount::from_piconero(10000); let tx_redeem_fee = alice_wallet @@ -57,6 +58,7 @@ mod tests { tx_redeem_fee, tx_punish_fee, spending_fee, + should_publish_tx_refund, &mut OsRng, ); @@ -149,6 +151,7 @@ mod tests { let spending_fee = Amount::from_sat(1_000); let btc_amount = Amount::from_sat(500_000); let btc_amnesty_amount = Amount::from_sat(100_000); + let should_publish_tx_refund = false; let xmr_amount = swap_core::monero::primitives::Amount::from_piconero(10000); let tx_redeem_fee = alice_wallet @@ -174,6 +177,7 @@ mod tests { tx_redeem_fee, tx_punish_fee, spending_fee, + should_publish_tx_refund, &mut OsRng, ); diff --git a/swap-p2p/src/out_event/alice.rs b/swap-p2p/src/out_event/alice.rs index 8f769f8775..51642300a9 100644 --- a/swap-p2p/src/out_event/alice.rs +++ b/swap-p2p/src/out_event/alice.rs @@ -22,7 +22,7 @@ pub enum OutEvent { // should go into the amnesty output send_wallet_snapshot: bmrng::RequestReceiver< bitcoin::Amount, - (swap_setup::alice::WalletSnapshot, bitcoin::Amount), + (swap_setup::alice::WalletSnapshot, bitcoin::Amount, bool), >, }, SwapSetupCompleted { diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 159d0e958e..e96fd5192a 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -30,7 +30,7 @@ use uuid::Uuid; pub enum OutEvent { Initiated { send_wallet_snapshot: - bmrng::RequestReceiver, + bmrng::RequestReceiver, }, Completed { peer_id: PeerId, @@ -263,7 +263,7 @@ impl Handler { #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum HandlerOutEvent { - Initiated(bmrng::RequestReceiver), + Initiated(bmrng::RequestReceiver), Completed(Result<(Uuid, State3)>), } @@ -296,12 +296,11 @@ where ConnectionEvent::FullyNegotiatedInbound(substream) => { let substream = substream.protocol; - let (sender, receiver) = bmrng::channel_with_timeout::< - bitcoin::Amount, - (WalletSnapshot, bitcoin::Amount), - >( - 1, crate::defaults::SWAP_SETUP_CHANNEL_TIMEOUT - ); + let (sender, receiver) = + bmrng::channel_with_timeout::< + bitcoin::Amount, + (WalletSnapshot, bitcoin::Amount, bool), + >(1, crate::defaults::SWAP_SETUP_CHANNEL_TIMEOUT); let resume_only = self.resume_only; let min_buy = self.min_buy; @@ -447,7 +446,7 @@ impl Error { async fn run_swap_setup( mut substream: libp2p::swarm::Stream, - sender: bmrng::RequestSender, + sender: bmrng::RequestSender, resume_only: bool, env_config: env::Config, min_buy: bitcoin::Amount, @@ -458,7 +457,7 @@ async fn run_swap_setup( .await .context("Failed to read spot price request")?; - let (wallet_snapshot, btc_amnesty_amount) = sender + let (wallet_snapshot, btc_amnesty_amount, should_burn_on_refund) = sender .send_receive(request.btc) .await .context("Failed to receive wallet snapshot")?; @@ -546,6 +545,7 @@ async fn run_swap_setup( wallet_snapshot.redeem_fee, wallet_snapshot.punish_fee, wallet_snapshot.refund_burn_fee, + should_burn_on_refund, &mut rand::thread_rng(), ); diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 058099f05f..0f811ac600 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -13,6 +13,7 @@ use crate::protocol::alice::swap::has_already_processed_enc_sig; use crate::protocol::alice::{AliceState, State3, Swap, TipConfig}; use crate::protocol::{Database, State}; use anyhow::{anyhow, Context, Result}; +use bdk::bitcoin::hashes::sha1; use bitcoin_wallet::BitcoinWallet; use futures::future; use futures::future::{BoxFuture, FutureExt}; @@ -253,13 +254,14 @@ where }; // TODO: propagate error to the swap_setup routine instead of swallowing it - let btc_amnesty_amount = match apply_bitcoin_amnesty_policy(btc, &self.refund_policy) { + let (btc_amnesty_amount, should_publish_tx_refund_burn )= match apply_bitcoin_amnesty_policy(btc, &self.refund_policy) { Ok(amount) => amount, Err(error) => { tracing::error!("Swap request will be ignored because we were unable to create wallet snapshot for swap: {:#}", error); continue; } }; + let wallet_snapshot = match capture_wallet_snapshot(self.bitcoin_wallet.clone(), &self.monero_wallet, &self.external_redeem_address, btc).await { Ok(wallet_snapshot) => wallet_snapshot, Err(error) => { @@ -269,7 +271,7 @@ where }; // Ignore result, we should never hit this because the receiver will alive as long as the connection is. - let _ = responder.respond((wallet_snapshot, btc_amnesty_amount)); + let _ = responder.respond((wallet_snapshot, btc_amnesty_amount, should_publish_tx_refund_burn)); } SwarmEvent::Behaviour(OutEvent::SwapSetupCompleted{peer_id, swap_id, state3}) => { if let Err(error) = self.handle_execution_setup_done(peer_id, swap_id, state3).await { @@ -833,13 +835,17 @@ impl EventLoopHandle { /// For a new swap of `swap_amount`, this function calculates how much /// Bitcoin should go into the amnesty-lock incase of a refund. /// Returns ZERO when taker_refund_ratio is 1.0 (100%), indicating full refund. +/// Also returns whether or not to burn the the amnesty output if the taker refunds. fn apply_bitcoin_amnesty_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, -) -> Result { +) -> Result<(bitcoin::Amount, bool)> { + // TODO: decide this somehow + let should_burn_on_refund = false; + // When ratio is 1.0, no amnesty - use full refund path if refund_policy.taker_refund_ratio == Decimal::ONE { - return Ok(bitcoin::Amount::ZERO); + return Ok((bitcoin::Amount::ZERO, should_burn_on_refund)); } let btc_amnesty_ratio = Decimal::ONE @@ -858,7 +864,10 @@ fn apply_bitcoin_amnesty_policy( .try_into() .context("Couldn't convert Decimal to u64")?; - Ok(bitcoin::Amount::from_sat(btc_amnesty_sats)) + Ok(( + bitcoin::Amount::from_sat(btc_amnesty_sats), + should_burn_on_refund, + )) } async fn capture_wallet_snapshot( From a7e6d97cd18db1ebf08a2ac09f921f542c94ff61 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 27 Dec 2025 11:44:36 +0100 Subject: [PATCH 075/146] alice: add states BtcRefundBurn{Published, Confirmed} and BtcFinalAmnesty{Granted, Published, Confirmed} --- monero-harness/src/lib.rs | 3 +- monero-harness/tests/wallet.rs | 6 +- monero-tests/tests/reserve_proof.rs | 2 +- monero-tests/tests/transfers.rs | 2 +- monero-tests/tests/transfers_wrong_key.rs | 2 +- swap-db/src/alice.rs | 110 +++++++++++++++--- swap-env/src/config.rs | 6 + swap-machine/src/alice/mod.rs | 106 +++++++++++++++-- swap-machine/src/bob/mod.rs | 1 + swap/src/asb/event_loop.rs | 3 +- swap/src/asb/recovery/cancel.rs | 7 +- swap/src/asb/recovery/punish.rs | 7 +- swap/src/asb/recovery/redeem.rs | 7 +- swap/src/asb/recovery/refund.rs | 11 +- swap/src/asb/recovery/safely_abort.rs | 7 +- swap/src/protocol/alice/swap.rs | 75 +++++++++++- swap/tests/harness/mod.rs | 94 ++++++++++++++- .../partial_refund_bob_claims_amnesty.rs | 2 + 18 files changed, 402 insertions(+), 49 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index cdc65e4a65..364288e24c 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -306,7 +306,8 @@ impl<'c> Monero { Ok(()) } - pub async fn generate_block(&self) -> Result<()> { + /// Generates 15 blocks + pub async fn generate_blocks(&self) -> Result<()> { let miner_wallet = self.wallet("miner")?; let miner_address = miner_wallet.address().await?.to_string(); self.monerod() diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 6277b6af34..4487f33db5 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -53,7 +53,7 @@ async fn fund_transfer_and_check_tx_key() { .await .unwrap(); - monero.generate_block().await.unwrap(); + monero.generate_blocks().await.unwrap(); tracing::info!("Waiting for Bob to catch up"); @@ -69,7 +69,7 @@ async fn fund_transfer_and_check_tx_key() { .await .unwrap(); - monero.generate_block().await.unwrap(); + monero.generate_blocks().await.unwrap(); wait_for_wallet_to_catch_up(bob_wallet, 0).await; @@ -86,7 +86,7 @@ async fn fund_transfer_and_check_tx_key() { .await .unwrap(); - monero.generate_block().await.unwrap(); + monero.generate_blocks().await.unwrap(); wait_for_wallet_to_catch_up(alice_wallet, 0).await; diff --git a/monero-tests/tests/reserve_proof.rs b/monero-tests/tests/reserve_proof.rs index 9859bea378..9577f7fb89 100644 --- a/monero-tests/tests/reserve_proof.rs +++ b/monero-tests/tests/reserve_proof.rs @@ -31,7 +31,7 @@ async fn setup(cli: &Cli) -> anyhow::Result> { // Fund alice's wallet miner.sweep(&alice.address().await?).await?; - monero.generate_block().await?; + monero.generate_blocks().await?; alice.refresh().await?; let alice_balance = alice.balance().await?; diff --git a/monero-tests/tests/transfers.rs b/monero-tests/tests/transfers.rs index 27ebd938f2..77777fda3b 100644 --- a/monero-tests/tests/transfers.rs +++ b/monero-tests/tests/transfers.rs @@ -41,7 +41,7 @@ async fn monero_transfers() -> anyhow::Result<()> { "Expect one tx key for each non-change output" ); - monero.generate_block().await?; + monero.generate_blocks().await?; let alice_txkey = tx_receipt .tx_keys diff --git a/monero-tests/tests/transfers_wrong_key.rs b/monero-tests/tests/transfers_wrong_key.rs index 1c90878a4c..8b411fcd7e 100644 --- a/monero-tests/tests/transfers_wrong_key.rs +++ b/monero-tests/tests/transfers_wrong_key.rs @@ -40,7 +40,7 @@ async fn monero_transfers_wrong_key() { "Expect one tx key for the output" ); - monero.generate_block().await.unwrap(); + monero.generate_blocks().await.unwrap(); // Use a wrong private key (just a simple constant key, not the real transfer key) let wrong_key = monero::PrivateKey::from_slice(&[ diff --git a/swap-db/src/alice.rs b/swap-db/src/alice.rs index 4d3c6cb57f..e3cc963c35 100644 --- a/swap-db/src/alice.rs +++ b/swap-db/src/alice.rs @@ -96,7 +96,10 @@ pub enum Alice { pub enum AliceEndState { SafelyAborted, BtcRedeemed, - XmrRefunded, + XmrRefunded { + #[serde(default)] + state3: Option, + }, BtcEarlyRefunded { state3: alice::State3, }, @@ -104,19 +107,34 @@ pub enum AliceEndState { state3: alice::State3, transfer_proof: TransferProof, }, + BtcRefundBurnPublished { + state3: alice::State3, + }, + BtcRefundBurnConfirmed { + state3: alice::State3, + }, + BtcFinalAmnestyGranted { + state3: alice::State3, + }, + BtcRefundFinalAmnestyPublished { + state3: alice::State3, + }, + BtcRefundFinalAmnestyConfirmed { + state3: alice::State3, + }, } impl From for Alice { fn from(alice_state: AliceState) -> Self { match alice_state { AliceState::Started { state3 } => Alice::Started { - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcLockTransactionSeen { state3 } => Alice::BtcLockTransactionSeen { - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcLocked { state3 } => Alice::BtcLocked { - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::XmrLockTransactionSent { monero_wallet_restore_blockheight, @@ -125,7 +143,7 @@ impl From for Alice { } => Alice::XmrLockTransactionSent { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::XmrLocked { monero_wallet_restore_blockheight, @@ -134,7 +152,7 @@ impl From for Alice { } => Alice::XmrLocked { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::XmrLockTransferProofSent { monero_wallet_restore_blockheight, @@ -143,7 +161,7 @@ impl From for Alice { } => Alice::XmrLockTransferProofSent { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::EncSigLearned { monero_wallet_restore_blockheight, @@ -153,14 +171,14 @@ impl From for Alice { } => Alice::EncSigLearned { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, encrypted_signature: encrypted_signature.as_ref().clone(), }, AliceState::BtcRedeemTransactionPublished { state3, transfer_proof, } => Alice::BtcRedeemTransactionPublished { - state3: state3.as_ref().clone(), + state3: *state3, transfer_proof, }, AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed), @@ -171,7 +189,7 @@ impl From for Alice { } => Alice::BtcCancelled { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcRefunded { monero_wallet_restore_blockheight, @@ -182,7 +200,7 @@ impl From for Alice { monero_wallet_restore_blockheight, transfer_proof, spend_key, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcPartiallyRefunded { monero_wallet_restore_blockheight, @@ -207,10 +225,10 @@ impl From for Alice { spend_key, }, AliceState::BtcEarlyRefundable { state3 } => Alice::BtcEarlyRefundable { - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcEarlyRefunded(state3) => Alice::Done(AliceEndState::BtcEarlyRefunded { - state3: state3.as_ref().clone(), + state3: *state3, }), AliceState::BtcPunishable { monero_wallet_restore_blockheight, @@ -219,9 +237,36 @@ impl From for Alice { } => Alice::BtcPunishable { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, - AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded), + AliceState::XmrRefunded { state3 } => Alice::Done(AliceEndState::XmrRefunded { + state3: state3.map(|s| s.as_ref().clone()), + }), + AliceState::BtcRefundBurnPublished { state3 } => { + Alice::Done(AliceEndState::BtcRefundBurnPublished { + state3: *state3, + }) + } + AliceState::BtcRefundBurnConfirmed { state3 } => { + Alice::Done(AliceEndState::BtcRefundBurnConfirmed { + state3: *state3, + }) + } + AliceState::BtcFinalAmnestyGranted { state3 } => { + Alice::Done(AliceEndState::BtcFinalAmnestyGranted { + state3: *state3, + }) + } + AliceState::BtcRefundFinalAmnestyPublished { state3 } => { + Alice::Done(AliceEndState::BtcRefundFinalAmnestyPublished { + state3: *state3, + }) + } + AliceState::BtcRefundFinalAmnestyConfirmed { state3 } => { + Alice::Done(AliceEndState::BtcRefundFinalAmnestyConfirmed { + state3: *state3, + }) + } AliceState::WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight, transfer_proof, @@ -229,7 +274,7 @@ impl From for Alice { } => Alice::WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::CancelTimelockExpired { monero_wallet_restore_blockheight, @@ -238,13 +283,13 @@ impl From for Alice { } => Alice::CancelTimelockExpired { monero_wallet_restore_blockheight, transfer_proof, - state3: state3.as_ref().clone(), + state3: *state3, }, AliceState::BtcPunished { state3, transfer_proof, } => Alice::Done(AliceEndState::BtcPunished { - state3: state3.as_ref().clone(), + state3: *state3, transfer_proof, }), AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted), @@ -384,7 +429,9 @@ impl From for AliceState { Alice::Done(end_state) => match end_state { AliceEndState::SafelyAborted => AliceState::SafelyAborted, AliceEndState::BtcRedeemed => AliceState::BtcRedeemed, - AliceEndState::XmrRefunded => AliceState::XmrRefunded, + AliceEndState::XmrRefunded { state3 } => AliceState::XmrRefunded { + state3: state3.map(Box::new), + }, AliceEndState::BtcPunished { state3, transfer_proof, @@ -395,6 +442,31 @@ impl From for AliceState { AliceEndState::BtcEarlyRefunded { state3 } => { AliceState::BtcEarlyRefunded(Box::new(state3)) } + AliceEndState::BtcRefundBurnPublished { state3 } => { + AliceState::BtcRefundBurnPublished { + state3: Box::new(state3), + } + } + AliceEndState::BtcRefundBurnConfirmed { state3 } => { + AliceState::BtcRefundBurnConfirmed { + state3: Box::new(state3), + } + } + AliceEndState::BtcFinalAmnestyGranted { state3 } => { + AliceState::BtcFinalAmnestyGranted { + state3: Box::new(state3), + } + } + AliceEndState::BtcRefundFinalAmnestyPublished { state3 } => { + AliceState::BtcRefundFinalAmnestyPublished { + state3: Box::new(state3), + } + } + AliceEndState::BtcRefundFinalAmnestyConfirmed { state3 } => { + AliceState::BtcRefundFinalAmnestyConfirmed { + state3: Box::new(state3), + } + } }, } } diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index 8a26691342..f1607a98a2 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -126,12 +126,18 @@ pub struct RefundPolicy { /// This protects the maker against griefing attacks. #[serde(default = "default_taker_refund_ratio")] pub taker_refund_ratio: Decimal, + /// If true, Alice will publish TxRefundBurn after refunding her XMR, + /// denying Bob access to the amnesty output. Alice can later grant + /// final amnesty to return the funds to Bob. + #[serde(default)] + pub burn_on_refund: bool, } impl Default for RefundPolicy { fn default() -> Self { Self { taker_refund_ratio: default_taker_refund_ratio(), + burn_on_refund: false, } } } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 872f76c2aa..fc61eea3e6 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -87,7 +87,26 @@ pub enum AliceState { state3: Box, }, // TODO: save redeem transaction id - XmrRefunded, + XmrRefunded { + state3: Option>, + }, + BtcRefundBurnPublished { + state3: Box, + }, + BtcRefundBurnConfirmed { + state3: Box, + }, + /// Operator has decided to grant final amnesty to Bob. + /// This state will publish TxFinalAmnesty and transition to BtcRefundFinalAmnestyPublished. + BtcFinalAmnestyGranted { + state3: Box, + }, + BtcRefundFinalAmnestyPublished { + state3: Box, + }, + BtcRefundFinalAmnestyConfirmed { + state3: Box, + }, WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight: BlockHeight, transfer_proof: TransferProof, @@ -111,14 +130,20 @@ pub enum AliceState { } pub fn is_complete(state: &AliceState) -> bool { - matches!( - state, - AliceState::XmrRefunded - | AliceState::BtcRedeemed - | AliceState::BtcPunished { .. } - | AliceState::SafelyAborted - | AliceState::BtcEarlyRefunded(_) - ) + match state { + // XmrRefunded is only complete if we don't need to publish TxRefundBurn + AliceState::XmrRefunded { state3 } => match state3 { + Some(s3) if s3.should_publish_tx_refund_burn == Some(true) => false, + _ => true, + }, + AliceState::BtcRedeemed + | AliceState::BtcPunished { .. } + | AliceState::SafelyAborted + | AliceState::BtcEarlyRefunded(_) + | AliceState::BtcRefundBurnConfirmed { .. } + | AliceState::BtcRefundFinalAmnestyConfirmed { .. } => true, + _ => false, + } } impl fmt::Display for AliceState { @@ -144,7 +169,16 @@ impl fmt::Display for AliceState { AliceState::BtcPunished { .. } => write!(f, "btc is punished"), AliceState::SafelyAborted => write!(f, "safely aborted"), AliceState::BtcPunishable { .. } => write!(f, "btc is punishable"), - AliceState::XmrRefunded => write!(f, "xmr is refunded"), + AliceState::XmrRefunded { .. } => write!(f, "xmr is refunded"), + AliceState::BtcRefundBurnPublished { .. } => write!(f, "btc refund burn published"), + AliceState::BtcRefundBurnConfirmed { .. } => write!(f, "btc refund burn confirmed"), + AliceState::BtcFinalAmnestyGranted { .. } => write!(f, "btc final amnesty granted"), + AliceState::BtcRefundFinalAmnestyPublished { .. } => { + write!(f, "btc final amnesty published") + } + AliceState::BtcRefundFinalAmnestyConfirmed { .. } => { + write!(f, "btc final amnesty confirmed") + } AliceState::WaitingForCancelTimelockExpiration { .. } => { write!(f, "waiting for cancel timelock expiration") } @@ -892,6 +926,58 @@ impl State3 { ) } + /// Check if we have Bob's signature for TxRefundBurn. + pub fn has_tx_refund_burn_sig(&self) -> bool { + self.tx_refund_burn_sig_bob.is_some() + } + + /// Construct TxRefundBurn from tx_partial_refund output. + pub fn tx_refund_burn(&self) -> Result { + TxRefundBurn::new( + &self.tx_partial_refund()?, + self.a.public(), + self.B, + self.tx_refund_burn_fee + .context("Missing tx_refund_burn_fee")?, + ) + } + + /// Construct signed TxRefundBurn using Alice's key and Bob's presigned signature. + pub fn signed_refund_burn_transaction(&self) -> Result { + let tx_refund_burn = self.tx_refund_burn()?; + + tx_refund_burn.complete_as_alice( + self.a.clone(), + self.B, + self.tx_refund_burn_sig_bob + .clone() + .context("missing Bob's signature for TxRefundBurn")?, + ) + } + + /// Construct TxFinalAmnesty from tx_refund_burn output. + pub fn tx_final_amnesty(&self) -> Result { + Ok(TxFinalAmnesty::new( + &self.tx_refund_burn()?, + &self.refund_address, + self.tx_final_amnesty_fee + .context("Missing tx_final_amnesty_fee")?, + )) + } + + /// Construct signed TxFinalAmnesty using Alice's key and Bob's presigned signature. + pub fn signed_final_amnesty_transaction(&self) -> Result { + let tx_final_amnesty = self.tx_final_amnesty()?; + + tx_final_amnesty.complete_as_alice( + self.a.clone(), + self.B, + self.tx_final_amnesty_sig_bob + .clone() + .context("missing Bob's signature for TxFinalAmnesty")?, + ) + } + pub async fn punish_btc( &self, bitcoin_wallet: &dyn bitcoin_wallet::BitcoinWallet, diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 1496a14487..416480588d 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -266,6 +266,7 @@ pub fn is_complete(state: &BobState) -> bool { | BobState::BtcEarlyRefunded { .. } | BobState::BtcAmnestyConfirmed { .. } | BobState::BtcFinalAmnestyConfirmed { .. } + | BobState::BtcRefundBurnt { .. } | BobState::XmrRedeemed { .. } | BobState::SafelyAborted ) diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 0f811ac600..e682daad97 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -840,8 +840,7 @@ fn apply_bitcoin_amnesty_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, ) -> Result<(bitcoin::Amount, bool)> { - // TODO: decide this somehow - let should_burn_on_refund = false; + let should_burn_on_refund = refund_policy.burn_on_refund; // When ratio is 1.0, no amnesty - use full refund path if refund_policy.taker_refund_ratio == Decimal::ONE { diff --git a/swap/src/asb/recovery/cancel.rs b/swap/src/asb/recovery/cancel.rs index 7e58193c82..9cc8a29cb4 100644 --- a/swap/src/asb/recovery/cancel.rs +++ b/swap/src/asb/recovery/cancel.rs @@ -41,7 +41,12 @@ pub async fn cancel( // Alice already in final state | AliceState::BtcRedeemed - | AliceState::XmrRefunded + | AliceState::XmrRefunded { .. } + | AliceState::BtcRefundBurnPublished { .. } + | AliceState::BtcRefundBurnConfirmed { .. } + | AliceState::BtcFinalAmnestyGranted { .. } + | AliceState::BtcRefundFinalAmnestyPublished { .. } + | AliceState::BtcRefundFinalAmnestyConfirmed { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) | AliceState::BtcPunished { .. } diff --git a/swap/src/asb/recovery/punish.rs b/swap/src/asb/recovery/punish.rs index 76b09a882d..d585564d1d 100644 --- a/swap/src/asb/recovery/punish.rs +++ b/swap/src/asb/recovery/punish.rs @@ -42,7 +42,12 @@ pub async fn punish( | AliceState::BtcLockTransactionSeen { .. } | AliceState::BtcLocked { .. } | AliceState::BtcRedeemed { .. } - | AliceState::XmrRefunded + | AliceState::XmrRefunded { .. } + | AliceState::BtcRefundBurnPublished { .. } + | AliceState::BtcRefundBurnConfirmed { .. } + | AliceState::BtcFinalAmnestyGranted { .. } + | AliceState::BtcRefundFinalAmnestyPublished { .. } + | AliceState::BtcRefundFinalAmnestyConfirmed { .. } | AliceState::BtcPunished { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) diff --git a/swap/src/asb/recovery/redeem.rs b/swap/src/asb/recovery/redeem.rs index c5bed032c9..48dcbf00ef 100644 --- a/swap/src/asb/recovery/redeem.rs +++ b/swap/src/asb/recovery/redeem.rs @@ -92,7 +92,12 @@ pub async fn redeem( | AliceState::BtcPartiallyRefunded { .. } | AliceState::BtcPunishable { .. } | AliceState::BtcRedeemed - | AliceState::XmrRefunded + | AliceState::XmrRefunded { .. } + | AliceState::BtcRefundBurnPublished { .. } + | AliceState::BtcRefundBurnConfirmed { .. } + | AliceState::BtcFinalAmnestyGranted { .. } + | AliceState::BtcRefundFinalAmnestyPublished { .. } + | AliceState::BtcRefundFinalAmnestyConfirmed { .. } | AliceState::XmrRefundable { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) diff --git a/swap/src/asb/recovery/refund.rs b/swap/src/asb/recovery/refund.rs index c79d6a41ab..22ba86f6de 100644 --- a/swap/src/asb/recovery/refund.rs +++ b/swap/src/asb/recovery/refund.rs @@ -60,7 +60,12 @@ pub async fn refund( // Alice already in final state AliceState::BtcRedeemTransactionPublished { .. } | AliceState::BtcRedeemed - | AliceState::XmrRefunded + | AliceState::XmrRefunded { .. } + | AliceState::BtcRefundBurnPublished { .. } + | AliceState::BtcRefundBurnConfirmed { .. } + | AliceState::BtcFinalAmnestyGranted { .. } + | AliceState::BtcRefundFinalAmnestyPublished { .. } + | AliceState::BtcRefundFinalAmnestyConfirmed { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) | AliceState::BtcPunished { .. } @@ -97,7 +102,9 @@ pub async fn refund( ) .await?; - let state = AliceState::XmrRefunded; + let state = AliceState::XmrRefunded { + state3: Some(state3), + }; db.insert_latest_state(swap_id, state.clone().into()) .await?; diff --git a/swap/src/asb/recovery/safely_abort.rs b/swap/src/asb/recovery/safely_abort.rs index f5382d3cc5..aed7c14d4c 100644 --- a/swap/src/asb/recovery/safely_abort.rs +++ b/swap/src/asb/recovery/safely_abort.rs @@ -33,7 +33,12 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc) -> Result AliceState::XmrRefunded, + AliceState::XmrRefunded { state3 } => { + let Some(state3) = state3 else { + tracing::info!( + "Running a pre-partial refund swap, there is no amnesty output to burn" + ); + return Ok(AliceState::XmrRefunded { state3: None }); + }; + + let signed_tx = state3.signed_refund_burn_transaction().context("Can't burn the amnesty output after Bob refunded because we couldn't construct the ")?; + + bitcoin_wallet + .ensure_broadcasted(signed_tx, "refund_burn") + .await + .context("Couldn't publish TxRefundBurn")?; + + AliceState::BtcRefundBurnPublished { state3 } + } + AliceState::BtcRefundBurnPublished { state3 } => { + let tx_refund_burn = state3 + .tx_refund_burn() + .context("Can't construct TxRefundBurn even though we published it")?; + + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; + + subscription + .wait_until_final() + .await + .context("Failed to wait for TxRefundBurn to be confirmed")?; + + AliceState::BtcRefundBurnConfirmed { state3 } + } + AliceState::BtcRefundBurnConfirmed { state3 } => { + // Nothing to do here. Final amnesty is triggered manually. + AliceState::BtcRefundBurnConfirmed { state3 } + } + AliceState::BtcFinalAmnestyGranted { state3 } => { + // Operator has decided to grant final amnesty to Bob + let signed_tx = state3 + .signed_final_amnesty_transaction() + .context("Failed to construct signed TxFinalAmnesty")?; + + bitcoin_wallet + .ensure_broadcasted(signed_tx, "final_amnesty") + .await + .context("Failed to publish TxFinalAmnesty")?; + + tracing::info!("TxFinalAmnesty published successfully"); + + AliceState::BtcRefundFinalAmnestyPublished { state3 } + } + AliceState::BtcRefundFinalAmnestyPublished { state3 } => { + // Wait for TxFinalAmnesty to be confirmed + let tx_final_amnesty = state3 + .tx_final_amnesty() + .context("Couldn't construct TxFinalAmnesty even though we have published it")?; + + let subscription = bitcoin_wallet + .subscribe_to(Box::new(tx_final_amnesty)) + .await; + + subscription + .wait_until_final() + .await + .context("Failed to wait for TxFinalAmnesty to be confirmed")?; + + AliceState::BtcRefundFinalAmnestyConfirmed { state3 } + } + AliceState::BtcRefundFinalAmnestyConfirmed { state3 } => { + AliceState::BtcRefundFinalAmnestyConfirmed { state3 } + } AliceState::BtcRedeemed => AliceState::BtcRedeemed, AliceState::BtcPunished { state3, diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index f5171906e0..9ef47fd4b3 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -212,6 +212,7 @@ pub async fn setup_test( developer_tip, refund_policy: refund_policy.unwrap_or_default(), monerod_container_id: containers._monerod_container.id().to_string(), + monero, }; testfn(test).await.unwrap() @@ -695,6 +696,10 @@ pub struct TestContext { // Store the container ID as String instead of reference monerod_container_id: String, + + // Handle for the Monero deamon. This allows us to skip waiting times by generating + // blocks instantly + pub monero: Monero, } impl TestContext { @@ -781,7 +786,7 @@ impl TestContext { } pub async fn assert_alice_refunded(&mut self, state: AliceState) { - assert!(matches!(state, AliceState::XmrRefunded)); + assert!(matches!(state, AliceState::XmrRefunded { .. })); assert_eventual_balance( self.alice_bitcoin_wallet.as_ref(), @@ -801,6 +806,51 @@ impl TestContext { .unwrap(); } + pub async fn assert_alice_refund_burn_confirmed(&mut self, state: AliceState) { + assert!(matches!(state, AliceState::BtcRefundBurnConfirmed { .. })); + + // Same as refunded - Alice still has her XMR back + assert_eventual_balance( + self.alice_bitcoin_wallet.as_ref(), + Ordering::Equal, + self.alice_refunded_btc_balance(), + ) + .await + .unwrap(); + + assert_eventual_balance( + &*self.alice_monero_wallet.main_wallet().await, + Ordering::Greater, + self.alice_refunded_xmr_balance(), + ) + .await + .unwrap(); + } + + pub async fn assert_alice_final_amnesty_confirmed(&mut self, state: AliceState) { + assert!(matches!( + state, + AliceState::BtcRefundFinalAmnestyConfirmed { .. } + )); + + // Same as refunded - Alice still has her XMR back + assert_eventual_balance( + self.alice_bitcoin_wallet.as_ref(), + Ordering::Equal, + self.alice_refunded_btc_balance(), + ) + .await + .unwrap(); + + assert_eventual_balance( + &*self.alice_monero_wallet.main_wallet().await, + Ordering::Greater, + self.alice_refunded_xmr_balance(), + ) + .await + .unwrap(); + } + pub async fn assert_alice_developer_tip_received(&self) { assert_eventual_balance( &*self.developer_tip_monero_wallet.main_wallet().await, @@ -1000,7 +1050,10 @@ impl TestContext { state6.tx_partial_refund_fee.expect("partial refund fee"), state6.tx_final_amnesty_fee.expect("final amnesty fee"), ), - _ => panic!("Bob is not in btc final amnesty confirmed state: {:?}", state), + _ => panic!( + "Bob is not in btc final amnesty confirmed state: {:?}", + state + ), }; let lock_tx_bitcoin_fee = self .bob_bitcoin_wallet @@ -1337,6 +1390,18 @@ pub mod alice_run_until { pub fn is_btc_partially_refunded(state: &AliceState) -> bool { matches!(state, AliceState::BtcPartiallyRefunded { .. }) } + + pub fn is_xmr_refunded(state: &AliceState) -> bool { + matches!(state, AliceState::XmrRefunded { .. }) + } + + pub fn is_btc_refund_burn_confirmed(state: &AliceState) -> bool { + matches!(state, AliceState::BtcRefundBurnConfirmed { .. }) + } + + pub fn is_btc_final_amnesty_confirmed(state: &AliceState) -> bool { + matches!(state, AliceState::BtcRefundFinalAmnestyConfirmed { .. }) + } } pub mod bob_run_until { @@ -1363,7 +1428,10 @@ pub mod bob_run_until { } pub fn is_waiting_for_remaining_refund_timelock(state: &BobState) -> bool { - matches!(state, BobState::WaitingForRemainingRefundTimelockExpiration(..)) + matches!( + state, + BobState::WaitingForRemainingRefundTimelockExpiration(..) + ) } pub fn is_remaining_refund_timelock_expired(state: &BobState) -> bool { @@ -1428,3 +1496,23 @@ impl GetConfig for FastAmnestyConfig { } } } + +/// Config with a longer remaining refund timelock for burn tests. +/// Alice needs time to refund XMR (which waits for 10 Monero confirmations) +/// before publishing the burn transaction. +pub struct SlowAmnestyConfig; + +impl GetConfig for SlowAmnestyConfig { + fn get_config() -> Config { + Config { + bitcoin_cancel_timelock: CancelTimelock::new(10).into(), + // Much longer timelock to give Alice time to: + // 1. Wait for 10 Monero confirmations on the lock tx + // 2. Sweep the XMR to her wallet + // 3. Then publish the burn transaction + // In regtest, each BTC block is ~5s, so 100 blocks is ~8 minutes + bitcoin_remaining_refund_timelock: 100, + ..env::Regtest::get_config() + } + } +} diff --git a/swap/tests/partial_refund_bob_claims_amnesty.rs b/swap/tests/partial_refund_bob_claims_amnesty.rs index 4c1c0c7c83..a37eb4afae 100644 --- a/swap/tests/partial_refund_bob_claims_amnesty.rs +++ b/swap/tests/partial_refund_bob_claims_amnesty.rs @@ -13,8 +13,10 @@ use swap_env::config::RefundPolicy; #[tokio::test] async fn given_partial_refund_bob_claims_amnesty_after_timelock() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice does NOT burn - Bob can claim amnesty after timelock let refund_policy = Some(RefundPolicy { taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% + burn_on_refund: false, }); harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { From 88e1bfe6d3d7d58e255e03d3423e06caa926dea3 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 27 Dec 2025 11:47:47 +0100 Subject: [PATCH 076/146] add new tests to ci.yml --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82a97c4e40..e33b3c1202 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -184,6 +184,10 @@ jobs: test_name: happy_path_alice_does_not_send_transfer_proof - package: swap test_name: partial_refund_bob_claims_amnesty + - package: swap + test_name: partial_refund_alice_burns + - package: swap + test_name: partial_refund_alice_grants_final_amnesty - package: monero-tests test_name: reserve_proof - package: monero-tests From b3696879e908b237a99372654d6028c1c37011ff Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 27 Dec 2025 22:50:24 +0100 Subject: [PATCH 077/146] add new integration tests for burn scenarios, add BurnRefund command to asb RpcServer --- swap-controller-api/src/lib.rs | 12 +++ swap/src/asb/event_loop.rs | 76 +++++++++++++++ swap/src/asb/rpc/server.rs | 17 ++++ swap/src/protocol/alice/swap.rs | 64 +++++++++++-- swap/tests/harness/mod.rs | 61 ++++++++++-- swap/tests/partial_refund_alice_burns.rs | 86 +++++++++++++++++ ...artial_refund_alice_burns_after_command.rs | 96 +++++++++++++++++++ ...rtial_refund_alice_grants_final_amnesty.rs | 76 +++++++++++++++ 8 files changed, 471 insertions(+), 17 deletions(-) create mode 100644 swap/tests/partial_refund_alice_burns.rs create mode 100644 swap/tests/partial_refund_alice_burns_after_command.rs create mode 100644 swap/tests/partial_refund_alice_grants_final_amnesty.rs diff --git a/swap-controller-api/src/lib.rs b/swap-controller-api/src/lib.rs index afc1f4de28..4d548dd789 100644 --- a/swap-controller-api/src/lib.rs +++ b/swap-controller-api/src/lib.rs @@ -88,6 +88,12 @@ pub struct MoneroSeedResponse { pub restore_height: u64, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SetBurnOnRefundRequest { + pub swap_id: String, + pub burn: bool, +} + #[rpc(client, server)] pub trait AsbApi { #[method(name = "check_connection")] @@ -112,4 +118,10 @@ pub trait AsbApi { async fn get_swaps(&self) -> Result, ErrorObjectOwned>; #[method(name = "registration_status")] async fn registration_status(&self) -> Result; + #[method(name = "set_burn_on_refund")] + async fn set_burn_on_refund( + &self, + swap_id: String, + burn: bool, + ) -> Result<(), ErrorObjectOwned>; } diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index e682daad97..edd029472b 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -69,6 +69,12 @@ where /// the sender is removed from this map. recv_encrypted_signature: HashMap>, + /// Stores where to send burn-on-refund instructions to + /// The corresponding receiver is stored in the EventLoopHandle + /// Uses watch channel to allow multiple updates before consumption + recv_burn_on_refund_instruction: + HashMap>>, + /// Once we receive an [`EncryptedSignature`] from Bob, we forward it to the EventLoopHandle. /// Once the EventLoopHandle acknowledges the receipt of the [`EncryptedSignature`], we need to confirm this to Bob. /// When the EventLoopHandle acknowledges the receipt, a future in this collection resolves and returns the libp2p channel @@ -170,6 +176,7 @@ where refund_policy, quote_cache, recv_encrypted_signature: Default::default(), + recv_burn_on_refund_instruction: Default::default(), inflight_encrypted_signatures: Default::default(), outgoing_transfer_proofs_requests, outgoing_transfer_proofs_sender, @@ -555,6 +562,15 @@ where let _ = respond_to.send(registrations); } + EventLoopRequest::SetBurnOnRefund { swap_id, burn, respond_to } => { + let result = if let Some(sender) = self.recv_burn_on_refund_instruction.get(&swap_id) { + sender.send(Some(burn)) + .map_err(|_| anyhow!("Failed to send burn instruction - receiver dropped")) + } else { + Err(anyhow!("No active swap found with id {}", swap_id)) + }; + let _ = respond_to.send(result); + } } } } @@ -692,12 +708,20 @@ where self.recv_encrypted_signature .insert(swap_id, encrypted_signature_sender); + // Create a watch channel for burn-on-refund instructions + // Uses watch instead of bmrng to allow multiple updates before consumption + let (burn_instruction_sender, burn_instruction_receiver) = + tokio::sync::watch::channel(None); + self.recv_burn_on_refund_instruction + .insert(swap_id, burn_instruction_sender); + let transfer_proof_sender = self.outgoing_transfer_proofs_sender.clone(); EventLoopHandle { swap_id, peer, recv_encrypted_signature: tokio::sync::Mutex::new(Some(encrypted_signature_receiver)), + recv_burn_on_refund_instruction: tokio::sync::Mutex::new(burn_instruction_receiver), transfer_proof_sender: tokio::sync::Mutex::new(Some(transfer_proof_sender)), } } @@ -710,6 +734,8 @@ pub struct EventLoopHandle { peer: PeerId, recv_encrypted_signature: tokio::sync::Mutex>>, + recv_burn_on_refund_instruction: + tokio::sync::Mutex>>, #[allow(clippy::type_complexity)] transfer_proof_sender: tokio::sync::Mutex< Option< @@ -830,6 +856,34 @@ impl EventLoopHandle { Ok(()) } + + /// Wait for a NEW burn-on-refund instruction from the operator + /// + /// This method waits until the operator sends a new decision via the EventLoopService. + /// Use this in select! arms to react to operator commands. + /// + /// Returns the new burn decision when one is received. + pub async fn wait_for_burn_on_refund_instruction(&self) -> Result { + let mut guard = self.recv_burn_on_refund_instruction.lock().await; + + guard + .changed() + .await + .map_err(|_| anyhow!("Burn instruction sender was dropped"))?; + + let value = *guard.borrow(); + Ok(value.expect("changed() returned Ok, so value should be set")) + } + + /// Get the current burn-on-refund instruction value + /// + /// Returns Some(bool) if an instruction has been set, None otherwise. + /// Use this to check the current decision before taking action. + pub async fn get_burn_on_refund_instruction(&self) -> Option { + let guard = self.recv_burn_on_refund_instruction.lock().await; + let value = *guard.borrow(); + value + } } /// For a new swap of `swap_amount`, this function calculates how much @@ -924,6 +978,11 @@ mod service { Vec, >, }, + SetBurnOnRefund { + swap_id: Uuid, + burn: bool, + respond_to: oneshot::Sender>, + }, } /// Tower service for communicating with the EventLoop @@ -969,6 +1028,23 @@ mod service { rx.await .map_err(|_| anyhow::anyhow!("EventLoop service did not respond")) } + + /// Set the burn-on-refund decision for a specific swap + /// + /// This can be called multiple times to update the decision before + /// the swap state machine polls for it. + pub async fn set_burn_on_refund(&self, swap_id: Uuid, burn: bool) -> anyhow::Result<()> { + let (tx, rx) = oneshot::channel(); + self.sender + .send(EventLoopRequest::SetBurnOnRefund { + swap_id, + burn, + respond_to: tx, + }) + .map_err(|_| anyhow::anyhow!("EventLoop service is down"))?; + rx.await + .map_err(|_| anyhow::anyhow!("EventLoop service did not respond"))? + } } } diff --git a/swap/src/asb/rpc/server.rs b/swap/src/asb/rpc/server.rs index 402ff7f58c..2595bbe33b 100644 --- a/swap/src/asb/rpc/server.rs +++ b/swap/src/asb/rpc/server.rs @@ -243,6 +243,23 @@ impl AsbApiServer for RpcImpl { Ok(RegistrationStatusResponse { registrations }) } + + async fn set_burn_on_refund( + &self, + swap_id: String, + burn: bool, + ) -> Result<(), ErrorObjectOwned> { + let swap_id = uuid::Uuid::parse_str(&swap_id) + .context("Invalid swap ID") + .into_json_rpc_result()?; + + self.event_loop_service + .set_burn_on_refund(swap_id, burn) + .await + .into_json_rpc_result()?; + + Ok(()) + } } trait IntoJsonRpcResult { diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 995439a143..853a9b3500 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -425,6 +425,17 @@ where state3, } } + burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { + let burn = burn_instruction.context("Failed to receive burn instruction")?; + let mut updated_state3 = (*state3).clone(); + updated_state3.should_publish_tx_refund_burn = Some(burn); + + AliceState::XmrLockTransferProofSent { + monero_wallet_restore_blockheight, + transfer_proof, + state3: Box::new(updated_state3), + } + } } } AliceState::EncSigLearned { @@ -543,15 +554,26 @@ where .subscribe_to(Box::new(state3.tx_lock.clone())) .await; - // TODO: Retry here - tx_lock_status_subscription - .wait_until_confirmed_with(state3.cancel_timelock) - .await?; + select! { + result = tx_lock_status_subscription.wait_until_confirmed_with(state3.cancel_timelock) => { + result?; + AliceState::CancelTimelockExpired { + monero_wallet_restore_blockheight, + transfer_proof, + state3, + } + } + burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { + let burn = burn_instruction.context("Failed to receive burn instruction")?; + let mut updated_state3 = (*state3).clone(); + updated_state3.should_publish_tx_refund_burn = Some(burn); - AliceState::CancelTimelockExpired { - monero_wallet_restore_blockheight, - transfer_proof, - state3, + AliceState::WaitingForCancelTimelockExpiration { + monero_wallet_restore_blockheight, + transfer_proof, + state3: Box::new(updated_state3), + } + } } } AliceState::CancelTimelockExpired { @@ -648,6 +670,17 @@ where state3, } } + burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { + let burn = burn_instruction.context("Failed to receive burn instruction")?; + let mut updated_state3 = (*state3).clone(); + updated_state3.should_publish_tx_refund_burn = Some(burn); + + AliceState::BtcCancelled { + monero_wallet_restore_blockheight, + transfer_proof, + state3: Box::new(updated_state3), + } + } } } AliceState::BtcRefunded { @@ -742,13 +775,26 @@ where .expect("We should never run out of retries while publishing the punish transaction") } AliceState::XmrRefunded { state3 } => { - let Some(state3) = state3 else { + // Only publish TxRefundBurn + let Some(mut state3) = state3 else { tracing::info!( "Running a pre-partial refund swap, there is no amnesty output to burn" ); return Ok(AliceState::XmrRefunded { state3: None }); }; + // Fetch the burn decision, if it was made via the controller + if let Some(burn_decision) = event_loop_handle.get_burn_on_refund_instruction().await { + state3.should_publish_tx_refund_burn = Some(burn_decision); + } + + if !state3.should_publish_tx_refund_burn.unwrap_or(false) { + tracing::info!("Not instructed to partially burn the takers refund. Finishing"); + return Ok(AliceState::XmrRefunded { + state3: Some(state3), + }); + } + let signed_tx = state3.signed_refund_burn_transaction().context("Can't burn the amnesty output after Bob refunded because we couldn't construct the ")?; bitcoin_wallet diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 9ef47fd4b3..38d4f4f6d1 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -152,7 +152,13 @@ pub async fn setup_test( .parse() .expect("failed to parse Alice's address"); - let (alice_handle, alice_swap_handle) = start_alice( + let alice_rpc_port = std::net::TcpListener::bind(("127.0.0.1", 0)) + .unwrap() + .local_addr() + .unwrap() + .port(); + + let (alice_handle, alice_swap_handle, alice_rpc_server_handle) = start_alice( &alice_seed, alice_db_path.clone(), alice_listen_address.clone(), @@ -161,9 +167,14 @@ pub async fn setup_test( alice_monero_wallet.clone(), developer_tip.clone(), refund_policy.clone().unwrap_or_default(), + alice_rpc_port, ) .await; + let alice_rpc_client = jsonrpsee::http_client::HttpClientBuilder::default() + .build(format!("http://127.0.0.1:{}", alice_rpc_port)) + .expect("Failed to create RPC client"); + let bob_seed = Seed::random().unwrap(); let bob_starting_balances = StartingBalances::new(btc_amount * 10, monero::Amount::ZERO, None); let bob_monero_dir = TempDir::new().unwrap().path().join("bob-monero-wallets"); @@ -199,6 +210,9 @@ pub async fn setup_test( alice_seed, alice_db_path, alice_listen_address, + alice_rpc_port, + alice_rpc_server_handle, + alice_rpc_client, alice_starting_balances, alice_bitcoin_wallet, alice_monero_wallet, @@ -304,7 +318,12 @@ async fn start_alice( monero_wallet: Arc, developer_tip: TipConfig, refund_policy: RefundPolicy, -) -> (AliceApplicationHandle, Receiver) { + rpc_port: u16, +) -> ( + AliceApplicationHandle, + Receiver, + tokio_util::task::AbortOnDropHandle<()>, +) { if let Some(parent_dir) = db_path.parent() { ensure_directory_exists(parent_dir).unwrap(); } @@ -338,12 +357,12 @@ async fn start_alice( .unwrap(); swarm.listen_on(listen_address).unwrap(); - let (event_loop, swap_handle, _service) = asb::EventLoop::new( + let (event_loop, swap_handle, service) = asb::EventLoop::new( swarm, env_config, - bitcoin_wallet, - monero_wallet, - db, + bitcoin_wallet.clone(), + monero_wallet.clone(), + db.clone(), FixedRate::default(), min_buy, max_buy, @@ -353,10 +372,26 @@ async fn start_alice( ) .unwrap(); + let rpc_server_handle = asb::rpc::RpcServer::start( + "127.0.0.1".to_string(), + rpc_port, + bitcoin_wallet, + monero_wallet, + service, + db, + ) + .await + .expect("Failed to start RPC server") + .spawn(); + let peer_id = event_loop.peer_id(); let handle = tokio::spawn(event_loop.run()); - (AliceApplicationHandle { handle, peer_id }, swap_handle) + ( + AliceApplicationHandle { handle, peer_id }, + swap_handle, + rpc_server_handle, + ) } #[allow(clippy::too_many_arguments)] @@ -680,6 +715,10 @@ pub struct TestContext { alice_seed: Seed, alice_db_path: PathBuf, alice_listen_address: Multiaddr, + alice_rpc_port: u16, + #[allow(dead_code)] + alice_rpc_server_handle: tokio_util::task::AbortOnDropHandle<()>, + pub alice_rpc_client: jsonrpsee::http_client::HttpClient, alice_starting_balances: StartingBalances, alice_bitcoin_wallet: Arc, @@ -716,8 +755,12 @@ impl TestContext { pub async fn restart_alice(&mut self) { self.alice_handle.abort(); + // Abort the old RPC server to release the port before starting a new one + self.alice_rpc_server_handle.abort(); + // Small delay to ensure port is released + tokio::time::sleep(Duration::from_millis(100)).await; - let (alice_handle, alice_swap_handle) = start_alice( + let (alice_handle, alice_swap_handle, alice_rpc_server_handle) = start_alice( &self.alice_seed, self.alice_db_path.clone(), self.alice_listen_address.clone(), @@ -726,11 +769,13 @@ impl TestContext { self.alice_monero_wallet.clone(), self.developer_tip.clone(), self.refund_policy.clone(), + self.alice_rpc_port, ) .await; self.alice_handle = alice_handle; self.alice_swap_handle = alice_swap_handle; + self.alice_rpc_server_handle = alice_rpc_server_handle; } pub async fn alice_next_swap(&mut self) -> alice::Swap { diff --git a/swap/tests/partial_refund_alice_burns.rs b/swap/tests/partial_refund_alice_burns.rs new file mode 100644 index 0000000000..d32651c43d --- /dev/null +++ b/swap/tests/partial_refund_alice_burns.rs @@ -0,0 +1,86 @@ +pub mod harness; + +use std::time::Duration; + +use harness::alice_run_until::is_xmr_lock_transaction_sent; +use harness::bob_run_until::is_btc_partially_refunded; +use harness::SlowAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use swap_env::config::RefundPolicy; + +/// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial +/// refund. Alice then burns the refund, denying Bob access to the amnesty. +#[tokio::test] +async fn given_partial_refund_alice_burns_the_amnesty() { + // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice burns the amnesty + let refund_policy = Some(RefundPolicy { + taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% + burn_on_refund: true, + }); + + harness::setup_test( + SlowAmnestyConfig, + None, + refund_policy, + |mut ctx| async move { + // Start Bob's swap + let (bob_swap, bob_join_handle) = ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + // Bob runs until he has done the partial refund + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_partially_refunded)); + + // Alice sends XMR lock then stops + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + // Alice finishes first (just sends XMR lock and stops) + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::XmrLockTransactionSent { .. } + )); + + // Bob runs until partial refund is done + let bob_state = bob_swap.await??; + assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); + + // Restart Alice so she can refund her XMR and burn Bob's amnesty + // Alice needs to publish burn BEFORE Bob's remaining refund timelock expires + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Bob continues - he's watching for TxRefundBurn while waiting for timelock + // Alice's burn should get published before Bob's timelock expires + let (bob_swap, _) = ctx + .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) + .await; + let bob_swap = tokio::spawn(bob::run(bob_swap)); + + // Generate some Monero blocks such that Alice's + // monero refund transaction gets confirmed in time. + tokio::time::sleep(Duration::from_secs(15)).await; + ctx.monero.generate_blocks().await?; + + // Bob should end up in BtcRefundBurnt because Alice's burn beat his amnesty + let bob_state = bob_swap.await??; + ctx.assert_bob_refund_burnt(bob_state).await; + + // Alice should be in refund burn confirmed state + let alice_state = alice_swap.await??; + ctx.assert_alice_refund_burn_confirmed(alice_state).await; + + Ok(()) + }, + ) + .await; +} diff --git a/swap/tests/partial_refund_alice_burns_after_command.rs b/swap/tests/partial_refund_alice_burns_after_command.rs new file mode 100644 index 0000000000..14b620d773 --- /dev/null +++ b/swap/tests/partial_refund_alice_burns_after_command.rs @@ -0,0 +1,96 @@ +pub mod harness; + +use std::time::Duration; + +use harness::alice_run_until::is_xmr_lock_transaction_sent; +use harness::bob_run_until::is_btc_partially_refunded; +use harness::SlowAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use swap_controller_api::AsbApiClient; +use swap_env::config::RefundPolicy; + +/// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial +/// refund. Alice receives an RPC command to burn the amnesty and then burns it. +#[tokio::test] +async fn given_partial_refund_alice_burns_after_command() { + // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice does NOT burn by default - burn_on_refund is false + let refund_policy = Some(RefundPolicy { + taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% + burn_on_refund: false, // Do not burn by default + }); + + harness::setup_test( + SlowAmnestyConfig, + None, + refund_policy, + |mut ctx| async move { + // Start Bob's swap + let (bob_swap, bob_join_handle) = ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + // Bob runs until he has done the partial refund + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_partially_refunded)); + + // Alice sends XMR lock then stops + let alice_swap = ctx.alice_next_swap().await; + let alice_swap_id = alice_swap.swap_id; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + // Alice finishes first (just sends XMR lock and stops) + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::XmrLockTransactionSent { .. } + )); + + // Bob runs until partial refund is done + let bob_state = bob_swap.await??; + assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); + + // Restart Alice so she can refund her XMR and burn Bob's amnesty + // Alice needs to publish burn BEFORE Bob's remaining refund timelock expires + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + + // Send RPC command to Alice to burn this swap's amnesty + // Must be done AFTER restart (so EventLoopHandle exists) but BEFORE running the swap + ctx.alice_rpc_client + .set_burn_on_refund(alice_swap_id.to_string(), true) + .await + .expect("Failed to send burn command to Alice"); + + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Bob continues - he's watching for TxRefundBurn while waiting for timelock + // Alice's burn should get published before Bob's timelock expires + let (bob_swap, _) = ctx + .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) + .await; + let bob_swap = tokio::spawn(bob::run(bob_swap)); + + // Generate some Monero blocks such that Alice's + // monero refund transaction gets confirmed in time. + tokio::time::sleep(Duration::from_secs(15)).await; + ctx.monero.generate_blocks().await?; + + // Bob should end up in BtcRefundBurnt because Alice's burn beat his amnesty + let bob_state = bob_swap.await??; + ctx.assert_bob_refund_burnt(bob_state).await; + + // Alice should be in refund burn confirmed state + let alice_state = alice_swap.await??; + ctx.assert_alice_refund_burn_confirmed(alice_state).await; + + Ok(()) + }, + ) + .await; +} diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs new file mode 100644 index 0000000000..d43f1261eb --- /dev/null +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -0,0 +1,76 @@ +pub mod harness; + +use harness::alice_run_until::{is_btc_refund_burn_confirmed, is_xmr_lock_transaction_sent}; +use harness::FastAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::{alice, bob}; +use swap_env::config::RefundPolicy; + +/// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial +/// refund. Alice burns the refund, then later grants final amnesty to Bob. +/// NOTE: This test cannot pass yet because we haven't implemented the manual +/// trigger for final amnesty. BtcRefundBurnConfirmed is currently terminal. +#[tokio::test] +#[ignore = "final amnesty manual trigger not implemented yet"] +async fn given_partial_refund_alice_grants_final_amnesty() { + // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice burns the amnesty, then grants final amnesty + let refund_policy = Some(RefundPolicy { + taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% + burn_on_refund: true, + }); + + harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { + let (bob_swap, _) = ctx.bob_swap().await; + let bob_swap = tokio::spawn(bob::run(bob_swap)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + // Alice finishes first (just sends XMR lock and stops) + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::XmrLockTransactionSent { .. } + )); + + // Bob continues: cancel timelock -> partial refund + // Bob will end up in BtcRefundBurnt because Alice burns the amnesty + let bob_state = bob_swap.await??; + ctx.assert_bob_refund_burnt(bob_state.clone()).await; + + // Restart Alice so she can refund her XMR and burn Bob's amnesty + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_btc_refund_burn_confirmed, + FixedRate::default(), + )); + + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::BtcRefundBurnConfirmed { .. } + )); + + // TODO: Trigger final amnesty manually here + // This requires a manual command to Alice to grant final amnesty + // For now, this test is ignored. + + // Bob should receive final amnesty + // ctx.assert_bob_final_amnesty_received(bob_state).await; + + // Alice should be in final amnesty confirmed state + // ctx.assert_alice_final_amnesty_confirmed(alice_state).await; + + Ok(()) + }) + .await; +} From a78f3dfeb0e0d02026b315d58ffdb02ec9b8cd2a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sat, 27 Dec 2025 23:14:33 +0100 Subject: [PATCH 078/146] unify ai agent instructions --- AGENT.md | 47 +---------------------------------------------- AGENTS.md | 31 +++++++++++++++++++++++++++++++ CLAUDE.md | 2 +- CONTRIBUTING.md | 13 +++++-------- 4 files changed, 38 insertions(+), 55 deletions(-) mode change 100644 => 120000 AGENT.md create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md diff --git a/AGENT.md b/AGENT.md deleted file mode 100644 index c805dc7496..0000000000 --- a/AGENT.md +++ /dev/null @@ -1,46 +0,0 @@ -# Repo Overview - -This repository hosts the core of the eigenwallet project. The code base is a Rust workspace with multiple crates and a Tauri based GUI. - -## Important directories - -- **swap/** – contains the main Rust crate with two binaries: - - `swap` – command line interface for performing swaps. - - `asb` – Automated Swap Backend for market makers. - It also hosts library code shared between the binaries and integration tests. -- **src-tauri/** – Rust crate that exposes the `swap` functionality to the Tauri front end and bundles the application. -- **src-gui/** – The front‑end written in TypeScript/React and bundled by Tauri. Communicates with `src-tauri` via Tauri commands. -- **monero-rpc/** and **monero-wallet/** – helper crates for interacting with the Monero ecosystem. -- **docs/** – Next.js documentation site. -- **dev-docs/** – additional markdown documentation for CLI and ASB. - -## Frequently edited files - -Looking at the latest ten pull requests in `git log`, the following files appear most often: - -| File | Times Changed | -| --------------------------- | ------------- | -| `src-tauri/Cargo.toml` | 7 | -| `Cargo.lock` | 7 | -| `CHANGELOG.md` | 7 | -| `swap/Cargo.toml` | 6 | -| `src-tauri/tauri.conf.json` | 5 | -| `.github/workflows/ci.yml` | 3 | - -Other files such as `swap/src/bin/asb.rs`, `swap/src/cli/api.rs`, and `src-gui/package.json` showed up less frequently. - -## Component interaction - -- The **swap** crate implements the atomic swap logic and provides a CLI. The binaries under `swap/src/bin` (`swap.rs` and `asb.rs`) start the client and maker services respectively. -- **src-tauri** wraps the swap crate and exposes its functionality to the GUI via Tauri commands. It also bundles the application with the `src-gui` assets. -- **src-gui** is the TypeScript/React interface. It communicates with the Rust back end through the commands defined in `src-tauri`. -- Helper crates like **monero-rpc** and **monero-wallet** provide abstractions over external services. They are used by the swap crate to interact with Monero. -- Continuous integration and release workflows live in `.github/workflows`. They build binaries, create releases and lint the code base. - -## Pull request titles - -Use descriptive titles following the `(): ` format. Examples include: - -- `feat(gui): New feature` -- `fix(swap): Issue fixed` -- `refactor(ci): Ci changes` diff --git a/AGENT.md b/AGENT.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/AGENT.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..a9efe8781f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,31 @@ + - When asked about libp2p, check if a rust-libp2p folder exists which contains the cloned rust libp2p codebase. Read through to figure out what the best response it. If its a question about best practice when implementing protocols read @rust-libp2p/protocols/ specificially. + - Never do `cargo clean`. Building `monero-sys` takes ages, and cleaning the build cache will cause a full rebuilt (horrible). + `cargo clean` has never fixed a build problem. + - Before suggesting a change, always give at least a short (1 sentence) summary of which function you are editing and why. + - When being asked to add something, check whether there is a similar thing already implemented, the architecture of which you can follow. + For example, when asked to add a new Tauri command, check out how other tauri commands are implemented and what conventions they follow. + - + + - Think about seperation of concerns. This has many facets. But the most ofen there are questions like: + "Which part of the code should decide how to handle this situation". In the context of an error, the solution is: + - Never use fallback values. They lead to + - swallowed errors + - breaking invariances + - breaking other implicit assumptions + - destroy any meaning the value might have had. + Instead, if an error/invlaid state is encountered, the error should be propagated. + This is most often correctly done by using anyhow's "Context" and the question mark operator`.context("Failed to ")?`. + - Keep error handling simple: it is basically never wrong to just propagate the error using `?` and maybe add some basic context. + + Other facetts of seperation of concern include: + - should this function need to have access to this ? + - should this function decide a parameter itself or just take an argument? + + We follow the principle of LEAST SURPRISE. Take a step back, and come back with a fresh view. Then ask yourself: "would I expect this function to do ?". + If not, then don't do it. + +- coding style tips: + - keep the code succint. Prefer `if let` and `let ... else` to `match` whenever possible. + - avoid nesting if possible. + - prefer early returns to nesting. + diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index eb3a82a418..0000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -- When asked about libp2p, check if a rust-libp2p folder exists which contains the cloned rust libp2p codebase. Read through to figure out what the best response it. If its a question about best practice when implementing protocols read @rust-libp2p/protocols/ specificially. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65a65cdf5e..779e37b085 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,20 +7,17 @@ Thank you for wanting to contribute to this project! There are a couple of things we are going to look out for in PRs and knowing them upfront is going to reduce the number of times we will be going back and forth, making things more efficient. 1. We have CI checks in place that validate formatting and code style. - Make sure `dprint check` and `cargo clippy` both finish without any warnings or errors. - If you don't already have it installed, you can obtain in [various ways](https://dprint.dev/install/). -2. Run the test suite with [cargo-nextest](https://nexte.st/docs/running/). - Install it using `cargo install cargo-nextest` and execute `cargo nextest run`. -3. All text document (`CHANGELOG.md`, `README.md`, etc) should follow the [semantic linebreaks](https://sembr.org/) specification. -4. We strive for atomic commits with good commit messages. + Make sure the branch is building with `--all-features` and `--all-targets` without errors + and all tests are passed. +2. All text document (`CHANGELOG.md`, `README.md`, etc) should follow the [semantic linebreaks](https://sembr.org/) specification. +3. We strive for atomic commits with good commit messages. As an inspiration, read [this](https://chris.beams.io/posts/git-commit/) blogpost. An atomic commit is a cohesive diff with formatting checks, linter and build passing. Ideally, all tests are passing as well but we acknowledge that this is not always possible depending on the change you are making. -5. If you are making any user visible changes, include a changelog entry. +4. If you are making any user visible changes, include a changelog entry. ## Contributing issues When contributing a feature request, please focus on your _problem_ as much as possible. It is okay to include ideas on how the feature should be implemented but they should be 2nd nature of your request. -For more loosely-defined problems and ideas, consider starting a [discussion](https://github.com/comit-network/xmr-btc-swap/discussions/new) instead of opening an issue. From 813d641b913059e56b9e05580270d528eb1e64e4 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sun, 28 Dec 2025 00:15:45 +0100 Subject: [PATCH 079/146] swap-controller: add set-burn-on-refund --- swap-controller/src/cli.rs | 8 ++++++++ swap-controller/src/main.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/swap-controller/src/cli.rs b/swap-controller/src/cli.rs index f0f89f200f..accc3ddc23 100644 --- a/swap-controller/src/cli.rs +++ b/swap-controller/src/cli.rs @@ -37,4 +37,12 @@ pub enum Cmd { GetSwaps, /// Show rendezvous registration status RegistrationStatus, + /// Set whether to burn Bitcoin on refund for a swap + SetBurnOnRefund { + /// The swap ID + swap_id: String, + /// Whether to burn the Bitcoin (true or false) + #[arg(action = clap::ArgAction::Set)] + burn: bool, + }, } diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index 042b0b6b9e..acaac8864e 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -130,6 +130,14 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { } } } + Cmd::SetBurnOnRefund { swap_id, burn } => { + client.set_burn_on_refund(swap_id.clone(), burn).await?; + if burn { + println!("Burn on refund enabled for swap {swap_id}"); + } else { + println!("Burn on refund disabled for swap {swap_id}"); + } + } } Ok(()) } From 79da674278e0668b112288d8f6f92d797bf3f708 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sun, 28 Dec 2025 14:31:14 +0100 Subject: [PATCH 080/146] add docker test instructions to AGENTS.md --- AGENTS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index a9efe8781f..4fcf62b2ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,4 +28,22 @@ - keep the code succint. Prefer `if let` and `let ... else` to `match` whenever possible. - avoid nesting if possible. - prefer early returns to nesting. + +- Docker tests: We have an extended test suite that simulates a whole blockchain environment for the purpose of testing swaps end to end. + The docker tests are located in `swap/tests` and can be executed using `just docker_test `. Get a list of all docker tests by `just list-docker-tests`. +- If you changed something could possibly affect the success of a swap, make sure to run the integration tests that could possibly be affected. + Be very liberal with assuming what might be affected. +- If not explicitly instructed yet, ask the user whether you should add {unit, integration} tests if you just added / changed some behaviour/code +- The docker tests are long (multiple minutes) and produce tens of thousands of log messages. + Don't try to read all of that output, it will fill you context up before finishing + the initialization. + Instead, spawn them as a background-task (each as it's own). + Then you can simply check in on the current status by checking it's output every minute or so. + If you are claude, use claude codes native background task system and read from the `/tmp/claude/tasks/foo/output.tmp` pipe file, or whatever the path is. + If you are not claude, then do the thing that best accomplishises this. + +- Before claiming you finished, make sure everything compiles (`cargo c --all-features`). + Also all tests (`cargo c --tests`) and all targets (`cargo c --all-targets`) must compile. + + From d51518d793789e70e7cb732039e46838302a4f39 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sun, 28 Dec 2025 14:38:38 +0100 Subject: [PATCH 081/146] asb: add final amnesty command to asb cli and controller + integration test --- Cargo.lock | 2 + swap-asb/src/command.rs | 21 +++ swap-asb/src/main.rs | 9 +- swap-controller-api/Cargo.toml | 1 + swap-controller-api/src/lib.rs | 9 +- swap-controller/Cargo.toml | 1 + swap-controller/src/cli.rs | 8 +- swap-controller/src/main.rs | 6 +- swap-machine/src/bob/mod.rs | 1 - swap/src/asb.rs | 1 + swap/src/asb/event_loop.rs | 71 +++++++++ swap/src/asb/recovery.rs | 1 + swap/src/asb/recovery/grant_final_amnesty.rs | 29 ++++ swap/src/asb/rpc/server.rs | 18 ++- swap/src/protocol/bob/swap.rs | 21 ++- swap/tests/harness/mod.rs | 3 +- ...rtial_refund_alice_grants_final_amnesty.rs | 144 +++++++++++------- 17 files changed, 273 insertions(+), 73 deletions(-) create mode 100644 swap/src/asb/recovery/grant_final_amnesty.rs diff --git a/Cargo.lock b/Cargo.lock index b7cffb695e..fef092c4df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10751,6 +10751,7 @@ dependencies = [ "shell-words", "swap-controller-api", "tokio", + "uuid", ] [[package]] @@ -10760,6 +10761,7 @@ dependencies = [ "bitcoin 0.32.8", "jsonrpsee", "serde", + "uuid", ] [[package]] diff --git a/swap-asb/src/command.rs b/swap-asb/src/command.rs index f0ed7fa488..72a138b446 100644 --- a/swap-asb/src/command.rs +++ b/swap-asb/src/command.rs @@ -178,6 +178,14 @@ where env_config: env_config(testnet), cmd: Command::SafelyAbort { swap_id }, }, + RawCommand::ManualRecovery(ManualRecovery::GrantFinalAmnesty { swap_id }) => Arguments { + testnet, + json, + trace, + config_path: config_path(config, testnet)?, + env_config: env_config(testnet), + cmd: Command::GrantFinalAmnesty { swap_id }, + }, }; Ok(arguments) @@ -250,6 +258,9 @@ pub enum Command { SafelyAbort { swap_id: Uuid, }, + GrantFinalAmnesty { + swap_id: Uuid, + }, ExportBitcoinWallet, ExportMoneroWallet, ExportMoneroLockWallet { @@ -412,6 +423,16 @@ pub enum ManualRecovery { )] swap_id: Uuid, }, + #[structopt( + about = "Grant final amnesty to a swap in BtcRefundBurnConfirmed state, allowing the taker to claim the remaining funds." + )] + GrantFinalAmnesty { + #[structopt( + long = "swap-id", + help = "The swap id can be retrieved using the history subcommand" + )] + swap_id: Uuid, + }, } #[derive(structopt::StructOpt, Debug)] diff --git a/swap-asb/src/main.rs b/swap-asb/src/main.rs index fb829eaddf..e98faf51d9 100644 --- a/swap-asb/src/main.rs +++ b/swap-asb/src/main.rs @@ -27,7 +27,7 @@ use structopt::clap::ErrorKind; mod command; use command::{parse_args, Arguments, Command}; use swap::asb::rpc::RpcServer; -use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, ExchangeRate, Finality}; +use swap::asb::{cancel, grant_final_amnesty, punish, redeem, refund, safely_abort, EventLoop, ExchangeRate, Finality}; use swap::common::tor::{bootstrap_tor_client, create_tor_client}; use swap::common::tracing_util::Format; use swap::common::{self, get_logs, warn_if_outdated}; @@ -482,6 +482,13 @@ pub async fn main() -> Result<()> { tracing::info!("Swap safely aborted"); } + Command::GrantFinalAmnesty { swap_id } => { + let db = open_db(db_file, AccessMode::ReadWrite, None).await?; + + grant_final_amnesty(swap_id, db).await?; + + tracing::info!("Final amnesty granted for swap {}", swap_id); + } Command::Redeem { swap_id, do_not_await_finality, diff --git a/swap-controller-api/Cargo.toml b/swap-controller-api/Cargo.toml index 6cc73f689b..06bf31f14a 100644 --- a/swap-controller-api/Cargo.toml +++ b/swap-controller-api/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bitcoin = { workspace = true } jsonrpsee = { workspace = true, features = ["macros", "server", "client-core", "http-client"] } serde = { workspace = true } +uuid = { workspace = true, features = ["serde"] } [lints] workspace = true diff --git a/swap-controller-api/src/lib.rs b/swap-controller-api/src/lib.rs index 4d548dd789..a22103f773 100644 --- a/swap-controller-api/src/lib.rs +++ b/swap-controller-api/src/lib.rs @@ -1,6 +1,7 @@ use jsonrpsee::proc_macros::rpc; use jsonrpsee::types::ErrorObjectOwned; use serde::{Deserialize, Serialize}; +use uuid::Uuid; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct BitcoinBalanceResponse { @@ -119,9 +120,7 @@ pub trait AsbApi { #[method(name = "registration_status")] async fn registration_status(&self) -> Result; #[method(name = "set_burn_on_refund")] - async fn set_burn_on_refund( - &self, - swap_id: String, - burn: bool, - ) -> Result<(), ErrorObjectOwned>; + async fn set_burn_on_refund(&self, swap_id: Uuid, burn: bool) -> Result<(), ErrorObjectOwned>; + #[method(name = "grant_final_amnesty")] + async fn grant_final_amnesty(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned>; } diff --git a/swap-controller/Cargo.toml b/swap-controller/Cargo.toml index c3ad61cdf4..ee8c8cf582 100644 --- a/swap-controller/Cargo.toml +++ b/swap-controller/Cargo.toml @@ -17,6 +17,7 @@ rustyline = "17.0.0" shell-words = "1.1" swap-controller-api = { path = "../swap-controller-api" } tokio = { workspace = true } +uuid = { workspace = true, features = ["serde"] } [lints] workspace = true diff --git a/swap-controller/src/cli.rs b/swap-controller/src/cli.rs index accc3ddc23..384502336e 100644 --- a/swap-controller/src/cli.rs +++ b/swap-controller/src/cli.rs @@ -1,4 +1,5 @@ use clap::{Parser, Subcommand}; +use uuid::Uuid; #[derive(Parser)] #[command(name = "asb-controller")] @@ -40,9 +41,14 @@ pub enum Cmd { /// Set whether to burn Bitcoin on refund for a swap SetBurnOnRefund { /// The swap ID - swap_id: String, + swap_id: Uuid, /// Whether to burn the Bitcoin (true or false) #[arg(action = clap::ArgAction::Set)] burn: bool, }, + /// Grant final amnesty for a swap in BtcRefundBurnConfirmed state + GrantFinalAmnesty { + /// The swap ID + swap_id: Uuid, + }, } diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index acaac8864e..d0a5b8fb04 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -131,13 +131,17 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { } } Cmd::SetBurnOnRefund { swap_id, burn } => { - client.set_burn_on_refund(swap_id.clone(), burn).await?; + client.set_burn_on_refund(swap_id, burn).await?; if burn { println!("Burn on refund enabled for swap {swap_id}"); } else { println!("Burn on refund disabled for swap {swap_id}"); } } + Cmd::GrantFinalAmnesty { swap_id } => { + client.grant_final_amnesty(swap_id).await?; + println!("Final amnesty granted for swap {swap_id}"); + } } Ok(()) } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 416480588d..1496a14487 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -266,7 +266,6 @@ pub fn is_complete(state: &BobState) -> bool { | BobState::BtcEarlyRefunded { .. } | BobState::BtcAmnestyConfirmed { .. } | BobState::BtcFinalAmnestyConfirmed { .. } - | BobState::BtcRefundBurnt { .. } | BobState::XmrRedeemed { .. } | BobState::SafelyAborted ) diff --git a/swap/src/asb.rs b/swap/src/asb.rs index de055d02a0..2457de7e69 100644 --- a/swap/src/asb.rs +++ b/swap/src/asb.rs @@ -11,6 +11,7 @@ pub use recovery::cancel::cancel; pub use recovery::punish::punish; pub use recovery::redeem::{redeem, Finality}; pub use recovery::refund::refund; +pub use recovery::grant_final_amnesty::grant_final_amnesty; pub use recovery::safely_abort::safely_abort; pub use recovery::{cancel, refund}; pub use swap_feed::{ExchangeRate, FixedRate, LatestRate, Rate}; diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index edd029472b..0b6c3d8dc9 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -571,6 +571,10 @@ where }; let _ = respond_to.send(result); } + EventLoopRequest::GrantFinalAmnesty { swap_id, respond_to } => { + let result = self.handle_grant_final_amnesty(swap_id).await; + let _ = respond_to.send(result); + } } } } @@ -725,6 +729,53 @@ where transfer_proof_sender: tokio::sync::Mutex::new(Some(transfer_proof_sender)), } } + + /// Handle a request to grant final amnesty for a swap. + /// + /// This checks that the swap is not currently running, transitions the + /// state to BtcFinalAmnestyGranted, and resumes the swap. + async fn handle_grant_final_amnesty(&mut self, swap_id: Uuid) -> Result<()> { + use crate::asb::grant_final_amnesty; + + // Check if swap is currently running + if self.recv_encrypted_signature.contains_key(&swap_id) + || self.recv_burn_on_refund_instruction.contains_key(&swap_id) + { + return Err(anyhow!( + "Cannot grant final amnesty while swap {} is still running", + swap_id + )); + } + + // Use the grant_final_amnesty function to transition the state + let new_state = grant_final_amnesty(swap_id, self.db.clone()).await?; + + // Get peer ID for this swap + let peer_id = self.db.get_peer_id(swap_id).await?; + + // Create handle and swap to resume + let handle = self.new_handle(peer_id, swap_id); + let swap = Swap { + event_loop_handle: handle, + bitcoin_wallet: self.bitcoin_wallet.clone(), + monero_wallet: self.monero_wallet.clone(), + env_config: self.env_config, + db: self.db.clone(), + state: new_state, + swap_id, + developer_tip: self.developer_tip.clone(), + }; + + // Send swap to be resumed + self.swap_sender + .send(swap) + .await + .context("Failed to send swap to be resumed")?; + + tracing::info!(%swap_id, "Granted final amnesty and resumed swap"); + + Ok(()) + } } // We use a Mutex here to allow recv_encrypted_signature and transfer_proof_sender to be accessed concurrently @@ -983,6 +1034,10 @@ mod service { burn: bool, respond_to: oneshot::Sender>, }, + GrantFinalAmnesty { + swap_id: Uuid, + respond_to: oneshot::Sender>, + }, } /// Tower service for communicating with the EventLoop @@ -1045,6 +1100,22 @@ mod service { rx.await .map_err(|_| anyhow::anyhow!("EventLoop service did not respond"))? } + + /// Grant final amnesty for a swap in BtcRefundBurnConfirmed state + /// + /// This transitions the swap to BtcFinalAmnestyGranted and resumes + /// the swap state machine to publish the final amnesty transaction. + pub async fn grant_final_amnesty(&self, swap_id: Uuid) -> anyhow::Result<()> { + let (tx, rx) = oneshot::channel(); + self.sender + .send(EventLoopRequest::GrantFinalAmnesty { + swap_id, + respond_to: tx, + }) + .map_err(|_| anyhow::anyhow!("EventLoop service is down"))?; + rx.await + .map_err(|_| anyhow::anyhow!("EventLoop service did not respond"))? + } } } diff --git a/swap/src/asb/recovery.rs b/swap/src/asb/recovery.rs index dd4a7b86a7..e730f77110 100644 --- a/swap/src/asb/recovery.rs +++ b/swap/src/asb/recovery.rs @@ -1,4 +1,5 @@ pub mod cancel; +pub mod grant_final_amnesty; pub mod punish; pub mod redeem; pub mod refund; diff --git a/swap/src/asb/recovery/grant_final_amnesty.rs b/swap/src/asb/recovery/grant_final_amnesty.rs new file mode 100644 index 0000000000..5a31cdbace --- /dev/null +++ b/swap/src/asb/recovery/grant_final_amnesty.rs @@ -0,0 +1,29 @@ +use crate::protocol::alice::AliceState; +use crate::protocol::Database; +use anyhow::{bail, Result}; +use std::convert::TryInto; +use std::sync::Arc; +use uuid::Uuid; + +pub async fn grant_final_amnesty( + swap_id: Uuid, + db: Arc, +) -> Result { + let state = db.get_state(swap_id).await?.try_into()?; + + match state { + AliceState::BtcRefundBurnConfirmed { state3 } => { + let new_state = AliceState::BtcFinalAmnestyGranted { state3 }; + + db.insert_latest_state(swap_id, new_state.clone().into()) + .await?; + + Ok(new_state) + } + _ => bail!( + "Cannot grant final amnesty for swap {} because it is in state {} which is not BtcRefundBurnConfirmed", + swap_id, + state + ), + } +} diff --git a/swap/src/asb/rpc/server.rs b/swap/src/asb/rpc/server.rs index 2595bbe33b..cd044ebaaa 100644 --- a/swap/src/asb/rpc/server.rs +++ b/swap/src/asb/rpc/server.rs @@ -14,6 +14,7 @@ use swap_controller_api::{ RendezvousRegistrationStatus, Swap, }; use tokio_util::task::AbortOnDropHandle; +use uuid::Uuid; pub struct RpcServer { handle: ServerHandle, @@ -244,17 +245,18 @@ impl AsbApiServer for RpcImpl { Ok(RegistrationStatusResponse { registrations }) } - async fn set_burn_on_refund( - &self, - swap_id: String, - burn: bool, - ) -> Result<(), ErrorObjectOwned> { - let swap_id = uuid::Uuid::parse_str(&swap_id) - .context("Invalid swap ID") + async fn set_burn_on_refund(&self, swap_id: Uuid, burn: bool) -> Result<(), ErrorObjectOwned> { + self.event_loop_service + .set_burn_on_refund(swap_id, burn) + .await .into_json_rpc_result()?; + Ok(()) + } + + async fn grant_final_amnesty(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned> { self.event_loop_service - .set_burn_on_refund(swap_id, burn) + .grant_final_amnesty(swap_id) .await .into_json_rpc_result()?; diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 2263711117..a3bb7b2bf9 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -48,8 +48,10 @@ pub fn has_already_processed_transfer_proof(state: &BobState) -> bool { // - We want to attempt recovery via cooperative XMR redeem once. // - If unsuccessful, we exit to avoid an infinite retry loop. // - The swap can still be manually resumed later and retried if desired. +// +// The same is true for the BtcRefundBurnt. pub fn is_run_at_most_once(state: &BobState) -> bool { - matches!(state, BobState::BtcPunished { .. }) + matches!(state, BobState::BtcPunished { .. } | BobState::BtcRefundBurnt(..)) } #[allow(clippy::too_many_arguments)] @@ -1311,9 +1313,20 @@ async fn next_state( BobState::BtcRefundBurnt(state) } BobState::BtcRefundBurnt(state) => { - // Terminal state - Alice needs to manually publish TxFinalAmnesty - // Similar to BtcPunished, we stop here - BobState::BtcRefundBurnt(state) + // Watch for Alice publishing TxFinalAmnesty + // Alice may grant final amnesty after burning our refund + // However, we don't expect Alice to publish the tx at once, if at all. + // Thus we only check once, and then stop the swap. + // User's can still manually resume the swap to check again. + let tx_final_amnesty = state.construct_tx_final_amnesty()?; + + let final_amnesty_status = bitcoin_wallet.status_of_script(&tx_final_amnesty).await.context("Failed to check TxFinalAmnesty status")?; + + if final_amnesty_status.has_been_seen() { + BobState::BtcFinalAmnestyPublished(state) + } else { + BobState::BtcRefundBurnt(state) + } } BobState::BtcFinalAmnestyPublished(state) => { // Wait for TxFinalAmnesty confirmation diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 38d4f4f6d1..a1b82c1240 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -466,6 +466,7 @@ async fn init_test_wallets( .finality_confirmations(1_u32) .target_block(1_u32) .sync_interval(Duration::from_secs(3)) // high sync interval to speed up tests + .use_mempool_space_fee_estimation(false) .build() .await .expect("could not init btc wallet"); @@ -685,7 +686,7 @@ impl BobParams { } } -pub struct BobApplicationHandle(JoinHandle<()>); +pub struct BobApplicationHandle(pub JoinHandle<()>); impl BobApplicationHandle { pub fn abort(&self) { diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index d43f1261eb..45beeb4aa9 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -1,19 +1,25 @@ pub mod harness; +use std::time::Duration; + use harness::alice_run_until::{is_btc_refund_burn_confirmed, is_xmr_lock_transaction_sent}; use harness::FastAmnestyConfig; use rust_decimal::Decimal; use swap::asb::FixedRate; use swap::protocol::alice::AliceState; use swap::protocol::{alice, bob}; +use swap_controller_api::AsbApiClient; use swap_env::config::RefundPolicy; +use swap_machine::bob::BobState; + +use crate::harness::alice_run_until::{is_btc_partially_refunded, is_xmr_refunded}; +use crate::harness::bob_run_until; /// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial /// refund. Alice burns the refund, then later grants final amnesty to Bob. /// NOTE: This test cannot pass yet because we haven't implemented the manual /// trigger for final amnesty. BtcRefundBurnConfirmed is currently terminal. #[tokio::test] -#[ignore = "final amnesty manual trigger not implemented yet"] async fn given_partial_refund_alice_grants_final_amnesty() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty // Alice burns the amnesty, then grants final amnesty @@ -22,55 +28,91 @@ async fn given_partial_refund_alice_grants_final_amnesty() { burn_on_refund: true, }); - harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { - let (bob_swap, _) = ctx.bob_swap().await; - let bob_swap = tokio::spawn(bob::run(bob_swap)); - - let alice_swap = ctx.alice_next_swap().await; - let alice_swap = tokio::spawn(alice::run_until( - alice_swap, - is_xmr_lock_transaction_sent, - FixedRate::default(), - )); - - // Alice finishes first (just sends XMR lock and stops) - let alice_state = alice_swap.await??; - assert!(matches!( - alice_state, - AliceState::XmrLockTransactionSent { .. } - )); - - // Bob continues: cancel timelock -> partial refund - // Bob will end up in BtcRefundBurnt because Alice burns the amnesty - let bob_state = bob_swap.await??; - ctx.assert_bob_refund_burnt(bob_state.clone()).await; - - // Restart Alice so she can refund her XMR and burn Bob's amnesty - ctx.restart_alice().await; - let alice_swap = ctx.alice_next_swap().await; - let alice_swap = tokio::spawn(alice::run_until( - alice_swap, - is_btc_refund_burn_confirmed, - FixedRate::default(), - )); - - let alice_state = alice_swap.await??; - assert!(matches!( - alice_state, - AliceState::BtcRefundBurnConfirmed { .. } - )); - - // TODO: Trigger final amnesty manually here - // This requires a manual command to Alice to grant final amnesty - // For now, this test is ignored. - - // Bob should receive final amnesty - // ctx.assert_bob_final_amnesty_received(bob_state).await; - - // Alice should be in final amnesty confirmed state - // ctx.assert_alice_final_amnesty_confirmed(alice_state).await; - - Ok(()) - }) + harness::setup_test( + FastAmnestyConfig, + None, + refund_policy, + |mut ctx| async move { + let (bob_swap, bob_app_handle) = ctx.bob_swap().await; + let bob_state = tokio::spawn(bob::run_until( + bob_swap, + bob_run_until::is_btc_partially_refunded, + )); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_refunded, + FixedRate::default(), + )); + + // Wait for bob to partially refund - stop here such that he doesn't publish amnesty + // TODO: fix regtest blocktimes instead + let bob_state = bob_state.await??; + + let alice_state = alice_swap.await??; + assert!(matches!(alice_state, AliceState::XmrRefunded { .. })); + + ctx.monero.generate_blocks().await?; + + // Restart alice and wait for bob to be burnt. + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let swap_id = alice_swap.swap_id; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Give alice time to publish TxRefundBurn before restarting bob + tokio::time::sleep(Duration::from_secs(20)).await; + + let (bob_swap, bob_app_handle) = ctx + .stop_and_resume_bob_from_db(bob_app_handle, swap_id) + .await; + let bob_state = tokio::spawn(bob::run(bob_swap)); // Bob should stop automatically after BtcRefundBurnt + + let alice_state = alice_swap.await??; + assert!(matches!( + alice_state, + AliceState::BtcRefundBurnConfirmed { .. } + )); + + let bob_state = bob_state.await??; + assert!(matches!(bob_state, BobState::BtcRefundBurnt(..))); + + // Simulate alice's controller sending the final amnesty command via `controller` cli + ctx.restart_alice().await; + ctx.alice_rpc_client + .grant_final_amnesty(swap_id.to_string()) + .await?; + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + let (bob_swap, _) = ctx + .stop_and_resume_bob_from_db(bob_app_handle, swap_id) + .await; + assert!(matches!(bob_swap.state, BobState::BtcRefundBurnt(..))); + + let alice_state = alice_swap.await??; + // Only start bob again after alice published the tx. otherwise bob immediately + // terminates when not finding the tx. + // TODO: maybe make bob check for a few minutes before giving up? + let bob_state = tokio::spawn(bob::run(bob_swap)); + let bob_state = bob_state.await??; + + assert!( + matches!( + alice_state, + AliceState::BtcRefundFinalAmnestyConfirmed { .. } + ), + "Actual state: {alice_state}" + ); + assert!( + matches!(bob_state, bob::BobState::BtcFinalAmnestyConfirmed(..)), + "Actual state: {bob_state}" + ); + + Ok(()) + }, + ) .await; } From 5f7276ab7cad6d5083de204450ffe8c5617ceddd Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 5 Jan 2026 18:19:11 +0100 Subject: [PATCH 082/146] add basic gui components for new states --- src-gui/src/models/tauriModelExt.ts | 35 +++++- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 113 +++++++++++++++++- .../pages/swap/swap/SwapStatePage.tsx | 20 +++- .../swap/swap/done/BitcoinRefundedPage.tsx | 21 ---- swap-machine/src/bob/mod.rs | 4 +- swap/src/cli/api/tauri_bindings.rs | 22 ++++ swap/src/protocol/bob/swap.rs | 28 +++++ 7 files changed, 211 insertions(+), 32 deletions(-) diff --git a/src-gui/src/models/tauriModelExt.ts b/src-gui/src/models/tauriModelExt.ts index 3fbe3cfeec..f3c9efdaaa 100644 --- a/src-gui/src/models/tauriModelExt.ts +++ b/src-gui/src/models/tauriModelExt.ts @@ -58,6 +58,10 @@ export enum BobStateName { BtcPartiallyRefunded = "btc is partially refunded", BtcAmnestyPublished = "btc amnesty is published", BtcAmnestyReceived = "btc amnesty is confirmed", + BtcRefundBurnPublished = "btc refund burn is published", + BtcRefundBurnt = "btc refund is burnt", + BtcFinalAmnestyPublished = "btc final amnesty is published", + BtcFinalAmnestyConfirmed = "btc final amnesty is confirmed", XmrRedeemed = "xmr is redeemed", BtcPunished = "btc is punished", SafelyAborted = "safely aborted", @@ -103,6 +107,14 @@ export function bobStateNameToHumanReadable(stateName: BobStateName): string { return "Bitcoin partially refunded"; case BobStateName.BtcAmnestyReceived: return "Bitcoin amnesty was received"; + case BobStateName.BtcRefundBurnPublished: + return "Bitcoin refund burn published"; + case BobStateName.BtcRefundBurnt: + return "Bitcoin refund is burnt"; + case BobStateName.BtcFinalAmnestyPublished: + return "Bitcoin final amnesty published"; + case BobStateName.BtcFinalAmnestyConfirmed: + return "Bitcoin final amnesty received"; case BobStateName.XmrRedeemed: return "Monero redeemed"; case BobStateName.BtcPunished: @@ -122,6 +134,14 @@ export type GetSwapInfoResponseExt = GetSwapInfoResponse & { export type TimelockNone = Extract; export type TimelockCancel = Extract; export type TimelockPunish = Extract; +export type TimelockWaitingForRemainingRefund = Extract< + ExpiredTimelocks, + { type: "WaitingForRemainingRefund" } +>; +export type TimelockRemainingRefund = Extract< + ExpiredTimelocks, + { type: "RemainingRefund" } +>; // This function returns the absolute block number of the timelock relative to the block the tx_lock was included in export function getAbsoluteBlock( @@ -138,6 +158,13 @@ export function getAbsoluteBlock( if (timelock.type === "Punish") { return cancelTimelock + punishTimelock; } + // These states are for the partial refund path - we're past cancel/punish timelocks + if (timelock.type === "WaitingForRemainingRefund") { + return cancelTimelock + punishTimelock; + } + if (timelock.type === "RemainingRefund") { + return cancelTimelock + punishTimelock; + } // We match all cases return exhaustiveGuard(timelock); @@ -148,11 +175,11 @@ export type BobStateNameRunningSwap = Exclude< | BobStateName.Started | BobStateName.SwapSetupCompleted | BobStateName.BtcRefunded - | BobStateName.BtcPartiallyRefunded - | BobStateName.BtcAmnestyPublished | BobStateName.BtcAmnestyReceived | BobStateName.BtcRefunded | BobStateName.BtcEarlyRefunded + | BobStateName.BtcRefundBurnt + | BobStateName.BtcFinalAmnestyConfirmed | BobStateName.BtcPunished | BobStateName.SafelyAborted | BobStateName.XmrRedeemed @@ -170,9 +197,9 @@ export function isBobStateNameRunningSwap( BobStateName.SwapSetupCompleted, BobStateName.BtcRefunded, BobStateName.BtcEarlyRefunded, - BobStateName.BtcPartiallyRefunded, - BobStateName.BtcAmnestyPublished, BobStateName.BtcAmnestyReceived, + BobStateName.BtcRefundBurnt, + BobStateName.BtcFinalAmnestyConfirmed, BobStateName.BtcPunished, BobStateName.SafelyAborted, BobStateName.XmrRedeemed, diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 80b565a594..2b4e003a8b 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -161,6 +161,77 @@ function PunishTimelockExpiredAlert() { ); } +/** + * Sub-component for alerts when waiting for remaining refund timelock. + * This occurs after a partial refund was confirmed but we're waiting for the amnesty timelock. + */ +function WaitingForRemainingRefundTimelockAlert({ + blocksLeft, +}: { + blocksLeft: number; +}) { + return ( + + Waiting{" "} + {" "} + for the amnesty timelock to expire + , + "The maker can burn the remaining Bitcoin before the timelock expires", + "If the maker doesn't burn it, you can claim the remaining Bitcoin once the timelock expires", + "Keep the app running or resume the swap once the timelock expires", + ]} + /> + ); +} + +/** + * Sub-component for alerts when remaining refund timelock has expired. + * The amnesty transaction can now be published. + */ +function RemainingRefundTimelockExpiredAlert() { + return ( + + ); +} + +/** + * Sub-component for alerts when the maker has burnt the amnesty output. + */ +function BtcRefundBurnPublishedAlert() { + return ( + + ); +} + +/** + * Sub-component for alerts when the maker has published the final amnesty transaction. + */ +function BtcFinalAmnestyPublishedAlert() { + return ( + + ); +} + /** * Main component for displaying the appropriate swap alert status text. * @param swap - The swap information. @@ -193,10 +264,12 @@ export function StateAlert({ case BobStateName.XmrLocked: case BobStateName.EncSigSent: case BobStateName.CancelTimelockExpired: + // Even if the refund transactions have been published, it cannot be + // guaranteed that they will be confirmed in time case BobStateName.BtcCancelled: - case BobStateName.BtcRefundPublished: // Even if the transactions have been published, it cannot be - case BobStateName.BtcPartialRefundPublished: // Even if the transactions have been published, it cannot be - case BobStateName.BtcEarlyRefundPublished: // guaranteed that they will be confirmed in time + case BobStateName.BtcRefundPublished: + case BobStateName.BtcPartialRefundPublished: + case BobStateName.BtcEarlyRefundPublished: if (timelock != null) { switch (timelock.type) { case "None": @@ -214,16 +287,50 @@ export function StateAlert({ ); case "Punish": return ; + // These two timelock types only exist once the partial refund tx has been confirmed + // They shouldn't occur for these states, so return null + case "WaitingForRemainingRefund": + case "RemainingRefund": + return null; default: exhaustiveGuard(timelock); } } return ; + case BobStateName.BtcPartiallyRefunded: + // Reuse existing timelock alerts for the amnesty waiting period + if (timelock != null) { + switch (timelock.type) { + case "WaitingForRemainingRefund": + return ( + + ); + case "RemainingRefund": + return ; + default: + return null; + } + } + return null; + + case BobStateName.BtcRefundBurnPublished: + return ; + + case BobStateName.BtcFinalAmnestyPublished: + return ; + + case BobStateName.BtcAmnestyPublished: + // Amnesty tx published, waiting for confirmation - no specific alert needed + return null; + // If the Bitcoin lock transaction has not been published yet // there is no need to display an alert case BobStateName.BtcLockReadyToPublish: return null; + default: exhaustiveGuard(swap.state_name); } diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index ed02e8b01a..458d7b89e3 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -7,11 +7,17 @@ import { BitcoinEarlyRefundedPage, BitcoinEarlyRefundPublishedPage, BitcoinRefundPublishedPage, +} from "./done/BitcoinRefundedPage"; +import { BitcoinPartialRefundPublished, BitcoinPartiallyRefunded, BitcoinAmnestyPublished, - BitcoinAmnestyReceived -} from "./done/BitcoinRefundedPage"; + BitcoinAmnestyReceived, + BitcoinRefundBurnPublished, + BitcoinRefundBurnt, + BitcoinFinalAmnestyPublished, + BitcoinFinalAmnestyConfirmed, +} from "./done/BitcoinPartialRefundPage"; import XmrRedeemInMempoolPage from "./done/XmrRedeemInMempoolPage"; import ProcessExitedPage from "./exited/ProcessExitedPage"; import BitcoinCancelledPage from "./in_progress/BitcoinCancelledPage"; @@ -140,6 +146,16 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { case "BtcAmnestyReceived": return ; + //// 4 different types of refund burn / final amnesty states + case "BtcRefundBurnPublished": + return ; + case "BtcRefundBurnt": + return ; + case "BtcFinalAmnestyPublished": + return ; + case "BtcFinalAmnestyConfirmed": + return ; + //// 4 different types of Bitcoin punished states we can be in case "BtcPunished": if (state.curr.type === "BtcPunished") { diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx index 5c56cd939f..d1496b85a1 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinRefundedPage.tsx @@ -92,24 +92,3 @@ function MultiBitcoinRefundedPage({ ); } -export function BitcoinPartialRefundPublished() { - return ( - <>TxPartialRefund published - ) -} - -export function BitcoinPartiallyRefunded() { - return ( - <>Bitcoin partially refunded - ) -} -export function BitcoinAmnestyPublished() { - return ( - <>TxAmnesty published - ) -} -export function BitcoinAmnestyReceived() { - return ( - <>Bitcoin amnesty received - ) -} diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 1496a14487..8f2c6614d4 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -594,7 +594,7 @@ pub struct State2 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - refund_signatures: RefundSignatures, + pub refund_signatures: RefundSignatures, min_monero_confirmations: u64, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -752,7 +752,7 @@ pub struct State3 { /// This field was changed in [#675](https://github.com/eigenwallet/core/pull/675). /// It boils down to the same json except that it now may also contain a partial refund signature. #[serde(flatten)] - refund_signatures: RefundSignatures, + pub refund_signatures: RefundSignatures, min_monero_confirmations: u64, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 881f5a5bc2..da818a71e1 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -98,6 +98,8 @@ pub struct LockBitcoinDetails { /// The amount of Bitcoin the taker will only be able to refund with cooperation from the maker #[typeshare(serialized_as = "number")] pub btc_amnesty_amount: bitcoin::Amount, + /// Whether we can guarantee we'll get the full refund + pub has_full_refund_signature: bool, } #[typeshare] @@ -1123,6 +1125,26 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "string")] btc_amnesty_txid: Txid, }, + // TxRefundBurn has been published (waiting for confirmation) + BtcRefundBurnPublished { + #[typeshare(serialized_as = "string")] + btc_refund_burn_txid: Txid, + }, + // TxRefundBurn has been confirmed - amnesty output is burnt + BtcRefundBurnt { + #[typeshare(serialized_as = "string")] + btc_refund_burn_txid: Txid, + }, + // Alice published TxFinalAmnesty + BtcFinalAmnestyPublished { + #[typeshare(serialized_as = "string")] + btc_final_amnesty_txid: Txid, + }, + // TxFinalAmnesty has been confirmed - user received burnt funds back + BtcFinalAmnestyConfirmed { + #[typeshare(serialized_as = "string")] + btc_final_amnesty_txid: Txid, + }, BtcPunished, AttemptingCooperativeRedeem, CooperativeRedeemAccepted, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index a3bb7b2bf9..d81506db77 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -188,6 +188,7 @@ async fn next_state( xmr_receive_amount, monero_receive_pool, swap_id, + has_full_refund_signature: state3.refund_signatures.has_full_refund_encsig() }; // We request approval before publishing the Bitcoin lock transaction, @@ -1306,6 +1307,12 @@ async fn next_state( BobState::BtcRefundBurnPublished(state) => { // Wait for TxRefundBurn confirmation let tx_refund_burn = state.construct_tx_refund_burn()?; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcRefundBurnPublished { + btc_refund_burn_txid: tx_refund_burn.txid(), + }, + ); let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; subscription.wait_until_final().await?; @@ -1318,6 +1325,14 @@ async fn next_state( // However, we don't expect Alice to publish the tx at once, if at all. // Thus we only check once, and then stop the swap. // User's can still manually resume the swap to check again. + let tx_refund_burn = state.construct_tx_refund_burn()?; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcRefundBurnt { + btc_refund_burn_txid: tx_refund_burn.txid(), + }, + ); + let tx_final_amnesty = state.construct_tx_final_amnesty()?; let final_amnesty_status = bitcoin_wallet.status_of_script(&tx_final_amnesty).await.context("Failed to check TxFinalAmnesty status")?; @@ -1331,6 +1346,12 @@ async fn next_state( BobState::BtcFinalAmnestyPublished(state) => { // Wait for TxFinalAmnesty confirmation let tx_final_amnesty = state.construct_tx_final_amnesty()?; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcFinalAmnestyPublished { + btc_final_amnesty_txid: tx_final_amnesty.txid(), + }, + ); let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_final_amnesty)).await; subscription.wait_until_final().await?; @@ -1339,6 +1360,13 @@ async fn next_state( } BobState::BtcFinalAmnestyConfirmed(state) => { // Terminal state - we received the burnt funds back + let tx_final_amnesty = state.construct_tx_final_amnesty()?; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcFinalAmnestyConfirmed { + btc_final_amnesty_txid: tx_final_amnesty.txid(), + }, + ); BobState::BtcFinalAmnestyConfirmed(state) } BobState::SafelyAborted => BobState::SafelyAborted, From fb838c7adeab696fcd09d337d37c96ef78340488 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 6 Jan 2026 10:01:50 +0100 Subject: [PATCH 083/146] add placeholder components for partial refund path --- .../swap/done/BitcoinPartialRefundPage.tsx | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx new file mode 100644 index 0000000000..12f8063e62 --- /dev/null +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -0,0 +1,45 @@ +/** + * Pages for the partial refund path of the swap. + * + * This path is taken when Alice only signs the partial refund transaction + * (not the full refund). The flow is: + * + * 1. BtcPartialRefundPublished - TxPartialRefund is published + * 2. BtcPartiallyRefunded - TxPartialRefund is confirmed + * 3. Either: + * a. BtcAmnestyPublished -> BtcAmnestyReceived (Bob claims amnesty via TxRefundAmnesty) + * b. BtcRefundBurnPublished -> BtcRefundBurnt (Alice burns amnesty via TxRefundBurn) + * -> optionally BtcFinalAmnestyPublished -> BtcFinalAmnestyConfirmed (Alice grants final amnesty) + */ + +export function BitcoinPartialRefundPublished() { + return <>TxPartialRefund published; +} + +export function BitcoinPartiallyRefunded() { + return <>Bitcoin partially refunded; +} + +export function BitcoinAmnestyPublished() { + return <>TxAmnesty published; +} + +export function BitcoinAmnestyReceived() { + return <>Bitcoin amnesty received; +} + +export function BitcoinRefundBurnPublished() { + return <>TxRefundBurn published - Alice burned the amnesty output; +} + +export function BitcoinRefundBurnt() { + return <>Bitcoin refund is burnt - waiting for Alice to grant final amnesty; +} + +export function BitcoinFinalAmnestyPublished() { + return <>TxFinalAmnesty published - Alice granted final amnesty; +} + +export function BitcoinFinalAmnestyConfirmed() { + return <>Bitcoin final amnesty received - swap complete; +} From 908db143aab906c0425f13c1212bf7c481ae2e39 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 6 Jan 2026 12:24:53 +0100 Subject: [PATCH 084/146] add mock swap states with stepping controls in dev mode --- src-gui/src/dev/mockSwapEvents.ts | 197 ++++++++++++++++++ .../modal/swap/pages/MockSwapControls.tsx | 125 +++++++++++ .../components/pages/swap/swap/SwapWidget.tsx | 17 +- .../swap/swap/exited/ProcessExitedPage.tsx | 5 +- ...artial_refund_alice_burns_after_command.rs | 2 +- ...rtial_refund_alice_grants_final_amnesty.rs | 4 +- 6 files changed, 339 insertions(+), 11 deletions(-) create mode 100644 src-gui/src/dev/mockSwapEvents.ts create mode 100644 src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts new file mode 100644 index 0000000000..5d4cc9b31f --- /dev/null +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -0,0 +1,197 @@ +import { + BidQuote, + MoneroAddressPool, + QuoteWithAddress, + TauriSwapProgressEvent, +} from "models/tauriModel"; + +// Mock transaction IDs +const MOCK_BTC_LOCK_TXID = + "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"; +const MOCK_XMR_LOCK_TXID = + "a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8"; +const MOCK_XMR_REDEEM_TXID = + "b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9"; +const MOCK_BTC_CANCEL_TXID = + "c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0"; +const MOCK_BTC_REFUND_TXID = + "d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1"; +const MOCK_BTC_EARLY_REFUND_TXID = + "e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2"; +const MOCK_BTC_PARTIAL_REFUND_TXID = + "f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3"; +const MOCK_BTC_AMNESTY_TXID = + "a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4"; +const MOCK_BTC_REFUND_BURN_TXID = + "b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5"; +const MOCK_BTC_FINAL_AMNESTY_TXID = + "c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"; + +// Mock addresses +const MOCK_BTC_DEPOSIT_ADDRESS = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"; +const MOCK_XMR_ADDRESS = + "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H"; + +export const MOCK_SWAP_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"; + +const MOCK_QUOTE: BidQuote = { + price: 0.007, + min_quantity: 10_000_000, + max_quantity: 100_000_000, +}; + +const MOCK_QUOTE_WITH_ADDRESS: QuoteWithAddress = { + multiaddr: "/ip4/127.0.0.1/tcp/9939", + peer_id: "12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi", + quote: MOCK_QUOTE, + version: "0.13.0", +}; + +const MOCK_RECEIVE_POOL: MoneroAddressPool = [ + { address: MOCK_XMR_ADDRESS, percentage: 100, label: "Main" }, +]; + +const XMR_TARGET_CONFIRMATIONS = 10; + +// Base scenario: swap start -> XMR locked (10 confirmations) +const baseScenario: TauriSwapProgressEvent[] = [ + { type: "ReceivedQuote", content: MOCK_QUOTE }, + { + type: "WaitingForBtcDeposit", + content: { + deposit_address: MOCK_BTC_DEPOSIT_ADDRESS, + max_giveable: 0, + min_bitcoin_lock_tx_fee: 1000, + known_quotes: [MOCK_QUOTE_WITH_ADDRESS], + }, + }, + { type: "SwapSetupInflight", content: { btc_lock_amount: 50_000_000 } }, + { type: "RetrievingMoneroBlockheight" }, + { type: "BtcLockPublishInflight" }, + // BTC lock confirmations: 0, 1, 2 + { type: "BtcLockTxInMempool", content: { btc_lock_txid: MOCK_BTC_LOCK_TXID, btc_lock_confirmations: 0 } }, + { type: "BtcLockTxInMempool", content: { btc_lock_txid: MOCK_BTC_LOCK_TXID, btc_lock_confirmations: 1 } }, + { type: "BtcLockTxInMempool", content: { btc_lock_txid: MOCK_BTC_LOCK_TXID, btc_lock_confirmations: 2 } }, + { type: "VerifyingXmrLockTx", content: { xmr_lock_txid: MOCK_XMR_LOCK_TXID } }, + // XMR lock confirmations: 0 through 10 + ...Array.from({ length: XMR_TARGET_CONFIRMATIONS + 1 }, (_, i) => ({ + type: "XmrLockTxInMempool" as const, + content: { + xmr_lock_txid: MOCK_XMR_LOCK_TXID, + xmr_lock_tx_confirmations: i, + xmr_lock_tx_target_confirmations: XMR_TARGET_CONFIRMATIONS, + }, + })), +]; + +const happyPath: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "PreflightEncSig" }, + { type: "InflightEncSig" }, + { type: "EncryptedSignatureSent" }, + { type: "RedeemingMonero" }, + { + type: "XmrRedeemInMempool", + content: { xmr_redeem_txids: [MOCK_XMR_REDEEM_TXID], xmr_receive_pool: MOCK_RECEIVE_POOL }, + }, + { type: "Released" }, +]; + +const cooperativeRedeem: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "AttemptingCooperativeRedeem" }, + { type: "CooperativeRedeemAccepted" }, + { type: "RedeemingMonero" }, + { + type: "XmrRedeemInMempool", + content: { xmr_redeem_txids: [MOCK_XMR_REDEEM_TXID], xmr_receive_pool: MOCK_RECEIVE_POOL }, + }, + { type: "Released" }, +]; + +const cooperativeRedeemRejected: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "AttemptingCooperativeRedeem" }, + { type: "CooperativeRedeemRejected", content: { reason: "Peer offline" } }, + { type: "WaitingForCancelTimelockExpiration" }, + { type: "CancelTimelockExpired" }, + { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, + { type: "BtcRefundPublished", content: { btc_refund_txid: MOCK_BTC_REFUND_TXID } }, + { type: "BtcRefunded", content: { btc_refund_txid: MOCK_BTC_REFUND_TXID } }, + { type: "Released" }, +]; + +const earlyRefund: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "BtcEarlyRefundPublished", content: { btc_early_refund_txid: MOCK_BTC_EARLY_REFUND_TXID } }, + { type: "BtcEarlyRefunded", content: { btc_early_refund_txid: MOCK_BTC_EARLY_REFUND_TXID } }, + { type: "Released" }, +]; + +const partialRefundWithAmnesty: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "WaitingForCancelTimelockExpiration" }, + { type: "CancelTimelockExpired" }, + { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, + { + type: "BtcPartialRefundPublished", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: true }, + }, + { + type: "BtcPartiallyRefunded", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: true }, + }, + { type: "BtcAmnestyPublished", content: { btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID } }, + { type: "BtcAmnestyReceived", content: { btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID } }, + { type: "Released" }, +]; + +const partialRefundWithBurn: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "WaitingForCancelTimelockExpiration" }, + { type: "CancelTimelockExpired" }, + { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, + { + type: "BtcPartialRefundPublished", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + }, + { + type: "BtcPartiallyRefunded", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + }, + { type: "BtcRefundBurnPublished", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, + { type: "BtcRefundBurnt", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, + { type: "Released" }, +]; + +const partialRefundWithBurnAndFinalAmnesty: TauriSwapProgressEvent[] = [ + ...baseScenario, + { type: "WaitingForCancelTimelockExpiration" }, + { type: "CancelTimelockExpired" }, + { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, + { + type: "BtcPartialRefundPublished", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + }, + { + type: "BtcPartiallyRefunded", + content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + }, + { type: "BtcRefundBurnPublished", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, + { type: "BtcRefundBurnt", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, + { type: "BtcFinalAmnestyPublished", content: { btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID } }, + { type: "BtcFinalAmnestyConfirmed", content: { btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID } }, + { type: "Released" }, +]; + +export const scenarios: Record = { + happyPath, + cooperativeRedeem, + cooperativeRedeemRejected, + earlyRefund, + partialRefundWithAmnesty, + partialRefundWithBurn, + partialRefundWithBurnAndFinalAmnesty, +}; + +export type MockScenario = keyof typeof scenarios; diff --git a/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx b/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx new file mode 100644 index 0000000000..4921a10f60 --- /dev/null +++ b/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx @@ -0,0 +1,125 @@ +import { useState } from "react"; +import { + Box, + IconButton, + MenuItem, + Paper, + Select, + Switch, + Typography, +} from "@mui/material"; +import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import { scenarios, MockScenario, MOCK_SWAP_ID } from "dev/mockSwapEvents"; +import { SwapState } from "models/storeModel"; + +function buildMockState(scenario: MockScenario, index: number): SwapState { + const events = scenarios[scenario]; + return { + curr: events[index], + prev: index > 0 ? events[index - 1] : null, + swapId: MOCK_SWAP_ID, + }; +} + +interface Props { + onMockStateChange: (state: SwapState | null) => void; +} + +export default function MockSwapControls({ onMockStateChange }: Props) { + const [scenario, setScenario] = useState(null); + const [index, setIndex] = useState(0); + + const enabled = scenario !== null; + const total = scenario ? scenarios[scenario].length : 0; + + const handleToggle = (checked: boolean) => { + if (checked) { + const firstScenario = Object.keys(scenarios)[0] as MockScenario; + setScenario(firstScenario); + setIndex(0); + onMockStateChange(buildMockState(firstScenario, 0)); + } else { + setScenario(null); + setIndex(0); + onMockStateChange(null); + } + }; + + const handleScenarioChange = (newScenario: MockScenario) => { + setScenario(newScenario); + setIndex(0); + onMockStateChange(buildMockState(newScenario, 0)); + }; + + const prev = () => { + if (!scenario || index === 0) return; + const newIndex = index - 1; + setIndex(newIndex); + onMockStateChange(buildMockState(scenario, newIndex)); + }; + + const next = () => { + if (!scenario || index >= total - 1) return; + const newIndex = index + 1; + setIndex(newIndex); + onMockStateChange(buildMockState(scenario, newIndex)); + }; + + const currentStateName = scenario ? scenarios[scenario][index].type : null; + + return ( + + + handleToggle(e.target.checked)} + /> + + Mock + + + {enabled && ( + <> + + + + + {index + 1}/{total} + + + + + + {currentStateName} + + + )} + + + ); +} diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx index 0411806372..06b8ec3378 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx @@ -1,4 +1,5 @@ import { Box, Button, Dialog, DialogActions, Paper } from "@mui/material"; +import { useState } from "react"; import { useActiveSwapInfo, useAppSelector } from "store/hooks"; import SwapStatePage from "renderer/components/pages/swap/swap/SwapStatePage"; import CancelButton from "./CancelButton"; @@ -6,13 +7,16 @@ import SwapStateStepper from "renderer/components/modal/swap/SwapStateStepper"; import SwapStatusAlert from "renderer/components/alert/SwapStatusAlert/SwapStatusAlert"; import DebugPageSwitchBadge from "renderer/components/modal/swap/pages/DebugPageSwitchBadge"; import DebugPage from "renderer/components/modal/swap/pages/DebugPage"; -import { useState } from "react"; +import MockSwapControls from "renderer/components/modal/swap/pages/MockSwapControls"; +import { SwapState } from "models/storeModel"; export default function SwapWidget() { - const swap = useAppSelector((state) => state.swap); + const swapState = useAppSelector((state) => state.swap.state); const swapInfo = useActiveSwapInfo(); - const [debug, setDebug] = useState(false); + const [mockState, setMockState] = useState(null); + + const displayState = mockState ?? swapState; return ( - + - {swap.state !== null && ( + {displayState !== null && ( <> - + + {import.meta.env.DEV && } )} diff --git a/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx index 5859c28019..18c94d1b59 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx @@ -21,7 +21,10 @@ export default function ProcessExitedPage({ (prevState.type === "XmrRedeemInMempool" || prevState.type === "BtcRefunded" || prevState.type === "BtcPunished" || - prevState.type === "CooperativeRedeemRejected") + prevState.type === "CooperativeRedeemRejected" || + prevState.type === "BtcRefundBurnt" || + prevState.type === "BtcFinalAmnestyConfirmed" || + prevState.type === "BtcAmnestyReceived") ) { return ( Date: Tue, 6 Jan 2026 16:25:08 +0100 Subject: [PATCH 085/146] improve components for the partial refund path --- src-gui/src/dev/mockSwapEvents.ts | 112 +- .../modal/swap/SwapStateStepper.tsx | 116 +- .../pages/swap/swap/SwapStatePage.tsx | 40 +- .../components/pages/swap/swap/SwapWidget.tsx | 2 +- .../swap/done/BitcoinPartialRefundPage.tsx | 311 +- src-gui/yarn.lock | 11178 ++++++---------- swap/src/cli/api/tauri_bindings.rs | 42 +- swap/src/protocol/bob/swap.rs | 24 +- 8 files changed, 4868 insertions(+), 6957 deletions(-) diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index 5d4cc9b31f..366f131c36 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -27,6 +27,10 @@ const MOCK_BTC_REFUND_BURN_TXID = const MOCK_BTC_FINAL_AMNESTY_TXID = "c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"; +// Mock amounts for partial refund scenarios +const MOCK_BTC_LOCK_AMOUNT = 50_000_000; // 0.5 BTC +const MOCK_BTC_AMNESTY_AMOUNT = 2_500_000; // 0.025 BTC (5% of lock amount) + // Mock addresses const MOCK_BTC_DEPOSIT_ADDRESS = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"; const MOCK_XMR_ADDRESS = @@ -135,14 +139,36 @@ const partialRefundWithAmnesty: TauriSwapProgressEvent[] = [ { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: true }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, { type: "BtcPartiallyRefunded", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: true }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcAmnestyPublished", + content: { + btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcAmnestyReceived", + content: { + btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, - { type: "BtcAmnestyPublished", content: { btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID } }, - { type: "BtcAmnestyReceived", content: { btc_amnesty_txid: MOCK_BTC_AMNESTY_TXID } }, { type: "Released" }, ]; @@ -153,14 +179,36 @@ const partialRefundWithBurn: TauriSwapProgressEvent[] = [ { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, { type: "BtcPartiallyRefunded", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcRefundBurnPublished", + content: { + btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcRefundBurnt", + content: { + btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, - { type: "BtcRefundBurnPublished", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, - { type: "BtcRefundBurnt", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, { type: "Released" }, ]; @@ -171,16 +219,52 @@ const partialRefundWithBurnAndFinalAmnesty: TauriSwapProgressEvent[] = [ { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, { type: "BtcPartiallyRefunded", - content: { btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, has_amnesty_signature: false }, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcRefundBurnPublished", + content: { + btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcRefundBurnt", + content: { + btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcFinalAmnestyPublished", + content: { + btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, + }, + { + type: "BtcFinalAmnestyConfirmed", + content: { + btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + }, }, - { type: "BtcRefundBurnPublished", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, - { type: "BtcRefundBurnt", content: { btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID } }, - { type: "BtcFinalAmnestyPublished", content: { btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID } }, - { type: "BtcFinalAmnestyConfirmed", content: { btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID } }, { type: "Released" }, ]; diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index f270cb0127..609cd0bd5a 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -1,14 +1,25 @@ import { Step, StepLabel, Stepper, Typography } from "@mui/material"; import { SwapState } from "models/storeModel"; -import { useAppSelector } from "store/hooks"; import logger from "utils/logger"; export enum PathType { HAPPY_PATH = "happy path", - UNHAPPY_PATH = "unhappy path", + RECOVERY_PATH = "recovery path", } -type PathStep = [type: PathType, step: number, isError: boolean]; +export enum RecoveryScenario { + GENERIC = "generic", + FULL_REFUND = "full_refund", + PARTIAL_REFUND = "partial_refund", + COOPERATIVE_REDEEM = "cooperative_redeem", +} + +type PathStep = [ + type: PathType, + step: number, + isError: boolean, + scenario?: RecoveryScenario, +]; /** * Determines the current step in the swap process based on the previous and latest state. @@ -92,38 +103,62 @@ function getActiveStep(state: SwapState | null): PathStep | null { case "XmrRedeemInMempool": return [PathType.HAPPY_PATH, 4, false]; - // Unhappy Path States + // Recovery Path States - Generic (early states before we know outcome) - // Step 1: Cancel timelock has expired. Waiting for cancel transaction to be published + case "WaitingForCancelTimelockExpiration": case "CancelTimelockExpired": - return [PathType.UNHAPPY_PATH, 0, isReleased]; + return [PathType.RECOVERY_PATH, 0, isReleased, RecoveryScenario.GENERIC]; - // Step 2: Swap has been cancelled. Waiting for Bitcoin to be refunded case "BtcCancelled": - return [PathType.UNHAPPY_PATH, 1, isReleased]; + return [PathType.RECOVERY_PATH, 1, isReleased, RecoveryScenario.GENERIC]; + + // Recovery Path States - Full Refund - // Step 2: One of the two Bitcoin refund transactions have been published - // but they haven't been confirmed yet case "BtcRefundPublished": case "BtcEarlyRefundPublished": - return [PathType.UNHAPPY_PATH, 1, isReleased]; + return [PathType.RECOVERY_PATH, 1, isReleased, RecoveryScenario.FULL_REFUND]; - // Step 2: One of the two Bitcoin refund transactions have been confirmed case "BtcRefunded": case "BtcEarlyRefunded": - return [PathType.UNHAPPY_PATH, 2, false]; + return [PathType.RECOVERY_PATH, 2, false, RecoveryScenario.FULL_REFUND]; + + // Recovery Path States - Partial Refund + + case "BtcPartialRefundPublished": + return [PathType.RECOVERY_PATH, 1, isReleased, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcPartiallyRefunded": + return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcAmnestyPublished": + return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcAmnestyReceived": + return [PathType.RECOVERY_PATH, 3, false, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcRefundBurnPublished": + return [PathType.RECOVERY_PATH, 2, true, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcRefundBurnt": + return [PathType.RECOVERY_PATH, 2, true, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcFinalAmnestyPublished": + return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; + + case "BtcFinalAmnestyConfirmed": + return [PathType.RECOVERY_PATH, 3, false, RecoveryScenario.PARTIAL_REFUND]; + + // Recovery Path States - Cooperative Redeem (after punishment) - // Step 2 (Failed): Failed to refund Bitcoin - // The timelock expired before we could refund, resulting in punishment case "BtcPunished": - return [PathType.UNHAPPY_PATH, 1, true]; + return [PathType.RECOVERY_PATH, 1, true, RecoveryScenario.COOPERATIVE_REDEEM]; - // Attempting cooperative redemption after punishment case "AttemptingCooperativeRedeem": case "CooperativeRedeemAccepted": - return [PathType.UNHAPPY_PATH, 1, isReleased]; + return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.COOPERATIVE_REDEEM]; + case "CooperativeRedeemRejected": - return [PathType.UNHAPPY_PATH, 1, true]; + return [PathType.RECOVERY_PATH, 2, true, RecoveryScenario.COOPERATIVE_REDEEM]; case "Resuming": return null; @@ -163,15 +198,34 @@ function SwapStepper({ const HAPPY_PATH_STEP_LABELS = [ { label: "Locking your BTC", duration: "~12min" }, - { label: "They lock their XMR", duration: "~10min" }, + { label: "They lock their XMR", duration: "~20min" }, { label: "They redeem the BTC", duration: "~2min" }, - { label: "Redeeming your XMR", duration: "~10min" }, + { label: "Redeeming your XMR", duration: "~1min" }, ]; -const UNHAPPY_PATH_STEP_LABELS = [ - { label: "Cancelling swap", duration: "~1min" }, - { label: "Attempting recovery", duration: "~5min" }, -]; +const RECOVERY_STEP_LABELS: Record< + RecoveryScenario, + Array<{ label: string; duration: string }> +> = { + [RecoveryScenario.GENERIC]: [ + { label: "Cancelling swap", duration: "~1min" }, + { label: "Attempting recovery", duration: "" }, + ], + [RecoveryScenario.FULL_REFUND]: [ + { label: "Cancelling swap", duration: "~1min" }, + { label: "Bitcoin refunded", duration: "~5min" }, + ], + [RecoveryScenario.PARTIAL_REFUND]: [ + { label: "Cancelling swap", duration: "~1min" }, + { label: "Partial refund", duration: "~30min" }, + { label: "Remaining Bitcoin", duration: "~2min" }, + ], + [RecoveryScenario.COOPERATIVE_REDEEM]: [ + { label: "Cancelling swap", duration: "~1min" }, + { label: "We have been punished", duration: "" }, + { label: "Attempting cooperative recovery", duration: "~2min" }, + ], +}; export default function SwapStateStepper({ state, @@ -184,12 +238,14 @@ export default function SwapStateStepper({ return null; } - const [pathType, activeStep, error] = result; + const [pathType, activeStep, error, scenario] = result; - const steps = - pathType === PathType.HAPPY_PATH - ? HAPPY_PATH_STEP_LABELS - : UNHAPPY_PATH_STEP_LABELS; + let steps: Array<{ label: string; duration: string }>; + if (pathType === PathType.HAPPY_PATH) { + steps = HAPPY_PATH_STEP_LABELS; + } else { + steps = RECOVERY_STEP_LABELS[scenario ?? RecoveryScenario.GENERIC]; + } return ; } diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index 458d7b89e3..a764a473e2 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -138,23 +138,47 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { } break; case "BtcPartialRefundPublished": - return ; + if (state.curr.type === "BtcPartialRefundPublished") { + return ; + } + break; case "BtcPartiallyRefunded": - return ; + if (state.curr.type === "BtcPartiallyRefunded") { + return ; + } + break; case "BtcAmnestyPublished": - return ; + if (state.curr.type === "BtcAmnestyPublished") { + return ; + } + break; case "BtcAmnestyReceived": - return ; + if (state.curr.type === "BtcAmnestyReceived") { + return ; + } + break; //// 4 different types of refund burn / final amnesty states case "BtcRefundBurnPublished": - return ; + if (state.curr.type === "BtcRefundBurnPublished") { + return ; + } + break; case "BtcRefundBurnt": - return ; + if (state.curr.type === "BtcRefundBurnt") { + return ; + } + break; case "BtcFinalAmnestyPublished": - return ; + if (state.curr.type === "BtcFinalAmnestyPublished") { + return ; + } + break; case "BtcFinalAmnestyConfirmed": - return ; + if (state.curr.type === "BtcFinalAmnestyConfirmed") { + return ; + } + break; //// 4 different types of Bitcoin punished states we can be in case "BtcPunished": diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx index 06b8ec3378..2340d8424d 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx @@ -28,6 +28,7 @@ export default function SwapWidget() { onlyShowIfUnusualAmountOfTimeHasPassed /> )} + {import.meta.env.DEV && } - {import.meta.env.DEV && } )} diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 12f8063e62..628d10c955 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -12,34 +12,313 @@ * -> optionally BtcFinalAmnestyPublished -> BtcFinalAmnestyConfirmed (Alice grants final amnesty) */ -export function BitcoinPartialRefundPublished() { - return <>TxPartialRefund published; +import { Alert, Box, Button, DialogContentText, Typography } from "@mui/material"; +import { TauriSwapProgressEventContent } from "models/tauriModelExt"; +import { useActiveSwapInfo } from "store/hooks"; +import FeedbackInfoBox from "renderer/components/pages/help/FeedbackInfoBox"; +import BitcoinTransactionInfoBox from "renderer/components/pages/swap/swap/components/BitcoinTransactionInfoBox"; +import DiscordIcon from "renderer/components/icons/DiscordIcon"; +import MatrixIcon from "renderer/components/icons/MatrixIcon"; + +export function BitcoinPartialRefundPublished({ + btc_partial_refund_txid, + btc_lock_amount, + btc_amnesty_amount, +}: TauriSwapProgressEventContent<"BtcPartialRefundPublished">) { + return ( + + ); +} + +export function BitcoinPartiallyRefunded({ + btc_partial_refund_txid, + btc_lock_amount, + btc_amnesty_amount, +}: TauriSwapProgressEventContent<"BtcPartiallyRefunded">) { + return ( + + ); +} + +function PartialRefundPage({ + txid, + confirmed, + btcLockAmount, + btcAmnestyAmount, +}: { + txid: string; + confirmed: boolean; + btcLockAmount: number; + btcAmnestyAmount: number; +}) { + const swap = useActiveSwapInfo(); + + const guaranteedPercent = Math.round(((btcLockAmount - btcAmnestyAmount) / btcLockAmount) * 100); + const atRiskPercent = Math.round((btcAmnestyAmount / btcLockAmount) * 100); + + const mainMessage = confirmed + ? `Refunded the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to revoke the remaining ${atRiskPercent}%. Unless they do that we will claim it shortly.` + : `Refunding the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to revoke the remaining ${atRiskPercent}%. Unless they do that we will claim it shortly.`; + + const additionalContent = swap ? ( + <> + {!confirmed && "Waiting for transaction to be confirmed..."} + {!confirmed &&
} + Refund address: {swap.btc_refund_address} + + ) : null; + + return ( + <> + {mainMessage} + + + Patience: We are first claiming the guaranteed {guaranteedPercent}% of the Bitcoin refund. + It is not guaranteed that we can claim the remaining {atRiskPercent}%. + We will be able to claim the remaining Bitcoin shortly unless the market maker decides to revoke it. + + + + + + + ); +} + +// Amnesty pages - We're claiming the remaining Bitcoin ourselves (good outcome) + +export function BitcoinAmnestyPublished({ + btc_amnesty_txid, +}: TauriSwapProgressEventContent<"BtcAmnestyPublished">) { + return ( + + ); } -export function BitcoinPartiallyRefunded() { - return <>Bitcoin partially refunded; +export function BitcoinAmnestyReceived({ + btc_amnesty_txid, +}: TauriSwapProgressEventContent<"BtcAmnestyReceived">) { + return ( + + ); } -export function BitcoinAmnestyPublished() { - return <>TxAmnesty published; +function AmnestyPage({ + txid, + confirmed, +}: { + txid: string; + confirmed: boolean; +}) { + const swap = useActiveSwapInfo(); + + const mainMessage = confirmed + ? "All your Bitcoin has been refunded. The swap is complete." + : "The remaining Bitcoin is being released to you. Waiting for confirmation."; + + const additionalContent = swap ? ( + <> + {!confirmed && "Waiting for transaction to be confirmed..."} + {!confirmed &&
} + Refund address: {swap.btc_refund_address} + + ) : null; + + return ( + <> + {mainMessage} + + + {confirmed ? "Complete:" : "Almost there:"} The + remaining Bitcoin from your partial refund{" "} + {confirmed ? "has been" : "is being"} released to you. + + + + + + + + ); +} + +// Refund Burn pages - The maker actively burned the remaining Bitcoin (bad outcome) +// Note: By default, the user would have received the remaining Bitcoin after a timelock. +// If we're in this state, it means the maker actively published TxBurn to revoke it. + +export function BitcoinRefundBurnPublished({ + btc_refund_burn_txid, + btc_lock_amount, + btc_amnesty_amount, +}: TauriSwapProgressEventContent<"BtcRefundBurnPublished">) { + return ( + + ); } -export function BitcoinAmnestyReceived() { - return <>Bitcoin amnesty received; +export function BitcoinRefundBurnt({ + btc_refund_burn_txid, + btc_lock_amount, + btc_amnesty_amount, +}: TauriSwapProgressEventContent<"BtcRefundBurnt">) { + return ( + + ); } -export function BitcoinRefundBurnPublished() { - return <>TxRefundBurn published - Alice burned the amnesty output; +function RefundBurnPage({ + txid, + confirmed, + btcLockAmount, + btcAmnestyAmount, +}: { + txid: string; + confirmed: boolean; + btcLockAmount: number; + btcAmnestyAmount: number; +}) { + const atRiskPercent = Math.round((btcAmnestyAmount / btcLockAmount) * 100); + + const mainMessage = confirmed + ? "The market maker has revoked your remaining Bitcoin refund." + : "The market maker is revoking your remaining Bitcoin refund."; + + return ( + + {mainMessage} + + + Refund revoked: The market maker has revoked the remaining {atRiskPercent}% of your Bitcoin refund. + This portion is now lost and we cannot recover it on our own. + + + + + Why did this happen? Aborting a swap incurs significant costs on makers. + To prevent spam attacks, they can revoke a previously agreed upon part of the refund. + The maker has exercised this option because they think you are spamming them. + + + + + You can appeal. If you did not mean to spam the market maker, contact them through our official + community. The maker can still help you recover the remaining Bitcoin. + +
+ + + + +
+ +
+ ); } -export function BitcoinRefundBurnt() { - return <>Bitcoin refund is burnt - waiting for Alice to grant final amnesty; +// Final Amnesty pages - The maker granted final amnesty after the user appealed + +export function BitcoinFinalAmnestyPublished({ + btc_final_amnesty_txid, +}: TauriSwapProgressEventContent<"BtcFinalAmnestyPublished">) { + return ; } -export function BitcoinFinalAmnestyPublished() { - return <>TxFinalAmnesty published - Alice granted final amnesty; +export function BitcoinFinalAmnestyConfirmed({ + btc_final_amnesty_txid, +}: TauriSwapProgressEventContent<"BtcFinalAmnestyConfirmed">) { + return ; } -export function BitcoinFinalAmnestyConfirmed() { - return <>Bitcoin final amnesty received - swap complete; +function FinalAmnestyPage({ + txid, + confirmed, +}: { + txid: string; + confirmed: boolean; +}) { + const swap = useActiveSwapInfo(); + + const mainMessage = confirmed + ? "The market maker has granted you final amnesty. The remaining Bitcoin has been recovered." + : "The market maker is granting you final amnesty. Waiting for confirmation."; + + const additionalContent = swap ? ( + <> + {!confirmed && "Waiting for transaction to be confirmed..."} + {!confirmed &&
} + Refund address: {swap.btc_refund_address} + + ) : null; + + return ( + <> + {mainMessage} + + + Appeal successful: The market maker has decided to + release the remaining Bitcoin to you. All your Bitcoin has now been + fully refunded. + + + + + + + ); } diff --git a/src-gui/yarn.lock b/src-gui/yarn.lock index 49a5789e01..21d2f1cb4b 100644 --- a/src-gui/yarn.lock +++ b/src-gui/yarn.lock @@ -1,6874 +1,4304 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10c0 - -"@ampproject/remapping@npm:^2.2.0": - version: 2.3.0 - resolution: "@ampproject/remapping@npm:2.3.0" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/code-frame@npm:7.27.1" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.27.1" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.1.1" - checksum: 10c0/5dd9a18baa5fce4741ba729acc3a3272c49c25cb8736c4b18e113099520e7ef7b545a4096a26d600e4416157e63e87d66db46aa3fbf0a5f2286da2705c12da00 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.27.2": - version: 7.28.0 - resolution: "@babel/compat-data@npm:7.28.0" - checksum: 10c0/c4e527302bcd61052423f757355a71c3bc62362bac13f7f130de16e439716f66091ff5bdecda418e8fa0271d4c725f860f0ee23ab7bf6e769f7a8bb16dfcb531 - languageName: node - linkType: hard - -"@babel/core@npm:^7.24.4": - version: 7.28.5 - resolution: "@babel/core@npm:7.28.5" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.5" - "@babel/helper-compilation-targets": "npm:^7.27.2" - "@babel/helper-module-transforms": "npm:^7.28.3" - "@babel/helpers": "npm:^7.28.4" - "@babel/parser": "npm:^7.28.5" - "@babel/template": "npm:^7.27.2" - "@babel/traverse": "npm:^7.28.5" - "@babel/types": "npm:^7.28.5" - "@jridgewell/remapping": "npm:^2.3.5" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10c0/535f82238027621da6bdffbdbe896ebad3558b311d6f8abc680637a9859b96edbf929ab010757055381570b29cf66c4a295b5618318d27a4273c0e2033925e72 - languageName: node - linkType: hard - -"@babel/core@npm:^7.28.0": - version: 7.28.3 - resolution: "@babel/core@npm:7.28.3" - dependencies: - "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.3" - "@babel/helper-compilation-targets": "npm:^7.27.2" - "@babel/helper-module-transforms": "npm:^7.28.3" - "@babel/helpers": "npm:^7.28.3" - "@babel/parser": "npm:^7.28.3" - "@babel/template": "npm:^7.27.2" - "@babel/traverse": "npm:^7.28.3" - "@babel/types": "npm:^7.28.2" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10c0/e6b3eb830c4b93f5a442b305776df1cd2bb4fafa4612355366f67c764f3e54a69d45b84def77fb2d4fd83439102667b0a92c3ea2838f678733245b748c602a7b - languageName: node - linkType: hard - -"@babel/generator@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/generator@npm:7.28.3" - dependencies: - "@babel/parser": "npm:^7.28.3" - "@babel/types": "npm:^7.28.2" - "@jridgewell/gen-mapping": "npm:^0.3.12" - "@jridgewell/trace-mapping": "npm:^0.3.28" - jsesc: "npm:^3.0.2" - checksum: 10c0/0ff58bcf04f8803dcc29479b547b43b9b0b828ec1ee0668e92d79f9e90f388c28589056637c5ff2fd7bcf8d153c990d29c448d449d852bf9d1bc64753ca462bc - languageName: node - linkType: hard - -"@babel/generator@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/generator@npm:7.28.5" - dependencies: - "@babel/parser": "npm:^7.28.5" - "@babel/types": "npm:^7.28.5" - "@jridgewell/gen-mapping": "npm:^0.3.12" - "@jridgewell/trace-mapping": "npm:^0.3.28" - jsesc: "npm:^3.0.2" - checksum: 10c0/9f219fe1d5431b6919f1a5c60db8d5d34fe546c0d8f5a8511b32f847569234ffc8032beb9e7404649a143f54e15224ecb53a3d11b6bb85c3203e573d91fca752 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.27.2": - version: 7.27.2 - resolution: "@babel/helper-compilation-targets@npm:7.27.2" - dependencies: - "@babel/compat-data": "npm:^7.27.2" - "@babel/helper-validator-option": "npm:^7.27.1" - browserslist: "npm:^4.24.0" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10c0/f338fa00dcfea931804a7c55d1a1c81b6f0a09787e528ec580d5c21b3ecb3913f6cb0f361368973ce953b824d910d3ac3e8a8ee15192710d3563826447193ad1 - languageName: node - linkType: hard - -"@babel/helper-globals@npm:^7.28.0": - version: 7.28.0 - resolution: "@babel/helper-globals@npm:7.28.0" - checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-module-imports@npm:7.27.1" - dependencies: - "@babel/traverse": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - checksum: 10c0/e00aace096e4e29290ff8648455c2bc4ed982f0d61dbf2db1b5e750b9b98f318bf5788d75a4f974c151bd318fd549e81dbcab595f46b14b81c12eda3023f51e8 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/helper-module-transforms@npm:7.28.3" - dependencies: - "@babel/helper-module-imports": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - "@babel/traverse": "npm:^7.28.3" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-plugin-utils@npm:7.27.1" - checksum: 10c0/94cf22c81a0c11a09b197b41ab488d416ff62254ce13c57e62912c85700dc2e99e555225787a4099ff6bae7a1812d622c80fbaeda824b79baa10a6c5ac4cf69b - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-string-parser@npm:7.27.1" - checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-identifier@npm:7.27.1" - checksum: 10c0/c558f11c4871d526498e49d07a84752d1800bf72ac0d3dad100309a2eaba24efbf56ea59af5137ff15e3a00280ebe588560534b0e894a4750f8b1411d8f78b84 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/helper-validator-identifier@npm:7.28.5" - checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-option@npm:7.27.1" - checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/helpers@npm:7.28.3" - dependencies: - "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.2" - checksum: 10c0/03a8f94135415eec62d37be9c62c63908f2d5386c7b00e04545de4961996465775330e3eb57717ea7451e19b0e24615777ebfec408c2adb1df3b10b4df6bf1ce - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.28.4": - version: 7.28.4 - resolution: "@babel/helpers@npm:7.28.4" - dependencies: - "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.4" - checksum: 10c0/aaa5fb8098926dfed5f223adf2c5e4c7fbba4b911b73dfec2d7d3083f8ba694d201a206db673da2d9b3ae8c01793e795767654558c450c8c14b4c2175b4fcb44 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/parser@npm:7.28.3" - dependencies: - "@babel/types": "npm:^7.28.2" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/1f41eb82623b0ca0f94521b57f4790c6c457cd922b8e2597985b36bdec24114a9ccf54640286a760ceb60f11fe9102d192bf60477aee77f5d45f1029b9b72729 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.24.4, @babel/parser@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/parser@npm:7.28.5" - dependencies: - "@babel/types": "npm:^7.28.5" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/5bbe48bf2c79594ac02b490a41ffde7ef5aa22a9a88ad6bcc78432a6ba8a9d638d531d868bd1f104633f1f6bba9905746e15185b8276a3756c42b765d131b1ef - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-self@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-source@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.26.9, @babel/runtime@npm:^7.28.2, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.28.3 - resolution: "@babel/runtime@npm:7.28.3" - checksum: 10c0/b360f82c2c5114f2a062d4d143d7b4ec690094764853937110585a9497977aed66c102166d0e404766c274e02a50ffb8f6d77fef7251ecf3f607f0e03e6397bc - languageName: node - linkType: hard - -"@babel/template@npm:^7.27.2": - version: 7.27.2 - resolution: "@babel/template@npm:7.27.2" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/parser": "npm:^7.27.2" - "@babel/types": "npm:^7.27.1" - checksum: 10c0/ed9e9022651e463cc5f2cc21942f0e74544f1754d231add6348ff1b472985a3b3502041c0be62dc99ed2d12cfae0c51394bf827452b98a2f8769c03b87aadc81 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.3": - version: 7.28.3 - resolution: "@babel/traverse@npm:7.28.3" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.3" - "@babel/helper-globals": "npm:^7.28.0" - "@babel/parser": "npm:^7.28.3" - "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.2" - debug: "npm:^4.3.1" - checksum: 10c0/26e95b29a46925b7b41255e03185b7e65b2c4987e14bbee7bbf95867fb19c69181f301bbe1c7b201d4fe0cce6aa0cbea0282dad74b3a0fef3d9058f6c76fdcb3 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/traverse@npm:7.28.5" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.5" - "@babel/helper-globals": "npm:^7.28.0" - "@babel/parser": "npm:^7.28.5" - "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.5" - debug: "npm:^4.3.1" - checksum: 10c0/f6c4a595993ae2b73f2d4cd9c062f2e232174d293edd4abe1d715bd6281da8d99e47c65857e8d0917d9384c65972f4acdebc6749a7c40a8fcc38b3c7fb3e706f - languageName: node - linkType: hard - -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.27.1, @babel/types@npm:^7.28.2": - version: 7.28.2 - resolution: "@babel/types@npm:7.28.2" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - checksum: 10c0/24b11c9368e7e2c291fe3c1bcd1ed66f6593a3975f479cbb9dd7b8c8d8eab8a962b0d2fca616c043396ce82500ac7d23d594fbbbd013828182c01596370a0b10 - languageName: node - linkType: hard - -"@babel/types@npm:^7.26.0, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/types@npm:7.28.5" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.28.5" - checksum: 10c0/a5a483d2100befbf125793640dec26b90b95fd233a94c19573325898a5ce1e52cdfa96e495c7dcc31b5eca5b66ce3e6d4a0f5a4a62daec271455959f208ab08a - languageName: node - linkType: hard - -"@emotion/babel-plugin@npm:^11.13.5": - version: 11.13.5 - resolution: "@emotion/babel-plugin@npm:11.13.5" - dependencies: - "@babel/helper-module-imports": "npm:^7.16.7" - "@babel/runtime": "npm:^7.18.3" - "@emotion/hash": "npm:^0.9.2" - "@emotion/memoize": "npm:^0.9.0" - "@emotion/serialize": "npm:^1.3.3" - babel-plugin-macros: "npm:^3.1.0" - convert-source-map: "npm:^1.5.0" - escape-string-regexp: "npm:^4.0.0" - find-root: "npm:^1.1.0" - source-map: "npm:^0.5.7" - stylis: "npm:4.2.0" - checksum: 10c0/8ccbfec7defd0e513cb8a1568fa179eac1e20c35fda18aed767f6c59ea7314363ebf2de3e9d2df66c8ad78928dc3dceeded84e6fa8059087cae5c280090aeeeb - languageName: node - linkType: hard - -"@emotion/cache@npm:^11.14.0": - version: 11.14.0 - resolution: "@emotion/cache@npm:11.14.0" - dependencies: - "@emotion/memoize": "npm:^0.9.0" - "@emotion/sheet": "npm:^1.4.0" - "@emotion/utils": "npm:^1.4.2" - "@emotion/weak-memoize": "npm:^0.4.0" - stylis: "npm:4.2.0" - checksum: 10c0/3fa3e7a431ab6f8a47c67132a00ac8358f428c1b6c8421d4b20de9df7c18e95eec04a5a6ff5a68908f98d3280044f247b4965ac63df8302d2c94dba718769724 - languageName: node - linkType: hard - -"@emotion/hash@npm:^0.9.2": - version: 0.9.2 - resolution: "@emotion/hash@npm:0.9.2" - checksum: 10c0/0dc254561a3cc0a06a10bbce7f6a997883fd240c8c1928b93713f803a2e9153a257a488537012efe89dbe1246f2abfe2add62cdb3471a13d67137fcb808e81c2 - languageName: node - linkType: hard - -"@emotion/is-prop-valid@npm:^1.3.0": - version: 1.3.1 - resolution: "@emotion/is-prop-valid@npm:1.3.1" - dependencies: - "@emotion/memoize": "npm:^0.9.0" - checksum: 10c0/123215540c816ff510737ec68dcc499c53ea4deb0bb6c2c27c03ed21046e2e69f6ad07a7a174d271c6cfcbcc9ea44e1763e0cf3875c92192f7689216174803cd - languageName: node - linkType: hard - -"@emotion/memoize@npm:^0.9.0": - version: 0.9.0 - resolution: "@emotion/memoize@npm:0.9.0" - checksum: 10c0/13f474a9201c7f88b543e6ea42f55c04fb2fdc05e6c5a3108aced2f7e7aa7eda7794c56bba02985a46d8aaa914fcdde238727a98341a96e2aec750d372dadd15 - languageName: node - linkType: hard - -"@emotion/react@npm:^11.14.0": - version: 11.14.0 - resolution: "@emotion/react@npm:11.14.0" - dependencies: - "@babel/runtime": "npm:^7.18.3" - "@emotion/babel-plugin": "npm:^11.13.5" - "@emotion/cache": "npm:^11.14.0" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" - "@emotion/utils": "npm:^1.4.2" - "@emotion/weak-memoize": "npm:^0.4.0" - hoist-non-react-statics: "npm:^3.3.1" - peerDependencies: - react: ">=16.8.0" - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/d0864f571a9f99ec643420ef31fde09e2006d3943a6aba079980e4d5f6e9f9fecbcc54b8f617fe003c00092ff9d5241179149ffff2810cb05cf72b4620cfc031 - languageName: node - linkType: hard - -"@emotion/serialize@npm:^1.3.3": - version: 1.3.3 - resolution: "@emotion/serialize@npm:1.3.3" - dependencies: - "@emotion/hash": "npm:^0.9.2" - "@emotion/memoize": "npm:^0.9.0" - "@emotion/unitless": "npm:^0.10.0" - "@emotion/utils": "npm:^1.4.2" - csstype: "npm:^3.0.2" - checksum: 10c0/b28cb7de59de382021de2b26c0c94ebbfb16967a1b969a56fdb6408465a8993df243bfbd66430badaa6800e1834724e84895f5a6a9d97d0d224de3d77852acb4 - languageName: node - linkType: hard - -"@emotion/sheet@npm:^1.4.0": - version: 1.4.0 - resolution: "@emotion/sheet@npm:1.4.0" - checksum: 10c0/3ca72d1650a07d2fbb7e382761b130b4a887dcd04e6574b2d51ce578791240150d7072a9bcb4161933abbcd1e38b243a6fb4464a7fe991d700c17aa66bb5acc7 - languageName: node - linkType: hard - -"@emotion/styled@npm:^11.14.0": - version: 11.14.1 - resolution: "@emotion/styled@npm:11.14.1" - dependencies: - "@babel/runtime": "npm:^7.18.3" - "@emotion/babel-plugin": "npm:^11.13.5" - "@emotion/is-prop-valid": "npm:^1.3.0" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" - "@emotion/utils": "npm:^1.4.2" - peerDependencies: - "@emotion/react": ^11.0.0-rc.0 - react: ">=16.8.0" - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/2bbf8451df49c967e41fbcf8111a7f6dafe6757f0cc113f2f6e287206c45ac1d54dc8a95a483b7c0cee8614b8a8d08155bded6453d6721de1f8cc8d5b9216963 - languageName: node - linkType: hard - -"@emotion/unitless@npm:^0.10.0": - version: 0.10.0 - resolution: "@emotion/unitless@npm:0.10.0" - checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49 - languageName: node - linkType: hard - -"@emotion/use-insertion-effect-with-fallbacks@npm:^1.2.0": - version: 1.2.0 - resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" - peerDependencies: - react: ">=16.8.0" - checksum: 10c0/074dbc92b96bdc09209871070076e3b0351b6b47efefa849a7d9c37ab142130767609ca1831da0055988974e3b895c1de7606e4c421fecaa27c3e56a2afd3b08 - languageName: node - linkType: hard - -"@emotion/utils@npm:^1.4.2": - version: 1.4.2 - resolution: "@emotion/utils@npm:1.4.2" - checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a - languageName: node - linkType: hard - -"@emotion/weak-memoize@npm:^0.4.0": - version: 0.4.0 - resolution: "@emotion/weak-memoize@npm:0.4.0" - checksum: 10c0/64376af11f1266042d03b3305c30b7502e6084868e33327e944b539091a472f089db307af69240f7188f8bc6b319276fd7b141a36613f1160d73d12a60f6ca1a - languageName: node - linkType: hard - -"@esbuild/aix-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/aix-ppc64@npm:0.21.5" - conditions: os=aix & cpu=ppc64 - languageName: node - linkType: hard - -"@esbuild/android-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm64@npm:0.21.5" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@esbuild/android-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm@npm:0.21.5" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@esbuild/android-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-x64@npm:0.21.5" - conditions: os=android & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/darwin-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-arm64@npm:0.21.5" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@esbuild/darwin-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-x64@npm:0.21.5" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/freebsd-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-arm64@npm:0.21.5" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - -"@esbuild/freebsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-x64@npm:0.21.5" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/linux-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm64@npm:0.21.5" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - -"@esbuild/linux-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm@npm:0.21.5" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@esbuild/linux-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ia32@npm:0.21.5" - conditions: os=linux & cpu=ia32 - languageName: node - linkType: hard - -"@esbuild/linux-loong64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-loong64@npm:0.21.5" - conditions: os=linux & cpu=loong64 - languageName: node - linkType: hard - -"@esbuild/linux-mips64el@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-mips64el@npm:0.21.5" - conditions: os=linux & cpu=mips64el - languageName: node - linkType: hard - -"@esbuild/linux-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ppc64@npm:0.21.5" - conditions: os=linux & cpu=ppc64 - languageName: node - linkType: hard - -"@esbuild/linux-riscv64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-riscv64@npm:0.21.5" - conditions: os=linux & cpu=riscv64 - languageName: node - linkType: hard - -"@esbuild/linux-s390x@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-s390x@npm:0.21.5" - conditions: os=linux & cpu=s390x - languageName: node - linkType: hard - -"@esbuild/linux-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-x64@npm:0.21.5" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/netbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/netbsd-x64@npm:0.21.5" - conditions: os=netbsd & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/openbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/openbsd-x64@npm:0.21.5" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/sunos-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/sunos-x64@npm:0.21.5" - conditions: os=sunos & cpu=x64 - languageName: node - linkType: hard - -"@esbuild/win32-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-arm64@npm:0.21.5" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@esbuild/win32-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-ia32@npm:0.21.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@esbuild/win32-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-x64@npm:0.21.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.7.0": - version: 4.7.0 - resolution: "@eslint-community/eslint-utils@npm:4.7.0" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/c0f4f2bd73b7b7a9de74b716a664873d08ab71ab439e51befe77d61915af41a81ecec93b408778b3a7856185244c34c2c8ee28912072ec14def84ba2dec70adf - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.1": - version: 4.12.1 - resolution: "@eslint-community/regexpp@npm:4.12.1" - checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 - languageName: node - linkType: hard - -"@eslint/config-array@npm:^0.21.0": - version: 0.21.0 - resolution: "@eslint/config-array@npm:0.21.0" - dependencies: - "@eslint/object-schema": "npm:^2.1.6" - debug: "npm:^4.3.1" - minimatch: "npm:^3.1.2" - checksum: 10c0/0ea801139166c4aa56465b309af512ef9b2d3c68f9198751bbc3e21894fe70f25fbf26e1b0e9fffff41857bc21bfddeee58649ae6d79aadcd747db0c5dca771f - languageName: node - linkType: hard - -"@eslint/config-helpers@npm:^0.3.1": - version: 0.3.1 - resolution: "@eslint/config-helpers@npm:0.3.1" - checksum: 10c0/f6c5b3a0b76a0d7d84cc93e310c259e6c3e0792ddd0a62c5fc0027796ffae44183432cb74b2c2b1162801ee1b1b34a6beb5d90a151632b4df7349f994146a856 - languageName: node - linkType: hard - -"@eslint/core@npm:^0.15.2": - version: 0.15.2 - resolution: "@eslint/core@npm:0.15.2" - dependencies: - "@types/json-schema": "npm:^7.0.15" - checksum: 10c0/c17a6dc4f5a6006ecb60165cc38bcd21fefb4a10c7a2578a0cfe5813bbd442531a87ed741da5adab5eb678e8e693fda2e2b14555b035355537e32bcec367ea17 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^3.3.1": - version: 3.3.1 - resolution: "@eslint/eslintrc@npm:3.3.1" - dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^10.0.1" - globals: "npm:^14.0.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/b0e63f3bc5cce4555f791a4e487bf999173fcf27c65e1ab6e7d63634d8a43b33c3693e79f192cbff486d7df1be8ebb2bd2edc6e70ddd486cbfa84a359a3e3b41 - languageName: node - linkType: hard - -"@eslint/js@npm:9.33.0, @eslint/js@npm:^9.9.0": - version: 9.33.0 - resolution: "@eslint/js@npm:9.33.0" - checksum: 10c0/4c42c9abde76a183b8e47205fd6c3116b058f82f07b6ad4de40de56cdb30a36e9ecd40efbea1b63a84d08c206aadbb0aa39a890197e1ad6455a8e542df98f186 - languageName: node - linkType: hard - -"@eslint/object-schema@npm:^2.1.6": - version: 2.1.6 - resolution: "@eslint/object-schema@npm:2.1.6" - checksum: 10c0/b8cdb7edea5bc5f6a96173f8d768d3554a628327af536da2fc6967a93b040f2557114d98dbcdbf389d5a7b290985ad6a9ce5babc547f36fc1fde42e674d11a56 - languageName: node - linkType: hard - -"@eslint/plugin-kit@npm:^0.3.5": - version: 0.3.5 - resolution: "@eslint/plugin-kit@npm:0.3.5" - dependencies: - "@eslint/core": "npm:^0.15.2" - levn: "npm:^0.4.1" - checksum: 10c0/c178c1b58c574200c0fd125af3e4bc775daba7ce434ba6d1eeaf9bcb64b2e9fea75efabffb3ed3ab28858e55a016a5efa95f509994ee4341b341199ca630b89e - languageName: node - linkType: hard - -"@fontsource/roboto@npm:^5.1.0": - version: 5.2.6 - resolution: "@fontsource/roboto@npm:5.2.6" - checksum: 10c0/a2fbadf2f3b8ebb859e7b13ad82d25e8b43901c30ad93b08095c201617fcfded279d99e64a7b110614d2a1b5bca77631df7d009abf1ad6c6a4df301ceb330a51 - languageName: node - linkType: hard - -"@humanfs/core@npm:^0.19.1": - version: 0.19.1 - resolution: "@humanfs/core@npm:0.19.1" - checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 - languageName: node - linkType: hard - -"@humanfs/node@npm:^0.16.6": - version: 0.16.6 - resolution: "@humanfs/node@npm:0.16.6" - dependencies: - "@humanfs/core": "npm:^0.19.1" - "@humanwhocodes/retry": "npm:^0.3.0" - checksum: 10c0/8356359c9f60108ec204cbd249ecd0356667359b2524886b357617c4a7c3b6aace0fd5a369f63747b926a762a88f8a25bc066fa1778508d110195ce7686243e1 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 - languageName: node - linkType: hard - -"@humanwhocodes/retry@npm:^0.3.0": - version: 0.3.1 - resolution: "@humanwhocodes/retry@npm:0.3.1" - checksum: 10c0/f0da1282dfb45e8120480b9e2e275e2ac9bbe1cf016d046fdad8e27cc1285c45bb9e711681237944445157b430093412b4446c1ab3fc4bb037861b5904101d3b - languageName: node - linkType: hard - -"@humanwhocodes/retry@npm:^0.4.2": - version: 0.4.3 - resolution: "@humanwhocodes/retry@npm:0.4.3" - checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 - languageName: node - linkType: hard - -"@isaacs/balanced-match@npm:^4.0.1": - version: 4.0.1 - resolution: "@isaacs/balanced-match@npm:4.0.1" - checksum: 10c0/7da011805b259ec5c955f01cee903da72ad97c5e6f01ca96197267d3f33103d5b2f8a1af192140f3aa64526c593c8d098ae366c2b11f7f17645d12387c2fd420 - languageName: node - linkType: hard - -"@isaacs/brace-expansion@npm:^5.0.0": - version: 5.0.0 - resolution: "@isaacs/brace-expansion@npm:5.0.0" - dependencies: - "@isaacs/balanced-match": "npm:^4.0.1" - checksum: 10c0/b4d4812f4be53afc2c5b6c545001ff7a4659af68d4484804e9d514e183d20269bb81def8682c01a22b17c4d6aed14292c8494f7d2ac664e547101c1a905aa977 - languageName: node - linkType: hard - -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.13 - resolution: "@jridgewell/gen-mapping@npm:0.3.13" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.5.0" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b - languageName: node - linkType: hard - -"@jridgewell/remapping@npm:^2.3.5": - version: 2.3.5 - resolution: "@jridgewell/remapping@npm:2.3.5" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.2 - resolution: "@jridgewell/resolve-uri@npm:3.1.2" - checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5": - version: 1.5.5 - resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" - checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": - version: 0.3.30 - resolution: "@jridgewell/trace-mapping@npm:0.3.30" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10c0/3a1516c10f44613b9ba27c37a02ff8f410893776b2b3dad20a391b51b884dd60f97bbb56936d65d2ff8fe978510a0000266654ab8426bdb9ceb5fb4585b19e23 - languageName: node - linkType: hard - -"@mui/core-downloads-tracker@npm:^7.3.1": - version: 7.3.1 - resolution: "@mui/core-downloads-tracker@npm:7.3.1" - checksum: 10c0/4d89ce22ebeba860e76a4fa35aa4946515d921c3c2834551639e99ff622afec2ae6c03fed881c4352283b2cad2f3b731fbde7802740b9b321451bf5e694f733c - languageName: node - linkType: hard - -"@mui/icons-material@npm:^7.1.1": - version: 7.3.1 - resolution: "@mui/icons-material@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - peerDependencies: - "@mui/material": ^7.3.1 - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/cd35a2417e5c655b3cda5ef9e90cdb9ff7482d36a0d74b05d22ea5fd43b5dd02be004e3ab314e57defcbabc55342e8bbb910660907ab219551fffd7a3bbc85fa - languageName: node - linkType: hard - -"@mui/material@npm:^7.1.1": - version: 7.3.1 - resolution: "@mui/material@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/core-downloads-tracker": "npm:^7.3.1" - "@mui/system": "npm:^7.3.1" - "@mui/types": "npm:^7.4.5" - "@mui/utils": "npm:^7.3.1" - "@popperjs/core": "npm:^2.11.8" - "@types/react-transition-group": "npm:^4.4.12" - clsx: "npm:^2.1.1" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.1.1" - react-transition-group: "npm:^4.4.5" - peerDependencies: - "@emotion/react": ^11.5.0 - "@emotion/styled": ^11.3.0 - "@mui/material-pigment-css": ^7.3.1 - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - "@mui/material-pigment-css": - optional: true - "@types/react": - optional: true - checksum: 10c0/078fc8ff9aae3ecbc07112a04dc1722afdae2564c51b5201340452f3bbef8deed4565734ca8b3222145431e3171cfeeff093b95920b7afb4f4bea3ea75346368 - languageName: node - linkType: hard - -"@mui/private-theming@npm:^7.3.1": - version: 7.3.1 - resolution: "@mui/private-theming@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/utils": "npm:^7.3.1" - prop-types: "npm:^15.8.1" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/f92ffdcdbaed42a6dbf4cc721921a6f64ae546e40e59f5da7ca6d7bb432870ae03d9ff84df26aede970e14f5eebb3743f76a212ac2ae46ff2bd06907ddd08005 - languageName: node - linkType: hard - -"@mui/styled-engine@npm:^7.3.1": - version: 7.3.1 - resolution: "@mui/styled-engine@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@emotion/cache": "npm:^11.14.0" - "@emotion/serialize": "npm:^1.3.3" - "@emotion/sheet": "npm:^1.4.0" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - peerDependencies: - "@emotion/react": ^11.4.1 - "@emotion/styled": ^11.3.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - checksum: 10c0/1b532153e3b7c357d3988e1a9fe569cb8e37aeece70ac17da8e1d1f3fb7dfc7134f6ec997b8cb3dcb70f8a0fea6574dc05bf198e14d971e0133e64c58d0a7755 - languageName: node - linkType: hard - -"@mui/system@npm:^7.3.1": - version: 7.3.1 - resolution: "@mui/system@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/private-theming": "npm:^7.3.1" - "@mui/styled-engine": "npm:^7.3.1" - "@mui/types": "npm:^7.4.5" - "@mui/utils": "npm:^7.3.1" - clsx: "npm:^2.1.1" - csstype: "npm:^3.1.3" - prop-types: "npm:^15.8.1" - peerDependencies: - "@emotion/react": ^11.5.0 - "@emotion/styled": ^11.3.0 - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - "@types/react": - optional: true - checksum: 10c0/032759c8f3b7c6575771f3865535ce89f74ee0340c7e90769ebe0f44f7e1cd23a14dc1c98b8d7e61bb20f685d7d9b0a283823084f25deb1b73179224cb86357e - languageName: node - linkType: hard - -"@mui/types@npm:^7.4.5": - version: 7.4.5 - resolution: "@mui/types@npm:7.4.5" - dependencies: - "@babel/runtime": "npm:^7.28.2" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/65015aacdc388a48e62c7bf11d167709f6d7e19e32fa8d4b36d34d391e10edc315bc2d64bf7f542d54fd973e812533800e715c5b0f149c29c3852e2c3dc11587 - languageName: node - linkType: hard - -"@mui/utils@npm:^7.3.1": - version: 7.3.1 - resolution: "@mui/utils@npm:7.3.1" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/types": "npm:^7.4.5" - "@types/prop-types": "npm:^15.7.15" - clsx: "npm:^2.1.1" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.1.1" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/5b36ba0d21f2394df9f9230d8c059d277f006adb31697b4a82da0cc5f720f8959fb24e281b59e5e1e6de6fc03dbc3e32fbd5ed4390570d465530c48a5ecbb2f8 - languageName: node - linkType: hard - -"@mui/x-date-pickers@npm:^8.8.0": - version: 8.10.2 - resolution: "@mui/x-date-pickers@npm:8.10.2" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/utils": "npm:^7.3.1" - "@mui/x-internals": "npm:8.10.2" - "@types/react-transition-group": "npm:^4.4.12" - clsx: "npm:^2.1.1" - prop-types: "npm:^15.8.1" - react-transition-group: "npm:^4.4.5" - peerDependencies: - "@emotion/react": ^11.9.0 - "@emotion/styled": ^11.8.1 - "@mui/material": ^5.15.14 || ^6.0.0 || ^7.0.0 - "@mui/system": ^5.15.14 || ^6.0.0 || ^7.0.0 - date-fns: ^2.25.0 || ^3.2.0 || ^4.0.0 - date-fns-jalali: ^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0 - dayjs: ^1.10.7 - luxon: ^3.0.2 - moment: ^2.29.4 - moment-hijri: ^2.1.2 || ^3.0.0 - moment-jalaali: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@emotion/react": - optional: true - "@emotion/styled": - optional: true - date-fns: - optional: true - date-fns-jalali: - optional: true - dayjs: - optional: true - luxon: - optional: true - moment: - optional: true - moment-hijri: - optional: true - moment-jalaali: - optional: true - checksum: 10c0/5ba6b3ff59b9203f24b91480bfd5c8830d7ef561083ec048fae75af806946635397b605f2cb37f3f0dc835bd8354d57db76861a79984914086da68e16e9e12b6 - languageName: node - linkType: hard - -"@mui/x-internals@npm:8.10.2": - version: 8.10.2 - resolution: "@mui/x-internals@npm:8.10.2" - dependencies: - "@babel/runtime": "npm:^7.28.2" - "@mui/utils": "npm:^7.3.1" - reselect: "npm:^5.1.1" - use-sync-external-store: "npm:^1.5.0" - peerDependencies: - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/644bd1be5fa19b9376c0853eaac0670fef6611f3cac0657acdee1931193a749fb49920deb41ad41ebf9abc2242ca807c0c9e8b6f088e8f7cf9c85a8f802f3022 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/agent@npm:4.0.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^11.2.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^5.0.0": - version: 5.0.0 - resolution: "@npmcli/fs@npm:5.0.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10c0/26e376d780f60ff16e874a0ac9bc3399186846baae0b6e1352286385ac134d900cc5dafaded77f38d77f86898fc923ae1cee9d7399f0275b1aa24878915d722b - languageName: node - linkType: hard - -"@popperjs/core@npm:^2.11.8": - version: 2.11.8 - resolution: "@popperjs/core@npm:2.11.8" - checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 - languageName: node - linkType: hard - -"@redux-devtools/core@npm:^4.1.1": - version: 4.1.1 - resolution: "@redux-devtools/core@npm:4.1.1" - dependencies: - "@babel/runtime": "npm:^7.26.9" - "@redux-devtools/instrument": "npm:^2.2.0" - peerDependencies: - react: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-redux: ^7.0.0 || ^8.0.0 || ^9.0.0 - redux: ^3.5.2 || ^4.0.0 || ^5.0.0 - checksum: 10c0/02a436c3c3f46a29e03f12b2659ed48c3952b8ee984fb997401b0fdf84e3df12f65b6fe73679a4d45efa12eff8e202460da1d68e981502514507c0b5abae4676 - languageName: node - linkType: hard - -"@redux-devtools/instrument@npm:^2.2.0": - version: 2.2.0 - resolution: "@redux-devtools/instrument@npm:2.2.0" - dependencies: - "@babel/runtime": "npm:^7.23.2" - lodash: "npm:^4.17.21" - peerDependencies: - redux: ^3.4.0 || ^4.0.0 || ^5.0.0 - checksum: 10c0/266cd15f1ef144bbb4a2ea472c096d2a4fa72341c4c892827d633a3c85b62d1240a35aaeab71a29020f1da4da0ab2f778c176fb30c35546f6a5020a26ba1c56a - languageName: node - linkType: hard - -"@redux-devtools/remote@npm:^0.9.5": - version: 0.9.5 - resolution: "@redux-devtools/remote@npm:0.9.5" - dependencies: - "@babel/runtime": "npm:^7.26.9" - "@redux-devtools/instrument": "npm:^2.2.0" - "@redux-devtools/utils": "npm:^3.1.1" - jsan: "npm:^3.1.14" - rn-host-detect: "npm:^1.2.0" - socketcluster-client: "npm:^19.2.3" - peerDependencies: - redux: ^3.5.2 || ^4.0.0 || ^5.0.0 - checksum: 10c0/ecb13fe01008afe25d860221c505a97774e43c81f04c2e381ec9a56e2f64c6ee3eb204ad34142f7d9149db8b64be1607e824d82a79eea3e5d99fe399b9805236 - languageName: node - linkType: hard - -"@redux-devtools/serialize@npm:^0.4.2": - version: 0.4.2 - resolution: "@redux-devtools/serialize@npm:0.4.2" - dependencies: - "@babel/runtime": "npm:^7.23.2" - jsan: "npm:^3.1.14" - peerDependencies: - immutable: ^4.0.0 - checksum: 10c0/9906d5fea1214ed82cb453d9a06b76c31fb9ddeea1f5fab18220af721f82c0efce6764353865cced3c481f0e421bfdd45701f2aea19a7678db07c56a5cdd5ad8 - languageName: node - linkType: hard - -"@redux-devtools/utils@npm:^3.1.1": - version: 3.1.1 - resolution: "@redux-devtools/utils@npm:3.1.1" - dependencies: - "@babel/runtime": "npm:^7.26.9" - "@redux-devtools/core": "npm:^4.1.1" - "@redux-devtools/serialize": "npm:^0.4.2" - "@types/get-params": "npm:^0.1.2" - get-params: "npm:^0.1.2" - immutable: "npm:^4.3.7" - jsan: "npm:^3.1.14" - nanoid: "npm:^5.1.2" - redux: "npm:^5.0.1" - peerDependencies: - "@redux-devtools/core": ^4.1.1 - immutable: ^4.3.7 - redux: ^4.0.0 || ^5.0.0 - checksum: 10c0/ea03fee3e633329d0d8cb84d7fb3aa739302b5e190fed23987e0663de4654e1d26be1ea01a61082b7497b8ac11a029fc4516a9f26d7aa057b5056e53fff170a0 - languageName: node - linkType: hard - -"@reduxjs/toolkit@npm:^2.3.0": - version: 2.8.2 - resolution: "@reduxjs/toolkit@npm:2.8.2" - dependencies: - "@standard-schema/spec": "npm:^1.0.0" - "@standard-schema/utils": "npm:^0.3.0" - immer: "npm:^10.0.3" - redux: "npm:^5.0.1" - redux-thunk: "npm:^3.1.0" - reselect: "npm:^5.1.0" - peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 || ^19 - react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true - checksum: 10c0/6a7a33bad5f1100340757151ff86ca0c4c248f030ae56ce0e6f1d98b39fa87c8f193e9faa2ebd6d5a4c0416921e9f9f7a2bbdd81156c39f08f6bf5ce70c2b927 - languageName: node - linkType: hard - -"@rolldown/pluginutils@npm:1.0.0-beta.27": - version: 1.0.0-beta.27 - resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27" - checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c - languageName: node - linkType: hard - -"@rollup/plugin-virtual@npm:^3.0.2": - version: 3.0.2 - resolution: "@rollup/plugin-virtual@npm:3.0.2" - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: 10c0/7115edb7989096d1ce334939fcf6e1ba365586b487bf61b2dd4f915386197f350db70904030342c0720fe58f5a52828975c645c4d415c1d432d9b1b6760a22ef - languageName: node - linkType: hard - -"@rollup/rollup-android-arm-eabi@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.47.1" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@rollup/rollup-android-arm64@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-android-arm64@npm:4.47.1" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-arm64@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-darwin-arm64@npm:4.47.1" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-darwin-x64@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-darwin-x64@npm:4.47.1" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-freebsd-arm64@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.47.1" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-freebsd-x64@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-freebsd-x64@npm:4.47.1" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-gnueabihf@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.47.1" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm-musleabihf@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.47.1" - conditions: os=linux & cpu=arm & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.47.1" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-arm64-musl@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.47.1" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-loongarch64-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.47.1" - conditions: os=linux & cpu=loong64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-ppc64-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.47.1" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-riscv64-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.47.1" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-riscv64-musl@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.47.1" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-linux-s390x-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.47.1" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-gnu@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.47.1" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@rollup/rollup-linux-x64-musl@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.47.1" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@rollup/rollup-win32-arm64-msvc@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.47.1" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@rollup/rollup-win32-ia32-msvc@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.47.1" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@rollup/rollup-win32-x64-msvc@npm:4.47.1": - version: 4.47.1 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.47.1" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b - languageName: node - linkType: hard - -"@standard-schema/spec@npm:^1.0.0": - version: 1.0.0 - resolution: "@standard-schema/spec@npm:1.0.0" - checksum: 10c0/a1ab9a8bdc09b5b47aa8365d0e0ec40cc2df6437be02853696a0e377321653b0d3ac6f079a8c67d5ddbe9821025584b1fb71d9cc041a6666a96f1fadf2ece15f - languageName: node - linkType: hard - -"@standard-schema/utils@npm:^0.3.0": - version: 0.3.0 - resolution: "@standard-schema/utils@npm:0.3.0" - checksum: 10c0/6eb74cd13e52d5fc74054df51e37d947ef53f3ab9e02c085665dcca3c38c60ece8d735cebbdf18fbb13c775fbcb9becb3f53109b0e092a63f0f7389ce0993fd0 - languageName: node - linkType: hard - -"@swc/core-darwin-arm64@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-darwin-arm64@npm:1.13.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@swc/core-darwin-x64@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-darwin-x64@npm:1.13.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@swc/core-linux-arm-gnueabihf@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.13.4" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@swc/core-linux-arm64-gnu@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-linux-arm64-gnu@npm:1.13.4" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@swc/core-linux-arm64-musl@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-linux-arm64-musl@npm:1.13.4" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@swc/core-linux-x64-gnu@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-linux-x64-gnu@npm:1.13.4" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@swc/core-linux-x64-musl@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-linux-x64-musl@npm:1.13.4" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@swc/core-win32-arm64-msvc@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-win32-arm64-msvc@npm:1.13.4" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@swc/core-win32-ia32-msvc@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-win32-ia32-msvc@npm:1.13.4" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@swc/core-win32-x64-msvc@npm:1.13.4": - version: 1.13.4 - resolution: "@swc/core-win32-x64-msvc@npm:1.13.4" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@swc/core@npm:^1.12.14": - version: 1.13.4 - resolution: "@swc/core@npm:1.13.4" - dependencies: - "@swc/core-darwin-arm64": "npm:1.13.4" - "@swc/core-darwin-x64": "npm:1.13.4" - "@swc/core-linux-arm-gnueabihf": "npm:1.13.4" - "@swc/core-linux-arm64-gnu": "npm:1.13.4" - "@swc/core-linux-arm64-musl": "npm:1.13.4" - "@swc/core-linux-x64-gnu": "npm:1.13.4" - "@swc/core-linux-x64-musl": "npm:1.13.4" - "@swc/core-win32-arm64-msvc": "npm:1.13.4" - "@swc/core-win32-ia32-msvc": "npm:1.13.4" - "@swc/core-win32-x64-msvc": "npm:1.13.4" - "@swc/counter": "npm:^0.1.3" - "@swc/types": "npm:^0.1.24" - peerDependencies: - "@swc/helpers": ">=0.5.17" - dependenciesMeta: - "@swc/core-darwin-arm64": - optional: true - "@swc/core-darwin-x64": - optional: true - "@swc/core-linux-arm-gnueabihf": - optional: true - "@swc/core-linux-arm64-gnu": - optional: true - "@swc/core-linux-arm64-musl": - optional: true - "@swc/core-linux-x64-gnu": - optional: true - "@swc/core-linux-x64-musl": - optional: true - "@swc/core-win32-arm64-msvc": - optional: true - "@swc/core-win32-ia32-msvc": - optional: true - "@swc/core-win32-x64-msvc": - optional: true - peerDependenciesMeta: - "@swc/helpers": - optional: true - checksum: 10c0/4c762961085421dcb88faa187466b36e363984f40003df87a82df0194d42bd930a788a1c8e0523534f007824a2c4c37888e6bceda93c72458e6b1d0caa3dff88 - languageName: node - linkType: hard - -"@swc/counter@npm:^0.1.3": - version: 0.1.3 - resolution: "@swc/counter@npm:0.1.3" - checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 - languageName: node - linkType: hard - -"@swc/types@npm:^0.1.24": - version: 0.1.24 - resolution: "@swc/types@npm:0.1.24" - dependencies: - "@swc/counter": "npm:^0.1.3" - checksum: 10c0/4ca95a338f070f48303e705996bacfc1219f606c45274bed4f6e3488b86b7b20397bd52792e58fdea0fa924fc939695b5eb5ff7f3ff4737382148fe6097e235a - languageName: node - linkType: hard - -"@swc/wasm@npm:^1.12.14": - version: 1.13.4 - resolution: "@swc/wasm@npm:1.13.4" - checksum: 10c0/cdbd4b1e30d9ad979c878c71b9e6c607c876fcc6a9efa10a4af68291924b47585302bfbba5262510f38c94c478ab3f4384d0a3c96e1ce47e2b3030070b3a3890 - languageName: node - linkType: hard - -"@tauri-apps/api@npm:^2.6.0, @tauri-apps/api@npm:^2.8.0": - version: 2.8.0 - resolution: "@tauri-apps/api@npm:2.8.0" - checksum: 10c0/fb111e4d7572372997b440ebe6879543fa8c4765151878e3fddfbfe809b18da29eed142ce83061d14a9ca6d896b3266dc8a4927c642d71cdc0b4277dc7e3aabf - languageName: node - linkType: hard - -"@tauri-apps/cli-darwin-arm64@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-darwin-arm64@npm:2.8.1" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@tauri-apps/cli-darwin-x64@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-darwin-x64@npm:2.8.1" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-arm-gnueabihf@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-arm-gnueabihf@npm:2.8.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-arm64-gnu@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-arm64-gnu@npm:2.8.1" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-arm64-musl@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-arm64-musl@npm:2.8.1" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-riscv64-gnu@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-riscv64-gnu@npm:2.8.1" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-x64-gnu@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-x64-gnu@npm:2.8.1" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@tauri-apps/cli-linux-x64-musl@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-linux-x64-musl@npm:2.8.1" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@tauri-apps/cli-win32-arm64-msvc@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-win32-arm64-msvc@npm:2.8.1" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@tauri-apps/cli-win32-ia32-msvc@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-win32-ia32-msvc@npm:2.8.1" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@tauri-apps/cli-win32-x64-msvc@npm:2.8.1": - version: 2.8.1 - resolution: "@tauri-apps/cli-win32-x64-msvc@npm:2.8.1" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@tauri-apps/cli@npm:^2.0.0": - version: 2.8.1 - resolution: "@tauri-apps/cli@npm:2.8.1" - dependencies: - "@tauri-apps/cli-darwin-arm64": "npm:2.8.1" - "@tauri-apps/cli-darwin-x64": "npm:2.8.1" - "@tauri-apps/cli-linux-arm-gnueabihf": "npm:2.8.1" - "@tauri-apps/cli-linux-arm64-gnu": "npm:2.8.1" - "@tauri-apps/cli-linux-arm64-musl": "npm:2.8.1" - "@tauri-apps/cli-linux-riscv64-gnu": "npm:2.8.1" - "@tauri-apps/cli-linux-x64-gnu": "npm:2.8.1" - "@tauri-apps/cli-linux-x64-musl": "npm:2.8.1" - "@tauri-apps/cli-win32-arm64-msvc": "npm:2.8.1" - "@tauri-apps/cli-win32-ia32-msvc": "npm:2.8.1" - "@tauri-apps/cli-win32-x64-msvc": "npm:2.8.1" - dependenciesMeta: - "@tauri-apps/cli-darwin-arm64": - optional: true - "@tauri-apps/cli-darwin-x64": - optional: true - "@tauri-apps/cli-linux-arm-gnueabihf": - optional: true - "@tauri-apps/cli-linux-arm64-gnu": - optional: true - "@tauri-apps/cli-linux-arm64-musl": - optional: true - "@tauri-apps/cli-linux-riscv64-gnu": - optional: true - "@tauri-apps/cli-linux-x64-gnu": - optional: true - "@tauri-apps/cli-linux-x64-musl": - optional: true - "@tauri-apps/cli-win32-arm64-msvc": - optional: true - "@tauri-apps/cli-win32-ia32-msvc": - optional: true - "@tauri-apps/cli-win32-x64-msvc": - optional: true - bin: - tauri: tauri.js - checksum: 10c0/78ceed9d56d0653ab3d6924a4f54e388f42a3ac92a2004ed43f68fe3e55c5de080f35c00110aef4c622d91cff8aeeb7d4cd87b691973d948043c8d8a959893f2 - languageName: node - linkType: hard - -"@tauri-apps/plugin-cli@npm:^2.4.0": - version: 2.4.0 - resolution: "@tauri-apps/plugin-cli@npm:2.4.0" - dependencies: - "@tauri-apps/api": "npm:^2.6.0" - checksum: 10c0/0ae04cf5a987d48dbd6aa3f89dae284ec8062b5657b7d0edf529754b554841bbe7464fc574f0726b971418bff011414a687b72d32854239f36f65deadf29cfbd - languageName: node - linkType: hard - -"@tauri-apps/plugin-clipboard-manager@npm:^2.3.0": - version: 2.3.0 - resolution: "@tauri-apps/plugin-clipboard-manager@npm:2.3.0" - dependencies: - "@tauri-apps/api": "npm:^2.6.0" - checksum: 10c0/e3bacee3575779d234d4411cfeebf787c548f7f775b481540a4cb81bd3a2cedfa351a7eef799030d449c05b52469af666fa1cf10cdf165de7d788480cd3323fc - languageName: node - linkType: hard - -"@tauri-apps/plugin-dialog@npm:^2.0.0": - version: 2.3.3 - resolution: "@tauri-apps/plugin-dialog@npm:2.3.3" - dependencies: - "@tauri-apps/api": "npm:^2.8.0" - checksum: 10c0/6e8555312dc2788da353a29c9dec9274fc03e5bb233a6f1ae1eee52df4198750f7718ab7dc5036ea2289fa09175d10ecb24737c64e2184ee346f778720fee283 - languageName: node - linkType: hard - -"@tauri-apps/plugin-opener@npm:^2.5.0": - version: 2.5.0 - resolution: "@tauri-apps/plugin-opener@npm:2.5.0" - dependencies: - "@tauri-apps/api": "npm:^2.8.0" - checksum: 10c0/31503644c64678e5f5d1d995c0db145a3dabeb1bef1b9f7cfef84a83e4188c169f630207705fc6484f9e1934be6bd59de50676e4b9f1e2f628d1b54e38f00dbd - languageName: node - linkType: hard - -"@tauri-apps/plugin-process@npm:^2.3.0": - version: 2.3.0 - resolution: "@tauri-apps/plugin-process@npm:2.3.0" - dependencies: - "@tauri-apps/api": "npm:^2.6.0" - checksum: 10c0/ef50344a7436d92278c2ef4526f72daaf3171c4d65743bbc1f7a00fa581644a8583bb8680f637a34af5c7e6a0e8722c22189290e903584fef70ed83b64b6e9c0 - languageName: node - linkType: hard - -"@tauri-apps/plugin-store@npm:^2.4.0": - version: 2.4.0 - resolution: "@tauri-apps/plugin-store@npm:2.4.0" - dependencies: - "@tauri-apps/api": "npm:^2.8.0" - checksum: 10c0/2896fe1e8d9f23015f4a586efd3dd100e8dc96a9d353dd396d7b274ec3fba45bcb4ba7f63915379c18a5a1e109301dbeb3950eee97bb542677f407c6e5229212 - languageName: node - linkType: hard - -"@tauri-apps/plugin-updater@npm:^2.9.0": - version: 2.9.0 - resolution: "@tauri-apps/plugin-updater@npm:2.9.0" - dependencies: - "@tauri-apps/api": "npm:^2.6.0" - checksum: 10c0/72ce83d1c241308a13b9929f0900e4d33453875877009166e3998e3e75a1003ac48c3641086b4d3230f0f18c64f475ad6c3556d1603fc641ca50dc9c18d61866 - languageName: node - linkType: hard - -"@testing-library/react@npm:^16.0.1": - version: 16.3.0 - resolution: "@testing-library/react@npm:16.3.0" - dependencies: - "@babel/runtime": "npm:^7.12.5" - peerDependencies: - "@testing-library/dom": ^10.0.0 - "@types/react": ^18.0.0 || ^19.0.0 - "@types/react-dom": ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - "@types/react-dom": - optional: true - checksum: 10c0/3a2cb1f87c9a67e1ebbbcfd99b94b01e496fc35147be8bc5d8bf07a699c7d523a09d57ef2f7b1d91afccd1a28e21eda3b00d80187fbb51b1de01e422592d845e - languageName: node - linkType: hard - -"@testing-library/user-event@npm:^14.5.2": - version: 14.6.1 - resolution: "@testing-library/user-event@npm:14.6.1" - peerDependencies: - "@testing-library/dom": ">=7.21.4" - checksum: 10c0/75fea130a52bf320d35d46ed54f3eec77e71a56911b8b69a3fe29497b0b9947b2dc80d30f04054ad4ce7f577856ae3e5397ea7dff0ef14944d3909784c7a93fe - languageName: node - linkType: hard - -"@types/babel__core@npm:^7.20.5": - version: 7.20.5 - resolution: "@types/babel__core@npm:7.20.5" - dependencies: - "@babel/parser": "npm:^7.20.7" - "@babel/types": "npm:^7.20.7" - "@types/babel__generator": "npm:*" - "@types/babel__template": "npm:*" - "@types/babel__traverse": "npm:*" - checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff - languageName: node - linkType: hard - -"@types/babel__generator@npm:*": - version: 7.27.0 - resolution: "@types/babel__generator@npm:7.27.0" - dependencies: - "@babel/types": "npm:^7.0.0" - checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd - languageName: node - linkType: hard - -"@types/babel__template@npm:*": - version: 7.4.4 - resolution: "@types/babel__template@npm:7.4.4" - dependencies: - "@babel/parser": "npm:^7.1.0" - "@babel/types": "npm:^7.0.0" - checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b - languageName: node - linkType: hard - -"@types/babel__traverse@npm:*": - version: 7.28.0 - resolution: "@types/babel__traverse@npm:7.28.0" - dependencies: - "@babel/types": "npm:^7.28.2" - checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994 - languageName: node - linkType: hard - -"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 - languageName: node - linkType: hard - -"@types/get-params@npm:^0.1.2": - version: 0.1.2 - resolution: "@types/get-params@npm:0.1.2" - checksum: 10c0/7138af23d6acf0737d462263b8d2e5decfd282f1164aa7e2783c2fc9aeb2ec6aa10f6288605740356a916ecc4d27e01c1d8e6ad4c4fd0cd92790b8f482063cf6 - languageName: node - linkType: hard - -"@types/hoist-non-react-statics@npm:^3.3.0": - version: 3.3.7 - resolution: "@types/hoist-non-react-statics@npm:3.3.7" - dependencies: - hoist-non-react-statics: "npm:^3.3.0" - peerDependencies: - "@types/react": "*" - checksum: 10c0/ed8f4e88338f7d021d0f956adf6089d2a12b2e254a03c05292324f2e986d2376eb9efdb8a4f04596823e8fca88c9d06361d20dab4a2a00dc935fb36ac911de55 - languageName: node - linkType: hard - -"@types/humanize-duration@npm:^3.27.4": - version: 3.27.4 - resolution: "@types/humanize-duration@npm:3.27.4" - checksum: 10c0/0d92b036ac284c4ae248dca6efa826f9d397e7369f2d5e11de1813e05b32fd44e3d696f999acdc5a7eb412efc33668b8a68f6ad671392c0bbcf797a6329d674f - languageName: node - linkType: hard - -"@types/json-schema@npm:^7.0.15": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db - languageName: node - linkType: hard - -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac - languageName: node - linkType: hard - -"@types/lodash@npm:^4.17.6": - version: 4.17.20 - resolution: "@types/lodash@npm:4.17.20" - checksum: 10c0/98cdd0faae22cbb8079a01a3bb65aa8f8c41143367486c1cbf5adc83f16c9272a2a5d2c1f541f61d0d73da543c16ee1d21cf2ef86cb93cd0cc0ac3bced6dd88f - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 24.10.1 - resolution: "@types/node@npm:24.10.1" - dependencies: - undici-types: "npm:~7.16.0" - checksum: 10c0/d6bca7a78f550fbb376f236f92b405d676003a8a09a1b411f55920ef34286ee3ee51f566203920e835478784df52662b5b2af89159d9d319352e9ea21801c002 - languageName: node - linkType: hard - -"@types/node@npm:^22.15.29": - version: 22.17.2 - resolution: "@types/node@npm:22.17.2" - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10c0/23cd13aa35da6322a6d66cf4b3a45dbd40764ba726ab8681960270156c3abba776dd8dc173250c467f708d40612ecd725755d7659b775b513904680d5205eaff - languageName: node - linkType: hard - -"@types/parse-json@npm:^4.0.0": - version: 4.0.2 - resolution: "@types/parse-json@npm:4.0.2" - checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 - languageName: node - linkType: hard - -"@types/prop-types@npm:^15.7.15": - version: 15.7.15 - resolution: "@types/prop-types@npm:15.7.15" - checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2 - languageName: node - linkType: hard - -"@types/react-dom@npm:^19.1.5": - version: 19.1.7 - resolution: "@types/react-dom@npm:19.1.7" - peerDependencies: - "@types/react": ^19.0.0 - checksum: 10c0/8db5751c1567552fe4e1ece9f5823b682f2994ec8d30ed34ba0ef984e3c8ace1435f8be93d02f55c350147e78ac8c4dbcd8ed2c3b6a60f575bc5374f588c51c9 - languageName: node - linkType: hard - -"@types/react-is@npm:^19.0.0": - version: 19.0.0 - resolution: "@types/react-is@npm:19.0.0" - dependencies: - "@types/react": "npm:*" - checksum: 10c0/d5fa0294f95cf301540f3e28fb44c00524c74a7de3ef9757703d76067206f3ecc002da6486e1581f23b54173b6449db8631acc3088009116e4569ff216df3ecc - languageName: node - linkType: hard - -"@types/react-redux@npm:^7.1.34": - version: 7.1.34 - resolution: "@types/react-redux@npm:7.1.34" - dependencies: - "@types/hoist-non-react-statics": "npm:^3.3.0" - "@types/react": "npm:*" - hoist-non-react-statics: "npm:^3.3.0" - redux: "npm:^4.0.0" - checksum: 10c0/6750964ec656eb6973b0e4fda787549aee5dbc266a0f0e78fc9efb417b4965c0b060d10b99a7b7fa0c8812b8a0a07d97a1ef46d094bf64fee07144e8bbad781a - languageName: node - linkType: hard - -"@types/react-transition-group@npm:^4.4.12": - version: 4.4.12 - resolution: "@types/react-transition-group@npm:4.4.12" - peerDependencies: - "@types/react": "*" - checksum: 10c0/0441b8b47c69312c89ec0760ba477ba1a0808a10ceef8dc1c64b1013ed78517332c30f18681b0ec0b53542731f1ed015169fed1d127cc91222638ed955478ec7 - languageName: node - linkType: hard - -"@types/react@npm:*, @types/react@npm:^19.1.6": - version: 19.1.10 - resolution: "@types/react@npm:19.1.10" - dependencies: - csstype: "npm:^3.0.2" - checksum: 10c0/fb583deacd0a815e2775dc1b9f764532d8cacb748ddd2c2914805a46c257ce6c237b4078f44009692074db212ab61a390301c6470f07f5aa5bfdeb78a2acfda1 - languageName: node - linkType: hard - -"@types/semver@npm:^7.5.8": - version: 7.7.0 - resolution: "@types/semver@npm:7.7.0" - checksum: 10c0/6b5f65f647474338abbd6ee91a6bbab434662ddb8fe39464edcbcfc96484d388baad9eb506dff217b6fc1727a88894930eb1f308617161ac0f376fe06be4e1ee - languageName: node - linkType: hard - -"@types/use-sync-external-store@npm:^0.0.6": - version: 0.0.6 - resolution: "@types/use-sync-external-store@npm:0.0.6" - checksum: 10c0/77c045a98f57488201f678b181cccd042279aff3da34540ad242f893acc52b358bd0a8207a321b8ac09adbcef36e3236944390e2df4fcedb556ce7bb2a88f2a8 - languageName: node - linkType: hard - -"@typescript-eslint/eslint-plugin@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.40.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.40.0" - "@typescript-eslint/type-utils": "npm:8.40.0" - "@typescript-eslint/utils": "npm:8.40.0" - "@typescript-eslint/visitor-keys": "npm:8.40.0" - graphemer: "npm:^1.4.0" - ignore: "npm:^7.0.0" - natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - "@typescript-eslint/parser": ^8.40.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/dc8889c3255bce6956432f099059179dd13826ba29670f81ba9238ecde46764ee63459eb73a7d88f4f30e1144a2f000d79c9e3f256fa759689d9b3b74d423bda - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/parser@npm:8.40.0" - dependencies: - "@typescript-eslint/scope-manager": "npm:8.40.0" - "@typescript-eslint/types": "npm:8.40.0" - "@typescript-eslint/typescript-estree": "npm:8.40.0" - "@typescript-eslint/visitor-keys": "npm:8.40.0" - debug: "npm:^4.3.4" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/43ca9589b8a1f3f4b30a214c0e2254fa0ad43458ef1258b1d62c5aad52710ad11b9315b124cda79163274147b82201a5d76fab7de413e34bfe8e377142b71e98 - languageName: node - linkType: hard - -"@typescript-eslint/project-service@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/project-service@npm:8.40.0" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.40.0" - "@typescript-eslint/types": "npm:^8.40.0" - debug: "npm:^4.3.4" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/23d62e9ada9750136d0251f268bbe1f9784442ef258bb340a2e1e866749d8076730a14749d9a320d94d7c76df2d108caf21fe35e5dc100385f04be846dc979cb - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/scope-manager@npm:8.40.0" - dependencies: - "@typescript-eslint/types": "npm:8.40.0" - "@typescript-eslint/visitor-keys": "npm:8.40.0" - checksum: 10c0/48af81f9cdcec466994d290561e8d2fa3f6b156a898b71dd0e65633c896543b44729c5353596e84de2ae61bfd20e1398c3309cdfe86714a9663fd5aded4c9cd0 - languageName: node - linkType: hard - -"@typescript-eslint/tsconfig-utils@npm:8.40.0, @typescript-eslint/tsconfig-utils@npm:^8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.40.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/c2366dcd802901d5cd4f59fc4eab7a00ed119aa4591ba59c507fe495d9af4cfca19431a603602ea675e4c861962230d1c2f100896903750cd1fcfc134702a7d0 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/type-utils@npm:8.40.0" - dependencies: - "@typescript-eslint/types": "npm:8.40.0" - "@typescript-eslint/typescript-estree": "npm:8.40.0" - "@typescript-eslint/utils": "npm:8.40.0" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/660b77d801b2538a4ccb65065269ad0e8370d0be985172b5ecb067f3eea22e64aa8af9e981b31bf2a34002339fe3253b09b55d181ce6d8242fc7daa80ac4aaca - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:8.40.0, @typescript-eslint/types@npm:^8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/types@npm:8.40.0" - checksum: 10c0/225374fff36d59288a5780667a7a1316c75090d5d60b70a8035ac18786120333ccd08dfdf0e05e30d5a82217e44c57b8708b769dd1eed89f12f2ac4d3a769f76 - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.40.0" - dependencies: - "@typescript-eslint/project-service": "npm:8.40.0" - "@typescript-eslint/tsconfig-utils": "npm:8.40.0" - "@typescript-eslint/types": "npm:8.40.0" - "@typescript-eslint/visitor-keys": "npm:8.40.0" - debug: "npm:^4.3.4" - fast-glob: "npm:^3.3.2" - is-glob: "npm:^4.0.3" - minimatch: "npm:^9.0.4" - semver: "npm:^7.6.0" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/6c1ffc17947cb36cbd987cf9705f85223ed1cce584b5244840e36a2b8480861f4dfdb0312f96afbc12e7d1ba586005f0d959042baa0a96a1913ac7ace8e8f6d4 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/utils@npm:8.40.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.7.0" - "@typescript-eslint/scope-manager": "npm:8.40.0" - "@typescript-eslint/types": "npm:8.40.0" - "@typescript-eslint/typescript-estree": "npm:8.40.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/6b3858b8725083fe7db7fb9bcbde930e758a6ba8ddedd1ed27d828fc1cbe04f54b774ef9144602f8eeaafeea9b19b4fd4c46fdad52a10ade99e6b282c7d0df92 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:8.40.0": - version: 8.40.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.40.0" - dependencies: - "@typescript-eslint/types": "npm:8.40.0" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/592f1c8c2d3da43a7f74f8ead14f05fafc2e4609d5df36811cf92ead5dc94f6f669556a494048e4746cb3774c60bc52a8c83d75369d5e196778d935c70e7d3a1 - languageName: node - linkType: hard - -"@vitejs/plugin-react@npm:^4.2.1": - version: 4.7.0 - resolution: "@vitejs/plugin-react@npm:4.7.0" - dependencies: - "@babel/core": "npm:^7.28.0" - "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" - "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" - "@rolldown/pluginutils": "npm:1.0.0-beta.27" - "@types/babel__core": "npm:^7.20.5" - react-refresh: "npm:^0.17.0" - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253 - languageName: node - linkType: hard - -"@vitest/expect@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/expect@npm:2.1.9" - dependencies: - "@vitest/spy": "npm:2.1.9" - "@vitest/utils": "npm:2.1.9" - chai: "npm:^5.1.2" - tinyrainbow: "npm:^1.2.0" - checksum: 10c0/98d1cf02917316bebef9e4720723e38298a1c12b3c8f3a81f259bb822de4288edf594e69ff64f0b88afbda6d04d7a4f0c2f720f3fec16b4c45f5e2669f09fdbb - languageName: node - linkType: hard - -"@vitest/mocker@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/mocker@npm:2.1.9" - dependencies: - "@vitest/spy": "npm:2.1.9" - estree-walker: "npm:^3.0.3" - magic-string: "npm:^0.30.12" - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - checksum: 10c0/f734490d8d1206a7f44dfdfca459282f5921d73efa72935bb1dc45307578defd38a4131b14853316373ec364cbe910dbc74594ed4137e0da35aa4d9bb716f190 - languageName: node - linkType: hard - -"@vitest/pretty-format@npm:2.1.9, @vitest/pretty-format@npm:^2.1.9": - version: 2.1.9 - resolution: "@vitest/pretty-format@npm:2.1.9" - dependencies: - tinyrainbow: "npm:^1.2.0" - checksum: 10c0/155f9ede5090eabed2a73361094bb35ed4ec6769ae3546d2a2af139166569aec41bb80e031c25ff2da22b71dd4ed51e5468e66a05e6aeda5f14b32e30bc18f00 - languageName: node - linkType: hard - -"@vitest/runner@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/runner@npm:2.1.9" - dependencies: - "@vitest/utils": "npm:2.1.9" - pathe: "npm:^1.1.2" - checksum: 10c0/e81f176badb12a815cbbd9bd97e19f7437a0b64e8934d680024b0f768d8670d59cad698ef0e3dada5241b6731d77a7bb3cd2c7cb29f751fd4dd35eb11c42963a - languageName: node - linkType: hard - -"@vitest/snapshot@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/snapshot@npm:2.1.9" - dependencies: - "@vitest/pretty-format": "npm:2.1.9" - magic-string: "npm:^0.30.12" - pathe: "npm:^1.1.2" - checksum: 10c0/394974b3a1fe96186a3c87f933b2f7f1f7b7cc42f9c781d80271dbb4c987809bf035fecd7398b8a3a2d54169e3ecb49655e38a0131d0e7fea5ce88960613b526 - languageName: node - linkType: hard - -"@vitest/spy@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/spy@npm:2.1.9" - dependencies: - tinyspy: "npm:^3.0.2" - checksum: 10c0/12a59b5095e20188b819a1d797e0a513d991b4e6a57db679927c43b362a3eff52d823b34e855a6dd9e73c9fa138dcc5ef52210841a93db5cbf047957a60ca83c - languageName: node - linkType: hard - -"@vitest/utils@npm:2.1.9": - version: 2.1.9 - resolution: "@vitest/utils@npm:2.1.9" - dependencies: - "@vitest/pretty-format": "npm:2.1.9" - loupe: "npm:^3.1.2" - tinyrainbow: "npm:^1.2.0" - checksum: 10c0/81a346cd72b47941f55411f5df4cc230e5f740d1e97e0d3f771b27f007266fc1f28d0438582f6409ea571bc0030ed37f684c64c58d1947d6298d770c21026fdf - languageName: node - linkType: hard - -"abbrev@npm:^4.0.0": - version: 4.0.0 - resolution: "abbrev@npm:4.0.0" - checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 - languageName: node - linkType: hard - -"acorn@npm:^8.15.0": - version: 8.15.0 - resolution: "acorn@npm:8.15.0" - bin: - acorn: bin/acorn - checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec - languageName: node - linkType: hard - -"ag-auth@npm:^2.1.0": - version: 2.1.0 - resolution: "ag-auth@npm:2.1.0" - dependencies: - jsonwebtoken: "npm:^9.0.0" - sc-errors: "npm:^3.0.0" - checksum: 10c0/10f144fb4fbc70379a196d43e2a1d3da8e77d188321ca48795371ac55f1b9ae8a6492dad80bfc596bdd7d534e292d7d6f3dd2557484e37ea384635aabe0aee36 - languageName: node - linkType: hard - -"ag-channel@npm:^5.0.0": - version: 5.0.0 - resolution: "ag-channel@npm:5.0.0" - dependencies: - consumable-stream: "npm:^2.0.0" - checksum: 10c0/54dcac553a21f28687c99beef8287c3c6bdebd23585fa9e1a54205eb46e8bf5bcd204c78ca5753ab0d5b01330576b49462cec6e8fdcfcf0f1478162439536ec4 - languageName: node - linkType: hard - -"ag-request@npm:^1.1.0": - version: 1.1.0 - resolution: "ag-request@npm:1.1.0" - dependencies: - sc-errors: "npm:^3.0.0" - checksum: 10c0/7a7a53252e66cab1a0e4ea422df83214ed9f277e895692c543aa2499184bc8812a65e3c8b4941c78ff949ecdff0fb8e8a12879e14c20e12057187cf801de2471 - languageName: node - linkType: hard - -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe - languageName: node - linkType: hard - -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 - languageName: node - linkType: hard - -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e - languageName: node - linkType: hard - -"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "array-buffer-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - is-array-buffer: "npm:^3.0.5" - checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d - languageName: node - linkType: hard - -"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8, array-includes@npm:^3.1.9": - version: 3.1.9 - resolution: "array-includes@npm:3.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.24.0" - es-object-atoms: "npm:^1.1.1" - get-intrinsic: "npm:^1.3.0" - is-string: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856 - languageName: node - linkType: hard - -"array.prototype.findlast@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.findlast@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 - languageName: node - linkType: hard - -"array.prototype.findlastindex@npm:^1.2.6": - version: 1.2.6 - resolution: "array.prototype.findlastindex@npm:1.2.6" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-shim-unscopables: "npm:^1.1.0" - checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flat@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flatmap@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54 - languageName: node - linkType: hard - -"array.prototype.tosorted@npm:^1.1.4": - version: 1.1.4 - resolution: "array.prototype.tosorted@npm:1.1.4" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - es-errors: "npm:^1.3.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943 - languageName: node - linkType: hard - -"arraybuffer.prototype.slice@npm:^1.0.4": - version: 1.0.4 - resolution: "arraybuffer.prototype.slice@npm:1.0.4" - dependencies: - array-buffer-byte-length: "npm:^1.0.1" - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - is-array-buffer: "npm:^3.0.4" - checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06 - languageName: node - linkType: hard - -"assertion-error@npm:^2.0.1": - version: 2.0.1 - resolution: "assertion-error@npm:2.0.1" - checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 - languageName: node - linkType: hard - -"async-stream-emitter@npm:^7.0.1": - version: 7.0.1 - resolution: "async-stream-emitter@npm:7.0.1" - dependencies: - stream-demux: "npm:^10.0.1" - checksum: 10c0/0e8d1daaca584f741dd10375748fa11bb7a52282d88c5b4ddcefeba776edf60dc3d4aa4820cdc0d162519b0838085ec250d427dd3e3b7f0926a91d95da320473 - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 - languageName: node - linkType: hard - -"babel-plugin-macros@npm:^3.1.0": - version: 3.1.0 - resolution: "babel-plugin-macros@npm:3.1.0" - dependencies: - "@babel/runtime": "npm:^7.12.5" - cosmiconfig: "npm:^7.0.0" - resolve: "npm:^1.19.0" - checksum: 10c0/c6dfb15de96f67871d95bd2e8c58b0c81edc08b9b087dc16755e7157f357dc1090a8dc60ebab955e92587a9101f02eba07e730adc253a1e4cf593ca3ebd3839c - languageName: node - linkType: hard - -"babel-plugin-react-compiler@npm:^1.0.0": - version: 1.0.0 - resolution: "babel-plugin-react-compiler@npm:1.0.0" - dependencies: - "@babel/types": "npm:^7.26.0" - checksum: 10c0/9406267ada8d7dbdfe8906b40ecadb816a5f4cee2922bee23f7729293b369624ee135b5a9b0f263851c263c9787522ac5d97016c9a2b82d1668300e42b18aff8 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf - languageName: node - linkType: hard - -"bl@npm:^1.2.1": - version: 1.2.3 - resolution: "bl@npm:1.2.3" - dependencies: - readable-stream: "npm:^2.3.5" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/ee6478864d3b1295614f269f3fbabeb2362a2f2fc7f8dc2f6c1f944a278d84e0572ecefd6d0b0736d7418763f98dc3b2738253191ea9e98e4b08de211cfac0a6 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.12 - resolution: "brace-expansion@npm:1.1.12" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.2 - resolution: "brace-expansion@npm:2.0.2" - dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf - languageName: node - linkType: hard - -"braces@npm:^3.0.3": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 - languageName: node - linkType: hard - -"browserslist@npm:^4.24.0": - version: 4.25.3 - resolution: "browserslist@npm:4.25.3" - dependencies: - caniuse-lite: "npm:^1.0.30001735" - electron-to-chromium: "npm:^1.5.204" - node-releases: "npm:^2.0.19" - update-browserslist-db: "npm:^1.1.3" - bin: - browserslist: cli.js - checksum: 10c0/cefbbf962b7c0f0d77e952a4b4b37469db7f7f02bc2be7297810ac3cf086660f48daf78d00f7aad8a11b682f88b0ee0022594165ead749e9e4158a0aa49cd161 - languageName: node - linkType: hard - -"buffer-equal-constant-time@npm:^1.0.1": - version: 1.0.1 - resolution: "buffer-equal-constant-time@npm:1.0.1" - checksum: 10c0/fb2294e64d23c573d0dd1f1e7a466c3e978fe94a4e0f8183937912ca374619773bef8e2aceb854129d2efecbbc515bbd0cc78d2734a3e3031edb0888531bbc8e - languageName: node - linkType: hard - -"buffer@npm:^5.2.1": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.1.13" - checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e - languageName: node - linkType: hard - -"cac@npm:^6.7.14": - version: 6.7.14 - resolution: "cac@npm:6.7.14" - checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 - languageName: node - linkType: hard - -"cacache@npm:^20.0.1": - version: 20.0.3 - resolution: "cacache@npm:20.0.3" - dependencies: - "@npmcli/fs": "npm:^5.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^13.0.0" - lru-cache: "npm:^11.1.0" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^13.0.0" - unique-filename: "npm:^5.0.0" - checksum: 10c0/c7da1ca694d20e8f8aedabd21dc11518f809a7d2b59aa76a1fc655db5a9e62379e465c157ddd2afe34b19230808882288effa6911b2de26a088a6d5645123462 - languageName: node - linkType: hard - -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" - dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.2" - checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4 - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001735": - version: 1.0.30001737 - resolution: "caniuse-lite@npm:1.0.30001737" - checksum: 10c0/9d9cfe3b46fe670d171cee10c5c1b0fb641946fd5d6bea26149f804003d53d82ade7ef5a4a640fb3a0eaec47c7839b57e06a6ddae4f0ad2cd58e1187d31997ce - languageName: node - linkType: hard - -"canvas-renderer@npm:~2.2.0": - version: 2.2.1 - resolution: "canvas-renderer@npm:2.2.1" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/436f2f516723cf2cac03dcb189907b282249cc33446c6bce7760fb3ebd22689b0a4a27b3a3ab077a2c8204bd597a5e923da505520735b00cd839a790e6bdda50 - languageName: node - linkType: hard - -"chai@npm:^5.1.2": - version: 5.3.2 - resolution: "chai@npm:5.3.2" - dependencies: - assertion-error: "npm:^2.0.1" - check-error: "npm:^2.1.1" - deep-eql: "npm:^5.0.1" - loupe: "npm:^3.1.0" - pathval: "npm:^2.0.0" - checksum: 10c0/43c2472b243afe6beea6daa9a6b667c1a2ebc80db37b29132412723ba5a2128a21fa245ff94315189318546b0803aa4ae40f45eb4ec4b68492d3dec168a3e9d8 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 - languageName: node - linkType: hard - -"check-error@npm:^2.1.1": - version: 2.1.1 - resolution: "check-error@npm:2.1.1" - checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e - languageName: node - linkType: hard - -"chownr@npm:^3.0.0": - version: 3.0.0 - resolution: "chownr@npm:3.0.0" - checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 - languageName: node - linkType: hard - -"clone-deep@npm:^4.0.1": - version: 4.0.1 - resolution: "clone-deep@npm:4.0.1" - dependencies: - is-plain-object: "npm:^2.0.4" - kind-of: "npm:^6.0.2" - shallow-clone: "npm:^3.0.0" - checksum: 10c0/637753615aa24adf0f2d505947a1bb75e63964309034a1cf56ba4b1f30af155201edd38d26ffe26911adaae267a3c138b344a4947d39f5fc1b6d6108125aa758 - languageName: node - linkType: hard - -"clsx@npm:^1.1.0": - version: 1.2.1 - resolution: "clsx@npm:1.2.1" - checksum: 10c0/34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27 - languageName: node - linkType: hard - -"clsx@npm:^2.1.1": - version: 2.1.1 - resolution: "clsx@npm:2.1.1" - checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f - languageName: node - linkType: hard - -"consumable-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "consumable-stream@npm:2.0.0" - checksum: 10c0/4276ac662d254ef17e38daeaf280584801906a661ab215bde5cc3a37e6bd3def428c19abd8db601527a1582c065529ad9608466f09619ba3d1dcd89abcfadaea - languageName: node - linkType: hard - -"consumable-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "consumable-stream@npm:3.0.0" - checksum: 10c0/a6e9a7f29666aa135e898628edf3671d92b6fe061dcab1eff6f8eadb35438ea0f6eb2d782b9ca8320bb05ae2e73706986a17392f2c6bcd5e5c6826745d353fcb - languageName: node - linkType: hard - -"convert-source-map@npm:^1.5.0": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b - languageName: node - linkType: hard - -"convert-source-map@npm:^2.0.0": - version: 2.0.0 - resolution: "convert-source-map@npm:2.0.0" - checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b - languageName: node - linkType: hard - -"cookie@npm:^1.0.1": - version: 1.0.2 - resolution: "cookie@npm:1.0.2" - checksum: 10c0/fd25fe79e8fbcfcaf6aa61cd081c55d144eeeba755206c058682257cb38c4bd6795c6620de3f064c740695bb65b7949ebb1db7a95e4636efb8357a335ad3f54b - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 - languageName: node - linkType: hard - -"cosmiconfig@npm:^7.0.0": - version: 7.1.0 - resolution: "cosmiconfig@npm:7.1.0" - dependencies: - "@types/parse-json": "npm:^4.0.0" - import-fresh: "npm:^3.2.1" - parse-json: "npm:^5.0.0" - path-type: "npm:^4.0.0" - yaml: "npm:^1.10.0" - checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": - version: 7.0.6 - resolution: "cross-spawn@npm:7.0.6" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 - languageName: node - linkType: hard - -"csstype@npm:^3.0.10": - version: 3.2.3 - resolution: "csstype@npm:3.2.3" - checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce - languageName: node - linkType: hard - -"csstype@npm:^3.0.2, csstype@npm:^3.1.3": - version: 3.1.3 - resolution: "csstype@npm:3.1.3" - checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 - languageName: node - linkType: hard - -"data-view-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-buffer@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c - languageName: node - linkType: hard - -"data-view-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55 - languageName: node - linkType: hard - -"data-view-byte-offset@npm:^1.0.1": - version: 1.0.1 - resolution: "data-view-byte-offset@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.1" - checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4 - languageName: node - linkType: hard - -"dayjs@npm:^1.11.13": - version: 1.11.13 - resolution: "dayjs@npm:1.11.13" - checksum: 10c0/a3caf6ac8363c7dade9d1ee797848ddcf25c1ace68d9fe8678ecf8ba0675825430de5d793672ec87b24a69bf04a1544b176547b2539982275d5542a7955f35b7 - languageName: node - linkType: hard - -"debug@npm:4": - version: 4.4.3 - resolution: "debug@npm:4.4.3" - dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 - languageName: node - linkType: hard - -"debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a - languageName: node - linkType: hard - -"debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7": - version: 4.4.1 - resolution: "debug@npm:4.4.1" - dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d2b44bc1afd912b49bb7ebb0d50a860dc93a4dd7d946e8de94abc957bb63726b7dd5aa48c18c2386c379ec024c46692e15ed3ed97d481729f929201e671fcd55 - languageName: node - linkType: hard - -"deep-eql@npm:^5.0.1": - version: 5.0.2 - resolution: "deep-eql@npm:5.0.2" - checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 - languageName: node - linkType: hard - -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c - languageName: node - linkType: hard - -"default-gateway@npm:^6.0.3": - version: 6.0.3 - resolution: "default-gateway@npm:6.0.3" - dependencies: - execa: "npm:^5.0.0" - checksum: 10c0/5184f9e6e105d24fb44ade9e8741efa54bb75e84625c1ea78c4ef8b81dff09ca52d6dbdd1185cf0dc655bb6b282a64fffaf7ed2dd561b8d9ad6f322b1f039aba - languageName: node - linkType: hard - -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.0.1" - checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 - languageName: node - linkType: hard - -"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 - languageName: node - linkType: hard - -"dns-over-http-resolver@npm:^1.2.3": - version: 1.2.3 - resolution: "dns-over-http-resolver@npm:1.2.3" - dependencies: - debug: "npm:^4.3.1" - native-fetch: "npm:^3.0.0" - receptacle: "npm:^1.3.2" - checksum: 10c0/231435742246115aeb4f153721effc4d995ab8f22572240b27d85e1be4123345cbe503e9922bc46b36caaa86307fbcf65ba252302dc7a4794f330aa6d6f920b8 - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac - languageName: node - linkType: hard - -"dom-helpers@npm:^5.0.1": - version: 5.2.1 - resolution: "dom-helpers@npm:5.2.1" - dependencies: - "@babel/runtime": "npm:^7.8.7" - csstype: "npm:^3.0.2" - checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"ecdsa-sig-formatter@npm:1.0.11": - version: 1.0.11 - resolution: "ecdsa-sig-formatter@npm:1.0.11" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/ebfbf19d4b8be938f4dd4a83b8788385da353d63307ede301a9252f9f7f88672e76f2191618fd8edfc2f24679236064176fab0b78131b161ee73daa37125408c - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.5.204": - version: 1.5.208 - resolution: "electron-to-chromium@npm:1.5.208" - checksum: 10c0/75469e473296a24c66b2f77ab8081aaafe62c8ec700c642940b985a71b111cbf75ae3442ac0c25b7bf30bfd21b49f8e74c21366cc7c513e45366233dbb43ce2b - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 - languageName: node - linkType: hard - -"err-code@npm:^3.0.1": - version: 3.0.1 - resolution: "err-code@npm:3.0.1" - checksum: 10c0/78b1c50500adebde6699b8d27b8ce4728c132dcaad75b5d18ba44f6ccb28769d1fff8368ae1164be4559dac8b95d4e26bb15b480ba9999e0cd0f0c64beaf1b24 - languageName: node - linkType: hard - -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: "npm:^0.2.1" - checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce - languageName: node - linkType: hard - -"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0": - version: 1.24.0 - resolution: "es-abstract@npm:1.24.0" - dependencies: - array-buffer-byte-length: "npm:^1.0.2" - arraybuffer.prototype.slice: "npm:^1.0.4" - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - data-view-buffer: "npm:^1.0.2" - data-view-byte-length: "npm:^1.0.2" - data-view-byte-offset: "npm:^1.0.1" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-set-tostringtag: "npm:^2.1.0" - es-to-primitive: "npm:^1.3.0" - function.prototype.name: "npm:^1.1.8" - get-intrinsic: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - get-symbol-description: "npm:^1.1.0" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - internal-slot: "npm:^1.1.0" - is-array-buffer: "npm:^3.0.5" - is-callable: "npm:^1.2.7" - is-data-view: "npm:^1.0.2" - is-negative-zero: "npm:^2.0.3" - is-regex: "npm:^1.2.1" - is-set: "npm:^2.0.3" - is-shared-array-buffer: "npm:^1.0.4" - is-string: "npm:^1.1.1" - is-typed-array: "npm:^1.1.15" - is-weakref: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - object-inspect: "npm:^1.13.4" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.7" - own-keys: "npm:^1.0.1" - regexp.prototype.flags: "npm:^1.5.4" - safe-array-concat: "npm:^1.1.3" - safe-push-apply: "npm:^1.0.0" - safe-regex-test: "npm:^1.1.0" - set-proto: "npm:^1.0.0" - stop-iteration-iterator: "npm:^1.1.0" - string.prototype.trim: "npm:^1.2.10" - string.prototype.trimend: "npm:^1.0.9" - string.prototype.trimstart: "npm:^1.0.8" - typed-array-buffer: "npm:^1.0.3" - typed-array-byte-length: "npm:^1.0.3" - typed-array-byte-offset: "npm:^1.0.4" - typed-array-length: "npm:^1.0.7" - unbox-primitive: "npm:^1.1.0" - which-typed-array: "npm:^1.1.19" - checksum: 10c0/b256e897be32df5d382786ce8cce29a1dd8c97efbab77a26609bd70f2ed29fbcfc7a31758cb07488d532e7ccccdfca76c1118f2afe5a424cdc05ca007867c318 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 - languageName: node - linkType: hard - -"es-iterator-helpers@npm:^1.2.1": - version: 1.2.1 - resolution: "es-iterator-helpers@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-set-tostringtag: "npm:^2.0.3" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.6" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - iterator.prototype: "npm:^1.1.4" - safe-array-concat: "npm:^1.1.3" - checksum: 10c0/97e3125ca472d82d8aceea11b790397648b52c26d8768ea1c1ee6309ef45a8755bb63225a43f3150c7591cffc17caf5752459f1e70d583b4184370a8f04ebd2f - languageName: node - linkType: hard - -"es-module-lexer@npm:^1.5.4": - version: 1.7.0 - resolution: "es-module-lexer@npm:1.7.0" - checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.0.3, es-set-tostringtag@npm:^2.1.0": - version: 2.1.0 - resolution: "es-set-tostringtag@npm:2.1.0" - dependencies: - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": - version: 1.1.0 - resolution: "es-shim-unscopables@npm:1.1.0" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.3.0": - version: 1.3.0 - resolution: "es-to-primitive@npm:1.3.0" - dependencies: - is-callable: "npm:^1.2.7" - is-date-object: "npm:^1.0.5" - is-symbol: "npm:^1.0.4" - checksum: 10c0/c7e87467abb0b438639baa8139f701a06537d2b9bc758f23e8622c3b42fd0fdb5bde0f535686119e446dd9d5e4c0f238af4e14960f4771877cf818d023f6730b - languageName: node - linkType: hard - -"esbuild@npm:^0.21.3": - version: 0.21.5 - resolution: "esbuild@npm:0.21.5" - dependencies: - "@esbuild/aix-ppc64": "npm:0.21.5" - "@esbuild/android-arm": "npm:0.21.5" - "@esbuild/android-arm64": "npm:0.21.5" - "@esbuild/android-x64": "npm:0.21.5" - "@esbuild/darwin-arm64": "npm:0.21.5" - "@esbuild/darwin-x64": "npm:0.21.5" - "@esbuild/freebsd-arm64": "npm:0.21.5" - "@esbuild/freebsd-x64": "npm:0.21.5" - "@esbuild/linux-arm": "npm:0.21.5" - "@esbuild/linux-arm64": "npm:0.21.5" - "@esbuild/linux-ia32": "npm:0.21.5" - "@esbuild/linux-loong64": "npm:0.21.5" - "@esbuild/linux-mips64el": "npm:0.21.5" - "@esbuild/linux-ppc64": "npm:0.21.5" - "@esbuild/linux-riscv64": "npm:0.21.5" - "@esbuild/linux-s390x": "npm:0.21.5" - "@esbuild/linux-x64": "npm:0.21.5" - "@esbuild/netbsd-x64": "npm:0.21.5" - "@esbuild/openbsd-x64": "npm:0.21.5" - "@esbuild/sunos-x64": "npm:0.21.5" - "@esbuild/win32-arm64": "npm:0.21.5" - "@esbuild/win32-ia32": "npm:0.21.5" - "@esbuild/win32-x64": "npm:0.21.5" - dependenciesMeta: - "@esbuild/aix-ppc64": - optional: true - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: 10c0/fa08508adf683c3f399e8a014a6382a6b65542213431e26206c0720e536b31c09b50798747c2a105a4bbba1d9767b8d3615a74c2f7bf1ddf6d836cd11eb672de - languageName: node - linkType: hard - -"escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.9": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: "npm:^3.2.7" - is-core-module: "npm:^2.13.0" - resolve: "npm:^1.22.4" - checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.12.1": - version: 2.12.1 - resolution: "eslint-module-utils@npm:2.12.1" - dependencies: - debug: "npm:^3.2.7" - peerDependenciesMeta: - eslint: - optional: true - checksum: 10c0/6f4efbe7a91ae49bf67b4ab3644cb60bc5bd7db4cb5521de1b65be0847ffd3fb6bce0dd68f0995e1b312d137f768e2a1f842ee26fe73621afa05f850628fdc40 - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.32.0": - version: 2.32.0 - resolution: "eslint-plugin-import@npm:2.32.0" - dependencies: - "@rtsao/scc": "npm:^1.1.0" - array-includes: "npm:^3.1.9" - array.prototype.findlastindex: "npm:^1.2.6" - array.prototype.flat: "npm:^1.3.3" - array.prototype.flatmap: "npm:^1.3.3" - debug: "npm:^3.2.7" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.12.1" - hasown: "npm:^2.0.2" - is-core-module: "npm:^2.16.1" - is-glob: "npm:^4.0.3" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - object.groupby: "npm:^1.0.3" - object.values: "npm:^1.2.1" - semver: "npm:^6.3.1" - string.prototype.trimend: "npm:^1.0.9" - tsconfig-paths: "npm:^3.15.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - checksum: 10c0/bfb1b8fc8800398e62ddfefbf3638d185286edfed26dfe00875cc2846d954491b4f5112457831588b757fa789384e1ae585f812614c4797f0499fa234fd4a48b - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^7.0.1": - version: 7.0.1 - resolution: "eslint-plugin-react-hooks@npm:7.0.1" - dependencies: - "@babel/core": "npm:^7.24.4" - "@babel/parser": "npm:^7.24.4" - hermes-parser: "npm:^0.25.1" - zod: "npm:^3.25.0 || ^4.0.0" - zod-validation-error: "npm:^3.5.0 || ^4.0.0" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - checksum: 10c0/1e711d1a9d1fa9cfc51fa1572500656577201199c70c795c6a27adfc1df39e5c598f69aab6aa91117753d23cc1f11388579a2bed14921cf9a4efe60ae8618496 - languageName: node - linkType: hard - -"eslint-plugin-react@npm:^7.35.0": - version: 7.37.5 - resolution: "eslint-plugin-react@npm:7.37.5" - dependencies: - array-includes: "npm:^3.1.8" - array.prototype.findlast: "npm:^1.2.5" - array.prototype.flatmap: "npm:^1.3.3" - array.prototype.tosorted: "npm:^1.1.4" - doctrine: "npm:^2.1.0" - es-iterator-helpers: "npm:^1.2.1" - estraverse: "npm:^5.3.0" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" - minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.9" - object.fromentries: "npm:^2.0.8" - object.values: "npm:^1.2.1" - prop-types: "npm:^15.8.1" - resolve: "npm:^2.0.0-next.5" - semver: "npm:^6.3.1" - string.prototype.matchall: "npm:^4.0.12" - string.prototype.repeat: "npm:^1.0.0" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 - languageName: node - linkType: hard - -"eslint-scope@npm:^8.4.0": - version: 8.4.0 - resolution: "eslint-scope@npm:8.4.0" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^5.2.0" - checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-visitor-keys@npm:4.2.1" - checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 - languageName: node - linkType: hard - -"eslint@npm:^9.9.0": - version: 9.33.0 - resolution: "eslint@npm:9.33.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.2.0" - "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.21.0" - "@eslint/config-helpers": "npm:^0.3.1" - "@eslint/core": "npm:^0.15.2" - "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.33.0" - "@eslint/plugin-kit": "npm:^0.3.5" - "@humanfs/node": "npm:^0.16.6" - "@humanwhocodes/module-importer": "npm:^1.0.1" - "@humanwhocodes/retry": "npm:^0.4.2" - "@types/estree": "npm:^1.0.6" - "@types/json-schema": "npm:^7.0.15" - ajv: "npm:^6.12.4" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.6" - debug: "npm:^4.3.2" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^8.4.0" - eslint-visitor-keys: "npm:^4.2.1" - espree: "npm:^10.4.0" - esquery: "npm:^1.5.0" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^8.0.0" - find-up: "npm:^5.0.0" - glob-parent: "npm:^6.0.2" - ignore: "npm:^5.2.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.3" - peerDependencies: - jiti: "*" - peerDependenciesMeta: - jiti: - optional: true - bin: - eslint: bin/eslint.js - checksum: 10c0/1e1f60d2b62d9d65553e9af916a8dccf00eeedd982103f35bf58c205803907cb1fda73ef595178d47384ea80d8624a182b63682a6b15d8387e9a5d86904a2a2d - languageName: node - linkType: hard - -"espree@npm:^10.0.1, espree@npm:^10.4.0": - version: 10.4.0 - resolution: "espree@npm:10.4.0" - dependencies: - acorn: "npm:^8.15.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b - languageName: node - linkType: hard - -"esquery@npm:^1.5.0": - version: 1.6.0 - resolution: "esquery@npm:1.6.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 - languageName: node - linkType: hard - -"estree-walker@npm:^3.0.3": - version: 3.0.3 - resolution: "estree-walker@npm:3.0.3" - dependencies: - "@types/estree": "npm:^1.0.0" - checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 - languageName: node - linkType: hard - -"execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^6.0.0" - human-signals: "npm:^2.1.0" - is-stream: "npm:^2.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^4.0.1" - onetime: "npm:^5.1.2" - signal-exit: "npm:^3.0.3" - strip-final-newline: "npm:^2.0.0" - checksum: 10c0/c8e615235e8de4c5addf2fa4c3da3e3aa59ce975a3e83533b4f6a71750fb816a2e79610dc5f1799b6e28976c9ae86747a36a606655bf8cb414a74d8d507b304f - languageName: node - linkType: hard - -"expect-type@npm:^1.1.0": - version: 1.2.2 - resolution: "expect-type@npm:1.2.2" - checksum: 10c0/6019019566063bbc7a690d9281d920b1a91284a4a093c2d55d71ffade5ac890cf37a51e1da4602546c4b56569d2ad2fc175a2ccee77d1ae06cb3af91ef84f44b - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.3 - resolution: "exponential-backoff@npm:3.1.3" - checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 - languageName: node - linkType: hard - -"fast-glob@npm:^3.3.2": - version: 3.3.3 - resolution: "fast-glob@npm:3.3.3" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.8" - checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.19.1 - resolution: "fastq@npm:1.19.1" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630 - languageName: node - linkType: hard - -"fdir@npm:^6.5.0": - version: 6.5.0 - resolution: "fdir@npm:6.5.0" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f - languageName: node - linkType: hard - -"file-entry-cache@npm:^8.0.0": - version: 8.0.0 - resolution: "file-entry-cache@npm:8.0.0" - dependencies: - flat-cache: "npm:^4.0.0" - checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 - languageName: node - linkType: hard - -"find-root@npm:^1.1.0": - version: 1.1.0 - resolution: "find-root@npm:1.1.0" - checksum: 10c0/1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a - languageName: node - linkType: hard - -"flat-cache@npm:^4.0.0": - version: 4.0.1 - resolution: "flat-cache@npm:4.0.1" - dependencies: - flatted: "npm:^3.2.9" - keyv: "npm:^4.5.4" - checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc - languageName: node - linkType: hard - -"flatted@npm:^3.2.9": - version: 3.3.3 - resolution: "flatted@npm:3.3.3" - checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 - languageName: node - linkType: hard - -"for-each@npm:^0.3.3, for-each@npm:^0.3.5": - version: 0.3.5 - resolution: "for-each@npm:0.3.5" - dependencies: - is-callable: "npm:^1.2.7" - checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 - languageName: node - linkType: hard - -"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": - version: 1.1.8 - resolution: "function.prototype.name@npm:1.1.8" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - functions-have-names: "npm:^1.2.3" - hasown: "npm:^2.0.2" - is-callable: "npm:^1.2.7" - checksum: 10c0/e920a2ab52663005f3cbe7ee3373e3c71c1fb5558b0b0548648cdf3e51961085032458e26c71ff1a8c8c20e7ee7caeb03d43a5d1fa8610c459333323a2e71253 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.2": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": - version: 1.3.0 - resolution: "get-intrinsic@npm:1.3.0" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a - languageName: node - linkType: hard - -"get-params@npm:^0.1.2": - version: 0.1.2 - resolution: "get-params@npm:0.1.2" - checksum: 10c0/bf83ed37d2c5e9d9cf04b0d9d380fa3f29997e4c4c5cbbcda0112747a43148111ab5a054e1681819aeb24b98726053196b183830ad9a4b246bdc5f79af5792f7 - languageName: node - linkType: hard - -"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 - languageName: node - linkType: hard - -"get-symbol-description@npm:^1.1.0": - version: 1.1.0 - resolution: "get-symbol-description@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: "npm:^4.0.3" - checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 - languageName: node - linkType: hard - -"glob@npm:^13.0.0": - version: 13.0.0 - resolution: "glob@npm:13.0.0" - dependencies: - minimatch: "npm:^10.1.1" - minipass: "npm:^7.1.2" - path-scurry: "npm:^2.0.0" - checksum: 10c0/8e2f5821f3f7c312dd102e23a15b80c79e0837a9872784293ba2e15ec73b3f3749a49a42a31bfcb4e52c84820a474e92331c2eebf18819d20308f5c33876630a - languageName: node - linkType: hard - -"globals@npm:^14.0.0": - version: 14.0.0 - resolution: "globals@npm:14.0.0" - checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d - languageName: node - linkType: hard - -"globals@npm:^15.9.0": - version: 15.15.0 - resolution: "globals@npm:15.15.0" - checksum: 10c0/f9ae80996392ca71316495a39bec88ac43ae3525a438b5626cd9d5ce9d5500d0a98a266409605f8cd7241c7acf57c354a48111ea02a767ba4f374b806d6861fe - languageName: node - linkType: hard - -"globalthis@npm:^1.0.4": - version: 1.0.4 - resolution: "globalthis@npm:1.0.4" - dependencies: - define-properties: "npm:^1.2.1" - gopd: "npm:^1.0.1" - checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 - languageName: node - linkType: hard - -"globrex@npm:^0.1.2": - version: 0.1.2 - resolution: "globrex@npm:0.1.2" - checksum: 10c0/a54c029520cf58bda1d8884f72bd49b4cd74e977883268d931fd83bcbd1a9eb96d57c7dbd4ad80148fb9247467ebfb9b215630b2ed7563b2a8de02e1ff7f89d1 - languageName: node - linkType: hard - -"goober@npm:^2.0.33": - version: 2.1.16 - resolution: "goober@npm:2.1.16" - peerDependencies: - csstype: ^3.0.10 - checksum: 10c0/f4c8256bf9c27873d47c1443f348779ac7f322516cb80a5dc647a6ebe790ce6bb9d3f487a0fb8be0b583fb96b9b2f6b7463f7fea3cd680306f95fa6fc9db1f6a - languageName: node - linkType: hard - -"gopd@npm:^1.0.1, gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 - languageName: node - linkType: hard - -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31 - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.2": - version: 1.1.0 - resolution: "has-bigints@npm:1.1.0" - checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" - dependencies: - es-define-property: "npm:^1.0.0" - checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 - languageName: node - linkType: hard - -"has-proto@npm:^1.2.0": - version: 1.2.0 - resolution: "has-proto@npm:1.2.0" - dependencies: - dunder-proto: "npm:^1.0.0" - checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 - languageName: node - linkType: hard - -"hermes-estree@npm:0.25.1": - version: 0.25.1 - resolution: "hermes-estree@npm:0.25.1" - checksum: 10c0/48be3b2fa37a0cbc77a112a89096fa212f25d06de92781b163d67853d210a8a5c3784fac23d7d48335058f7ed283115c87b4332c2a2abaaccc76d0ead1a282ac - languageName: node - linkType: hard - -"hermes-parser@npm:^0.25.1": - version: 0.25.1 - resolution: "hermes-parser@npm:0.25.1" - dependencies: - hermes-estree: "npm:0.25.1" - checksum: 10c0/3abaa4c6f1bcc25273f267297a89a4904963ea29af19b8e4f6eabe04f1c2c7e9abd7bfc4730ddb1d58f2ea04b6fee74053d8bddb5656ec6ebf6c79cc8d14202c - languageName: node - linkType: hard - -"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1": - version: 3.3.2 - resolution: "hoist-non-react-statics@npm:3.3.2" - dependencies: - react-is: "npm:^16.7.0" - checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.2.0 - resolution: "http-cache-semantics@npm:4.2.0" - checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac - languageName: node - linkType: hard - -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: 10c0/695edb3edfcfe9c8b52a76926cd31b36978782062c0ed9b1192b36bebc75c4c87c82e178dfcb0ed0fc27ca59d434198aac0bd0be18f5781ded775604db22304a - languageName: node - linkType: hard - -"humanize-duration@npm:^3.32.1": - version: 3.33.0 - resolution: "humanize-duration@npm:3.33.0" - checksum: 10c0/516c966e848177df526444f83f27d92fdfb7b96f8cd3d42e5b1bdbda950c8b56db0ac8ea25bc130445b577d19c382c35fe3d458643c10f0fe071ab1b8fe8ad80 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 - languageName: node - linkType: hard - -"ieee754@npm:^1.1.13": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb - languageName: node - linkType: hard - -"ignore@npm:^5.2.0": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 - languageName: node - linkType: hard - -"ignore@npm:^7.0.0": - version: 7.0.5 - resolution: "ignore@npm:7.0.5" - checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d - languageName: node - linkType: hard - -"immer@npm:^10.0.3": - version: 10.1.1 - resolution: "immer@npm:10.1.1" - checksum: 10c0/b749e10d137ccae91788f41bd57e9387f32ea6d6ea8fd7eb47b23fd7766681575efc7f86ceef7fe24c3bc9d61e38ff5d2f49c2663b2b0c056e280a4510923653 - languageName: node - linkType: hard - -"immutable@npm:^4.3.7": - version: 4.3.7 - resolution: "immutable@npm:4.3.7" - checksum: 10c0/9b099197081b22f6433003e34929da8ecddbbdc1474cdc8aa3b7669dee4adda349c06143de22def36016d1b6de5322b043eccd7a11db1dad2ca85dad4fff5435 - languageName: node - linkType: hard - -"import-fresh@npm:^3.2.1": - version: 3.3.1 - resolution: "import-fresh@npm:3.3.1" - dependencies: - parent-module: "npm:^1.0.0" - resolve-from: "npm:^4.0.0" - checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 - languageName: node - linkType: hard - -"inherits@npm:~2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - -"internal-ip@npm:^7.0.0": - version: 7.0.0 - resolution: "internal-ip@npm:7.0.0" - dependencies: - default-gateway: "npm:^6.0.3" - ipaddr.js: "npm:^2.0.1" - is-ip: "npm:^3.1.0" - p-event: "npm:^4.2.0" - checksum: 10c0/22eb24ad1e1c5eb9c3742cfb4ce7c85b3328632aee8f595e5587e699c386b46b44c6655141135187ed09c60a19e7357188f2cf306ee569711f23f8a8cf56f359 - languageName: node - linkType: hard - -"internal-slot@npm:^1.1.0": - version: 1.1.0 - resolution: "internal-slot@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - hasown: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7 - languageName: node - linkType: hard - -"ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 - languageName: node - linkType: hard - -"ip-regex@npm:^4.0.0": - version: 4.3.0 - resolution: "ip-regex@npm:4.3.0" - checksum: 10c0/f9ef1f5d0df05b9133a882974e572ae525ccd205260cb103dae337f1fc7451ed783391acc6ad688e56dd2598f769e8e72ecbb650ec34763396af822a91768562 - languageName: node - linkType: hard - -"ipaddr.js@npm:^2.0.1": - version: 2.2.0 - resolution: "ipaddr.js@npm:2.2.0" - checksum: 10c0/e4ee875dc1bd92ac9d27e06cfd87cdb63ca786ff9fd7718f1d4f7a8ef27db6e5d516128f52d2c560408cbb75796ac2f83ead669e73507c86282d45f84c5abbb6 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": - version: 3.0.5 - resolution: "is-array-buffer@npm:3.0.5" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 - languageName: node - linkType: hard - -"is-async-function@npm:^2.0.0": - version: 2.1.1 - resolution: "is-async-function@npm:2.1.1" - dependencies: - async-function: "npm:^1.0.0" - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298 - languageName: node - linkType: hard - -"is-bigint@npm:^1.1.0": - version: 1.1.0 - resolution: "is-bigint@npm:1.1.0" - dependencies: - has-bigints: "npm:^1.0.2" - checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4 - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.2.1": - version: 1.2.2 - resolution: "is-boolean-object@npm:1.2.2" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e - languageName: node - linkType: hard - -"is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0, is-core-module@npm:^2.16.1": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd - languageName: node - linkType: hard - -"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": - version: 1.0.2 - resolution: "is-data-view@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - is-typed-array: "npm:^1.1.13" - checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0": - version: 1.1.0 - resolution: "is-date-object@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - -"is-finalizationregistry@npm:^1.1.0": - version: 1.1.1 - resolution: "is-finalizationregistry@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97 - languageName: node - linkType: hard - -"is-generator-function@npm:^1.0.10": - version: 1.1.0 - resolution: "is-generator-function@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.0" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/fdfa96c8087bf36fc4cd514b474ba2ff404219a4dd4cfa6cf5426404a1eed259bdcdb98f082a71029a48d01f27733e3436ecc6690129a7ec09cb0434bee03a2a - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - -"is-ip@npm:^3.1.0": - version: 3.1.0 - resolution: "is-ip@npm:3.1.0" - dependencies: - ip-regex: "npm:^4.0.0" - checksum: 10c0/4cb643c831314b8fc72770c93a795c0d3dde339f36c8430544c36727956027e2cb329641ace73c5951085ecf93ac608c898859d3d4f7b117d405e1e13c703c76 - languageName: node - linkType: hard - -"is-map@npm:^2.0.3": - version: 2.0.3 - resolution: "is-map@npm:2.0.3" - checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.3": - version: 2.0.3 - resolution: "is-negative-zero@npm:2.0.3" - checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e - languageName: node - linkType: hard - -"is-number-object@npm:^1.1.1": - version: 1.1.1 - resolution: "is-number-object@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53 - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 - languageName: node - linkType: hard - -"is-plain-object@npm:^2.0.4": - version: 2.0.4 - resolution: "is-plain-object@npm:2.0.4" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 - languageName: node - linkType: hard - -"is-regex@npm:^1.2.1": - version: 1.2.1 - resolution: "is-regex@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04 - languageName: node - linkType: hard - -"is-set@npm:^2.0.3": - version: 2.0.3 - resolution: "is-set@npm:2.0.3" - checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.4": - version: 1.0.4 - resolution: "is-shared-array-buffer@npm:1.0.4" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 - languageName: node - linkType: hard - -"is-string@npm:^1.1.1": - version: 1.1.1 - resolution: "is-string@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1": - version: 1.1.1 - resolution: "is-symbol@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" - dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.2": - version: 2.0.2 - resolution: "is-weakmap@npm:2.0.2" - checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": - version: 1.1.1 - resolution: "is-weakref@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.3": - version: 2.0.4 - resolution: "is-weakset@npm:2.0.4" - dependencies: - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647 - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 - languageName: node - linkType: hard - -"isobject@npm:^3.0.1": - version: 3.0.1 - resolution: "isobject@npm:3.0.1" - checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db - languageName: node - linkType: hard - -"iterator.prototype@npm:^1.1.4": - version: 1.1.5 - resolution: "iterator.prototype@npm:1.1.5" - dependencies: - define-data-property: "npm:^1.1.4" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - get-proto: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0 - languageName: node - linkType: hard - -"jdenticon@npm:^3.3.0": - version: 3.3.0 - resolution: "jdenticon@npm:3.3.0" - dependencies: - canvas-renderer: "npm:~2.2.0" - bin: - jdenticon: bin/jdenticon.js - checksum: 10c0/be2642fe3a9a9013d56ced80ec76a2ae6990363d7c2d92470125fc3d646fe711ba8a8695e49cd5bd696b84574fab4e93f3694414fdb95e150c5ce340c385d9e1 - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: "npm:^2.0.1" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f - languageName: node - linkType: hard - -"jsan@npm:^3.1.14": - version: 3.1.14 - resolution: "jsan@npm:3.1.14" - checksum: 10c0/86b6738e90769d8e717849f7bd9ba4742a4ffb1edfa28354521e0c8f106a3addd15eb79d723b47dc9867c70ed06245e4ee14cb2a10c99b91ea612071688137dc - languageName: node - linkType: hard - -"jsesc@npm:^3.0.2": - version: 3.1.0 - resolution: "jsesc@npm:3.1.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.0": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 - languageName: node - linkType: hard - -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f - languageName: node - linkType: hard - -"json5@npm:^2.2.3": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c - languageName: node - linkType: hard - -"jsonwebtoken@npm:^9.0.0": - version: 9.0.2 - resolution: "jsonwebtoken@npm:9.0.2" - dependencies: - jws: "npm:^3.2.2" - lodash.includes: "npm:^4.3.0" - lodash.isboolean: "npm:^3.0.3" - lodash.isinteger: "npm:^4.0.4" - lodash.isnumber: "npm:^3.0.3" - lodash.isplainobject: "npm:^4.0.6" - lodash.isstring: "npm:^4.0.1" - lodash.once: "npm:^4.0.0" - ms: "npm:^2.1.1" - semver: "npm:^7.5.4" - checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131 - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": - version: 3.3.5 - resolution: "jsx-ast-utils@npm:3.3.5" - dependencies: - array-includes: "npm:^3.1.6" - array.prototype.flat: "npm:^1.3.1" - object.assign: "npm:^4.1.4" - object.values: "npm:^1.1.6" - checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 - languageName: node - linkType: hard - -"jwa@npm:^1.4.1": - version: 1.4.2 - resolution: "jwa@npm:1.4.2" - dependencies: - buffer-equal-constant-time: "npm:^1.0.1" - ecdsa-sig-formatter: "npm:1.0.11" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/210a544a42ca22203e8fc538835205155ba3af6a027753109f9258bdead33086bac3c25295af48ac1981f87f9c5f941bc8f70303670f54ea7dcaafb53993d92c - languageName: node - linkType: hard - -"jws@npm:^3.2.2": - version: 3.2.2 - resolution: "jws@npm:3.2.2" - dependencies: - jwa: "npm:^1.4.1" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/e770704533d92df358adad7d1261fdecad4d7b66fa153ba80d047e03ca0f1f73007ce5ed3fbc04d2eba09ba6e7e6e645f351e08e5ab51614df1b0aa4f384dfff - languageName: node - linkType: hard - -"keyv@npm:^4.5.4": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: "npm:3.0.1" - checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e - languageName: node - linkType: hard - -"kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e - languageName: node - linkType: hard - -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d - languageName: node - linkType: hard - -"linked-list@npm:^2.1.0": - version: 2.1.0 - resolution: "linked-list@npm:2.1.0" - checksum: 10c0/d039f664f847022be908460a06a7f63792aadcdfd3061f999726a92d89bf3a10688e7dfb98236f65d9980e2a175839028a374070e48e0676ab9e66122fca7063 - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: "npm:^5.0.0" - checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 - languageName: node - linkType: hard - -"lodash.includes@npm:^4.3.0": - version: 4.3.0 - resolution: "lodash.includes@npm:4.3.0" - checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b - languageName: node - linkType: hard - -"lodash.isboolean@npm:^3.0.3": - version: 3.0.3 - resolution: "lodash.isboolean@npm:3.0.3" - checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 - languageName: node - linkType: hard - -"lodash.isinteger@npm:^4.0.4": - version: 4.0.4 - resolution: "lodash.isinteger@npm:4.0.4" - checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 - languageName: node - linkType: hard - -"lodash.isnumber@npm:^3.0.3": - version: 3.0.3 - resolution: "lodash.isnumber@npm:3.0.3" - checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d - languageName: node - linkType: hard - -"lodash.isplainobject@npm:^4.0.6": - version: 4.0.6 - resolution: "lodash.isplainobject@npm:4.0.6" - checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb - languageName: node - linkType: hard - -"lodash.isstring@npm:^4.0.1": - version: 4.0.1 - resolution: "lodash.isstring@npm:4.0.1" - checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 - languageName: node - linkType: hard - -"lodash.once@npm:^4.0.0": - version: 4.1.1 - resolution: "lodash.once@npm:4.1.1" - checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 - languageName: node - linkType: hard - -"lodash@npm:^4.17.21": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c - languageName: node - linkType: hard - -"loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e - languageName: node - linkType: hard - -"loupe@npm:^3.1.0, loupe@npm:^3.1.2": - version: 3.2.1 - resolution: "loupe@npm:3.2.1" - checksum: 10c0/910c872cba291309664c2d094368d31a68907b6f5913e989d301b5c25f30e97d76d77f23ab3bf3b46d0f601ff0b6af8810c10c31b91d2c6b2f132809ca2cc705 - languageName: node - linkType: hard - -"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": - version: 11.2.4 - resolution: "lru-cache@npm:11.2.4" - checksum: 10c0/4a24f9b17537619f9144d7b8e42cd5a225efdfd7076ebe7b5e7dc02b860a818455201e67fbf000765233fe7e339d3c8229fc815e9b58ee6ede511e07608c19b2 - languageName: node - linkType: hard - -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 - languageName: node - linkType: hard - -"magic-string@npm:^0.30.12": - version: 0.30.18 - resolution: "magic-string@npm:0.30.18" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.5.5" - checksum: 10c0/80fba01e13ce1f5c474a0498a5aa462fa158eb56567310747089a0033e432d83a2021ee2c109ac116010cd9dcf90a5231d89fbe3858165f73c00a50a74dbefcd - languageName: node - linkType: hard - -"make-fetch-happen@npm:^15.0.0": - version: 15.0.3 - resolution: "make-fetch-happen@npm:15.0.3" - dependencies: - "@npmcli/agent": "npm:^4.0.0" - cacache: "npm:^20.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^5.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^6.0.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^13.0.0" - checksum: 10c0/525f74915660be60b616bcbd267c4a5b59481b073ba125e45c9c3a041bb1a47a2bd0ae79d028eb6f5f95bf9851a4158423f5068539c3093621abb64027e8e461 - languageName: node - linkType: hard - -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 - languageName: node - linkType: hard - -"merge2@npm:^1.3.0": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb - languageName: node - linkType: hard - -"micromatch@npm:^4.0.8": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: 10c0/b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4 - languageName: node - linkType: hard - -"minimatch@npm:^10.1.1": - version: 10.1.1 - resolution: "minimatch@npm:10.1.1" - dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902 - languageName: node - linkType: hard - -"minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 - languageName: node - linkType: hard - -"minimatch@npm:^5.1.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e - languageName: node - linkType: hard - -"minipass-fetch@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass-fetch@npm:5.0.0" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^3.0.1" - dependenciesMeta: - encoding: - optional: true - checksum: 10c0/9443aab5feab190972f84b64116e54e58dd87a58e62399cae0a4a7461b80568281039b7c3a38ba96453431ebc799d1e26999e548540156216729a4967cd5ef06 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c - languageName: node - linkType: hard - -"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 - languageName: node - linkType: hard - -"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": - version: 3.1.0 - resolution: "minizlib@npm:3.1.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec - languageName: node - linkType: hard - -"ms@npm:^2.1.1, ms@npm:^2.1.3": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 - languageName: node - linkType: hard - -"multiaddr@npm:^10.0.1": - version: 10.0.1 - resolution: "multiaddr@npm:10.0.1" - dependencies: - dns-over-http-resolver: "npm:^1.2.3" - err-code: "npm:^3.0.1" - is-ip: "npm:^3.1.0" - multiformats: "npm:^9.4.5" - uint8arrays: "npm:^3.0.0" - varint: "npm:^6.0.0" - checksum: 10c0/948d0c69d75992d754fd36154db4d4a435b977c56a617183a9d8c2075081e2cfcacda3bedb72bbd6759bb329956a45b216e804829e708af8d2f780f8152a4bf6 - languageName: node - linkType: hard - -"multiformats@npm:^9.4.2, multiformats@npm:^9.4.5": - version: 9.9.0 - resolution: "multiformats@npm:9.9.0" - checksum: 10c0/1fdb34fd2fb085142665e8bd402570659b50a5fae5994027e1df3add9e1ce1283ed1e0c2584a5c63ac0a58e871b8ee9665c4a99ca36ce71032617449d48aa975 - languageName: node - linkType: hard - -"nanoid@npm:^3.3.11": - version: 3.3.11 - resolution: "nanoid@npm:3.3.11" - bin: - nanoid: bin/nanoid.cjs - checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b - languageName: node - linkType: hard - -"nanoid@npm:^5.1.2": - version: 5.1.5 - resolution: "nanoid@npm:5.1.5" - bin: - nanoid: bin/nanoid.js - checksum: 10c0/e6004f1ad6c7123eeb037062c4441d44982037dc043aabb162457ef6986e99964ba98c63c975f96c547403beb0bf95bc537bd7bf9a09baf381656acdc2975c3c - languageName: node - linkType: hard - -"native-fetch@npm:^3.0.0": - version: 3.0.0 - resolution: "native-fetch@npm:3.0.0" - peerDependencies: - node-fetch: "*" - checksum: 10c0/737cdd209dd366df8b748dabac39340089d57a2bcc460ffc029ec145f30aeffea0c6a6f177013069d6f7f04ffc8c3e39cfb8e3825e7071a373c4f86b187ae1b5 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 12.1.0 - resolution: "node-gyp@npm:12.1.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^15.0.0" - nopt: "npm:^9.0.0" - proc-log: "npm:^6.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.5.2" - tinyglobby: "npm:^0.2.12" - which: "npm:^6.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10c0/f43efea8aaf0beb6b2f6184e533edad779b2ae38062953e21951f46221dd104006cc574154f2ad4a135467a5aae92c49e84ef289311a82e08481c5df0e8dc495 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.19": - version: 2.0.19 - resolution: "node-releases@npm:2.0.19" - checksum: 10c0/52a0dbd25ccf545892670d1551690fe0facb6a471e15f2cfa1b20142a5b255b3aa254af5f59d6ecb69c2bec7390bc643c43aa63b13bf5e64b6075952e716b1aa - languageName: node - linkType: hard - -"nopt@npm:^9.0.0": - version: 9.0.0 - resolution: "nopt@npm:9.0.0" - dependencies: - abbrev: "npm:^4.0.0" - bin: - nopt: bin/nopt.js - checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd - languageName: node - linkType: hard - -"notistack@npm:^3.0.1": - version: 3.0.2 - resolution: "notistack@npm:3.0.2" - dependencies: - clsx: "npm:^1.1.0" - goober: "npm:^2.0.33" - peerDependencies: - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/82a0270ee1b9e70bc1dfad4d7e1d2bbb6dc08ac887b920986dcfa58cc2aa975bd48b71f7cf3afc2e11badd142ba9ade5f708c858ee2080b9d4cd950b80c43811 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: "npm:^3.0.0" - checksum: 10c0/6f9353a95288f8455cf64cbeb707b28826a7f29690244c1e4bb61ec573256e021b6ad6651b394eb1ccfd00d6ec50147253aba2c5fe58a57ceb111fad62c519ac - languageName: node - linkType: hard - -"object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 - languageName: node - linkType: hard - -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d - languageName: node - linkType: hard - -"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": - version: 4.1.7 - resolution: "object.assign@npm:4.1.7" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc - languageName: node - linkType: hard - -"object.entries@npm:^1.1.9": - version: 1.1.9 - resolution: "object.entries@npm:1.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.1.1" - checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.8": - version: 2.0.8 - resolution: "object.fromentries@npm:2.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b - languageName: node - linkType: hard - -"object.groupby@npm:^1.0.3": - version: 1.0.3 - resolution: "object.groupby@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c - languageName: node - linkType: hard - -"object.values@npm:^1.1.6, object.values@npm:^1.2.1": - version: 1.2.1 - resolution: "object.values@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: "npm:^2.1.0" - checksum: 10c0/ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f - languageName: node - linkType: hard - -"optionator@npm:^0.9.3": - version: 0.9.4 - resolution: "optionator@npm:0.9.4" - dependencies: - deep-is: "npm:^0.1.3" - fast-levenshtein: "npm:^2.0.6" - levn: "npm:^0.4.1" - prelude-ls: "npm:^1.2.1" - type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.5" - checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 - languageName: node - linkType: hard - -"own-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "own-keys@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.2.6" - object-keys: "npm:^1.1.1" - safe-push-apply: "npm:^1.0.0" - checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a - languageName: node - linkType: hard - -"p-event@npm:^4.2.0": - version: 4.2.0 - resolution: "p-event@npm:4.2.0" - dependencies: - p-timeout: "npm:^3.1.0" - checksum: 10c0/f1b6a2fb13d47f2a8afc00150da5ece0d28940ce3d8fa562873e091d3337d298e78fee9cb18b768598ff1d11df608b2ae23868309ff6405b864a2451ccd6d25a - languageName: node - linkType: hard - -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: "npm:^3.0.2" - checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a - languageName: node - linkType: hard - -"p-map@npm:^7.0.2": - version: 7.0.4 - resolution: "p-map@npm:7.0.4" - checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd - languageName: node - linkType: hard - -"p-timeout@npm:^3.1.0": - version: 3.2.0 - resolution: "p-timeout@npm:3.2.0" - dependencies: - p-finally: "npm:^1.0.0" - checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: "npm:^3.0.0" - checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 - languageName: node - linkType: hard - -"parse-json@npm:^5.0.0": - version: 5.2.0 - resolution: "parse-json@npm:5.2.0" - dependencies: - "@babel/code-frame": "npm:^7.0.0" - error-ex: "npm:^1.3.1" - json-parse-even-better-errors: "npm:^2.3.0" - lines-and-columns: "npm:^1.1.6" - checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 - languageName: node - linkType: hard - -"path-scurry@npm:^2.0.0": - version: 2.0.1 - resolution: "path-scurry@npm:2.0.1" - dependencies: - lru-cache: "npm:^11.0.0" - minipass: "npm:^7.1.2" - checksum: 10c0/2a16ed0e81fbc43513e245aa5763354e25e787dab0d539581a6c3f0f967461a159ed6236b2559de23aa5b88e7dc32b469b6c47568833dd142a4b24b4f5cd2620 - languageName: node - linkType: hard - -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c - languageName: node - linkType: hard - -"pathe@npm:^1.1.2": - version: 1.1.2 - resolution: "pathe@npm:1.1.2" - checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 - languageName: node - linkType: hard - -"pathval@npm:^2.0.0": - version: 2.0.1 - resolution: "pathval@npm:2.0.1" - checksum: 10c0/460f4709479fbf2c45903a65655fc8f0a5f6d808f989173aeef5fdea4ff4f303dc13f7870303999add60ec49d4c14733895c0a869392e9866f1091fa64fd7581 - languageName: node - linkType: hard - -"picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 - languageName: node - linkType: hard - -"picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be - languageName: node - linkType: hard - -"picomatch@npm:^4.0.3": - version: 4.0.3 - resolution: "picomatch@npm:4.0.3" - checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2 - languageName: node - linkType: hard - -"possible-typed-array-names@npm:^1.0.0": - version: 1.1.0 - resolution: "possible-typed-array-names@npm:1.1.0" - checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196 - languageName: node - linkType: hard - -"postcss@npm:^8.4.43": - version: 8.5.6 - resolution: "postcss@npm:8.5.6" - dependencies: - nanoid: "npm:^3.3.11" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10c0/5127cc7c91ed7a133a1b7318012d8bfa112da9ef092dddf369ae699a1f10ebbd89b1b9f25f3228795b84585c72aabd5ced5fc11f2ba467eedf7b081a66fad024 - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd - languageName: node - linkType: hard - -"proc-log@npm:^6.0.0": - version: 6.1.0 - resolution: "proc-log@npm:6.1.0" - checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 - languageName: node - linkType: hard - -"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": - version: 15.8.1 - resolution: "prop-types@npm:15.8.1" - dependencies: - loose-envify: "npm:^1.4.0" - object-assign: "npm:^4.1.1" - react-is: "npm:^16.13.1" - checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 - languageName: node - linkType: hard - -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - -"qr.js@npm:0.0.0": - version: 0.0.0 - resolution: "qr.js@npm:0.0.0" - checksum: 10c0/1c6a4c7a58d04e52ec2fee99e39b680fdc5b2a510a981df42c36b716a8eac6634d130fc4d65af8f030f2a07dbf5fa046b97cdfa7456c250ebb50a73916efdcb5 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 - languageName: node - linkType: hard - -"react-dom@npm:^19.1.0": - version: 19.1.1 - resolution: "react-dom@npm:19.1.1" - dependencies: - scheduler: "npm:^0.26.0" - peerDependencies: - react: ^19.1.1 - checksum: 10c0/8c91198510521299c56e4e8d5e3a4508b2734fb5e52f29eeac33811de64e76fe586ad32c32182e2e84e070d98df67125da346c3360013357228172dbcd20bcdd - languageName: node - linkType: hard - -"react-is@npm:^16.13.1, react-is@npm:^16.7.0": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 - languageName: node - linkType: hard - -"react-is@npm:^19.1.1": - version: 19.1.1 - resolution: "react-is@npm:19.1.1" - checksum: 10c0/3dba763fcd69835ae263dcd6727d7ffcc44c1d616f04b7329e67aefdc66a567af4f8dcecdd29454c7a707c968aa1eb85083a83fb616f01675ef25e71cf082f97 - languageName: node - linkType: hard - -"react-qr-code@npm:^2.0.15": - version: 2.0.18 - resolution: "react-qr-code@npm:2.0.18" - dependencies: - prop-types: "npm:^15.8.1" - qr.js: "npm:0.0.0" - peerDependencies: - react: "*" - checksum: 10c0/4e13b795cbb10f1dcf0e39d682bb59851e4c84010ba2be7225b2ad9d5c1ffea52d2d38f884ee26235b7002b8ca99e83b805f55e877663c39d67496764d975cf1 - languageName: node - linkType: hard - -"react-redux@npm:^9.2.0": - version: 9.2.0 - resolution: "react-redux@npm:9.2.0" - dependencies: - "@types/use-sync-external-store": "npm:^0.0.6" - use-sync-external-store: "npm:^1.4.0" - peerDependencies: - "@types/react": ^18.2.25 || ^19 - react: ^18.0 || ^19 - redux: ^5.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - redux: - optional: true - checksum: 10c0/00d485f9d9219ca1507b4d30dde5f6ff8fb68ba642458f742e0ec83af052f89e65cd668249b99299e1053cc6ad3d2d8ac6cb89e2f70d2ac5585ae0d7fa0ef259 - languageName: node - linkType: hard - -"react-refresh@npm:^0.17.0": - version: 0.17.0 - resolution: "react-refresh@npm:0.17.0" - checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c - languageName: node - linkType: hard - -"react-router-dom@npm:^7.6.1": - version: 7.8.1 - resolution: "react-router-dom@npm:7.8.1" - dependencies: - react-router: "npm:7.8.1" - peerDependencies: - react: ">=18" - react-dom: ">=18" - checksum: 10c0/7616ae6b6c741446c6168a4ec760c01cbe24e8d14364a605bb002ba3f9bc060c0307ae1fb01cb76552aceb0dd956f023a0fb23b2f40436173e7e587a28301a8f - languageName: node - linkType: hard - -"react-router@npm:7.8.1": - version: 7.8.1 - resolution: "react-router@npm:7.8.1" - dependencies: - cookie: "npm:^1.0.1" - set-cookie-parser: "npm:^2.6.0" - peerDependencies: - react: ">=18" - react-dom: ">=18" - peerDependenciesMeta: - react-dom: - optional: true - checksum: 10c0/6d3229080a0f67f4644e0d8ecdb5e2637f640bf9e3a87c3e1e6ca91cce156cf3606d57dac3899869b25156b8343bc274291345914e45bb30ef38556a14e24eac - languageName: node - linkType: hard - -"react-transition-group@npm:^4.4.5": - version: 4.4.5 - resolution: "react-transition-group@npm:4.4.5" - dependencies: - "@babel/runtime": "npm:^7.5.5" - dom-helpers: "npm:^5.0.1" - loose-envify: "npm:^1.4.0" - prop-types: "npm:^15.6.2" - peerDependencies: - react: ">=16.6.0" - react-dom: ">=16.6.0" - checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82 - languageName: node - linkType: hard - -"react@npm:^19.1.0": - version: 19.1.1 - resolution: "react@npm:19.1.1" - checksum: 10c0/8c9769a2dfd02e603af6445058325e6c8a24b47b185d0e461f66a6454765ddcaecb3f0a90184836c68bb509f3c38248359edbc42f0d07c23eb500a5c30c87b4e - languageName: node - linkType: hard - -"readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa - languageName: node - linkType: hard - -"receptacle@npm:^1.3.2": - version: 1.3.2 - resolution: "receptacle@npm:1.3.2" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/213dc9e4e80969cde60c5877fae08d8438f0bf7dd10bf4ea47916a10c053ca05d6581bda374d8f22ce15e6b50739efe319d847362f5ec9e1a4cbdcbde3ddf355 - languageName: node - linkType: hard - -"redux-persist@npm:^6.0.0": - version: 6.0.0 - resolution: "redux-persist@npm:6.0.0" - peerDependencies: - redux: ">4.0.0" - checksum: 10c0/8242d265ab8d28bbc95cf2dc2a05b869eb67aa309b1ed08163c926f3af56dd8eb1ea62118286083461b8ef2024d3b349fd264e5a62a70eb2e74d068c832d5bf2 - languageName: node - linkType: hard - -"redux-thunk@npm:^3.1.0": - version: 3.1.0 - resolution: "redux-thunk@npm:3.1.0" - peerDependencies: - redux: ^5.0.0 - checksum: 10c0/21557f6a30e1b2e3e470933247e51749be7f1d5a9620069a3125778675ce4d178d84bdee3e2a0903427a5c429e3aeec6d4df57897faf93eb83455bc1ef7b66fd - languageName: node - linkType: hard - -"redux@npm:^4.0.0": - version: 4.2.1 - resolution: "redux@npm:4.2.1" - dependencies: - "@babel/runtime": "npm:^7.9.2" - checksum: 10c0/136d98b3d5dbed1cd6279c8c18a6a74c416db98b8a432a46836bdd668475de6279a2d4fd9d1363f63904e00f0678a8a3e7fa532c897163340baf1e71bb42c742 - languageName: node - linkType: hard - -"redux@npm:^5.0.1": - version: 5.0.1 - resolution: "redux@npm:5.0.1" - checksum: 10c0/b10c28357194f38e7d53b760ed5e64faa317cc63de1fb95bc5d9e127fab956392344368c357b8e7a9bedb0c35b111e7efa522210cfdc3b3c75e5074718e9069c - languageName: node - linkType: hard - -"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": - version: 1.0.10 - resolution: "reflect.getprototypeof@npm:1.0.10" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.1" - which-builtin-type: "npm:^1.2.1" - checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": - version: 1.5.4 - resolution: "regexp.prototype.flags@npm:1.5.4" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-errors: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77 - languageName: node - linkType: hard - -"reselect@npm:^5.1.0, reselect@npm:^5.1.1": - version: 5.1.1 - resolution: "reselect@npm:5.1.1" - checksum: 10c0/219c30da122980f61853db3aebd173524a2accd4b3baec770e3d51941426c87648a125ca08d8c57daa6b8b086f2fdd2703cb035dd6231db98cdbe1176a71f489 - languageName: node - linkType: hard - -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 - languageName: node - linkType: hard - -"resolve@npm:^1.19.0": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/8967e1f4e2cc40f79b7e080b4582b9a8c5ee36ffb46041dccb20e6461161adf69f843b43067b4a375de926a2cd669157e29a29578191def399dd5ef89a1b5203 - languageName: node - linkType: hard - -"resolve@npm:^1.22.4": - version: 1.22.11 - resolution: "resolve@npm:1.22.11" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409 - languageName: node - linkType: hard - -"resolve@npm:^2.0.0-next.5": - version: 2.0.0-next.5 - resolution: "resolve@npm:2.0.0-next.5" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/a6c33555e3482ea2ec4c6e3d3bf0d78128abf69dca99ae468e64f1e30acaa318fd267fb66c8836b04d558d3e2d6ed875fe388067e7d8e0de647d3c21af21c43a - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.19.0#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/52a4e505bbfc7925ac8f4cd91fd8c4e096b6a89728b9f46861d3b405ac9a1ccf4dcbf8befb4e89a2e11370dacd0160918163885cbc669369590f2f31f4c58939 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": - version: 1.22.11 - resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": - version: 2.0.0-next.5 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/78ad6edb8309a2bfb720c2c1898f7907a37f858866ce11a5974643af1203a6a6e05b2fa9c53d8064a673a447b83d42569260c306d43628bff5bb101969708355 - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.1.0 - resolution: "reusify@npm:1.1.0" - checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa - languageName: node - linkType: hard - -"rn-host-detect@npm:^1.2.0": - version: 1.2.0 - resolution: "rn-host-detect@npm:1.2.0" - checksum: 10c0/94067014566c738b3cb786d507a3cf4f4fab79b51b0d7c38bea0a48d536458c7218e01f259e03fa51cf1cf6f62ad4c01fcd36c6fa3b725a86eace02dd30d929f - languageName: node - linkType: hard - -"rollup@npm:^4.20.0": - version: 4.47.1 - resolution: "rollup@npm:4.47.1" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.47.1" - "@rollup/rollup-android-arm64": "npm:4.47.1" - "@rollup/rollup-darwin-arm64": "npm:4.47.1" - "@rollup/rollup-darwin-x64": "npm:4.47.1" - "@rollup/rollup-freebsd-arm64": "npm:4.47.1" - "@rollup/rollup-freebsd-x64": "npm:4.47.1" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.47.1" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.47.1" - "@rollup/rollup-linux-arm64-gnu": "npm:4.47.1" - "@rollup/rollup-linux-arm64-musl": "npm:4.47.1" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.47.1" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.47.1" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.47.1" - "@rollup/rollup-linux-riscv64-musl": "npm:4.47.1" - "@rollup/rollup-linux-s390x-gnu": "npm:4.47.1" - "@rollup/rollup-linux-x64-gnu": "npm:4.47.1" - "@rollup/rollup-linux-x64-musl": "npm:4.47.1" - "@rollup/rollup-win32-arm64-msvc": "npm:4.47.1" - "@rollup/rollup-win32-ia32-msvc": "npm:4.47.1" - "@rollup/rollup-win32-x64-msvc": "npm:4.47.1" - "@types/estree": "npm:1.0.8" - fsevents: "npm:~2.3.2" - dependenciesMeta: - "@rollup/rollup-android-arm-eabi": - optional: true - "@rollup/rollup-android-arm64": - optional: true - "@rollup/rollup-darwin-arm64": - optional: true - "@rollup/rollup-darwin-x64": - optional: true - "@rollup/rollup-freebsd-arm64": - optional: true - "@rollup/rollup-freebsd-x64": - optional: true - "@rollup/rollup-linux-arm-gnueabihf": - optional: true - "@rollup/rollup-linux-arm-musleabihf": - optional: true - "@rollup/rollup-linux-arm64-gnu": - optional: true - "@rollup/rollup-linux-arm64-musl": - optional: true - "@rollup/rollup-linux-loongarch64-gnu": - optional: true - "@rollup/rollup-linux-ppc64-gnu": - optional: true - "@rollup/rollup-linux-riscv64-gnu": - optional: true - "@rollup/rollup-linux-riscv64-musl": - optional: true - "@rollup/rollup-linux-s390x-gnu": - optional: true - "@rollup/rollup-linux-x64-gnu": - optional: true - "@rollup/rollup-linux-x64-musl": - optional: true - "@rollup/rollup-win32-arm64-msvc": - optional: true - "@rollup/rollup-win32-ia32-msvc": - optional: true - "@rollup/rollup-win32-x64-msvc": - optional: true - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 10c0/4d792f8a8bfb4408485bbc6c1f393a88422230c14d06b9de4d27bcf443fe3569f9fa4ed6111972bf6b8b515bd0133bfeb16ab66cdf32494ef0fbd2da41dc2855 - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.1.3": - version: 1.1.3 - resolution: "safe-array-concat@npm:1.1.3" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - has-symbols: "npm:^1.1.0" - isarray: "npm:^2.0.5" - checksum: 10c0/43c86ffdddc461fb17ff8a17c5324f392f4868f3c7dd2c6a5d9f5971713bc5fd755667212c80eab9567595f9a7509cc2f83e590ddaebd1bd19b780f9c79f9a8d - languageName: node - linkType: hard - -"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 - languageName: node - linkType: hard - -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 - languageName: node - linkType: hard - -"safe-push-apply@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-push-apply@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - isarray: "npm:^2.0.5" - checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750 - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex-test@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-regex: "npm:^1.2.1" - checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 - languageName: node - linkType: hard - -"sc-errors@npm:^3.0.0": - version: 3.0.0 - resolution: "sc-errors@npm:3.0.0" - checksum: 10c0/d015423572cf0b68a6ddb5a9088cb7509da013cdb304691128443f6240e095b3de0e126e0d8e6c5fce14dc0973ad1c3f6ef9c77f4667599f2e99e5377c72a133 - languageName: node - linkType: hard - -"sc-formatter@npm:^4.0.0": - version: 4.0.0 - resolution: "sc-formatter@npm:4.0.0" - checksum: 10c0/1ef2e29bbfcd4ee17c9bbeaaa766169b8e0d210cecac6bcfd71341306438948536b59e060e1edd28ddee1ede1108c3ac1e1789813349d15aab677a5f64ea7cc9 - languageName: node - linkType: hard - -"scheduler@npm:^0.26.0": - version: 0.26.0 - resolution: "scheduler@npm:0.26.0" - checksum: 10c0/5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356 - languageName: node - linkType: hard - -"semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d - languageName: node - linkType: hard - -"semver@npm:^7.3.5": - version: 7.7.3 - resolution: "semver@npm:7.7.3" - bin: - semver: bin/semver.js - checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e - languageName: node - linkType: hard - -"semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2": - version: 7.7.2 - resolution: "semver@npm:7.7.2" - bin: - semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea - languageName: node - linkType: hard - -"set-cookie-parser@npm:^2.6.0": - version: 2.7.1 - resolution: "set-cookie-parser@npm:2.7.1" - checksum: 10c0/060c198c4c92547ac15988256f445eae523f57f2ceefeccf52d30d75dedf6bff22b9c26f756bd44e8e560d44ff4ab2130b178bd2e52ef5571bf7be3bd7632d9a - languageName: node - linkType: hard - -"set-function-length@npm:^1.2.2": - version: 1.2.2 - resolution: "set-function-length@npm:1.2.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.2": - version: 2.0.2 - resolution: "set-function-name@npm:2.0.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 - languageName: node - linkType: hard - -"set-proto@npm:^1.0.0": - version: 1.0.0 - resolution: "set-proto@npm:1.0.0" - dependencies: - dunder-proto: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a - languageName: node - linkType: hard - -"shallow-clone@npm:^3.0.0": - version: 3.0.1 - resolution: "shallow-clone@npm:3.0.1" - dependencies: - kind-of: "npm:^6.0.2" - checksum: 10c0/7bab09613a1b9f480c85a9823aebec533015579fa055ba6634aa56ba1f984380670eaf33b8217502931872aa1401c9fcadaa15f9f604d631536df475b05bcf1e - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 - languageName: node - linkType: hard - -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 - languageName: node - linkType: hard - -"siginfo@npm:^2.0.0": - version: 2.0.0 - resolution: "siginfo@npm:2.0.0" - checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.3": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 - languageName: node - linkType: hard - -"socketcluster-client@npm:^19.2.3": - version: 19.2.7 - resolution: "socketcluster-client@npm:19.2.7" - dependencies: - ag-auth: "npm:^2.1.0" - ag-channel: "npm:^5.0.0" - ag-request: "npm:^1.1.0" - async-stream-emitter: "npm:^7.0.1" - buffer: "npm:^5.2.1" - clone-deep: "npm:^4.0.1" - linked-list: "npm:^2.1.0" - sc-errors: "npm:^3.0.0" - sc-formatter: "npm:^4.0.0" - stream-demux: "npm:^10.0.1" - uuid: "npm:^8.3.2" - vinyl-buffer: "npm:^1.0.1" - ws: "npm:^8.18.0" - checksum: 10c0/58a333f2ac376043ea7bf38c42a473042258000e9ea8e56eec3d2ff3b6e85c04d8f710b2bd1f79436878bc802358259e3aa1dcc22241a1d7ae2600288fc75412 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.7 - resolution: "socks@npm:2.8.7" - dependencies: - ip-address: "npm:^10.0.1" - smart-buffer: "npm:^4.2.0" - checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 - languageName: node - linkType: hard - -"source-map-js@npm:^1.2.1": - version: 1.2.1 - resolution: "source-map-js@npm:1.2.1" - checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf - languageName: node - linkType: hard - -"source-map@npm:^0.5.7": - version: 0.5.7 - resolution: "source-map@npm:0.5.7" - checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 - languageName: node - linkType: hard - -"ssri@npm:^13.0.0": - version: 13.0.0 - resolution: "ssri@npm:13.0.0" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/405f3a531cd98b013cecb355d63555dca42fd12c7bc6671738aaa9a82882ff41cdf0ef9a2b734ca4f9a760338f114c29d01d9238a65db3ccac27929bd6e6d4b2 - languageName: node - linkType: hard - -"stackback@npm:0.0.2": - version: 0.0.2 - resolution: "stackback@npm:0.0.2" - checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 - languageName: node - linkType: hard - -"std-env@npm:^3.8.0": - version: 3.9.0 - resolution: "std-env@npm:3.9.0" - checksum: 10c0/4a6f9218aef3f41046c3c7ecf1f98df00b30a07f4f35c6d47b28329bc2531eef820828951c7d7b39a1c5eb19ad8a46e3ddfc7deb28f0a2f3ceebee11bab7ba50 - languageName: node - linkType: hard - -"stop-iteration-iterator@npm:^1.1.0": - version: 1.1.0 - resolution: "stop-iteration-iterator@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - internal-slot: "npm:^1.1.0" - checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09 - languageName: node - linkType: hard - -"stream-demux@npm:^10.0.1": - version: 10.0.1 - resolution: "stream-demux@npm:10.0.1" - dependencies: - consumable-stream: "npm:^3.0.0" - writable-consumable-stream: "npm:^4.1.0" - checksum: 10c0/9c6b42af758560ceab49b0fdae169599cfca95fcd6f234b45fa3e1465751c2576ad65fd86e54bf5365fda6152955d06d6e6957c506b51460343c4801260402cf - languageName: node - linkType: hard - -"string.prototype.matchall@npm:^4.0.12": - version: 4.0.12 - resolution: "string.prototype.matchall@npm:4.0.12" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - regexp.prototype.flags: "npm:^1.5.3" - set-function-name: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c - languageName: node - linkType: hard - -"string.prototype.repeat@npm:^1.0.0": - version: 1.0.0 - resolution: "string.prototype.repeat@npm:1.0.0" - dependencies: - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.17.5" - checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40 - languageName: node - linkType: hard - -"string.prototype.trim@npm:^1.2.10": - version: 1.2.10 - resolution: "string.prototype.trim@npm:1.2.10" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-data-property: "npm:^1.1.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-object-atoms: "npm:^1.0.0" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/8a8854241c4b54a948e992eb7dd6b8b3a97185112deb0037a134f5ba57541d8248dd610c966311887b6c2fd1181a3877bffb14d873ce937a344535dabcc648f8 - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.9": - version: 1.0.9 - resolution: "string.prototype.trimend@npm:1.0.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/59e1a70bf9414cb4c536a6e31bef5553c8ceb0cf44d8b4d0ed65c9653358d1c64dd0ec203b100df83d0413bbcde38b8c5d49e14bc4b86737d74adc593a0d35b6 - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.8": - version: 1.0.8 - resolution: "string.prototype.trimstart@npm:1.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e - languageName: node - linkType: hard - -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 10c0/bddf8ccd47acd85c0e09ad7375409d81653f645fda13227a9d459642277c253d877b68f2e5e4d819fe75733b0e626bac7e954c04f3236f6d196f79c94fa4a96f - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd - languageName: node - linkType: hard - -"stylis@npm:4.2.0": - version: 4.2.0 - resolution: "stylis@npm:4.2.0" - checksum: 10c0/a7128ad5a8ed72652c6eba46bed4f416521bc9745a460ef5741edc725252cebf36ee45e33a8615a7057403c93df0866ab9ee955960792db210bb80abd5ac6543 - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 - languageName: node - linkType: hard - -"tar@npm:^7.5.2": - version: 7.5.2 - resolution: "tar@npm:7.5.2" - dependencies: - "@isaacs/fs-minipass": "npm:^4.0.0" - chownr: "npm:^3.0.0" - minipass: "npm:^7.1.2" - minizlib: "npm:^3.1.0" - yallist: "npm:^5.0.0" - checksum: 10c0/a7d8b801139b52f93a7e34830db0de54c5aa45487c7cb551f6f3d44a112c67f1cb8ffdae856b05fd4f17b1749911f1c26f1e3a23bbe0279e17fd96077f13f467 - languageName: node - linkType: hard - -"through2@npm:^2.0.3": - version: 2.0.5 - resolution: "through2@npm:2.0.5" - dependencies: - readable-stream: "npm:~2.3.6" - xtend: "npm:~4.0.1" - checksum: 10c0/cbfe5b57943fa12b4f8c043658c2a00476216d79c014895cef1ac7a1d9a8b31f6b438d0e53eecbb81054b93128324a82ecd59ec1a4f91f01f7ac113dcb14eade - languageName: node - linkType: hard - -"tinybench@npm:^2.9.0": - version: 2.9.0 - resolution: "tinybench@npm:2.9.0" - checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c - languageName: node - linkType: hard - -"tinyexec@npm:^0.3.1": - version: 0.3.2 - resolution: "tinyexec@npm:0.3.2" - checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 - languageName: node - linkType: hard - -"tinyglobby@npm:^0.2.12": - version: 0.2.15 - resolution: "tinyglobby@npm:0.2.15" - dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.3" - checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 - languageName: node - linkType: hard - -"tinypool@npm:^1.0.1": - version: 1.1.1 - resolution: "tinypool@npm:1.1.1" - checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b - languageName: node - linkType: hard - -"tinyrainbow@npm:^1.2.0": - version: 1.2.0 - resolution: "tinyrainbow@npm:1.2.0" - checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192 - languageName: node - linkType: hard - -"tinyspy@npm:^3.0.2": - version: 3.0.2 - resolution: "tinyspy@npm:3.0.2" - checksum: 10c0/55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 - languageName: node - linkType: hard - -"ts-api-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "ts-api-utils@npm:2.1.0" - peerDependencies: - typescript: ">=4.8.4" - checksum: 10c0/9806a38adea2db0f6aa217ccc6bc9c391ddba338a9fe3080676d0d50ed806d305bb90e8cef0276e793d28c8a929f400abb184ddd7ff83a416959c0f4d2ce754f - languageName: node - linkType: hard - -"tsconfck@npm:^3.0.3": - version: 3.1.6 - resolution: "tsconfck@npm:3.1.6" - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - bin: - tsconfck: bin/tsconfck.js - checksum: 10c0/269c3c513540be44844117bb9b9258fe6f8aeab026d32aeebf458d5299125f330711429dbb556dbf125a0bc25f4a81e6c24ac96de2740badd295c3fb400f66c4 - languageName: node - linkType: hard - -"tsconfig-paths@npm:^3.15.0": - version: 3.15.0 - resolution: "tsconfig-paths@npm:3.15.0" - dependencies: - "@types/json5": "npm:^0.0.29" - json5: "npm:^1.0.2" - minimist: "npm:^1.2.6" - strip-bom: "npm:^3.0.0" - checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: "npm:^1.2.1" - checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 - languageName: node - linkType: hard - -"typed-array-buffer@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-buffer@npm:1.0.3" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079 - languageName: node - linkType: hard - -"typed-array-byte-length@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-byte-length@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e - languageName: node - linkType: hard - -"typed-array-byte-offset@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-byte-offset@npm:1.0.4" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.15" - reflect.getprototypeof: "npm:^1.0.9" - checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53 - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.7": - version: 1.0.7 - resolution: "typed-array-length@npm:1.0.7" - dependencies: - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - is-typed-array: "npm:^1.1.13" - possible-typed-array-names: "npm:^1.0.0" - reflect.getprototypeof: "npm:^1.0.6" - checksum: 10c0/e38f2ae3779584c138a2d8adfa8ecf749f494af3cd3cdafe4e688ce51418c7d2c5c88df1bd6be2bbea099c3f7cea58c02ca02ed438119e91f162a9de23f61295 - languageName: node - linkType: hard - -"typescript-eslint@npm:^8.1.0": - version: 8.40.0 - resolution: "typescript-eslint@npm:8.40.0" - dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.40.0" - "@typescript-eslint/parser": "npm:8.40.0" - "@typescript-eslint/typescript-estree": "npm:8.40.0" - "@typescript-eslint/utils": "npm:8.40.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/b9bf9cbe13a89348ae2a13a7839238b1b058c1e188d9cc1028810c43f1b48cf256f5255ca94c38acf3cd5a405c918ad96d5b7f7a6ad3f82fa7429122a7883a83 - languageName: node - linkType: hard - -"typescript@npm:^5.2.2": - version: 5.9.2 - resolution: "typescript@npm:5.9.2" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 - languageName: node - linkType: hard - -"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin": - version: 5.9.2 - resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e - languageName: node - linkType: hard - -"uint8arrays@npm:^3.0.0": - version: 3.1.1 - resolution: "uint8arrays@npm:3.1.1" - dependencies: - multiformats: "npm:^9.4.2" - checksum: 10c0/9946668e04f29b46bbb73cca3d190f63a2fbfe5452f8e6551ef4257d9d597b72da48fa895c15ef2ef772808a5335b3305f69da5f13a09f8c2924896b409565ff - languageName: node - linkType: hard - -"unbox-primitive@npm:^1.1.0": - version: 1.1.0 - resolution: "unbox-primitive@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - has-bigints: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - which-boxed-primitive: "npm:^1.1.1" - checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982 - languageName: node - linkType: hard - -"undici-types@npm:~6.21.0": - version: 6.21.0 - resolution: "undici-types@npm:6.21.0" - checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 - languageName: node - linkType: hard - -"undici-types@npm:~7.16.0": - version: 7.16.0 - resolution: "undici-types@npm:7.16.0" - checksum: 10c0/3033e2f2b5c9f1504bdc5934646cb54e37ecaca0f9249c983f7b1fc2e87c6d18399ebb05dc7fd5419e02b2e915f734d872a65da2e3eeed1813951c427d33cc9a - languageName: node - linkType: hard - -"unique-filename@npm:^5.0.0": - version: 5.0.0 - resolution: "unique-filename@npm:5.0.0" - dependencies: - unique-slug: "npm:^6.0.0" - checksum: 10c0/afb897e9cf4c2fb622ea716f7c2bb462001928fc5f437972213afdf1cc32101a230c0f1e9d96fc91ee5185eca0f2feb34127145874975f347be52eb91d6ccc2c - languageName: node - linkType: hard - -"unique-slug@npm:^6.0.0": - version: 6.0.0 - resolution: "unique-slug@npm:6.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10c0/da7ade4cb04eb33ad0499861f82fe95ce9c7c878b7139dc54d140ecfb6a6541c18a5c8dac16188b8b379fe62c0c1f1b710814baac910cde5f4fec06212126c6a - languageName: node - linkType: hard - -"unstoppableswap-gui-rs@workspace:.": - version: 0.0.0-use.local - resolution: "unstoppableswap-gui-rs@workspace:." - dependencies: - "@emotion/react": "npm:^11.14.0" - "@emotion/styled": "npm:^11.14.0" - "@eslint/js": "npm:^9.9.0" - "@fontsource/roboto": "npm:^5.1.0" - "@mui/icons-material": "npm:^7.1.1" - "@mui/material": "npm:^7.1.1" - "@mui/x-date-pickers": "npm:^8.8.0" - "@redux-devtools/remote": "npm:^0.9.5" - "@reduxjs/toolkit": "npm:^2.3.0" - "@tauri-apps/api": "npm:^2.8.0" - "@tauri-apps/cli": "npm:^2.0.0" - "@tauri-apps/plugin-cli": "npm:^2.4.0" - "@tauri-apps/plugin-clipboard-manager": "npm:^2.3.0" - "@tauri-apps/plugin-dialog": "npm:^2.0.0" - "@tauri-apps/plugin-opener": "npm:^2.5.0" - "@tauri-apps/plugin-process": "npm:^2.3.0" - "@tauri-apps/plugin-store": "npm:^2.4.0" - "@tauri-apps/plugin-updater": "npm:^2.9.0" - "@testing-library/react": "npm:^16.0.1" - "@testing-library/user-event": "npm:^14.5.2" - "@types/humanize-duration": "npm:^3.27.4" - "@types/lodash": "npm:^4.17.6" - "@types/node": "npm:^22.15.29" - "@types/react": "npm:^19.1.6" - "@types/react-dom": "npm:^19.1.5" - "@types/react-is": "npm:^19.0.0" - "@types/react-redux": "npm:^7.1.34" - "@types/semver": "npm:^7.5.8" - "@vitejs/plugin-react": "npm:^4.2.1" - babel-plugin-react-compiler: "npm:^1.0.0" - dayjs: "npm:^1.11.13" - eslint: "npm:^9.9.0" - eslint-plugin-import: "npm:^2.32.0" - eslint-plugin-react: "npm:^7.35.0" - eslint-plugin-react-hooks: "npm:^7.0.1" - globals: "npm:^15.9.0" - humanize-duration: "npm:^3.32.1" - internal-ip: "npm:^7.0.0" - jdenticon: "npm:^3.3.0" - lodash: "npm:^4.17.21" - multiaddr: "npm:^10.0.1" - notistack: "npm:^3.0.1" - react: "npm:^19.1.0" - react-dom: "npm:^19.1.0" - react-qr-code: "npm:^2.0.15" - react-redux: "npm:^9.2.0" - react-router-dom: "npm:^7.6.1" - redux-persist: "npm:^6.0.0" - semver: "npm:^7.6.2" - typescript: "npm:^5.2.2" - typescript-eslint: "npm:^8.1.0" - virtua: "npm:^0.33.2" - vite: "npm:^5.3.1" - vite-plugin-top-level-await: "npm:^1.4.4" - vite-plugin-watch: "npm:^0.3.1" - vite-tsconfig-paths: "npm:^4.3.2" - vitest: "npm:^2.1.1" - languageName: unknown - linkType: soft - -"update-browserslist-db@npm:^1.1.3": - version: 1.1.3 - resolution: "update-browserslist-db@npm:1.1.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10c0/682e8ecbf9de474a626f6462aa85927936cdd256fe584c6df2508b0df9f7362c44c957e9970df55dfe44d3623807d26316ea2c7d26b80bb76a16c56c37233c32 - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - -"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0": - version: 1.5.0 - resolution: "use-sync-external-store@npm:1.5.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/1b8663515c0be34fa653feb724fdcce3984037c78dd4a18f68b2c8be55cc1a1084c578d5b75f158d41b5ddffc2bf5600766d1af3c19c8e329bb20af2ec6f52f4 - languageName: node - linkType: hard - -"util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - -"uuid@npm:10.0.0": - version: 10.0.0 - resolution: "uuid@npm:10.0.0" - bin: - uuid: dist/bin/uuid - checksum: 10c0/eab18c27fe4ab9fb9709a5d5f40119b45f2ec8314f8d4cf12ce27e4c6f4ffa4a6321dc7db6c515068fa373c075b49691ba969f0010bf37f44c37ca40cd6bf7fe - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 - languageName: node - linkType: hard - -"varint@npm:^6.0.0": - version: 6.0.0 - resolution: "varint@npm:6.0.0" - checksum: 10c0/737fc37088a62ed3bd21466e318d21ca7ac4991d0f25546f518f017703be4ed0f9df1c5559f1dd533dddba4435a1b758fd9230e4772c1a930ef72b42f5c750fd - languageName: node - linkType: hard - -"vinyl-buffer@npm:^1.0.1": - version: 1.0.1 - resolution: "vinyl-buffer@npm:1.0.1" - dependencies: - bl: "npm:^1.2.1" - through2: "npm:^2.0.3" - checksum: 10c0/0dedb6bd3dbdd33ef77feae6535284d9fcd65be4826cb15c3afa91e77a0d384ff5c91a02768a96e6914671db5b65133c69ff44dd25b399494d2628dc71de259b - languageName: node - linkType: hard - -"virtua@npm:^0.33.2": - version: 0.33.7 - resolution: "virtua@npm:0.33.7" - peerDependencies: - react: ">=16.14.0" - react-dom: ">=16.14.0" - solid-js: ">=1.0" - svelte: ">=4.0" - vue: ">=3.2" - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - solid-js: - optional: true - svelte: - optional: true - vue: - optional: true - checksum: 10c0/bc42cd6fc5119c18f5bc83c9c887e40120e4cb4bbf4abf499cc2543ce790b2d23868815975dd472643b07da5804cc5e11919ac0026fc26f540608793aa3eefba - languageName: node - linkType: hard - -"vite-node@npm:2.1.9": - version: 2.1.9 - resolution: "vite-node@npm:2.1.9" - dependencies: - cac: "npm:^6.7.14" - debug: "npm:^4.3.7" - es-module-lexer: "npm:^1.5.4" - pathe: "npm:^1.1.2" - vite: "npm:^5.0.0" - bin: - vite-node: vite-node.mjs - checksum: 10c0/0d3589f9f4e9cff696b5b49681fdb75d1638c75053728be52b4013f70792f38cb0120a9c15e3a4b22bdd6b795ad7c2da13bcaf47242d439f0906049e73bdd756 - languageName: node - linkType: hard - -"vite-plugin-top-level-await@npm:^1.4.4": - version: 1.6.0 - resolution: "vite-plugin-top-level-await@npm:1.6.0" - dependencies: - "@rollup/plugin-virtual": "npm:^3.0.2" - "@swc/core": "npm:^1.12.14" - "@swc/wasm": "npm:^1.12.14" - uuid: "npm:10.0.0" - peerDependencies: - vite: ">=2.8" - checksum: 10c0/499054e67f38ce925b1bae270cc334e1ee42194d00cae084792a5a00c7f246f27f3fd7798e0d4cfe07510f1c7620288bcbcf463570e7650f57977ac0591bf8da - languageName: node - linkType: hard - -"vite-plugin-watch@npm:^0.3.1": - version: 0.3.1 - resolution: "vite-plugin-watch@npm:0.3.1" - dependencies: - minimatch: "npm:^5.1.1" - checksum: 10c0/a14998cb9d678b5e1b92d68af0e40164d7fb413a4b112edfe44f831bda701a46f44e4253d612bd8101933a55364e6448ee3c7899616c57b0b0477812ebbffa4e - languageName: node - linkType: hard - -"vite-tsconfig-paths@npm:^4.3.2": - version: 4.3.2 - resolution: "vite-tsconfig-paths@npm:4.3.2" - dependencies: - debug: "npm:^4.1.1" - globrex: "npm:^0.1.2" - tsconfck: "npm:^3.0.3" - peerDependencies: - vite: "*" - peerDependenciesMeta: - vite: - optional: true - checksum: 10c0/f390ac1d1c3992fc5ac50f9274c1090f8b55ab34a89ea88893db9a6924a3b26c9f64bc1163615150ad100749db73b6b2cf1d57f6cd60df6e762ceb5b8ad30024 - languageName: node - linkType: hard - -"vite@npm:^5.0.0, vite@npm:^5.3.1": - version: 5.4.19 - resolution: "vite@npm:5.4.19" - dependencies: - esbuild: "npm:^0.21.3" - fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.43" - rollup: "npm:^4.20.0" - peerDependencies: - "@types/node": ^18.0.0 || >=20.0.0 - less: "*" - lightningcss: ^1.21.0 - sass: "*" - sass-embedded: "*" - stylus: "*" - sugarss: "*" - terser: ^5.4.0 - dependenciesMeta: - fsevents: - optional: true - peerDependenciesMeta: - "@types/node": - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - bin: - vite: bin/vite.js - checksum: 10c0/c97601234dba482cea5290f2a2ea0fcd65e1fab3df06718ea48adc8ceb14bc3129508216c4989329c618f6a0470b42f439677a207aef62b0c76f445091c2d89e - languageName: node - linkType: hard - -"vitest@npm:^2.1.1": - version: 2.1.9 - resolution: "vitest@npm:2.1.9" - dependencies: - "@vitest/expect": "npm:2.1.9" - "@vitest/mocker": "npm:2.1.9" - "@vitest/pretty-format": "npm:^2.1.9" - "@vitest/runner": "npm:2.1.9" - "@vitest/snapshot": "npm:2.1.9" - "@vitest/spy": "npm:2.1.9" - "@vitest/utils": "npm:2.1.9" - chai: "npm:^5.1.2" - debug: "npm:^4.3.7" - expect-type: "npm:^1.1.0" - magic-string: "npm:^0.30.12" - pathe: "npm:^1.1.2" - std-env: "npm:^3.8.0" - tinybench: "npm:^2.9.0" - tinyexec: "npm:^0.3.1" - tinypool: "npm:^1.0.1" - tinyrainbow: "npm:^1.2.0" - vite: "npm:^5.0.0" - vite-node: "npm:2.1.9" - why-is-node-running: "npm:^2.3.0" - peerDependencies: - "@edge-runtime/vm": "*" - "@types/node": ^18.0.0 || >=20.0.0 - "@vitest/browser": 2.1.9 - "@vitest/ui": 2.1.9 - happy-dom: "*" - jsdom: "*" - peerDependenciesMeta: - "@edge-runtime/vm": - optional: true - "@types/node": - optional: true - "@vitest/browser": - optional: true - "@vitest/ui": - optional: true - happy-dom: - optional: true - jsdom: - optional: true - bin: - vitest: vitest.mjs - checksum: 10c0/e339e16dccacf4589ff43cb1f38c7b4d14427956ae8ef48702af6820a9842347c2b6c77356aeddb040329759ca508a3cb2b104ddf78103ea5bc98ab8f2c3a54e - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": - version: 1.1.1 - resolution: "which-boxed-primitive@npm:1.1.1" - dependencies: - is-bigint: "npm:^1.1.0" - is-boolean-object: "npm:^1.2.1" - is-number-object: "npm:^1.1.1" - is-string: "npm:^1.1.1" - is-symbol: "npm:^1.1.1" - checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe - languageName: node - linkType: hard - -"which-builtin-type@npm:^1.2.1": - version: 1.2.1 - resolution: "which-builtin-type@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - function.prototype.name: "npm:^1.1.6" - has-tostringtag: "npm:^1.0.2" - is-async-function: "npm:^2.0.0" - is-date-object: "npm:^1.1.0" - is-finalizationregistry: "npm:^1.1.0" - is-generator-function: "npm:^1.0.10" - is-regex: "npm:^1.2.1" - is-weakref: "npm:^1.0.2" - isarray: "npm:^2.0.5" - which-boxed-primitive: "npm:^1.1.0" - which-collection: "npm:^1.0.2" - which-typed-array: "npm:^1.1.16" - checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471 - languageName: node - linkType: hard - -"which-collection@npm:^1.0.2": - version: 1.0.2 - resolution: "which-collection@npm:1.0.2" - dependencies: - is-map: "npm:^2.0.3" - is-set: "npm:^2.0.3" - is-weakmap: "npm:^2.0.2" - is-weakset: "npm:^2.0.3" - checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19": - version: 1.1.19 - resolution: "which-typed-array@npm:1.1.19" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - for-each: "npm:^0.3.5" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/702b5dc878addafe6c6300c3d0af5983b175c75fcb4f2a72dfc3dd38d93cf9e89581e4b29c854b16ea37e50a7d7fca5ae42ece5c273d8060dcd603b2404bbb3f - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f - languageName: node - linkType: hard - -"which@npm:^6.0.0": - version: 6.0.0 - resolution: "which@npm:6.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10c0/fe9d6463fe44a76232bb6e3b3181922c87510a5b250a98f1e43a69c99c079b3f42ddeca7e03d3e5f2241bf2d334f5a7657cfa868b97c109f3870625842f4cc15 - languageName: node - linkType: hard - -"why-is-node-running@npm:^2.3.0": - version: 2.3.0 - resolution: "why-is-node-running@npm:2.3.0" - dependencies: - siginfo: "npm:^2.0.0" - stackback: "npm:0.0.2" - bin: - why-is-node-running: cli.js - checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 - languageName: node - linkType: hard - -"word-wrap@npm:^1.2.5": - version: 1.2.5 - resolution: "word-wrap@npm:1.2.5" - checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 - languageName: node - linkType: hard - -"writable-consumable-stream@npm:^4.1.0": - version: 4.2.0 - resolution: "writable-consumable-stream@npm:4.2.0" - dependencies: - consumable-stream: "npm:^3.0.0" - checksum: 10c0/d674d68c52025f988fa18c717e8ea56b3fd10c54fcb04c9716ad1ca45dbaaaf0d027b3b1e6e0e67d495d267ffc6b95ccf37cb62d15daefeec0c942bdae2f616b - languageName: node - linkType: hard - -"ws@npm:^8.18.0": - version: 8.18.3 - resolution: "ws@npm:8.18.3" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 - languageName: node - linkType: hard - -"xtend@npm:~4.0.1": - version: 4.0.2 - resolution: "xtend@npm:4.0.2" - checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a - languageName: node - linkType: hard - -"yallist@npm:^5.0.0": - version: 5.0.0 - resolution: "yallist@npm:5.0.0" - checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 - languageName: node - linkType: hard - -"yaml@npm:^1.10.0": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: 10c0/5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f - languageName: node - linkType: hard - -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f - languageName: node - linkType: hard - -"zod-validation-error@npm:^3.5.0 || ^4.0.0": - version: 4.0.2 - resolution: "zod-validation-error@npm:4.0.2" - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - checksum: 10c0/0ccfec48c46de1be440b719cd02044d4abb89ed0e14c13e637cd55bf29102f67ccdba373f25def0fc7130e5f15025be4d557a7edcc95d5a3811599aade689e1b - languageName: node - linkType: hard - -"zod@npm:^3.25.0 || ^4.0.0": - version: 4.1.13 - resolution: "zod@npm:4.1.13" - checksum: 10c0/d7e74e82dba81a91ffc3239cd85bc034abe193a28f7087a94ab258a3e48e9a7ca4141920cac979a0d781495b48fc547777394149f26be04c3dc642f58bbc3941 - languageName: node - linkType: hard +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f" + integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== + +"@babel/core@^7.24.4", "@babel/core@^7.28.0": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" + integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298" + integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== + dependencies: + "@babel/parser" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.24.4", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08" + integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== + dependencies: + "@babel/types" "^7.28.5" + +"@babel/plugin-transform-react-jsx-self@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92" + integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-source@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0" + integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.26.9", "@babel/runtime@^7.28.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326" + integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== + +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" + integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.5" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.26.0", "@babel/types@^7.27.1", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" + integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@emotion/babel-plugin@^11.13.5": + version "11.13.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0" + integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/serialize" "^1.3.3" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.2.0" + +"@emotion/cache@^11.14.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76" + integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA== + dependencies: + "@emotion/memoize" "^0.9.0" + "@emotion/sheet" "^1.4.0" + "@emotion/utils" "^1.4.2" + "@emotion/weak-memoize" "^0.4.0" + stylis "4.2.0" + +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== + +"@emotion/is-prop-valid@^1.3.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz#e9ad47adff0b5c94c72db3669ce46de33edf28c0" + integrity sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw== + dependencies: + "@emotion/memoize" "^0.9.0" + +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== + +"@emotion/react@^11.14.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d" + integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" + "@emotion/weak-memoize" "^0.4.0" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8" + integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA== + dependencies: + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/unitless" "^0.10.0" + "@emotion/utils" "^1.4.2" + csstype "^3.0.2" + +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== + +"@emotion/styled@^11.14.0": + version "11.14.1" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.14.1.tgz#8c34bed2948e83e1980370305614c20955aacd1c" + integrity sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/is-prop-valid" "^1.3.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" + +"@emotion/unitless@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== + +"@emotion/use-insertion-effect-with-fallbacks@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf" + integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg== + +"@emotion/utils@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52" + integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA== + +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== + dependencies: + "@eslint/object-schema" "^2.1.7" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== + dependencies: + "@eslint/core" "^0.17.0" + +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.1": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz#26393a0806501b5e2b6a43aa588a4d8df67880ac" + integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.1" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.39.2", "@eslint/js@^9.9.0": + version "9.39.2" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.2.tgz#2d4b8ec4c3ea13c1b3748e0c97ecd766bdd80599" + integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== + +"@eslint/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== + +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== + dependencies: + "@eslint/core" "^0.17.0" + levn "^0.4.1" + +"@fontsource/roboto@^5.1.0": + version "5.2.9" + resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-5.2.9.tgz#55092cf992ab8d5082be73b79b42f383a9c0903c" + integrity sha512-ZTkyHiPk74B/aj8BZWbsxD5Yu+Lq+nR64eV4wirlrac2qXR7jYk2h6JlLYuOuoruTkGQWNw2fMuKNavw7/rg0w== + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.7" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.4.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@mui/core-downloads-tracker@^7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz#e7e3a4dc161a377be8224aa988410e89571ab40a" + integrity sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg== + +"@mui/icons-material@^7.1.1": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-7.3.6.tgz#c0092afd04a661603d9751c851e0099a27c1d556" + integrity sha512-0FfkXEj22ysIq5pa41A2NbcAhJSvmcZQ/vcTIbjDsd6hlslG82k5BEBqqS0ZJprxwIL3B45qpJ+bPHwJPlF7uQ== + dependencies: + "@babel/runtime" "^7.28.4" + +"@mui/material@^7.1.1": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.3.6.tgz#6bd4705ca97d80fd5ae1b6b2b7c56ba0cfab0d6a" + integrity sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/core-downloads-tracker" "^7.3.6" + "@mui/system" "^7.3.6" + "@mui/types" "^7.4.9" + "@mui/utils" "^7.3.6" + "@popperjs/core" "^2.11.8" + "@types/react-transition-group" "^4.4.12" + clsx "^2.1.1" + csstype "^3.1.3" + prop-types "^15.8.1" + react-is "^19.2.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-7.3.6.tgz#1ca65a08e8f7f538d9a10ba974f1f4db5231a969" + integrity sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/utils" "^7.3.6" + prop-types "^15.8.1" + +"@mui/styled-engine@^7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.3.6.tgz#dde8e6ae32c9b5b400dcd37afd9514a5344f7d91" + integrity sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ== + dependencies: + "@babel/runtime" "^7.28.4" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/sheet" "^1.4.0" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/system@^7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-7.3.6.tgz#460f82fc6fe1b79b8c04dc97694f6b162ffc3d25" + integrity sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/private-theming" "^7.3.6" + "@mui/styled-engine" "^7.3.6" + "@mui/types" "^7.4.9" + "@mui/utils" "^7.3.6" + clsx "^2.1.1" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/types@^7.4.9": + version "7.4.9" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.4.9.tgz#99accc87920b4c8c4ce33c5076a58f7f81b528fa" + integrity sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw== + dependencies: + "@babel/runtime" "^7.28.4" + +"@mui/utils@^7.3.5", "@mui/utils@^7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-7.3.6.tgz#508fbe864832f99b215d134eb89e1198cdc66b34" + integrity sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/types" "^7.4.9" + "@types/prop-types" "^15.7.15" + clsx "^2.1.1" + prop-types "^15.8.1" + react-is "^19.2.0" + +"@mui/x-date-pickers@^8.8.0": + version "8.23.0" + resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-8.23.0.tgz#fe2940550bde75d7faafea6ab4bdfd3127ba61ae" + integrity sha512-uKtam5wqMEuErmRxZLPEX/7CZZFTMfrl05V9cWNjBkpGTcdDBIs1Kba8z2pfQU93e9lSLrRlxbCMJzCu6iF0Rg== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/utils" "^7.3.5" + "@mui/x-internals" "8.23.0" + "@types/react-transition-group" "^4.4.12" + clsx "^2.1.1" + prop-types "^15.8.1" + react-transition-group "^4.4.5" + +"@mui/x-internals@8.23.0": + version "8.23.0" + resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-8.23.0.tgz#f02c126e68896b2fc23b877a0112d2a7f2d110c6" + integrity sha512-FN7wdqwTxqq1tJBYVz8TA/HMcViuaHS0Jphr4pEjT/8Iuf94Yt3P82WbsTbXyYrgOQDQl07UqE7qWcJetRcHcg== + dependencies: + "@babel/runtime" "^7.28.4" + "@mui/utils" "^7.3.5" + reselect "^5.1.1" + use-sync-external-store "^1.6.0" + +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + +"@redux-devtools/core@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@redux-devtools/core/-/core-4.1.1.tgz#4e0d6fe7d250f10d927872448f0085b6c48cd933" + integrity sha512-ZyyJwiHX4DFDU0llk45tYSFPoIMekdoKLz0Q7soowpNOtchvTxruQx4Xy//Cohkwsw+DH8W1amdo4C/NYT6ARA== + dependencies: + "@babel/runtime" "^7.26.9" + "@redux-devtools/instrument" "^2.2.0" + +"@redux-devtools/instrument@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@redux-devtools/instrument/-/instrument-2.2.0.tgz#bc9d015da693aa9fabdb32f4fd07ee4c1328eb95" + integrity sha512-HKaL+ghBQ4ZQkM/kEQIKx8dNwz4E1oeiCDfdQlpPXxEi/BrisyrFFncAXb1y2HIJsLV9zSvQUR2jRtMDWgfi8w== + dependencies: + "@babel/runtime" "^7.23.2" + lodash "^4.17.21" + +"@redux-devtools/remote@^0.9.5": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@redux-devtools/remote/-/remote-0.9.5.tgz#e0553026ea2d2f132246991c68dad57ac4d034e1" + integrity sha512-ETOUWgB5n6yopU4xH6wSwwmcVQT6liGBJbrWHkJkXCbCq9j/VqXHQ7spNN398p59vDseFZWOPo8KXNI0Mvo1RQ== + dependencies: + "@babel/runtime" "^7.26.9" + "@redux-devtools/instrument" "^2.2.0" + "@redux-devtools/utils" "^3.1.1" + jsan "^3.1.14" + rn-host-detect "^1.2.0" + socketcluster-client "^19.2.3" + +"@redux-devtools/serialize@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@redux-devtools/serialize/-/serialize-0.4.2.tgz#564c0cf2e5cb119a1884b1994a51f6d2e138b9a5" + integrity sha512-YVqZCChJld5l3Ni2psEZ5loe9x5xpf9J4ckz+7OJdzCNsplC7vzjnkQbFxE6+ULZbywRVp+nSBslTXmaXqAw4A== + dependencies: + "@babel/runtime" "^7.23.2" + jsan "^3.1.14" + +"@redux-devtools/utils@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@redux-devtools/utils/-/utils-3.1.1.tgz#a0c0aecf2c2e0f02518d48450dda90b9fe6eeb11" + integrity sha512-l+m3/8a7lcxULInBADIqE/3Tt2DkTJm5MAGVA/4czMCXW0VE+gdjkoRFqgZhTBoDJW1fi1z8pdL+4G/+R1rDJw== + dependencies: + "@babel/runtime" "^7.26.9" + "@redux-devtools/core" "^4.1.1" + "@redux-devtools/serialize" "^0.4.2" + "@types/get-params" "^0.1.2" + get-params "^0.1.2" + immutable "^4.3.7" + jsan "^3.1.14" + nanoid "^5.1.2" + redux "^5.0.1" + +"@reduxjs/toolkit@^2.3.0": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.11.2.tgz#582225acea567329ca6848583e7dd72580d38e82" + integrity sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ== + dependencies: + "@standard-schema/spec" "^1.0.0" + "@standard-schema/utils" "^0.3.0" + immer "^11.0.0" + redux "^5.0.1" + redux-thunk "^3.1.0" + reselect "^5.1.0" + +"@rolldown/pluginutils@1.0.0-beta.27": + version "1.0.0-beta.27" + resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz#47d2bf4cef6d470b22f5831b420f8964e0bf755f" + integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA== + +"@rollup/plugin-virtual@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz#17e17eeecb4c9fa1c0a6e72c9e5f66382fddbb82" + integrity sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A== + +"@rollup/rollup-android-arm-eabi@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz#76e0fef6533b3ce313f969879e61e8f21f0eeb28" + integrity sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg== + +"@rollup/rollup-android-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz#d3cfc675a40bbdec97bda6d7fe3b3b05f0e1cd93" + integrity sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg== + +"@rollup/rollup-darwin-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz#eb912b8f59dd47c77b3c50a78489013b1d6772b4" + integrity sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg== + +"@rollup/rollup-darwin-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz#e7d0839fdfd1276a1d34bc5ebbbd0dfd7d0b81a0" + integrity sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ== + +"@rollup/rollup-freebsd-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz#7ff8118760f7351e48fd0cd3717ff80543d6aac8" + integrity sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg== + +"@rollup/rollup-freebsd-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz#49d330dadbda1d4e9b86b4a3951b59928a9489a9" + integrity sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw== + +"@rollup/rollup-linux-arm-gnueabihf@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz#98c5f1f8b9776b4a36e466e2a1c9ed1ba52ef1b6" + integrity sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ== + +"@rollup/rollup-linux-arm-musleabihf@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz#b9acecd3672e742f70b0c8a94075c816a91ff040" + integrity sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg== + +"@rollup/rollup-linux-arm64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz#7a6ab06651bc29e18b09a50ed1a02bc972977c9b" + integrity sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ== + +"@rollup/rollup-linux-arm64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz#3c8c9072ba4a4d4ef1156b85ab9a2cbb57c1fad0" + integrity sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA== + +"@rollup/rollup-linux-loong64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz#17a7af13530f4e4a7b12cd26276c54307a84a8b0" + integrity sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g== + +"@rollup/rollup-linux-loong64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz#5cd7a900fd7b077ecd753e34a9b7ff1157fe70c1" + integrity sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw== + +"@rollup/rollup-linux-ppc64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz#03a097e70243ddf1c07b59d3c20f38e6f6800539" + integrity sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw== + +"@rollup/rollup-linux-ppc64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz#a5389873039d4650f35b4fa060d286392eb21a94" + integrity sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw== + +"@rollup/rollup-linux-riscv64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz#789e60e7d6e2b76132d001ffb24ba80007fb17d0" + integrity sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw== + +"@rollup/rollup-linux-riscv64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz#3556fa88d139282e9a73c337c9a170f3c5fe7aa4" + integrity sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg== + +"@rollup/rollup-linux-s390x-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz#c085995b10143c16747a67f1a5487512b2ff04b2" + integrity sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg== + +"@rollup/rollup-linux-x64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz#9563a5419dd2604841bad31a39ccfdd2891690fb" + integrity sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg== + +"@rollup/rollup-linux-x64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz#691bb06e6269a8959c13476b0cd2aa7458facb31" + integrity sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w== + +"@rollup/rollup-openbsd-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz#223e71224746a59ce6d955bbc403577bb5a8be9d" + integrity sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg== + +"@rollup/rollup-openharmony-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz#0817e5d8ecbfeb8b7939bf58f8ce3c9dd67fce77" + integrity sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw== + +"@rollup/rollup-win32-arm64-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz#de56d8f2013c84570ef5fb917aae034abda93e4a" + integrity sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g== + +"@rollup/rollup-win32-ia32-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz#659aff5244312475aeea2c9479a6c7d397b517bf" + integrity sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA== + +"@rollup/rollup-win32-x64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz#2cb09549cbb66c1b979f9238db6dd454cac14a88" + integrity sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg== + +"@rollup/rollup-win32-x64-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz#f79437939020b83057faf07e98365b1fa51c458b" + integrity sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@standard-schema/spec@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" + integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== + +"@standard-schema/utils@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@standard-schema/utils/-/utils-0.3.0.tgz#3d5e608f16c2390c10528e98e59aef6bf73cae7b" + integrity sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g== + +"@swc/core-darwin-arm64@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.8.tgz#f565a2744ee840389eba800f1bd454a5ab5c8235" + integrity sha512-M9cK5GwyWWRkRGwwCbREuj6r8jKdES/haCZ3Xckgkl8MUQJZA3XB7IXXK1IXRNeLjg6m7cnoMICpXv1v1hlJOg== + +"@swc/core-darwin-x64@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.8.tgz#52e1bb71fddca37d8c18dcfc33d4117e9de11789" + integrity sha512-j47DasuOvXl80sKJHSi2X25l44CMc3VDhlJwA7oewC1nV1VsSzwX+KOwE5tLnfORvVJJyeiXgJORNYg4jeIjYQ== + +"@swc/core-linux-arm-gnueabihf@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.8.tgz#19586971697767c465bbecaed96940e03a12ac5c" + integrity sha512-siAzDENu2rUbwr9+fayWa26r5A9fol1iORG53HWxQL1J8ym4k7xt9eME0dMPXlYZDytK5r9sW8zEA10F2U3Xwg== + +"@swc/core-linux-arm64-gnu@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.8.tgz#22a55b71cfff34cddd772619aa4ca2bf913032cb" + integrity sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q== + +"@swc/core-linux-arm64-musl@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.8.tgz#ce5a26ff25ab76fb699e7171b90884cfe63c1841" + integrity sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw== + +"@swc/core-linux-x64-gnu@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.8.tgz#cbacd43d4971fe6e4d41b8d8051ea1a8aabf40e5" + integrity sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ== + +"@swc/core-linux-x64-musl@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.8.tgz#6317cf3b75fde62c88faec3750e3aeb9bec83b3d" + integrity sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA== + +"@swc/core-win32-arm64-msvc@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.8.tgz#3a25a4d530e62be5b6b938b7eca70af117b34832" + integrity sha512-djQPJ9Rh9vP8GTS/Df3hcc6XP6xnG5c8qsngWId/BLA9oX6C7UzCPAn74BG/wGb9a6j4w3RINuoaieJB3t+7iQ== + +"@swc/core-win32-ia32-msvc@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.8.tgz#1c7a3ba04216ce3b0a00b4c742e8e3bff9ff8b14" + integrity sha512-/wfAgxORg2VBaUoFdytcVBVCgf1isWZIEXB9MZEUty4wwK93M/PxAkjifOho9RN3WrM3inPLabICRCEgdHpKKQ== + +"@swc/core-win32-x64-msvc@1.15.8": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.8.tgz#5bdcbe3fc0e0ccbae8abc9285a661a1bc3bdd65a" + integrity sha512-GpMePrh9Sl4d61o4KAHOOv5is5+zt6BEXCOCgs/H0FLGeii7j9bWDE8ExvKFy2GRRZVNR1ugsnzaGWHKM6kuzA== + +"@swc/core@^1.12.14": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.8.tgz#818abeab1cc57546a773b11dec4edd8ab26ae687" + integrity sha512-T8keoJjXaSUoVBCIjgL6wAnhADIb09GOELzKg10CjNg+vLX48P93SME6jTfte9MZIm5m+Il57H3rTSk/0kzDUw== + dependencies: + "@swc/counter" "^0.1.3" + "@swc/types" "^0.1.25" + optionalDependencies: + "@swc/core-darwin-arm64" "1.15.8" + "@swc/core-darwin-x64" "1.15.8" + "@swc/core-linux-arm-gnueabihf" "1.15.8" + "@swc/core-linux-arm64-gnu" "1.15.8" + "@swc/core-linux-arm64-musl" "1.15.8" + "@swc/core-linux-x64-gnu" "1.15.8" + "@swc/core-linux-x64-musl" "1.15.8" + "@swc/core-win32-arm64-msvc" "1.15.8" + "@swc/core-win32-ia32-msvc" "1.15.8" + "@swc/core-win32-x64-msvc" "1.15.8" + +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/types@^0.1.25": + version "0.1.25" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078" + integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g== + dependencies: + "@swc/counter" "^0.1.3" + +"@swc/wasm@^1.12.14": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@swc/wasm/-/wasm-1.15.8.tgz#8b8adc4a132db05cecc040901a9e0cb1c5bd661b" + integrity sha512-RG2BxGbbsjtddFCo1ghKH6A/BMXbY1eMBfpysV0lJMCpI4DZOjW1BNBnxvBt7YsYmlJtmy5UXIg9/4ekBTFFaQ== + +"@tauri-apps/api@^2.6.0", "@tauri-apps/api@^2.8.0": + version "2.9.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.9.1.tgz#e539bfa437e53864fd5e7ed0f28e8217fbc74de1" + integrity sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw== + +"@tauri-apps/cli-darwin-arm64@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.9.6.tgz#bb1576a6567db0d331e34d2322dc6aebde6681e8" + integrity sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ== + +"@tauri-apps/cli-darwin-x64@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.9.6.tgz#7beb6ba8218002d7e160764326ce03407e76305d" + integrity sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw== + +"@tauri-apps/cli-linux-arm-gnueabihf@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.9.6.tgz#523ddcd86a99bdda5156bd9de96dfd3e4fa75b7f" + integrity sha512-/zde3bFroFsNXOHN204DC2qUxAcAanUjVXXSdEGmhwMUZeAQalNj5cz2Qli2elsRjKN/hVbZOJj0gQ5zaYUjSg== + +"@tauri-apps/cli-linux-arm64-gnu@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.9.6.tgz#60b4cbd4b8b97c5f5be6cc70fa75455b5a6d6292" + integrity sha512-pvbljdhp9VOo4RnID5ywSxgBs7qiylTPlK56cTk7InR3kYSTJKYMqv/4Q/4rGo/mG8cVppesKIeBMH42fw6wjg== + +"@tauri-apps/cli-linux-arm64-musl@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.9.6.tgz#ce5e5396db6c7f22b80154757479b1486163364a" + integrity sha512-02TKUndpodXBCR0oP//6dZWGYcc22Upf2eP27NvC6z0DIqvkBBFziQUcvi2n6SrwTRL0yGgQjkm9K5NIn8s6jw== + +"@tauri-apps/cli-linux-riscv64-gnu@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.9.6.tgz#aa8ec23d62cbb85a75c3e172637e78f485dbfcf8" + integrity sha512-fmp1hnulbqzl1GkXl4aTX9fV+ubHw2LqlLH1PE3BxZ11EQk+l/TmiEongjnxF0ie4kV8DQfDNJ1KGiIdWe1GvQ== + +"@tauri-apps/cli-linux-x64-gnu@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.9.6.tgz#036c0463c5eee2298ed6ca8cb2838738816c7290" + integrity sha512-vY0le8ad2KaV1PJr+jCd8fUF9VOjwwQP/uBuTJvhvKTloEwxYA/kAjKK9OpIslGA9m/zcnSo74czI6bBrm2sYA== + +"@tauri-apps/cli-linux-x64-musl@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.9.6.tgz#62b05db3d28b0f12c150836a387bd572de44f5be" + integrity sha512-TOEuB8YCFZTWVDzsO2yW0+zGcoMiPPwcUgdnW1ODnmgfwccpnihDRoks+ABT1e3fHb1ol8QQWsHSCovb3o2ENQ== + +"@tauri-apps/cli-win32-arm64-msvc@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.9.6.tgz#01f69ba09a6581e70bdfa206c5801b64b329d28d" + integrity sha512-ujmDGMRc4qRLAnj8nNG26Rlz9klJ0I0jmZs2BPpmNNf0gM/rcVHhqbEkAaHPTBVIrtUdf7bGvQAD2pyIiUrBHQ== + +"@tauri-apps/cli-win32-ia32-msvc@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.9.6.tgz#b36c60db5119d74f126d4c4d8288d1c6ae4b45f0" + integrity sha512-S4pT0yAJgFX8QRCyKA1iKjZ9Q/oPjCZf66A/VlG5Yw54Nnr88J1uBpmenINbXxzyhduWrIXBaUbEY1K80ZbpMg== + +"@tauri-apps/cli-win32-x64-msvc@2.9.6": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.9.6.tgz#d58c9f8af835b7e4fc30e201e979342c70bea426" + integrity sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw== + +"@tauri-apps/cli@^2.0.0": + version "2.9.6" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-2.9.6.tgz#f15ae8e03bf48308055c15ab25b439bed9906bc9" + integrity sha512-3xDdXL5omQ3sPfBfdC8fCtDKcnyV7OqyzQgfyT5P3+zY6lcPqIYKQBvUasNvppi21RSdfhy44ttvJmftb0PCDw== + optionalDependencies: + "@tauri-apps/cli-darwin-arm64" "2.9.6" + "@tauri-apps/cli-darwin-x64" "2.9.6" + "@tauri-apps/cli-linux-arm-gnueabihf" "2.9.6" + "@tauri-apps/cli-linux-arm64-gnu" "2.9.6" + "@tauri-apps/cli-linux-arm64-musl" "2.9.6" + "@tauri-apps/cli-linux-riscv64-gnu" "2.9.6" + "@tauri-apps/cli-linux-x64-gnu" "2.9.6" + "@tauri-apps/cli-linux-x64-musl" "2.9.6" + "@tauri-apps/cli-win32-arm64-msvc" "2.9.6" + "@tauri-apps/cli-win32-ia32-msvc" "2.9.6" + "@tauri-apps/cli-win32-x64-msvc" "2.9.6" + +"@tauri-apps/plugin-cli@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-cli/-/plugin-cli-2.4.1.tgz#5cd8353c6cb7f079ac86c21a0e11305fdd32b041" + integrity sha512-8JXofQFI5cmiGolh1PlU4hzE2YJgrgB1lyaztyBYiiMCy13luVxBXaXChYPeqMkUo46J1UadxvYdjRjj0E8zaw== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-clipboard-manager@^2.3.0": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-clipboard-manager/-/plugin-clipboard-manager-2.3.2.tgz#41def8a008eca94fd5abe2915d26a9c4b6ce54ca" + integrity sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-dialog@^2.0.0": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-dialog/-/plugin-dialog-2.4.2.tgz#59937d28757ce834838ad69530ea36cd439acc4f" + integrity sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-opener@^2.5.0": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-opener/-/plugin-opener-2.5.2.tgz#6e2127d0ad7627a16103215ed596e4fa42bda199" + integrity sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-process@^2.3.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-process/-/plugin-process-2.3.1.tgz#fff77aa7550c9c5347689c859d581f88287bf7ae" + integrity sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-store@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-store/-/plugin-store-2.4.1.tgz#5e2d3362e41861d2fa79a3f1a78c091e12963236" + integrity sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-updater@^2.9.0": + version "2.9.0" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-updater/-/plugin-updater-2.9.0.tgz#ba50b4e644fe19fa6f8465bd86d48119b0d3f41c" + integrity sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg== + dependencies: + "@tauri-apps/api" "^2.6.0" + +"@testing-library/react@^16.0.1": + version "16.3.1" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.3.1.tgz#60a9f1f6a930399d9e41b506a8bf68dbf4831fe8" + integrity sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw== + dependencies: + "@babel/runtime" "^7.12.5" + +"@testing-library/user-event@^14.5.2": + version "14.6.1" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.6.1.tgz#13e09a32d7a8b7060fe38304788ebf4197cd2149" + integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/get-params@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/get-params/-/get-params-0.1.2.tgz#815f80eceb0f0e2f0bb00a2527c9d2e6e57e2a52" + integrity sha512-ujqPyr1UDsOTDngJPV+WFbR0iHT5AfZKlNPMX6XOCnQcMhEqR+r64dVC/nwYCitqjR3DcpWofnOEAInUQmI/eA== + +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.7" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz#306e3a3a73828522efa1341159da4846e7573a6c" + integrity sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g== + dependencies: + hoist-non-react-statics "^3.3.0" + +"@types/humanize-duration@^3.27.4": + version "3.27.4" + resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.4.tgz#51d6d278213374735440bc3749de920935e9127e" + integrity sha512-yaf7kan2Sq0goxpbcwTQ+8E9RP6HutFBPv74T/IA/ojcHKhuKVlk2YFYyHhWZeLvZPzzLE3aatuQB4h0iqyyUA== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/lodash@^4.17.6": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.21.tgz#b806831543d696b14f8112db600ea9d3a1df6ea4" + integrity sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ== + +"@types/node@*": + version "25.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.0.3.tgz#79b9ac8318f373fbfaaf6e2784893efa9701f269" + integrity sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA== + dependencies: + undici-types "~7.16.0" + +"@types/node@^22.15.29": + version "22.19.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.3.tgz#8dfde7630d7a8528dc9b34db23d34f764467c02c" + integrity sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA== + dependencies: + undici-types "~6.21.0" + +"@types/parse-json@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== + +"@types/prop-types@^15.7.15": + version "15.7.15" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" + integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== + +"@types/react-dom@^19.1.5": + version "19.2.3" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c" + integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== + +"@types/react-is@^19.0.0": + version "19.2.0" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-19.2.0.tgz#b72a01627e4820f2333abdc9945c3daac48245e7" + integrity sha512-NP2xtcjZfORsOa4g2JwdseyEnF+wUCx25fTdG/J/HIY6yKga6+NozRBg2xR2gyh7kKYyd6DXndbq0YbQuTJ7Ew== + dependencies: + "@types/react" "*" + +"@types/react-redux@^7.1.34": + version "7.1.34" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.34.tgz#83613e1957c481521e6776beeac4fd506d11bd0e" + integrity sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + +"@types/react-transition-group@^4.4.12": + version "4.4.12" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" + integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== + +"@types/react@*", "@types/react@^19.1.6": + version "19.2.7" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.7.tgz#84e62c0f23e8e4e5ac2cadcea1ffeacccae7f62f" + integrity sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg== + dependencies: + csstype "^3.2.2" + +"@types/semver@^7.5.8": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.7.1.tgz#3ce3af1a5524ef327d2da9e4fd8b6d95c8d70528" + integrity sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA== + +"@types/use-sync-external-store@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc" + integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== + +"@typescript-eslint/eslint-plugin@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.52.0.tgz#9a9f1d2ee974ed77a8b1bda94e77123f697ee8b4" + integrity sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/type-utils" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.4.0" + +"@typescript-eslint/parser@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.52.0.tgz#9fae9f5f13ebb1c8f31a50c34381bfd6bf96a05f" + integrity sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg== + dependencies: + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.52.0.tgz#5fb4c16af4eda6d74c70cbc62f5d3f77b96e4cbe" + integrity sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.52.0" + "@typescript-eslint/types" "^8.52.0" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.52.0.tgz#9884ff690fad30380ccabfb08af1ac200af6b4e5" + integrity sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA== + dependencies: + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + +"@typescript-eslint/tsconfig-utils@8.52.0", "@typescript-eslint/tsconfig-utils@^8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.52.0.tgz#0296751c22ed05c83787a6eaec65ae221bd8b8ed" + integrity sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg== + +"@typescript-eslint/type-utils@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.52.0.tgz#6e554113f8a074cf9b2faa818d2ebfccb867d6c5" + integrity sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ== + dependencies: + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + debug "^4.4.3" + ts-api-utils "^2.4.0" + +"@typescript-eslint/types@8.52.0", "@typescript-eslint/types@^8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.52.0.tgz#1eb0a16b324824bc23b89d109a267c38c9213c4a" + integrity sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg== + +"@typescript-eslint/typescript-estree@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.52.0.tgz#2ad7721c671be2127951286cb7f44c4ce55b0591" + integrity sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ== + dependencies: + "@typescript-eslint/project-service" "8.52.0" + "@typescript-eslint/tsconfig-utils" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/visitor-keys" "8.52.0" + debug "^4.4.3" + minimatch "^9.0.5" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.4.0" + +"@typescript-eslint/utils@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.52.0.tgz#b249be8264899b80d996fa353b4b84da4662f962" + integrity sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.52.0" + "@typescript-eslint/types" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + +"@typescript-eslint/visitor-keys@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.52.0.tgz#50361c48a6302676230fe498f80f6decce4bf673" + integrity sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ== + dependencies: + "@typescript-eslint/types" "8.52.0" + eslint-visitor-keys "^4.2.1" + +"@vitejs/plugin-react@^4.2.1": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz#647af4e7bb75ad3add578e762ad984b90f4a24b9" + integrity sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA== + dependencies: + "@babel/core" "^7.28.0" + "@babel/plugin-transform-react-jsx-self" "^7.27.1" + "@babel/plugin-transform-react-jsx-source" "^7.27.1" + "@rolldown/pluginutils" "1.0.0-beta.27" + "@types/babel__core" "^7.20.5" + react-refresh "^0.17.0" + +"@vitest/expect@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.9.tgz#b566ea20d58ea6578d8dc37040d6c1a47ebe5ff8" + integrity sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw== + dependencies: + "@vitest/spy" "2.1.9" + "@vitest/utils" "2.1.9" + chai "^5.1.2" + tinyrainbow "^1.2.0" + +"@vitest/mocker@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.9.tgz#36243b27351ca8f4d0bbc4ef91594ffd2dc25ef5" + integrity sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg== + dependencies: + "@vitest/spy" "2.1.9" + estree-walker "^3.0.3" + magic-string "^0.30.12" + +"@vitest/pretty-format@2.1.9", "@vitest/pretty-format@^2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.9.tgz#434ff2f7611689f9ce70cd7d567eceb883653fdf" + integrity sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ== + dependencies: + tinyrainbow "^1.2.0" + +"@vitest/runner@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.9.tgz#cc18148d2d797fd1fd5908d1f1851d01459be2f6" + integrity sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g== + dependencies: + "@vitest/utils" "2.1.9" + pathe "^1.1.2" + +"@vitest/snapshot@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.9.tgz#24260b93f798afb102e2dcbd7e61c6dfa118df91" + integrity sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ== + dependencies: + "@vitest/pretty-format" "2.1.9" + magic-string "^0.30.12" + pathe "^1.1.2" + +"@vitest/spy@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.9.tgz#cb28538c5039d09818b8bfa8edb4043c94727c60" + integrity sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ== + dependencies: + tinyspy "^3.0.2" + +"@vitest/utils@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.9.tgz#4f2486de8a54acf7ecbf2c5c24ad7994a680a6c1" + integrity sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ== + dependencies: + "@vitest/pretty-format" "2.1.9" + loupe "^3.1.2" + tinyrainbow "^1.2.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ag-auth@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ag-auth/-/ag-auth-2.1.1.tgz#4a48ba6a34cf71f4cb75863da5e8bb367f07e0f7" + integrity sha512-7XkzbCoW/jWpI/1wdmCCr1LXk4ucywXoORG68OzPQl/Y8/sWTMiGIU/stfnUh07kVkihn4dKelz3HJ2T6niPng== + dependencies: + jsonwebtoken "^9.0.2" + sc-errors "^3.0.0" + +ag-channel@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ag-channel/-/ag-channel-5.0.0.tgz#c2c00dfbe372ae43e0466ec89e29aca1bbb2fb3e" + integrity sha512-bArHkdqQxynim981t8FLZM5TfA0v7p081OlFdOxs6clB79GSGcGlOQMDa31DT9F5VMjzqNiJmhfGwinvfU/3Zg== + dependencies: + consumable-stream "^2.0.0" + +ag-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ag-request/-/ag-request-1.1.0.tgz#62ef63c572510bbce34993a5d47e467d0040a17f" + integrity sha512-d4K7QC1KnIpzcnUNNOeh1ddxmYMLiIdhdc1M8osxiHbZP/uoia4IINhhf2+1CrlnNJEPUoUH0Y58Sx0qeqoIvg== + dependencies: + sc-errors "^3.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + +array-includes@^3.1.6, array-includes@^3.1.8, array-includes@^3.1.9: + version "3.1.9" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.0" + es-object-atoms "^1.1.1" + get-intrinsic "^1.3.0" + is-string "^1.1.1" + math-intrinsics "^1.1.0" + +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + +async-stream-emitter@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/async-stream-emitter/-/async-stream-emitter-7.0.1.tgz#c01832cddcc8f07d8ed528347803ec1517f8886d" + integrity sha512-1bgA3iZ80rCBX2LocvsyZPy0QB3/xM+CsXBze2HDHLmshOqx2JlAANGq23djaJ48e9fpcKzTzS1QM0hAKKI0UQ== + dependencies: + stream-demux "^10.0.1" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +babel-plugin-react-compiler@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz#bdf7360a23a4d5ebfca090255da3893efd07425f" + integrity sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw== + dependencies: + "@babel/types" "^7.26.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +baseline-browser-mapping@^2.9.0: + version "2.9.11" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz#53724708c8db5f97206517ecfe362dbe5181deea" + integrity sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ== + +bl@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +buffer-equal-constant-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer@^5.2.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001759: + version "1.0.30001762" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz#e4dbfeda63d33258cdde93e53af2023a13ba27d4" + integrity sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw== + +canvas-renderer@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/canvas-renderer/-/canvas-renderer-2.2.1.tgz#c1d131f78a9799aca8af9679ad0a005052b65550" + integrity sha512-RrBgVL5qCEDIXpJ6NrzyRNoTnXxYarqm/cS/W6ERhUJts5UQtt/XPEosGN3rqUkZ4fjBArlnCbsISJ+KCFnIAg== + dependencies: + "@types/node" "*" + +chai@^5.1.2: + version "5.3.3" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clsx@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +consumable-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/consumable-stream/-/consumable-stream-2.0.0.tgz#11d3c7281b747eb9efd31c199b3a8b1711bec654" + integrity sha512-I6WA2JVYXs/68rEvi1ie3rZjP6qusTVFEQkbzR+WC+fY56TpwiGTIDJETsrnlxv5CsnmK69ps6CkYvIbpEEqBA== + +consumable-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/consumable-stream/-/consumable-stream-3.0.0.tgz#2bf140e0c5f9b63d6fa116ac6b05e53713d3cb41" + integrity sha512-CnnsJ9OG9ouxAjt3pc63/DaerezRo/WudqU71pc5epaIUi7NHu2T4v+3f0nKbbCY7icS/TfQ1Satr9rwZ7Jwsg== + +convert-source-map@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.1.1.tgz#3bb9bdfc82369db9c2f69c93c9c3ceb310c88b3c" + integrity sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +csstype@^3.0.2, csstype@^3.1.3, csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +dayjs@^1.11.13: + version "1.11.19" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" + integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.7, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +dns-over-http-resolver@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz#194d5e140a42153f55bb79ac5a64dd2768c36af9" + integrity sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA== + dependencies: + debug "^4.3.1" + native-fetch "^3.0.0" + receptacle "^1.3.2" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== + +err-code@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" + integrity sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA== + +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1: + version "1.24.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899" + integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-iterator-helpers@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz#d979a9f686e2b0b72f88dbead7229924544720bc" + integrity sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.1" + es-errors "^1.3.0" + es-set-tostringtag "^2.1.0" + function-bind "^1.1.2" + get-intrinsic "^1.3.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.5" + safe-array-concat "^1.1.3" + +es-module-lexer@^1.5.4: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== + dependencies: + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz#f76d3220bfb83c057651359295ab5854eaad75ff" + integrity sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.32.0: + version "2.32.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980" + integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.9" + array.prototype.findlastindex "^1.2.6" + array.prototype.flat "^1.3.3" + array.prototype.flatmap "^1.3.3" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.1" + hasown "^2.0.2" + is-core-module "^2.16.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.1" + semver "^6.3.1" + string.prototype.trimend "^1.0.9" + tsconfig-paths "^3.15.0" + +eslint-plugin-react-hooks@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz#66e258db58ece50723ef20cc159f8aa908219169" + integrity sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA== + dependencies: + "@babel/core" "^7.24.4" + "@babel/parser" "^7.24.4" + hermes-parser "^0.25.1" + zod "^3.25.0 || ^4.0.0" + zod-validation-error "^3.5.0 || ^4.0.0" + +eslint-plugin-react@^7.35.0: + version "7.37.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.3" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.2.1" + estraverse "^5.3.0" + hasown "^2.0.2" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.9" + object.fromentries "^2.0.8" + object.values "^1.2.1" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.12" + string.prototype.repeat "^1.0.0" + +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9.9.0: + version "9.39.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.2.tgz#cb60e6d16ab234c0f8369a3fe7cc87967faf4b6c" + integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.1" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.39.2" + "@eslint/plugin-kit" "^0.4.1" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + +esquery@^1.5.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +expect-type@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +generator-function@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/generator-function/-/generator-function-2.0.1.tgz#0e75dd410d1243687a0ba2e951b94eedb8f737a2" + integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-params@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/get-params/-/get-params-0.1.2.tgz#bae0dfaba588a0c60d7834c0d8dc2ff60eeef2fe" + integrity sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q== + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.9.0: + version "15.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globrex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" + integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== + +goober@^2.0.33: + version "2.1.18" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.18.tgz#b72d669bd24d552d441638eee26dfd5716ea6442" + integrity sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw== + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== + +hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== + dependencies: + hermes-estree "0.25.1" + +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +humanize-duration@^3.32.1: + version "3.33.2" + resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.33.2.tgz#2e41986eabb00cb5ad0eef616a78233099dbdac4" + integrity sha512-K7Ny/ULO1hDm2nnhvAY+SJV1skxFb61fd073SG1IWJl+D44ULrruCuTyjHKjBVVcSuTlnY99DKtgEG39CM5QOQ== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +immer@^11.0.0: + version "11.1.3" + resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.3.tgz#78681e1deb6cec39753acf04eb16d7576c04f4d6" + integrity sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q== + +immutable@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381" + integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-ip@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-7.0.0.tgz#5b1c6a9d7e188aa73a1b69717daf50c8d8ed774f" + integrity sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw== + dependencies: + default-gateway "^6.0.3" + ipaddr.js "^2.0.1" + is-ip "^3.1.0" + p-event "^4.2.0" + +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + +ip-regex@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== + +ipaddr.js@^2.0.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.3.0.tgz#71dce70e1398122208996d1c22f2ba46a24b1abc" + integrity sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg== + +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + +is-generator-function@^1.0.10: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.2.tgz#ae3b61e3d5ea4e4839b90bad22b02335051a17d5" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-ip@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" + integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== + dependencies: + ip-regex "^4.0.0" + +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +iterator.prototype@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== + dependencies: + define-data-property "^1.1.4" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + get-proto "^1.0.0" + has-symbols "^1.1.0" + set-function-name "^2.0.2" + +jdenticon@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/jdenticon/-/jdenticon-3.3.0.tgz#64bae9f9b3cf5c2a210e183648117afe3a89b367" + integrity sha512-DhuBRNRIybGPeAjMjdHbkIfiwZCCmf8ggu7C49jhp6aJ7DYsZfudnvnTY5/1vgUhrGA7JaDAx1WevnpjCPvaGg== + dependencies: + canvas-renderer "~2.2.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + +jsan@^3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/jsan/-/jsan-3.1.14.tgz#197fee2d260b85acacb049c1ffa41bd09fb1f213" + integrity sha512-wStfgOJqMv4QKktuH273f5fyi3D3vy2pHOiSDGPvpcS/q+wb/M7AK3vkCcaHbkZxDOlDU/lDJgccygKSG2OhtA== + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonwebtoken@^9.0.2: + version "9.0.3" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz#6cd57ab01e9b0ac07cb847d53d3c9b6ee31f7ae2" + integrity sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g== + dependencies: + jws "^4.0.1" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +jwa@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.1.tgz#bf8176d1ad0cd72e0f3f58338595a13e110bc804" + integrity sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg== + dependencies: + buffer-equal-constant-time "^1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.1.tgz#07edc1be8fac20e677b283ece261498bd38f0690" + integrity sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA== + dependencies: + jwa "^2.0.1" + safe-buffer "^5.0.1" + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +linked-list@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/linked-list/-/linked-list-2.1.0.tgz#fa7b63a6caf4b17862a1eb90d14ead4ee57649f2" + integrity sha512-0GK/ylO6e5cv1PCOIdTRHxOaCgQ+0jKwHt+cHzkiCAZlx0KM5Id1bBAPad6g2mkvBNp1pNdmG0cohFGfqjkv9A== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loupe@^3.1.0, loupe@^3.1.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.30.12: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multiaddr@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-10.0.1.tgz#0d15848871370860a4d266bb44d93b3dac5d90ef" + integrity sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg== + dependencies: + dns-over-http-resolver "^1.2.3" + err-code "^3.0.1" + is-ip "^3.1.0" + multiformats "^9.4.5" + uint8arrays "^3.0.0" + varint "^6.0.0" + +multiformats@^9.4.2, multiformats@^9.4.5: + version "9.9.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" + integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +nanoid@^5.1.2: + version "5.1.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.1.6.tgz#30363f664797e7d40429f6c16946d6bd7a3f26c9" + integrity sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg== + +native-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-3.0.0.tgz#06ccdd70e79e171c365c75117959cf4fe14a09bb" + integrity sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + +notistack@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/notistack/-/notistack-3.0.2.tgz#009799c3fccddeffac58565ba1657d27616dfabd" + integrity sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA== + dependencies: + clsx "^1.1.0" + goober "^2.0.33" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-object-atoms "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.1.6, object.values@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + +p-event@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" + integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== + dependencies: + p-timeout "^3.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-timeout@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss@^8.4.43: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +prop-types@^15.6.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ== + +react-dom@^19.1.0: + version "19.2.3" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.3.tgz#f0b61d7e5c4a86773889fcc1853af3ed5f215b17" + integrity sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg== + dependencies: + scheduler "^0.27.0" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^19.2.0: + version "19.2.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.3.tgz#eec2feb69c7fb31f77d0b5c08c10ae1c88886b29" + integrity sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA== + +react-qr-code@^2.0.15: + version "2.0.18" + resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.0.18.tgz#237de8fbab537885d6b2b10f4fd5318b371e3b17" + integrity sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg== + dependencies: + prop-types "^15.8.1" + qr.js "0.0.0" + +react-redux@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5" + integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== + dependencies: + "@types/use-sync-external-store" "^0.0.6" + use-sync-external-store "^1.4.0" + +react-refresh@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53" + integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== + +react-router-dom@^7.6.1: + version "7.11.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.11.0.tgz#2165f63e52798bd0eb138480c098ad058cdf3413" + integrity sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g== + dependencies: + react-router "7.11.0" + +react-router@7.11.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.11.0.tgz#d3b91567fdbe910caf9064ea69b7b4d9264f2945" + integrity sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ== + dependencies: + cookie "^1.0.1" + set-cookie-parser "^2.6.0" + +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^19.1.0: + version "19.2.3" + resolved "https://registry.yarnpkg.com/react/-/react-19.2.3.tgz#d83e5e8e7a258cf6b4fe28640515f99b87cd19b8" + integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA== + +readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +receptacle@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/receptacle/-/receptacle-1.3.2.tgz#a7994c7efafc7a01d0e2041839dab6c4951360d2" + integrity sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A== + dependencies: + ms "^2.1.1" + +redux-persist@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8" + integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ== + +redux-thunk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" + integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== + +redux@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + +redux@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== + +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + +reselect@^5.1.0, reselect@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e" + integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.19.0, resolve@^1.22.4: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rn-host-detect@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0" + integrity sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A== + +rollup@^4.20.0: + version "4.55.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.55.1.tgz#4ec182828be440648e7ee6520dc35e9f20e05144" + integrity sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.55.1" + "@rollup/rollup-android-arm64" "4.55.1" + "@rollup/rollup-darwin-arm64" "4.55.1" + "@rollup/rollup-darwin-x64" "4.55.1" + "@rollup/rollup-freebsd-arm64" "4.55.1" + "@rollup/rollup-freebsd-x64" "4.55.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.55.1" + "@rollup/rollup-linux-arm-musleabihf" "4.55.1" + "@rollup/rollup-linux-arm64-gnu" "4.55.1" + "@rollup/rollup-linux-arm64-musl" "4.55.1" + "@rollup/rollup-linux-loong64-gnu" "4.55.1" + "@rollup/rollup-linux-loong64-musl" "4.55.1" + "@rollup/rollup-linux-ppc64-gnu" "4.55.1" + "@rollup/rollup-linux-ppc64-musl" "4.55.1" + "@rollup/rollup-linux-riscv64-gnu" "4.55.1" + "@rollup/rollup-linux-riscv64-musl" "4.55.1" + "@rollup/rollup-linux-s390x-gnu" "4.55.1" + "@rollup/rollup-linux-x64-gnu" "4.55.1" + "@rollup/rollup-linux-x64-musl" "4.55.1" + "@rollup/rollup-openbsd-x64" "4.55.1" + "@rollup/rollup-openharmony-arm64" "4.55.1" + "@rollup/rollup-win32-arm64-msvc" "4.55.1" + "@rollup/rollup-win32-ia32-msvc" "4.55.1" + "@rollup/rollup-win32-x64-gnu" "4.55.1" + "@rollup/rollup-win32-x64-msvc" "4.55.1" + fsevents "~2.3.2" + +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +sc-errors@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sc-errors/-/sc-errors-3.0.0.tgz#df2e124f011be5fdd633e92d1de5ce6a6b4c1b85" + integrity sha512-rIqv2HTPb9DVreZwK/DV0ytRUqyw2DbDcoB9XTKjEQL7oMEQKsfPA8V8dGGr7p8ZYfmvaRIGZ4Wu5qwvs/hGDA== + +sc-formatter@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/sc-formatter/-/sc-formatter-4.0.0.tgz#2dda494a08e9d4cb069cbc9238a9f670adb3e7a6" + integrity sha512-MgUIvuca+90fBrCWY5LdlU9YUWjlkPFwdpvmomcwQEu3t2id/6YHdG2nhB6o7nhRp4ocfmcXQTh00r/tJtynSg== + +scheduler@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd" + integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.2, semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +set-cookie-parser@^2.6.0: + version "2.7.2" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz#ccd08673a9ae5d2e44ea2a2de25089e67c7edf68" + integrity sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw== + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +socketcluster-client@^19.2.3: + version "19.2.7" + resolved "https://registry.yarnpkg.com/socketcluster-client/-/socketcluster-client-19.2.7.tgz#70d96a491323cc044d1171efabc3aa05023d959a" + integrity sha512-c6caNOr/49FUjlVnQfXb0TasMnrqY1uN/uevT99xicF+7NkvGSNwjP6rlMP0v1ZZjz+MosT2/qJNDDc2b3v/Jw== + dependencies: + ag-auth "^2.1.0" + ag-channel "^5.0.0" + ag-request "^1.1.0" + async-stream-emitter "^7.0.1" + buffer "^5.2.1" + clone-deep "^4.0.1" + linked-list "^2.1.0" + sc-errors "^3.0.0" + sc-formatter "^4.0.0" + stream-demux "^10.0.1" + uuid "^8.3.2" + vinyl-buffer "^1.0.1" + ws "^8.18.0" + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.8.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + +stream-demux@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/stream-demux/-/stream-demux-10.0.1.tgz#204b65fb8973c87cea65119e99622405b3dbcc10" + integrity sha512-QjTYLJWpZxZ6uL5R1JzgOzjvao8zDx78ec+uOjHNeVc/9TuasYLldoVrYARZeT1xI1hFYuiKf13IM8b4wamhHg== + dependencies: + consumable-stream "^3.0.0" + writable-consumable-stream "^4.1.0" + +string.prototype.matchall@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + regexp.prototype.flags "^1.5.3" + set-function-name "^2.0.2" + side-channel "^1.1.0" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tinypool@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== + +tinyrainbow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" + integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== + +tinyspy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== + +ts-api-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== + +tsconfck@^3.0.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-3.1.6.tgz#da1f0b10d82237ac23422374b3fce1edb23c3ead" + integrity sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w== + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + +typescript-eslint@^8.1.0: + version "8.52.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.52.0.tgz#b8c156b6f2b4dee202a85712ff6a37f614476413" + integrity sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.52.0" + "@typescript-eslint/parser" "8.52.0" + "@typescript-eslint/typescript-estree" "8.52.0" + "@typescript-eslint/utils" "8.52.0" + +typescript@^5.2.2: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +uint8arrays@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" + integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== + dependencies: + multiformats "^9.4.2" + +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +use-sync-external-store@^1.4.0, use-sync-external-store@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" + integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +varint@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" + integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== + +vinyl-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz#96c1a3479b8c5392542c612029013b5b27f88bbf" + integrity sha512-LRBE2/g3C1hSHL2k/FynSZcVTRhEw8sb08oKGt/0hukZXwrh2m8nfy+r5yLhGEk7eFFuclhyIuPct/Bxlxk6rg== + dependencies: + bl "^1.2.1" + through2 "^2.0.3" + +virtua@^0.33.2: + version "0.33.7" + resolved "https://registry.yarnpkg.com/virtua/-/virtua-0.33.7.tgz#bd46d7d31f257886e6245347354fb4e80e27441f" + integrity sha512-IepZaMD/oeEh/ymTqokeQGLrMuRV25+lizPegxVIhOwqX+dEeV9ml1P57Eosok4qiZaeBeQIbIkF9QZrT+EeRQ== + +vite-node@2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.9.tgz#549710f76a643f1c39ef34bdb5493a944e4f895f" + integrity sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA== + dependencies: + cac "^6.7.14" + debug "^4.3.7" + es-module-lexer "^1.5.4" + pathe "^1.1.2" + vite "^5.0.0" + +vite-plugin-top-level-await@^1.4.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.6.0.tgz#c6ed0be438a1c14f48b4f9a56da859c12821a7c2" + integrity sha512-bNhUreLamTIkoulCR9aDXbTbhLk6n1YE8NJUTTxl5RYskNRtzOR0ASzSjBVRtNdjIfngDXo11qOsybGLNsrdww== + dependencies: + "@rollup/plugin-virtual" "^3.0.2" + "@swc/core" "^1.12.14" + "@swc/wasm" "^1.12.14" + uuid "10.0.0" + +vite-plugin-watch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/vite-plugin-watch/-/vite-plugin-watch-0.3.1.tgz#5000f7ded6eb1c42e9483d6ea3d812061ab8188f" + integrity sha512-tmLJ5tqSqXY7wSXoM8+huOgbictUG6SKLh/tZ6LAY51KPSAnPBr0dYwyxPPPQm+JgIIBbKSyNnPHpW11ad+qlw== + dependencies: + minimatch "^5.1.1" + +vite-tsconfig-paths@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz#321f02e4b736a90ff62f9086467faf4e2da857a9" + integrity sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA== + dependencies: + debug "^4.1.1" + globrex "^0.1.2" + tsconfck "^3.0.3" + +vite@^5.0.0, vite@^5.3.1: + version "5.4.21" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.21.tgz#84a4f7c5d860b071676d39ba513c0d598fdc7027" + integrity sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^2.1.1: + version "2.1.9" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.9.tgz#7d01ffd07a553a51c87170b5e80fea3da7fb41e7" + integrity sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q== + dependencies: + "@vitest/expect" "2.1.9" + "@vitest/mocker" "2.1.9" + "@vitest/pretty-format" "^2.1.9" + "@vitest/runner" "2.1.9" + "@vitest/snapshot" "2.1.9" + "@vitest/spy" "2.1.9" + "@vitest/utils" "2.1.9" + chai "^5.1.2" + debug "^4.3.7" + expect-type "^1.1.0" + magic-string "^0.30.12" + pathe "^1.1.2" + std-env "^3.8.0" + tinybench "^2.9.0" + tinyexec "^0.3.1" + tinypool "^1.0.1" + tinyrainbow "^1.2.0" + vite "^5.0.0" + vite-node "2.1.9" + why-is-node-running "^2.3.0" + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +writable-consumable-stream@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/writable-consumable-stream/-/writable-consumable-stream-4.2.0.tgz#731cb8bc7c16d5e120adfaddd7d41c52179934d7" + integrity sha512-A2g0/Xaq/I2DQlYofh7nvKaJYZ0v4UOKuNLePG/G1ylx7p8e904jMTKhS+cdHNO1OulZpP2ModXs37EkG6tqSQ== + dependencies: + consumable-stream "^3.0.0" + +ws@^8.18.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== + +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +"zod-validation-error@^3.5.0 || ^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== + +"zod@^3.25.0 || ^4.0.0": + version "4.3.5" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.5.tgz#aeb269a6f9fc259b1212c348c7c5432aaa474d2a" + integrity sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g== diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index da818a71e1..9aa3fc2896 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -1090,16 +1090,20 @@ pub enum TauriSwapProgressEvent { BtcPartialRefundPublished { #[typeshare(serialized_as = "string")] btc_partial_refund_txid: Txid, - /// Whether we have Alice's signature on the amnesty transaction - /// such that we will be able to refund the rest of the locked Bitcoin - /// after the partial refund went through. - has_amnesty_signature: bool, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // BtcAmnesty was published but not yet confirmed. // Requires BtcPartialRefund to be published first. BtcAmnestyPublished { #[typeshare(serialized_as = "string")] btc_amnesty_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // tx_early_refund has been confirmed BtcEarlyRefunded { @@ -1115,35 +1119,55 @@ pub enum TauriSwapProgressEvent { BtcPartiallyRefunded { #[typeshare(serialized_as = "string")] btc_partial_refund_txid: Txid, - /// Whether we have Alice's signature on the amnesty transaction - /// such that we will be able to refund the rest of the locked Bitcoin - /// after the partial refund went through. - has_amnesty_signature: bool, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, - // BtcAmnesty was published but not yet confirmed. + // BtcAmnesty was confirmed. BtcAmnestyReceived { #[typeshare(serialized_as = "string")] btc_amnesty_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // TxRefundBurn has been published (waiting for confirmation) BtcRefundBurnPublished { #[typeshare(serialized_as = "string")] btc_refund_burn_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // TxRefundBurn has been confirmed - amnesty output is burnt BtcRefundBurnt { #[typeshare(serialized_as = "string")] btc_refund_burn_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // Alice published TxFinalAmnesty BtcFinalAmnestyPublished { #[typeshare(serialized_as = "string")] btc_final_amnesty_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, // TxFinalAmnesty has been confirmed - user received burnt funds back BtcFinalAmnestyConfirmed { #[typeshare(serialized_as = "string")] btc_final_amnesty_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, }, BtcPunished, AttemptingCooperativeRedeem, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index d81506db77..cba59669c3 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1027,7 +1027,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcPartialRefundPublished { btc_partial_refund_txid: state.construct_tx_partial_refund()?.txid(), - has_amnesty_signature: state.refund_signatures.tx_refund_amnesty_sig().is_some(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); @@ -1054,13 +1055,12 @@ async fn next_state( } } BobState::BtcPartiallyRefunded(state) => { - let has_amnesty_signature = state.refund_signatures.tx_refund_amnesty_sig().is_some(); - event_emitter.emit_swap_progress_event( swap_id, TauriSwapProgressEvent::BtcPartiallyRefunded { btc_partial_refund_txid: state.construct_tx_partial_refund()?.txid(), - has_amnesty_signature, + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); @@ -1086,9 +1086,11 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcAmnestyPublished { btc_amnesty_txid: tx_amnesty.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); - + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_amnesty.clone())).await; retry("Waiting for Bitcoin amnesty transaction to be published by Alice", || async { @@ -1102,6 +1104,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcAmnestyReceived { btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); @@ -1251,6 +1255,8 @@ async fn next_state( BobState::BtcAmnestyConfirmed(state) => { event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcAmnestyReceived { btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }); BobState::BtcAmnestyConfirmed(state) }, @@ -1311,6 +1317,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcRefundBurnPublished { btc_refund_burn_txid: tx_refund_burn.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; @@ -1330,6 +1338,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcRefundBurnt { btc_refund_burn_txid: tx_refund_burn.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); @@ -1350,6 +1360,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcFinalAmnestyPublished { btc_final_amnesty_txid: tx_final_amnesty.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_final_amnesty)).await; @@ -1365,6 +1377,8 @@ async fn next_state( swap_id, TauriSwapProgressEvent::BtcFinalAmnestyConfirmed { btc_final_amnesty_txid: tx_final_amnesty.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); BobState::BtcFinalAmnestyConfirmed(state) From 2bf3d518177d0713d2f8c149a11f4f4a4d5f13cf Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 12 Jan 2026 15:32:09 +0100 Subject: [PATCH 086/146] add RefundPolicyWire (same as RefundPolicy for now) to quote, bump protocol version --- swap-p2p/Cargo.toml | 1 + swap-p2p/src/protocols/quote.rs | 36 ++++++++++++++++++++++++++++++++- swap/src/asb/event_loop.rs | 19 ++++++++++++++--- swap/src/bin/swap.rs | 3 ++- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/swap-p2p/Cargo.toml b/swap-p2p/Cargo.toml index a4ea31de93..b5514859c1 100644 --- a/swap-p2p/Cargo.toml +++ b/swap-p2p/Cargo.toml @@ -27,6 +27,7 @@ unsigned-varint = { version = "0.8.0", features = ["codec", "asynchronous_codec" bitcoin = { workspace = true } monero = { workspace = true } rand = { workspace = true } +rust_decimal = { workspace = true } # Utils anyhow = { workspace = true } diff --git a/swap-p2p/src/protocols/quote.rs b/swap-p2p/src/protocols/quote.rs index b84705cb63..f77dd24a88 100644 --- a/swap-p2p/src/protocols/quote.rs +++ b/swap-p2p/src/protocols/quote.rs @@ -1,16 +1,47 @@ use crate::out_event; use libp2p::request_response::{self, ProtocolSupport}; use libp2p::{PeerId, StreamProtocol}; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use swap_core::bitcoin; +use swap_env::config::RefundPolicy; use typeshare::typeshare; -pub(crate) const PROTOCOL: &str = "/comit/xmr/btc/bid-quote/1.0.0"; +pub(crate) const PROTOCOL: &str = "/comit/xmr/btc/bid-quote/2.0.0"; pub type OutEvent = request_response::Event<(), BidQuote>; pub type Message = request_response::Message<(), BidQuote>; pub type Behaviour = request_response::json::Behaviour<(), BidQuote>; +/// The refund policy that will apply if the swap is cancelled. +/// Communicated in quotes so takers know the terms upfront. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(tag = "type", content = "content")] +#[typeshare] +pub enum RefundPolicyWire { + /// Taker receives 100% of their Bitcoin back on refund. + FullRefund, + /// Taker receives a partial refund; the remainder goes to an amnesty output + /// that the maker may or may not release later. + PartialRefund { + /// Ratio (0.0-1.0) of Bitcoin the taker receives immediately. + #[typeshare(serialized_as = "number")] + taker_refund_ratio: Decimal, + }, +} + +impl From for RefundPolicyWire { + fn from(policy: RefundPolicy) -> Self { + if policy.taker_refund_ratio == Decimal::ONE { + RefundPolicyWire::FullRefund + } else { + RefundPolicyWire::PartialRefund { + taker_refund_ratio: policy.taker_refund_ratio, + } + } + } +} + #[derive(Debug, Clone, Copy, Default)] pub struct BidQuoteProtocol; @@ -33,6 +64,8 @@ pub struct BidQuote { /// The maximum quantity the maker is willing to buy. #[typeshare(serialized_as = "number")] pub max_quantity: bitcoin::Amount, + /// The refund policy that will apply if the swap is cancelled. + pub refund_policy: RefundPolicyWire, /// Monero "ReserveProofV2" which proves that Alice has the funds to fulfill the quote. /// See "Zero to Monero" section 8.1.6 for more details. /// @@ -47,6 +80,7 @@ impl BidQuote { price: bitcoin::Amount::ZERO, min_quantity: bitcoin::Amount::ZERO, max_quantity: bitcoin::Amount::ZERO, + refund_policy: RefundPolicyWire::FullRefund, reserve_proof: None, }; } diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 0b6c3d8dc9..8f865f3eeb 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -6,7 +6,7 @@ use crate::asb::{Behaviour, OutEvent}; use crate::monero; use crate::network::cooperative_xmr_redeem_after_punish::CooperativeXmrRedeemRejectReason; use crate::network::cooperative_xmr_redeem_after_punish::Response::{Fullfilled, Rejected}; -use crate::network::quote::BidQuote; +use crate::network::quote::{BidQuote, RefundPolicyWire}; use crate::network::swap_setup::alice::WalletSnapshot; use crate::network::transfer_proof; use crate::protocol::alice::swap::has_already_processed_enc_sig; @@ -289,7 +289,7 @@ where tracing::warn!(%peer, "Ignoring spot price request: {}", error); } SwarmEvent::Behaviour(OutEvent::QuoteRequested { channel, peer }) => { - match self.make_quote_or_use_cached(self.min_buy, self.max_buy, self.developer_tip.ratio).await { + match self.make_quote_or_use_cached(self.min_buy, self.max_buy, self.developer_tip.ratio, self.refund_policy.clone().into()).await { Ok(quote_arc) => { if self.swarm.behaviour_mut().quote.send_response(channel, (*quote_arc).clone()).is_err() { tracing::debug!(%peer, "Failed to respond with quote"); @@ -588,6 +588,7 @@ where min_buy: bitcoin::Amount, max_buy: bitcoin::Amount, developer_tip: Decimal, + refund_policy: RefundPolicyWire, ) -> Result, Arc> { // We use the min and max buy amounts to create a unique key for the cache // Although these values stay constant over the lifetime of an instance of the asb, this might change in the future @@ -638,6 +639,7 @@ where get_reserved_items, get_reserve_proof, developer_tip, + refund_policy, ) .await; @@ -1128,7 +1130,7 @@ mod quote { use tokio::time::timeout; use crate::{ - network::quote::{BidQuote, ReserveProofWithAddress}, + network::quote::{BidQuote, RefundPolicyWire, ReserveProofWithAddress}, protocol::alice::ReservesMonero, }; @@ -1152,6 +1154,7 @@ mod quote { get_reserved_items: I, get_reserve_proof: P, developer_tip: Decimal, + refund_policy: RefundPolicyWire, ) -> Result, Arc> where LR: LatestRate, @@ -1221,6 +1224,7 @@ mod quote { price: ask_price, min_quantity: bitcoin::Amount::ZERO, max_quantity: bitcoin::Amount::ZERO, + refund_policy: refund_policy.clone(), reserve_proof, })); } @@ -1235,6 +1239,7 @@ mod quote { price: ask_price, min_quantity: min_buy, max_quantity: max_bitcoin_for_monero, + refund_policy: refund_policy.clone(), reserve_proof, })); } @@ -1243,6 +1248,7 @@ mod quote { price: ask_price, min_quantity: min_buy, max_quantity: max_buy, + refund_policy, reserve_proof, })) } @@ -1485,6 +1491,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); @@ -1517,6 +1524,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); @@ -1544,6 +1552,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); @@ -1569,6 +1578,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); @@ -1599,6 +1609,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); @@ -1623,6 +1634,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await; @@ -1649,6 +1661,7 @@ mod tests { || async { Ok(reserved_items) }, || async { Err(anyhow::anyhow!("no reserve proof")) }, Decimal::ZERO, + RefundPolicyWire::FullRefund, ) .await .unwrap(); diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index b0f5b875b6..f32999099a 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -46,7 +46,7 @@ mod tests { use std::time::Duration; use swap::cli::api::request::determine_btc_to_swap; use swap::cli::QuoteWithAddress; - use swap::network::quote::BidQuote; + use swap::network::quote::{BidQuote, RefundPolicyWire}; use tracing::level_filters::LevelFilter; use tracing_ext::capture_logs; @@ -424,6 +424,7 @@ mod tests { price: Amount::from_btc(0.001).unwrap(), max_quantity, min_quantity, + refund_policy: RefundPolicyWire::FullRefund, reserve_proof: None, }, version: Some("1.0.0".parse().unwrap()), From 656556986bc58f524f70c834cbacf2cf8054941c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 12 Jan 2026 15:33:12 +0100 Subject: [PATCH 087/146] gui: extend mocking system, make it possible to view SwapSetupInflight component for mock swap --- Cargo.lock | 1 + src-gui/src/dev/mockSwapEvents.ts | 74 ++++++++++++- src-gui/src/models/storeModel.ts | 2 + src-gui/src/renderer/background.ts | 5 +- .../modal/swap/pages/MockSwapControls.tsx | 56 ++++++---- .../components/pages/swap/swap/SwapWidget.tsx | 12 +- .../in_progress/SwapSetupInflightPage.tsx | 104 +++++++++++++++--- .../MakerOfferItem.tsx | 20 +++- src-gui/src/renderer/rpc.ts | 5 + src-gui/src/store/features/swapSlice.ts | 14 ++- src-gui/src/store/middleware/storeListener.ts | 5 + 11 files changed, 247 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fef092c4df..4f03708e94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10919,6 +10919,7 @@ dependencies = [ "libp2p-tor", "monero", "rand 0.8.5", + "rust_decimal", "semver", "serde", "serde_cbor", diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index 366f131c36..ddc446ebb2 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -1,5 +1,7 @@ import { + ApprovalRequest, BidQuote, + LockBitcoinDetails, MoneroAddressPool, QuoteWithAddress, TauriSwapProgressEvent, @@ -29,7 +31,7 @@ const MOCK_BTC_FINAL_AMNESTY_TXID = // Mock amounts for partial refund scenarios const MOCK_BTC_LOCK_AMOUNT = 50_000_000; // 0.5 BTC -const MOCK_BTC_AMNESTY_AMOUNT = 2_500_000; // 0.025 BTC (5% of lock amount) +const MOCK_BTC_AMNESTY_AMOUNT = 1_000_000; // 0.01 BTC (2% of lock amount) // Mock addresses const MOCK_BTC_DEPOSIT_ADDRESS = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"; @@ -42,13 +44,28 @@ const MOCK_QUOTE: BidQuote = { price: 0.007, min_quantity: 10_000_000, max_quantity: 100_000_000, + refund_policy: { type: "FullRefund" }, }; const MOCK_QUOTE_WITH_ADDRESS: QuoteWithAddress = { multiaddr: "/ip4/127.0.0.1/tcp/9939", peer_id: "12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi", quote: MOCK_QUOTE, - version: "0.13.0", + version: "3.6.1", +}; + +const MOCK_QUOTE_PARTIAL_REFUND: BidQuote = { + price: 0.0068, + min_quantity: 5_000_000, + max_quantity: 200_000_000, + refund_policy: { type: "PartialRefund", content: { taker_refund_ratio: 0.98 } }, +}; + +const MOCK_QUOTE_WITH_ADDRESS_PARTIAL: QuoteWithAddress = { + multiaddr: "/ip4/192.168.1.50/tcp/9940", + peer_id: "12D3KooWEyoppNCUzN3sX7atGxPHvqgZvUNQmKzz1mQvNfFhuqP9", + quote: MOCK_QUOTE_PARTIAL_REFUND, + version: "3.6.1", }; const MOCK_RECEIVE_POOL: MoneroAddressPool = [ @@ -66,7 +83,7 @@ const baseScenario: TauriSwapProgressEvent[] = [ deposit_address: MOCK_BTC_DEPOSIT_ADDRESS, max_giveable: 0, min_bitcoin_lock_tx_fee: 1000, - known_quotes: [MOCK_QUOTE_WITH_ADDRESS], + known_quotes: [MOCK_QUOTE_WITH_ADDRESS, MOCK_QUOTE_WITH_ADDRESS_PARTIAL], }, }, { type: "SwapSetupInflight", content: { btc_lock_amount: 50_000_000 } }, @@ -279,3 +296,54 @@ export const scenarios: Record = { }; export type MockScenario = keyof typeof scenarios; + +// Mock LockBitcoin approval requests for testing confirmation screen + +// Partial refund version (5% amnesty) +const MOCK_LOCK_BITCOIN_DETAILS_PARTIAL: LockBitcoinDetails = { + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_network_fee: 5000, + xmr_receive_amount: 7_000_000_000_000, // 7 XMR in piconeros + monero_receive_pool: MOCK_RECEIVE_POOL, + swap_id: MOCK_SWAP_ID, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + has_full_refund_signature: false, +}; + +// Full refund version (no amnesty) +const MOCK_LOCK_BITCOIN_DETAILS_FULL: LockBitcoinDetails = { + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_network_fee: 5000, + xmr_receive_amount: 7_000_000_000_000, // 7 XMR in piconeros + monero_receive_pool: MOCK_RECEIVE_POOL, + swap_id: MOCK_SWAP_ID, + btc_amnesty_amount: 0, + has_full_refund_signature: true, +}; + +const PARTIAL_REFUND_SCENARIOS: MockScenario[] = [ + "partialRefundWithAmnesty", + "partialRefundWithBurn", + "partialRefundWithBurnAndFinalAmnesty", +]; + +export function isPartialRefundScenario(scenario: MockScenario): boolean { + return PARTIAL_REFUND_SCENARIOS.includes(scenario); +} + +export function getMockLockBitcoinApproval(scenario: MockScenario | null): ApprovalRequest { + const isPartial = scenario !== null && isPartialRefundScenario(scenario); + return { + request_id: "00000000-0000-0000-0000-000000000001", + request: { + type: "LockBitcoin", + content: isPartial ? MOCK_LOCK_BITCOIN_DETAILS_PARTIAL : MOCK_LOCK_BITCOIN_DETAILS_FULL, + }, + request_status: { + state: "Pending", + content: { + expiration_ts: Number.MAX_SAFE_INTEGER, + }, + }, + }; +} diff --git a/src-gui/src/models/storeModel.ts b/src-gui/src/models/storeModel.ts index 56e14588be..9065265e8d 100644 --- a/src-gui/src/models/storeModel.ts +++ b/src-gui/src/models/storeModel.ts @@ -11,4 +11,6 @@ export interface SwapSlice { state: SwapState | null; logs: CliLog[]; spawnType: SwapSpawnType | null; + /** DEV ONLY: When true, prevents Tauri calls in the swap progress listener */ + _mockOnlyDisableTauriCallsOnSwapProgress: boolean; } diff --git a/src-gui/src/renderer/background.ts b/src-gui/src/renderer/background.ts index bd234e18d0..aebfa073a4 100644 --- a/src-gui/src/renderer/background.ts +++ b/src-gui/src/renderer/background.ts @@ -118,7 +118,10 @@ listen(TAURI_UNIFIED_EVENT_CHANNEL_NAME, (event) => { switch (channelName) { case "SwapProgress": - store.dispatch(swapProgressEventReceived(eventData)); + // Skip when mocking is enabled (DEV only) - mock dispatches bypass this listener + if (!store.getState().swap._mockOnlyDisableTauriCallsOnSwapProgress) { + store.dispatch(swapProgressEventReceived(eventData)); + } break; case "CliLog": diff --git a/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx b/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx index 4921a10f60..366388ba77 100644 --- a/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx +++ b/src-gui/src/renderer/components/modal/swap/pages/MockSwapControls.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { Box, + Button, IconButton, MenuItem, Paper, @@ -10,60 +11,70 @@ import { } from "@mui/material"; import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; import ChevronRightIcon from "@mui/icons-material/ChevronRight"; -import { scenarios, MockScenario, MOCK_SWAP_ID } from "dev/mockSwapEvents"; -import { SwapState } from "models/storeModel"; - -function buildMockState(scenario: MockScenario, index: number): SwapState { - const events = scenarios[scenario]; - return { - curr: events[index], - prev: index > 0 ? events[index - 1] : null, - swapId: MOCK_SWAP_ID, - }; -} - -interface Props { - onMockStateChange: (state: SwapState | null) => void; -} +import { scenarios, MockScenario, MOCK_SWAP_ID, getMockLockBitcoinApproval } from "dev/mockSwapEvents"; +import { useAppDispatch } from "store/hooks"; +import { approvalEventReceived } from "store/features/rpcSlice"; +import { + swapProgressEventReceived, + swapReset, + setMockOnlyDisableTauriCallsOnSwapProgress, +} from "store/features/swapSlice"; -export default function MockSwapControls({ onMockStateChange }: Props) { +export default function MockSwapControls() { + const dispatch = useAppDispatch(); const [scenario, setScenario] = useState(null); const [index, setIndex] = useState(0); const enabled = scenario !== null; const total = scenario ? scenarios[scenario].length : 0; + const dispatchMockState = (mockScenario: MockScenario, eventIndex: number) => { + const event = scenarios[mockScenario][eventIndex]; + dispatch( + swapProgressEventReceived({ + swap_id: MOCK_SWAP_ID, + event, + }), + ); + }; + + const handleMockConfirmation = () => { + dispatch(approvalEventReceived(getMockLockBitcoinApproval(scenario))); + }; + const handleToggle = (checked: boolean) => { if (checked) { const firstScenario = Object.keys(scenarios)[0] as MockScenario; setScenario(firstScenario); setIndex(0); - onMockStateChange(buildMockState(firstScenario, 0)); + dispatch(setMockOnlyDisableTauriCallsOnSwapProgress(true)); + dispatchMockState(firstScenario, 0); } else { setScenario(null); setIndex(0); - onMockStateChange(null); + dispatch(setMockOnlyDisableTauriCallsOnSwapProgress(false)); + dispatch(swapReset()); } }; const handleScenarioChange = (newScenario: MockScenario) => { setScenario(newScenario); setIndex(0); - onMockStateChange(buildMockState(newScenario, 0)); + dispatchMockState(newScenario, 0); }; const prev = () => { if (!scenario || index === 0) return; const newIndex = index - 1; setIndex(newIndex); - onMockStateChange(buildMockState(scenario, newIndex)); + dispatchMockState(scenario, newIndex); }; const next = () => { if (!scenario || index >= total - 1) return; const newIndex = index + 1; setIndex(newIndex); - onMockStateChange(buildMockState(scenario, newIndex)); + dispatchMockState(scenario, newIndex); }; const currentStateName = scenario ? scenarios[scenario][index].type : null; @@ -119,6 +130,9 @@ export default function MockSwapControls({ onMockStateChange }: Props) { )} + ); diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx index 2340d8424d..f166d22ded 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx @@ -8,15 +8,11 @@ import SwapStatusAlert from "renderer/components/alert/SwapStatusAlert/SwapStatu import DebugPageSwitchBadge from "renderer/components/modal/swap/pages/DebugPageSwitchBadge"; import DebugPage from "renderer/components/modal/swap/pages/DebugPage"; import MockSwapControls from "renderer/components/modal/swap/pages/MockSwapControls"; -import { SwapState } from "models/storeModel"; export default function SwapWidget() { const swapState = useAppSelector((state) => state.swap.state); const swapInfo = useActiveSwapInfo(); const [debug, setDebug] = useState(false); - const [mockState, setMockState] = useState(null); - - const displayState = mockState ?? swapState; return ( )} - {import.meta.env.DEV && } + {import.meta.env.DEV && } - + - {displayState !== null && ( + {swapState !== null && ( <> - + state.rates.xmrBtcRate); + + // Calculate markup compared to market rate + const makerRate = satsToBtc(btc_lock_amount) / piconerosToXmr(Number(xmr_receive_amount)); + const markupPercent = xmrBtcRate != null ? getMarkup(makerRate, xmrBtcRate) : null; + + // Calculate refund percentages + const guaranteedRefundPercent = ((btc_lock_amount - btc_amnesty_amount) / btc_lock_amount) * 100; + const depositPercent = (btc_amnesty_amount / btc_lock_amount) * 100; + const hasDeposit = btc_amnesty_amount > 0; + return ( @@ -128,6 +140,77 @@ export default function SwapSetupInflightPage({ + {/* Info section: Rate and Refund details */} + + {markupPercent != null && ( + <> + + Rate: {Math.abs(markupPercent).toFixed(1)}% {markupPercent >= 0 ? "above" : "below"} market + + + + )} + {hasDeposit ? ( + + theme.palette.success.main + "15", + borderRadius: 1, + borderLeft: 3, + borderColor: "success.main", + }} + > + + {guaranteedRefundPercent.toFixed(0)}% guaranteed refund + + + theme.palette.info.main + "15", + borderRadius: 1, + borderLeft: 3, + borderColor: "info.main", + }} + > + + {depositPercent.toFixed(0)}% anti-spam deposit + + + └ Usually returned; maker may lock for abuse + + + + ) : ( + theme.palette.success.main + "15", + borderRadius: 1, + borderLeft: 3, + borderColor: "success.main", + }} + > + + Full refund if swap fails (guaranteed) + + + )} + + - ({ - color: theme.palette.text.primary, - })} - > - ({guaranteedRefundPercentage}% refund guaranteed) - {/* Network fee box attached to the bottom */} diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index a7a80ec201..1be09b9aa7 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -1,6 +1,6 @@ import { Box, Chip, Divider, Paper, Tooltip, Typography } from "@mui/material"; import Jdenticon from "renderer/components/other/Jdenticon"; -import { QuoteWithAddress } from "models/tauriModel"; +import { QuoteWithAddress, RefundPolicyWire } from "models/tauriModel"; import { MoneroSatsExchangeRate, MoneroSatsMarkup, @@ -11,6 +11,13 @@ import { resolveApproval } from "renderer/rpc"; import { isMakerVersionOutdated } from "utils/multiAddrUtils"; import WarningIcon from "@mui/icons-material/Warning"; +function getRefundPercentage(policy: RefundPolicyWire): number { + if (policy.type === "FullRefund") { + return 100; + } + return policy.content.taker_refund_ratio * 100; +} + export default function MakerOfferItem({ quoteWithAddress, requestId, @@ -130,6 +137,17 @@ export default function MakerOfferItem({ size="small" /> + + + {isMakerVersionOutdated(version) ? ( ( } export async function refreshApprovals(): Promise { + // Skip when mocking is enabled (DEV only) + if (store.getState().swap._mockOnlyDisableTauriCallsOnSwapProgress) { + return; + } + const response = await invokeNoArgs( "get_pending_approvals", ); diff --git a/src-gui/src/store/features/swapSlice.ts b/src-gui/src/store/features/swapSlice.ts index d2acec5c7b..6bf863b53b 100644 --- a/src-gui/src/store/features/swapSlice.ts +++ b/src-gui/src/store/features/swapSlice.ts @@ -8,6 +8,8 @@ const initialState: SwapSlice = { // TODO: Remove this and replace logic entirely with Tauri events spawnType: null, + + _mockOnlyDisableTauriCallsOnSwapProgress: false, }; export const swapSlice = createSlice({ @@ -37,9 +39,19 @@ export const swapSlice = createSlice({ swapReset() { return initialState; }, + setMockOnlyDisableTauriCallsOnSwapProgress( + swap, + action: PayloadAction, + ) { + swap._mockOnlyDisableTauriCallsOnSwapProgress = action.payload; + }, }, }); -export const { swapReset, swapProgressEventReceived } = swapSlice.actions; +export const { + swapReset, + swapProgressEventReceived, + setMockOnlyDisableTauriCallsOnSwapProgress, +} = swapSlice.actions; export default swapSlice.reducer; diff --git a/src-gui/src/store/middleware/storeListener.ts b/src-gui/src/store/middleware/storeListener.ts index aff8524507..38fb9dfefe 100644 --- a/src-gui/src/store/middleware/storeListener.ts +++ b/src-gui/src/store/middleware/storeListener.ts @@ -159,6 +159,11 @@ export function createMainListeners() { listener.startListening({ actionCreator: swapProgressEventReceived, effect: async (action) => { + // Skip Tauri calls when mocking is enabled (DEV only) + if (store.getState().swap._mockOnlyDisableTauriCallsOnSwapProgress) { + return; + } + if (action.payload.event.type === "Released") { logger.info("Swap released, updating bitcoin balance..."); await checkBitcoinBalance(); From 3e65462b10f43dcb83c2709c91bebfb7e035b93c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 12 Jan 2026 16:48:46 +0100 Subject: [PATCH 088/146] wait for tx refund confirmation in refund command --- swap/src/cli/cancel_and_refund.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 26f2f5e93e..58722febcc 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -244,16 +244,30 @@ pub async fn refund( .ensure_broadcasted(refund_tx, &refund_type.to_string()) .await { - Ok(_) => { - let state = match refund_type { - RefundType::Full => BobState::BtcRefundPublished(state6), - RefundType::Partial { .. } => BobState::BtcPartialRefundPublished(state6), + Ok((_txid, subscription)) => { + // First save the "published" state + let published_state = match &refund_type { + RefundType::Full => BobState::BtcRefundPublished(state6.clone()), + RefundType::Partial { .. } => BobState::BtcPartialRefundPublished(state6.clone()), }; - db.insert_latest_state(swap_id, state.clone().into()) + db.insert_latest_state(swap_id, published_state.into()) + .await?; + + // Wait for the transaction to be confirmed + tracing::info!("Waiting for refund transaction to be confirmed..."); + subscription.wait_until_final().await?; + + // Now save and return the confirmed state + let confirmed_state = match refund_type { + RefundType::Full => BobState::BtcRefunded(state6), + RefundType::Partial { .. } => BobState::BtcPartiallyRefunded(state6), + }; + + db.insert_latest_state(swap_id, confirmed_state.clone().into()) .await?; - Ok(state) + Ok(confirmed_state) } // If we fail to submit the refund transaction it can have one of two reasons: From 4f9895f5f08b14d40b818c5366aeb6e569d1dcfe Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 12 Jan 2026 17:28:01 +0100 Subject: [PATCH 089/146] gui: small react refactors --- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 1 + .../components/inputs/NumberInput.tsx | 19 +++---- .../modal/donation-tip/DonationTipDialog.tsx | 11 ++-- .../components/modal/feedback/useFeedback.ts | 55 ++++++++----------- .../seed-selection/SeedSelectionDialog.tsx | 35 ++++++------ .../components/other/ValidatedTextField.tsx | 10 ++-- .../pages/monero/SendTransactionModal.tsx | 2 +- .../in_progress/SwapSetupInflightPage.tsx | 5 +- .../MakerDiscoveryStatus.tsx | 20 ++++--- 9 files changed, 76 insertions(+), 82 deletions(-) diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 2b4e003a8b..22a17dbded 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -266,6 +266,7 @@ export function StateAlert({ case BobStateName.CancelTimelockExpired: // Even if the refund transactions have been published, it cannot be // guaranteed that they will be confirmed in time + // falls through case BobStateName.BtcCancelled: case BobStateName.BtcRefundPublished: case BobStateName.BtcPartialRefundPublished: diff --git a/src-gui/src/renderer/components/inputs/NumberInput.tsx b/src-gui/src/renderer/components/inputs/NumberInput.tsx index 4fa2f18158..8909417bf4 100644 --- a/src-gui/src/renderer/components/inputs/NumberInput.tsx +++ b/src-gui/src/renderer/components/inputs/NumberInput.tsx @@ -42,10 +42,15 @@ export default function NumberInput({ return 0; }; - const [userPrecision, setUserPrecision] = useState(() => - getDecimalPrecision(step), - ); // Track user's decimal precision - const [minPrecision, setMinPrecision] = useState(3); + // minPrecision is purely derived from step - no state needed + const minPrecision = getDecimalPrecision(step); + + // Track user's decimal precision, reset when step changes + const [userPrecision, setUserPrecision] = useState(() => minPrecision); + + // eslint-disable-next-line react-hooks/set-state-in-effect -- reset state when prop changes + useEffect(() => setUserPrecision(minPrecision), [step, minPrecision]); + const appliedPrecision = userPrecision > minPrecision ? userPrecision : minPrecision; @@ -61,12 +66,6 @@ export default function NumberInput({ } }, [placeholder, isFocused, value, onChange]); - // Update precision when step changes - useEffect(() => { - setUserPrecision(getDecimalPrecision(step)); - setMinPrecision(getDecimalPrecision(step)); - }, [step]); - // Measure text width to size input dynamically useEffect(() => { if (measureRef.current) { diff --git a/src-gui/src/renderer/components/modal/donation-tip/DonationTipDialog.tsx b/src-gui/src/renderer/components/modal/donation-tip/DonationTipDialog.tsx index 7e089a157a..2d8bea415d 100644 --- a/src-gui/src/renderer/components/modal/donation-tip/DonationTipDialog.tsx +++ b/src-gui/src/renderer/components/modal/donation-tip/DonationTipDialog.tsx @@ -23,7 +23,7 @@ import { } from "store/hooks"; import ExternalLink from "renderer/components/other/ExternalLink"; import GitHubIcon from "@mui/icons-material/GitHub"; -import { useState, useEffect } from "react"; +import { useState } from "react"; const GITHUB_BOUNTIES_URL = "https://eigenwallet.org/bounties"; @@ -239,15 +239,14 @@ export function GlobalDonationTipDialog() { // "Latch" pattern: once conditions are met, we remember that the dialog should be shown. // This prevents the dialog from closing when the user moves their mouse (which would // break the idle condition). Once triggered, it stays triggered. + // Uses "adjust state during render" pattern instead of useEffect. const [hasTriggered, setHasTriggered] = useState(false); const shouldOpen = hasntSelectedTipYet && isExperiencedUser && isIdle; - useEffect(() => { - if (shouldOpen && !hasTriggered) { - setHasTriggered(true); - } - }, [shouldOpen, hasTriggered]); + if (shouldOpen && !hasTriggered) { + setHasTriggered(true); + } // Show dialog if we've triggered and user hasn't dismissed const open = hasTriggered && !dismissed; diff --git a/src-gui/src/renderer/components/modal/feedback/useFeedback.ts b/src-gui/src/renderer/components/modal/feedback/useFeedback.ts index deec3b9862..56fec91e0c 100644 --- a/src-gui/src/renderer/components/modal/feedback/useFeedback.ts +++ b/src-gui/src/renderer/components/modal/feedback/useFeedback.ts @@ -49,13 +49,12 @@ export function useFeedback() { }); const [logsState, setLogsState] = useState(initialLogsState); - const [isPending, setIsPending] = useState(false); const [error, setError] = useState(null); - const bodyTooLong = inputState.bodyText.length > MAX_FEEDBACK_LENGTH; - + // Fetch swap logs when selection changes useEffect(() => { if (inputState.selectedSwap === null) { + // eslint-disable-next-line react-hooks/set-state-in-effect -- clear when deselected setLogsState((prev) => ({ ...prev, swapLogs: [] })); return; } @@ -76,41 +75,33 @@ export function useFeedback() { }); }, [inputState.selectedSwap, inputState.isSwapLogsRedacted]); + // Fetch/process daemon logs when settings change useEffect(() => { if (!inputState.attachDaemonLogs) { + // eslint-disable-next-line react-hooks/set-state-in-effect -- clear when detached setLogsState((prev) => ({ ...prev, daemonLogs: [] })); return; } - try { - const hashedLogs = store.getState().logs?.state.logs ?? []; - - if (inputState.isDaemonLogsRedacted) { - const logs = hashedLogs.map((h) => h.log); - redactLogs(logs) - .then((redactedLogs) => { - setLogsState((prev) => ({ - ...prev, - daemonLogs: hashLogs(redactedLogs), - })); - setError(null); - }) - .catch((e) => { - logger.error(`Failed to redact daemon logs: ${e}`); - setLogsState((prev) => ({ ...prev, daemonLogs: [] })); - setError(`Failed to redact daemon logs: ${e}`); - }); - } else { - setLogsState((prev) => ({ - ...prev, - daemonLogs: hashedLogs, - })); - setError(null); - } - } catch (e) { - logger.error(`Failed to fetch daemon logs: ${e}`); - setLogsState((prev) => ({ ...prev, daemonLogs: [] })); - setError(`Failed to fetch daemon logs: ${e}`); + const hashedLogs = store.getState().logs?.state.logs ?? []; + + if (inputState.isDaemonLogsRedacted) { + const logs = hashedLogs.map((h) => h.log); + redactLogs(logs) + .then((redactedLogs) => { + setLogsState((prev) => ({ + ...prev, + daemonLogs: hashLogs(redactedLogs), + })); + setError(null); + }) + .catch((e) => { + logger.error(`Failed to redact daemon logs: ${e}`); + setLogsState((prev) => ({ ...prev, daemonLogs: [] })); + setError(`Failed to redact daemon logs: ${e}`); + }); + } else { + setLogsState((prev) => ({ ...prev, daemonLogs: hashedLogs })); } }, [inputState.attachDaemonLogs, inputState.isDaemonLogsRedacted]); diff --git a/src-gui/src/renderer/components/modal/seed-selection/SeedSelectionDialog.tsx b/src-gui/src/renderer/components/modal/seed-selection/SeedSelectionDialog.tsx index 9852eb5a22..a23154ef1c 100644 --- a/src-gui/src/renderer/components/modal/seed-selection/SeedSelectionDialog.tsx +++ b/src-gui/src/renderer/components/modal/seed-selection/SeedSelectionDialog.tsx @@ -20,7 +20,7 @@ import { CardContent, } from "@mui/material"; import NewPasswordInput from "renderer/components/other/NewPasswordInput"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { usePendingSeedSelectionApproval } from "store/hooks"; import { resolveApproval, checkSeed } from "renderer/rpc"; import { SeedChoice } from "models/tauriModel"; @@ -74,7 +74,7 @@ export default function SeedSelectionDialog() { >("RandomSeed"); const [customSeed, setCustomSeed] = useState(""); const [blockheightInput, setBlockheightInput] = useState(""); - const [isSeedValid, setIsSeedValid] = useState(false); + const [asyncSeedValidation, setAsyncSeedValidation] = useState(false); const [password, setPassword] = useState(""); const [isPasswordValid, setIsPasswordValid] = useState(true); const [walletPath, setWalletPath] = useState(""); @@ -87,26 +87,29 @@ export default function SeedSelectionDialog() { ? approval.request.content.recent_wallets : []; + // Only run async validation when in "FromSeed" mode with content + const needsSeedValidation = selectedOption === "FromSeed" && customSeed.trim(); + useEffect(() => { - if (selectedOption === "FromSeed" && customSeed.trim()) { - checkSeed(customSeed.trim()) - .then((valid) => { - setIsSeedValid(valid); - }) - .catch(() => { - setIsSeedValid(false); - }); - } else { - setIsSeedValid(false); - } - }, [customSeed, selectedOption]); + if (!needsSeedValidation) return; + + checkSeed(customSeed.trim()) + .then(setAsyncSeedValidation) + .catch(() => setAsyncSeedValidation(false)); + }, [customSeed, needsSeedValidation]); + + // isSeedValid is derived: only true if we need validation AND async check passed + const isSeedValid = needsSeedValidation && asyncSeedValidation; - // Auto-select the first recent wallet if available + // Auto-select the first recent wallet if available (one-time initialization) + const hasInitializedRef = useRef(false); useEffect(() => { - if (recentWallets.length > 0) { + if (recentWallets.length > 0 && !hasInitializedRef.current) { + hasInitializedRef.current = true; setSelectedOption("FromWalletPath"); setWalletPath(recentWallets[0]); } + // eslint-disable-next-line react-hooks/exhaustive-deps -- only init once when wallets available }, [recentWallets.length]); const selectWalletFile = async () => { diff --git a/src-gui/src/renderer/components/other/ValidatedTextField.tsx b/src-gui/src/renderer/components/other/ValidatedTextField.tsx index 37a8c9d6ec..ca3573cadd 100644 --- a/src-gui/src/renderer/components/other/ValidatedTextField.tsx +++ b/src-gui/src/renderer/components/other/ValidatedTextField.tsx @@ -1,5 +1,5 @@ import { TextFieldProps, TextField } from "@mui/material"; -import { useState, useEffect, useCallback } from "react"; +import { useState, useCallback, useEffect } from "react"; interface ValidatedTextFieldProps extends Omit { @@ -24,6 +24,10 @@ export default function ValidatedTextField({ }: ValidatedTextFieldProps) { const [inputValue, setInputValue] = useState(value || ""); + // Sync internal state with prop (controlled component pattern) + // eslint-disable-next-line react-hooks/set-state-in-effect -- sync internal state with external prop + useEffect(() => setInputValue(value || ""), [value]); + const handleChange = useCallback( (newValue: string) => { const trimmedValue = newValue.trim(); @@ -38,10 +42,6 @@ export default function ValidatedTextField({ [allowEmpty, isValid, onValidatedChange], ); - useEffect(() => { - setInputValue(value || ""); - }, [value]); - const isError = (allowEmpty && inputValue === "") || (inputValue === "" && noErrorWhenEmpty) ? false diff --git a/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx b/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx index f589569b6f..1f9dd5422b 100644 --- a/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx +++ b/src-gui/src/renderer/components/pages/monero/SendTransactionModal.tsx @@ -27,7 +27,7 @@ export default function SendTransactionModal({ const showSuccess = successResponse !== null; - const handleClose = (_: any, reason: string) => { + const handleClose = (_: unknown, reason: string) => { // We want the user to explicitly close the dialog. // We do not close the dialog upon a backdrop click. if (reason === "backdropClick") { diff --git a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx index 96afe11cb6..0a5eb4eb25 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx @@ -29,6 +29,8 @@ export default function SwapSetupInflightPage({ btc_lock_amount, }: TauriSwapProgressEventContent<"SwapSetupInflight">) { const request = useActiveLockBitcoinApprovalRequest(); + // Get market rate for markup calculation (must be called unconditionally) + const xmrBtcRate = useAppSelector((state) => state.rates.xmrBtcRate); const [timeLeft, setTimeLeft] = useState(0); const expirationTs = @@ -79,9 +81,6 @@ export default function SwapSetupInflightPage({ const { btc_network_fee, monero_receive_pool, xmr_receive_amount, btc_amnesty_amount } = request.request.content; - // Get market rate for markup calculation - const xmrBtcRate = useAppSelector((state) => state.rates.xmrBtcRate); - // Calculate markup compared to market rate const makerRate = satsToBtc(btc_lock_amount) / piconerosToXmr(Number(xmr_receive_amount)); const markupPercent = xmrBtcRate != null ? getMarkup(makerRate, xmrBtcRate) : null; diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerDiscoveryStatus.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerDiscoveryStatus.tsx index 6256930101..828da25015 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerDiscoveryStatus.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerDiscoveryStatus.tsx @@ -24,7 +24,7 @@ import { Close as CloseIcon, Refresh as RefreshIcon, } from "@mui/icons-material"; -import { useEffect, useState, useMemo } from "react"; +import { useState, useMemo, useEffect } from "react"; import { useAppSelector } from "store/hooks"; import { QuoteStatus, ConnectionStatus } from "models/tauriModel"; import { selectPeers } from "store/selectors"; @@ -48,15 +48,17 @@ export default function MakerDiscoveryStatus() { .filter((p) => p.connection === ConnectionStatus.Connected) .map((p) => p.peer_id); - // Track peers that have ever been connected + // Track peers that have ever been connected (accumulating historical state) useEffect(() => { - if (connectedPeerIds.length > 0) { - setEverConnectedPeers((prev) => { - const updated = new Set(prev); - connectedPeerIds.forEach((id) => updated.add(id)); - return updated; - }); - } + if (connectedPeerIds.length === 0) return; + setEverConnectedPeers((prev) => { + const newIds = connectedPeerIds.filter((id) => !prev.has(id)); + if (newIds.length === 0) return prev; + const updated = new Set(prev); + newIds.forEach((id) => updated.add(id)); + return updated; + }); + // eslint-disable-next-line react-hooks/exhaustive-deps -- peers is the stable source }, [peers]); const quotesInflight = peers.filter( From 677323710f1a7915d913108bfc4c614c2296a442 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 19 Jan 2026 14:33:05 +0100 Subject: [PATCH 090/146] undo debugging code --- swap/src/database/sqlite.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/swap/src/database/sqlite.rs b/swap/src/database/sqlite.rs index 28a4f2f26d..421863349f 100644 --- a/swap/src/database/sqlite.rs +++ b/swap/src/database/sqlite.rs @@ -411,29 +411,18 @@ impl Database for SqliteDatabase { let result = rows .iter() - .filter_map(|row| { + .map(|row| { let state_str: &str = &row.state; - match serde_json::from_str::(state_str) { - Ok(a) => { - // debugging - if swap_id.to_string().as_str() == "ef5435d3-bb7d-4b3a-a83b-42f2b9f7ca4b" { - tracing::info!("Managed to deserialize swap: {a}") - } - Some(State::from(a)) - } - Err(e) => { - // debugging - if swap_id.to_string().as_str() == "ef5435d3-bb7d-4b3a-a83b-42f2b9f7ca4b" { - tracing::error!(error=%e, "Failed to deserialize swap") - } - None - } - } + let state = match serde_json::from_str::(state_str) { + Ok(a) => Ok(State::from(a)), + Err(e) => Err(e), + }?; + Ok(state) }) - .collect::>(); + .collect::>>(); - Ok(result) + result } async fn insert_buffered_transfer_proof( From 3d22a041d36b116e0ea704c826ba5ab37fa2ae74 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 19 Jan 2026 14:33:57 +0100 Subject: [PATCH 091/146] extract earnest deposit chip into component --- .../MakerOfferItem.tsx | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index 1be09b9aa7..1cc3e06b36 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -1,6 +1,6 @@ import { Box, Chip, Divider, Paper, Tooltip, Typography } from "@mui/material"; import Jdenticon from "renderer/components/other/Jdenticon"; -import { QuoteWithAddress, RefundPolicyWire } from "models/tauriModel"; +import { BidQuote, QuoteWithAddress, RefundPolicyWire } from "models/tauriModel"; import { MoneroSatsExchangeRate, MoneroSatsMarkup, @@ -10,6 +10,7 @@ import PromiseInvokeButton from "renderer/components/PromiseInvokeButton"; import { resolveApproval } from "renderer/rpc"; import { isMakerVersionOutdated } from "utils/multiAddrUtils"; import WarningIcon from "@mui/icons-material/Warning"; +import { RefundPolicy } from "store/features/settingsSlice"; function getRefundPercentage(policy: RefundPolicyWire): number { if (policy.type === "FullRefund") { @@ -137,17 +138,7 @@ export default function MakerOfferItem({ size="small" /> - - - + {EarnestDepositChip(quote)} {isMakerVersionOutdated(version) ? ( ); } + +function EarnestDepositChip(quote: BidQuote) { + const full_refund: boolean = quote.refund_policy.type === "FullRefund" ? true : quote.refund_policy.content.taker_refund_ratio === 1; + // Rounded to 0.001 precision + const earnest_deposit_ratio = Math.round( + (quote.refund_policy.type === "FullRefund" ? 0 : 1 - quote.refund_policy.content?.taker_refund_ratio) + * 1000 + ) / 1000; + const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `If the swap is refunded, the maker may choose to freeze ${earnest_deposit_ratio * 100}% of your refund. This is allows them to protect themselves against griefing.`; + const text = full_refund ? "No earnest deposit" : `${earnest_deposit_ratio * 100}% earnest deposit`; + + return + + ; +} + From b9b8e985021953287e851d43143a8b9f7a313b71 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 19 Jan 2026 15:17:48 +0100 Subject: [PATCH 092/146] gui: update lanugage in partial refund components --- .../modal/swap/SwapStateStepper.tsx | 2 +- .../swap/done/BitcoinPartialRefundPage.tsx | 53 ++++++++++--------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index 609cd0bd5a..b0d7f47322 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -218,7 +218,7 @@ const RECOVERY_STEP_LABELS: Record< [RecoveryScenario.PARTIAL_REFUND]: [ { label: "Cancelling swap", duration: "~1min" }, { label: "Partial refund", duration: "~30min" }, - { label: "Remaining Bitcoin", duration: "~2min" }, + { label: "Claiming deposit", duration: "~2min" }, ], [RecoveryScenario.COOPERATIVE_REDEEM]: [ { label: "Cancelling swap", duration: "~1min" }, diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 628d10c955..5bcd3947ed 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -67,8 +67,8 @@ function PartialRefundPage({ const atRiskPercent = Math.round((btcAmnestyAmount / btcLockAmount) * 100); const mainMessage = confirmed - ? `Refunded the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to revoke the remaining ${atRiskPercent}%. Unless they do that we will claim it shortly.` - : `Refunding the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to revoke the remaining ${atRiskPercent}%. Unless they do that we will claim it shortly.`; + ? `Refunded the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to withhold the earnest deposit of ${atRiskPercent}%. Unless they do that we will claim it shortly.` + : `Refunding the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to withhold the earnest deposit of ${atRiskPercent}%. Unless they do that we will claim it shortly.`; const additionalContent = swap ? ( <> @@ -83,9 +83,9 @@ function PartialRefundPage({ {mainMessage} - Patience: We are first claiming the guaranteed {guaranteedPercent}% of the Bitcoin refund. - It is not guaranteed that we can claim the remaining {atRiskPercent}%. - We will be able to claim the remaining Bitcoin shortly unless the market maker decides to revoke it. + Patience: We are first refunding the guaranteed {guaranteedPercent}% of the Bitcoin refund. + It is not guaranteed that we can claim the earnest deposit, which makes up the remaining {atRiskPercent}%. + The maker has a short timeframe to withhold the deposit, after that we can claim it. @@ -128,8 +128,8 @@ function AmnestyPage({ const swap = useActiveSwapInfo(); const mainMessage = confirmed - ? "All your Bitcoin has been refunded. The swap is complete." - : "The remaining Bitcoin is being released to you. Waiting for confirmation."; + ? "All your Bitcoin have been refunded. The swap is complete." + : "The remaingin Bitcoin (earnest deposit) are being released to you. Waiting for confirmation."; const additionalContent = swap ? ( <> @@ -162,7 +162,7 @@ function AmnestyPage({ ); } -// Refund Burn pages - The maker actively burned the remaining Bitcoin (bad outcome) +// Refund Burn pages - The maker actively withheld the remaining Bitcoin (bad outcome) // Note: By default, the user would have received the remaining Bitcoin after a timelock. // If we're in this state, it means the maker actively published TxBurn to revoke it. @@ -209,30 +209,33 @@ function RefundBurnPage({ }) { const atRiskPercent = Math.round((btcAmnestyAmount / btcLockAmount) * 100); - const mainMessage = confirmed - ? "The market maker has revoked your remaining Bitcoin refund." - : "The market maker is revoking your remaining Bitcoin refund."; + const mainMessage = "The market maker is withholding the earnest deposit." return ( {mainMessage} - Refund revoked: The market maker has revoked the remaining {atRiskPercent}% of your Bitcoin refund. - This portion is now lost and we cannot recover it on our own. + Earnest deposit withheld: The market maker has choosen to withhold the remaining {atRiskPercent}% of your Bitcoin refund. + - + Why did this happen? Aborting a swap incurs significant costs on makers. - To prevent spam attacks, they can revoke a previously agreed upon part of the refund. - The maker has exercised this option because they think you are spamming them. + To prevent spam attacks, makers can choose to require an "earnest deposit", + which they can withhold if the swap is aborted. + + + Makers do not have access to the withheld deposit. + The maker you are swapping with has exercised their option to withhold, because they think you are spamming them. - You can appeal. If you did not mean to spam the market maker, contact them through our official - community. The maker can still help you recover the remaining Bitcoin. + You can contact the maker: If you think this was a mistake, you can contact the maker through our official + community channels. + The maker can still release the deposit.
@@ -255,14 +258,14 @@ function RefundBurnPage({
-
+
); } @@ -290,8 +293,8 @@ function FinalAmnestyPage({ const swap = useActiveSwapInfo(); const mainMessage = confirmed - ? "The market maker has granted you final amnesty. The remaining Bitcoin has been recovered." - : "The market maker is granting you final amnesty. Waiting for confirmation."; + ? "The market maker has release the earnest deposit they withheld. The refund is complete." + : "The market maker is releasing the earnest deposit they withheld. Waiting for transaction confirmation."; const additionalContent = swap ? ( <> @@ -306,14 +309,14 @@ function FinalAmnestyPage({ {mainMessage} - Appeal successful: The market maker has decided to - release the remaining Bitcoin to you. All your Bitcoin has now been + Mercy granted: The market maker has decided to + release the earnest deposit, which they previously withheld. All your Bitcoin has now been fully refunded. Date: Mon, 19 Jan 2026 16:04:22 +0100 Subject: [PATCH 093/146] gui: simplify language in PartialRefund TxClaim page --- .../pages/swap/swap/done/BitcoinPartialRefundPage.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 5bcd3947ed..e7ce310e4f 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -129,7 +129,7 @@ function AmnestyPage({ const mainMessage = confirmed ? "All your Bitcoin have been refunded. The swap is complete." - : "The remaingin Bitcoin (earnest deposit) are being released to you. Waiting for confirmation."; + : "The remaining Bitcoin (earnest deposit) are being released to you. Waiting for confirmation."; const additionalContent = swap ? ( <> @@ -141,12 +141,9 @@ function AmnestyPage({ return ( <> - {mainMessage} - {confirmed ? "Complete:" : "Almost there:"} The - remaining Bitcoin from your partial refund{" "} - {confirmed ? "has been" : "is being"} released to you. + {confirmed ? "Complete:" : "Almost there:"}{" "}{mainMessage} From ccf4ca7b3b2a84e6c2cf875dffdfab4eff23a637 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 20 Jan 2026 12:46:21 +0100 Subject: [PATCH 094/146] bob: emit new tauri event when waiting for timelock on the remaining bitcoin refund to expire --- bitcoin-wallet/src/primitives.rs | 9 ++++++++ swap/src/cli/api/tauri_bindings.rs | 15 +++++++++++++ swap/src/protocol/bob/swap.rs | 34 +++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/bitcoin-wallet/src/primitives.rs b/bitcoin-wallet/src/primitives.rs index 2a84cd1008..2318f0aa60 100644 --- a/bitcoin-wallet/src/primitives.rs +++ b/bitcoin-wallet/src/primitives.rs @@ -266,4 +266,13 @@ impl ScriptStatus { pub fn has_been_seen(&self) -> bool { matches!(self, ScriptStatus::InMempool | ScriptStatus::Confirmed(_)) } + + pub fn confirmations(&self) -> u32 { + match self { + ScriptStatus::Unseen => 0, + ScriptStatus::InMempool => 0, + ScriptStatus::Retrying => 0, + ScriptStatus::Confirmed(depth) => depth, + } + } } diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 9aa3fc2896..1936bdd23b 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -1124,6 +1124,21 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "number")] btc_amnesty_amount: bitcoin::Amount, }, + /// Waiting for the earnest deposit timelock to expire after partial refund confirmed. + WaitingForEarnestDepositTimelockExpiration { + #[typeshare(serialized_as = "string")] + btc_partial_refund_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_lock_amount: bitcoin::Amount, + #[typeshare(serialized_as = "number")] + btc_amnesty_amount: bitcoin::Amount, + /// Total blocks required for timelock (target) + #[typeshare(serialized_as = "number")] + target_blocks: u32, + /// Blocks remaining until expiry + #[typeshare(serialized_as = "number")] + blocks_until_expiry: u32, + }, // BtcAmnesty was confirmed. BtcAmnestyReceived { #[typeshare(serialized_as = "string")] diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index cba59669c3..83fcb87217 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1271,17 +1271,45 @@ async fn next_state( "Can't wait for remaining refund timelock because remaining_refund_timelock is missing", )?; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::WaitingForEarnestDepositTimelockExpiration { + btc_partial_refund_txid: tx_partial_refund.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), + target_blocks: remaining_refund_timelock.into(), + blocks_until_expiry: remaining_refund_timelock.into(), + }, + ); + let (tx_partial_refund_status, tx_refund_burn_status) = tokio::join!( bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund)), bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)), ); + // Emit a tauri event everytime the TxPartialRefund status changes so we can + // show an estimate when we will be able to claim the remaining bitcoin + let timelock_expired_future = tx_partial_refund_status.wait_until(|status| { + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::WaitingForEarnestDepositTimelockExpiration { + btc_partial_refund_txid: tx_partial_refund.txid(), + btc_lock_amount: state.tx_lock.lock_amount(), + btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), + target_blocks: remaining_refund_timelock.into(), + blocks_until_expiry: status.confirmations(), + }, + ); + + status.is_confirmed_with(remaining_refund_timelock.0) + }); + select! { // Wait for remaining_refund_timelock confirmations on tx_partial_refund - result = tx_partial_refund_status.wait_until_confirmed_with(remaining_refund_timelock) => { + result = timelock_expired_future => { result?; - tracing::info!("Remaining refund timelock expired, can now publish TxRefundAmnesty"); - BobState::RemainingRefundTimelockExpired(state) + tracing::info!("RemainingBitcoinTimelock expired"); + BobState::BtcRemainingTimelockExpired(state) } // Watch for Alice publishing TxRefundBurn _ = tx_refund_burn_status.wait_until_seen() => { From b8a743799de83f16b8be3a52e8ff074e913719c3 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 20 Jan 2026 13:05:20 +0100 Subject: [PATCH 095/146] fix compilation errors --- bitcoin-wallet/src/primitives.rs | 2 +- swap/src/protocol/bob/swap.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bitcoin-wallet/src/primitives.rs b/bitcoin-wallet/src/primitives.rs index 2318f0aa60..2104d0fa5b 100644 --- a/bitcoin-wallet/src/primitives.rs +++ b/bitcoin-wallet/src/primitives.rs @@ -272,7 +272,7 @@ impl ScriptStatus { ScriptStatus::Unseen => 0, ScriptStatus::InMempool => 0, ScriptStatus::Retrying => 0, - ScriptStatus::Confirmed(depth) => depth, + ScriptStatus::Confirmed(confirmed) => confirmed.confirmations(), } } } diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 83fcb87217..576d698b96 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1283,7 +1283,7 @@ async fn next_state( ); let (tx_partial_refund_status, tx_refund_burn_status) = tokio::join!( - bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund)), + bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund.clone())), bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)), ); @@ -1308,8 +1308,8 @@ async fn next_state( // Wait for remaining_refund_timelock confirmations on tx_partial_refund result = timelock_expired_future => { result?; - tracing::info!("RemainingBitcoinTimelock expired"); - BobState::BtcRemainingTimelockExpired(state) + tracing::info!("Remaining refund timelock expired, can now publish TxRefundAmnesty"); + BobState::RemainingRefundTimelockExpired(state) } // Watch for Alice publishing TxRefundBurn _ = tx_refund_burn_status.wait_until_seen() => { From 19b86b785c2eeb4091c9469fb0bea4c7e140b9c6 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Tue, 20 Jan 2026 13:06:33 +0100 Subject: [PATCH 096/146] gui: add new page when waiting for timelock on remaining refund to expire --- .../modal/swap/SwapStateStepper.tsx | 7 ++- .../pages/swap/swap/SwapStatePage.tsx | 6 +++ .../swap/done/BitcoinPartialRefundPage.tsx | 53 ++++++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index b0d7f47322..1bae6a3bcc 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -128,8 +128,7 @@ function getActiveStep(state: SwapState | null): PathStep | null { return [PathType.RECOVERY_PATH, 1, isReleased, RecoveryScenario.PARTIAL_REFUND]; case "BtcPartiallyRefunded": - return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; - + case "WaitingForEarnestDepositTimelockExpiration": case "BtcAmnestyPublished": return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; @@ -217,8 +216,8 @@ const RECOVERY_STEP_LABELS: Record< ], [RecoveryScenario.PARTIAL_REFUND]: [ { label: "Cancelling swap", duration: "~1min" }, - { label: "Partial refund", duration: "~30min" }, - { label: "Claiming deposit", duration: "~2min" }, + { label: "Partial refund", duration: "~2min" }, + { label: "Claiming deposit", duration: "~30min" }, ], [RecoveryScenario.COOPERATIVE_REDEEM]: [ { label: "Cancelling swap", duration: "~1min" }, diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index a764a473e2..9243ab5aed 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -11,6 +11,7 @@ import { import { BitcoinPartialRefundPublished, BitcoinPartiallyRefunded, + WaitingForEarnestDepositTimelockExpirationPage, BitcoinAmnestyPublished, BitcoinAmnestyReceived, BitcoinRefundBurnPublished, @@ -147,6 +148,11 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { return ; } break; + case "WaitingForEarnestDepositTimelockExpiration": + if (state.curr.type === "WaitingForEarnestDepositTimelockExpiration") { + return ; + } + break; case "BtcAmnestyPublished": if (state.curr.type === "BtcAmnestyPublished") { return ; diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index e7ce310e4f..488e3c75d7 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -12,8 +12,9 @@ * -> optionally BtcFinalAmnestyPublished -> BtcFinalAmnestyConfirmed (Alice grants final amnesty) */ -import { Alert, Box, Button, DialogContentText, Typography } from "@mui/material"; +import { Alert, Box, Button, DialogContentText, LinearProgress, Typography } from "@mui/material"; import { TauriSwapProgressEventContent } from "models/tauriModelExt"; +import HumanizedBitcoinBlockDuration from "renderer/components/other/HumanizedBitcoinBlockDuration"; import { useActiveSwapInfo } from "store/hooks"; import FeedbackInfoBox from "renderer/components/pages/help/FeedbackInfoBox"; import BitcoinTransactionInfoBox from "renderer/components/pages/swap/swap/components/BitcoinTransactionInfoBox"; @@ -50,6 +51,56 @@ export function BitcoinPartiallyRefunded({ ); } +export function WaitingForEarnestDepositTimelockExpirationPage({ + btc_partial_refund_txid, + btc_lock_amount, + btc_amnesty_amount, + target_blocks, + blocks_until_expiry, +}: TauriSwapProgressEventContent<"WaitingForEarnestDepositTimelockExpiration">) { + const swap = useActiveSwapInfo(); + + const blocksConfirmed = target_blocks - blocks_until_expiry; + const progressPercent = Math.round((blocksConfirmed / target_blocks) * 100); + const atRiskPercent = Math.round((btc_amnesty_amount / btc_lock_amount) * 100); + + const additionalContent = swap ? ( + <>Refund address: {swap.btc_refund_address} + ) : null; + + return ( + <> + + Waiting to claim the earnest deposit ({atRiskPercent}% of your Bitcoin). + The maker can still withhold it during this time. + + + + Timelock progress: {blocksConfirmed} of {target_blocks} blocks confirmed ({progressPercent}%). + {blocks_until_expiry > 0 && ( + <> + {" "}Approximately remaining. + + )} + + + + + + + + ); +} + function PartialRefundPage({ txid, confirmed, From de69009407ef306957f312a4d383f1b082bf60f0 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 21 Jan 2026 14:24:39 +0100 Subject: [PATCH 097/146] gui: add WaitingForEarnestDeposit page to mock paths --- src-gui/src/dev/mockSwapEvents.ts | 36 +++++++++++++++ .../modal/swap/SwapStateStepper.tsx | 5 +-- .../swap/done/BitcoinPartialRefundPage.tsx | 44 +++++-------------- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index ddc446ebb2..071c408bba 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -29,6 +29,9 @@ const MOCK_BTC_REFUND_BURN_TXID = const MOCK_BTC_FINAL_AMNESTY_TXID = "c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"; +// Mock timelock blocks for earnest deposit +const EARNEST_DEPOSIT_TARGET_BLOCKS = 3; + // Mock amounts for partial refund scenarios const MOCK_BTC_LOCK_AMOUNT = 50_000_000; // 0.5 BTC const MOCK_BTC_AMNESTY_AMOUNT = 1_000_000; // 0.01 BTC (2% of lock amount) @@ -170,6 +173,17 @@ const partialRefundWithAmnesty: TauriSwapProgressEvent[] = [ btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, + // Waiting for earnest deposit timelock: 3/3, 2/3, 1/3, 0/3 blocks remaining + ...Array.from({ length: EARNEST_DEPOSIT_TARGET_BLOCKS + 1 }, (_, i) => ({ + type: "WaitingForEarnestDepositTimelockExpiration" as const, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + target_blocks: EARNEST_DEPOSIT_TARGET_BLOCKS, + blocks_until_expiry: EARNEST_DEPOSIT_TARGET_BLOCKS - i, + }, + })), { type: "BtcAmnestyPublished", content: { @@ -210,6 +224,17 @@ const partialRefundWithBurn: TauriSwapProgressEvent[] = [ btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, + // Waiting for earnest deposit timelock: 3/3, 2/3, 1/3, 0/3 blocks remaining + ...Array.from({ length: EARNEST_DEPOSIT_TARGET_BLOCKS + 1 }, (_, i) => ({ + type: "WaitingForEarnestDepositTimelockExpiration" as const, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + target_blocks: EARNEST_DEPOSIT_TARGET_BLOCKS, + blocks_until_expiry: EARNEST_DEPOSIT_TARGET_BLOCKS - i, + }, + })), { type: "BtcRefundBurnPublished", content: { @@ -250,6 +275,17 @@ const partialRefundWithBurnAndFinalAmnesty: TauriSwapProgressEvent[] = [ btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, + // Waiting for earnest deposit timelock: 3/3, 2/3, 1/3, 0/3 blocks remaining + ...Array.from({ length: EARNEST_DEPOSIT_TARGET_BLOCKS + 1 }, (_, i) => ({ + type: "WaitingForEarnestDepositTimelockExpiration" as const, + content: { + btc_partial_refund_txid: MOCK_BTC_PARTIAL_REFUND_TXID, + btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, + btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, + target_blocks: EARNEST_DEPOSIT_TARGET_BLOCKS, + blocks_until_expiry: EARNEST_DEPOSIT_TARGET_BLOCKS - i, + }, + })), { type: "BtcRefundBurnPublished", content: { diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index 1bae6a3bcc..7a9b27a846 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -23,8 +23,7 @@ type PathStep = [ /** * Determines the current step in the swap process based on the previous and latest state. - * @param prevState - The previous state of the swap process (null if it's the initial state) - * @param latestState - The latest state of the swap process + * @param state - The state of the swap process (null if it's the initial state) * @returns A tuple containing [PathType, activeStep, errorFlag] */ function getActiveStep(state: SwapState | null): PathStep | null { @@ -217,7 +216,7 @@ const RECOVERY_STEP_LABELS: Record< [RecoveryScenario.PARTIAL_REFUND]: [ { label: "Cancelling swap", duration: "~1min" }, { label: "Partial refund", duration: "~2min" }, - { label: "Claiming deposit", duration: "~30min" }, + { label: "Reclaiming deposit", duration: "~30min" }, ], [RecoveryScenario.COOPERATIVE_REDEEM]: [ { label: "Cancelling swap", duration: "~1min" }, diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 488e3c75d7..9b3dcc4aa4 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -12,9 +12,8 @@ * -> optionally BtcFinalAmnestyPublished -> BtcFinalAmnestyConfirmed (Alice grants final amnesty) */ -import { Alert, Box, Button, DialogContentText, LinearProgress, Typography } from "@mui/material"; +import { Alert, Box, Button, DialogContentText, Typography } from "@mui/material"; import { TauriSwapProgressEventContent } from "models/tauriModelExt"; -import HumanizedBitcoinBlockDuration from "renderer/components/other/HumanizedBitcoinBlockDuration"; import { useActiveSwapInfo } from "store/hooks"; import FeedbackInfoBox from "renderer/components/pages/help/FeedbackInfoBox"; import BitcoinTransactionInfoBox from "renderer/components/pages/swap/swap/components/BitcoinTransactionInfoBox"; @@ -58,45 +57,22 @@ export function WaitingForEarnestDepositTimelockExpirationPage({ target_blocks, blocks_until_expiry, }: TauriSwapProgressEventContent<"WaitingForEarnestDepositTimelockExpiration">) { - const swap = useActiveSwapInfo(); - const blocksConfirmed = target_blocks - blocks_until_expiry; - const progressPercent = Math.round((blocksConfirmed / target_blocks) * 100); const atRiskPercent = Math.round((btc_amnesty_amount / btc_lock_amount) * 100); - const additionalContent = swap ? ( - <>Refund address: {swap.btc_refund_address} - ) : null; - return ( <> - + Waiting to claim the earnest deposit ({atRiskPercent}% of your Bitcoin). - The maker can still withhold it during this time. + The timelock of {target_blocks} Bitcoin blocks needs to expire first. + The maker can choose to withhold it during this time. - - - Timelock progress: {blocksConfirmed} of {target_blocks} blocks confirmed ({progressPercent}%). - {blocks_until_expiry > 0 && ( - <> - {" "}Approximately remaining. - - )} - - - - - - + ); } From 459376150de209fc7dc5d47b015c2d73045f56ba Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Sun, 25 Jan 2026 19:58:11 +0100 Subject: [PATCH 098/146] fix compilation warnings --- Cargo.lock | 1355 ++++++++--------- Cargo.toml | 13 +- monero-oxide-ext/src/lib.rs | 8 + monero-sys/build.rs | 18 +- monero-tests/Cargo.toml | 7 +- monero-tests/tests/subaddresses.rs | 8 +- src-tauri/src/commands.rs | 3 +- swap-controller/src/main.rs | 3 +- swap-core/src/monero/primitives.rs | 1 - swap-machine/src/alice/mod.rs | 22 +- swap-machine/src/lib.rs | 1 - swap-orchestrator/tests/spec.rs | 2 + swap-p2p/Cargo.toml | 7 + swap-p2p/examples/fetch_quotes.rs | 18 +- swap-p2p/src/protocols/swap_setup/alice.rs | 2 +- swap/src/asb/event_loop.rs | 1 - swap/src/asb/rpc/server.rs | 2 +- ...rtial_refund_alice_grants_final_amnesty.rs | 5 +- 18 files changed, 717 insertions(+), 759 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c74a838e89..fff222ecce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "version_check", ] @@ -106,7 +106,7 @@ dependencies = [ "amplify_derive", "amplify_num", "ascii", - "getrandom 0.2.16", + "getrandom 0.2.17", "getrandom 0.3.4", "wasm-bindgen", ] @@ -274,7 +274,7 @@ dependencies = [ "cfg-if", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "fs-mistrust", "futures", @@ -287,7 +287,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -322,27 +322,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" -[[package]] -name = "ashpd" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" -dependencies = [ - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.9.2", - "raw-window-handle", - "serde", - "serde_repr", - "tokio", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus", -] - [[package]] name = "asn1-rs" version = "0.5.2" @@ -387,7 +366,7 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -410,7 +389,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure 0.13.2", ] @@ -422,7 +401,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure 0.13.2", ] @@ -445,7 +424,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -496,13 +475,12 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" dependencies = [ "compression-codecs", "compression-core", - "futures-core", "futures-io", "pin-project-lite", ] @@ -541,9 +519,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -576,7 +554,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -597,28 +575,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "async-task" version = "4.7.1" @@ -633,7 +589,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -760,9 +716,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.1" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" dependencies = [ "aws-lc-sys", "zeroize", @@ -770,9 +726,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" +checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" dependencies = [ "cc", "cmake", @@ -782,9 +738,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "axum-macros", @@ -816,9 +772,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", @@ -841,7 +797,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -851,7 +807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ "futures-core", - "getrandom 0.2.16", + "getrandom 0.2.17", "instant", "pin-project-lite", "rand 0.8.5", @@ -916,9 +872,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bdk" @@ -930,7 +886,7 @@ dependencies = [ "bdk-macros", "bitcoin 0.29.2", "electrum-client 0.12.1", - "getrandom 0.2.16", + "getrandom 0.2.17", "js-sys", "log", "miniscript 9.2.1", @@ -1109,7 +1065,7 @@ dependencies = [ "hmac", "jsonrpc_client", "rand 0.8.5", - "reqwest 0.12.25", + "reqwest 0.12.28", "serde", "serde_json", "sha2", @@ -1163,7 +1119,7 @@ dependencies = [ "futures", "moka", "proptest", - "reqwest 0.12.25", + "reqwest 0.12.28", "rust_decimal", "serde", "serde_json", @@ -1250,7 +1206,7 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1333,7 +1289,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1379,9 +1335,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "by_address" @@ -1474,9 +1430,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ "serde_core", ] @@ -1506,7 +1462,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1516,7 +1472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", ] [[package]] @@ -1536,9 +1492,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.49" +version = "1.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", "jobserver", @@ -1611,9 +1567,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", "js-sys", @@ -1678,9 +1634,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -1688,9 +1644,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -1707,14 +1663,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "clipboard-win" @@ -1727,18 +1683,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b042e5d8a74ae91bb0961acd039822472ec99f8ab0948cbf6d1369588f8be586" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] [[package]] name = "coarsetime" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91849686042de1b41cd81490edc83afbcb0abe5a9b6f2c4114f23ce8cca1bcf4" +checksum = "e58eb270476aa4fc7843849f8a35063e8743b4dbcdf6dd0f8ea0886980c204c2" dependencies = [ "libc", "wasix", @@ -1764,11 +1720,11 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" -version = "3.0.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1783,9 +1739,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.2.1" +version = "7.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" dependencies = [ "crossterm", "unicode-segmentation", @@ -1799,7 +1755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fd9b9dc67f2b3024582ec6d861950f0af0aeaabb8350ccda1f0e51ff8e5895c" dependencies = [ "compose_spec_macros", - "indexmap 2.12.1", + "indexmap 2.13.0", "ipnet", "itoa", "serde", @@ -1816,14 +1772,14 @@ checksum = "b77735bd89be8da01c8d7e61faec5a9ccb0e313cece3c773c6b3ae251b90c7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "compression-codecs" -version = "0.4.35" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" dependencies = [ "compression-core", "flate2", @@ -1871,9 +1827,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" dependencies = [ "encode_unicode", "libc", @@ -2035,7 +1991,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.53", + "clap 4.5.54", "criterion-plot", "itertools 0.13.0", "num-traits", @@ -2200,7 +2156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2210,7 +2166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2232,7 +2188,7 @@ dependencies = [ "cuprate-hex", "paste", "ref-cast", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2241,7 +2197,7 @@ version = "0.1.0" source = "git+https://github.com/Cuprate/cuprate.git#27eec55f5b7851a2b36e158065a6be95c091e904" dependencies = [ "bytes", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2279,7 +2235,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2298,9 +2254,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.190" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7620f6cfc4dcca21f2b085b7a890e16c60fd66f560cd69ee60594908dc72ab1" +checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e" dependencies = [ "cc", "cxx-build", @@ -2313,49 +2269,49 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.190" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9bc1a22964ff6a355fbec24cf68266a0ed28f8b84c0864c386474ea3d0e479" +checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e" dependencies = [ "cc", "codespan-reporting", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro2", "quote", "scratch", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "cxxbridge-cmd" -version = "1.0.190" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f29a879d35f7906e3c9b77d7a1005a6a0787d330c09dfe4ffb5f617728cb44" +checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328" dependencies = [ - "clap 4.5.53", + "clap 4.5.54", "codespan-reporting", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "cxxbridge-flags" -version = "1.0.190" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67109015f93f683e364085aa6489a5b2118b4a40058482101d699936a7836d6" +checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a" [[package]] name = "cxxbridge-macro" -version = "1.0.190" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d187e019e7b05a1f3e69a8396b70800ee867aa9fc2ab972761173ccee03742df" +checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2437,7 +2393,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2451,7 +2407,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2484,7 +2440,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2495,20 +2451,20 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "data-encoding-macro" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" +checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2516,12 +2472,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" +checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2610,14 +2566,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "337f65eb93d9996551b9442423480eca4532586b337484446eb5138d0cd8fcf0" dependencies = [ "heck 0.5.0", - "indexmap 2.12.1", + "indexmap 2.13.0", "itertools 0.14.0", "proc-macro-crate 3.4.0", "proc-macro2", "quote", "sha3", "strum 0.27.2", - "syn 2.0.111", + "syn 2.0.114", "void", ] @@ -2629,7 +2585,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2650,7 +2606,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2681,7 +2637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2704,29 +2660,29 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "derive_more" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.111", + "syn 2.0.114", "unicode-xid", ] @@ -2889,16 +2845,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.9", + "syn 2.0.114", ] [[package]] @@ -2921,7 +2868,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2962,9 +2909,9 @@ dependencies = [ [[package]] name = "dtoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dtoa-short" @@ -3088,7 +3035,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls 0.23.35", + "rustls 0.23.36", "serde", "serde_json", "webpki-roots 0.25.4", @@ -3136,7 +3083,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", "vswhom", "winreg 0.55.0", ] @@ -3183,7 +3130,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3196,7 +3143,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3208,7 +3155,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3229,7 +3176,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3250,7 +3197,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3363,7 +3310,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3427,21 +3374,20 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.60.2", ] [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" [[package]] name = "fixedbitset" @@ -3451,13 +3397,13 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", - "libz-rs-sys", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -3522,7 +3468,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3556,7 +3502,7 @@ dependencies = [ "libc", "pwd-grp", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "walkdir", ] @@ -3602,7 +3548,7 @@ version = "0.5.1" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ "fslock-arti-fork", - "thiserror 2.0.17", + "thiserror 2.0.18", "winapi", ] @@ -3713,7 +3659,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3733,7 +3679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.35", + "rustls 0.23.36", "rustls-pki-types", ] @@ -3927,9 +3873,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -3961,7 +3907,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4053,7 +3999,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4161,7 +4107,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4176,7 +4122,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -4185,9 +4131,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -4195,7 +4141,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -4548,7 +4494,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.12", + "h2 0.4.13", "http 1.4.0", "http-body 1.0.1", "httparse", @@ -4571,13 +4517,13 @@ dependencies = [ "hyper 1.8.1", "hyper-util", "log", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 1.0.4", + "webpki-roots 1.0.5", ] [[package]] @@ -4611,7 +4557,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2 0.6.2", "system-configuration 0.6.1", "tokio", "tower-layer", @@ -4841,9 +4787,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -4930,9 +4876,9 @@ dependencies = [ [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -4983,9 +4929,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "javascriptcore-rs" @@ -5044,9 +4990,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -5092,7 +5038,7 @@ source = "git+https://github.com/delta1/rust-jsonrpc-client.git?rev=3b6081697cd6 dependencies = [ "async-trait", "jsonrpc_client_macro", - "reqwest 0.12.25", + "reqwest 0.12.28", "serde", "serde_json", "url", @@ -5141,7 +5087,7 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tower", "tracing", @@ -5160,11 +5106,11 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.35", + "rustls 0.23.36", "rustls-platform-verifier", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tower", "url", @@ -5180,7 +5126,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5202,7 +5148,7 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", @@ -5219,7 +5165,7 @@ dependencies = [ "http 1.4.0", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -5280,7 +5226,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 2.12.1", + "indexmap 2.13.0", "selectors", ] @@ -5313,7 +5259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading 0.7.4", + "libloading", "once_cell", ] @@ -5325,9 +5271,9 @@ checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libgit2-sys" @@ -5351,16 +5297,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - [[package]] name = "liblzma" version = "0.4.5" @@ -5372,9 +5308,9 @@ dependencies = [ [[package]] name = "liblzma-sys" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736" +checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186" dependencies = [ "cc", "libc", @@ -5383,9 +5319,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libp2p" @@ -5397,7 +5333,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom 0.2.16", + "getrandom 0.2.17", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -5509,7 +5445,7 @@ dependencies = [ "fnv", "futures", "futures-ticker", - "getrandom 0.2.16", + "getrandom 0.2.17", "hex_fmt", "instant", "libp2p-core", @@ -5566,7 +5502,7 @@ dependencies = [ "ring 0.17.14", "serde", "sha2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "zeroize", ] @@ -5700,7 +5636,7 @@ dependencies = [ "quinn", "rand 0.8.5", "ring 0.17.14", - "rustls 0.23.35", + "rustls 0.23.36", "socket2 0.5.10", "thiserror 1.0.69", "tokio", @@ -5787,7 +5723,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5838,7 +5774,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.17.14", - "rustls 0.23.35", + "rustls 0.23.36", "rustls-webpki 0.101.7", "thiserror 1.0.69", "x509-parser 0.16.0", @@ -5920,13 +5856,13 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.10.0", "libc", - "redox_syscall 0.5.18", + "redox_syscall 0.7.0", ] [[package]] @@ -5940,15 +5876,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libz-rs-sys" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15413ef615ad868d4d65dce091cb233b229419c7c0c4bcaa746c0901c49ff39c" -dependencies = [ - "zlib-rs", -] - [[package]] name = "libz-sys" version = "1.1.23" @@ -6055,13 +5982,13 @@ dependencies = [ [[package]] name = "match-lookup" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" +checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -6072,7 +5999,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6240,9 +6167,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" dependencies = [ "async-lock", "crossbeam-channel", @@ -6253,7 +6180,6 @@ dependencies = [ "futures-util", "parking_lot 0.12.5", "portable-atomic", - "rustc_version", "smallvec", "tagptr", "uuid", @@ -6262,20 +6188,20 @@ dependencies = [ [[package]] name = "monero-address" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "monero-base58", "monero-ed25519", "monero-io", "monero-primitives", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "monero-base58" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "monero-primitives", "std-shims", @@ -6284,7 +6210,7 @@ dependencies = [ [[package]] name = "monero-borromean" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "monero-ed25519", @@ -6296,7 +6222,7 @@ dependencies = [ [[package]] name = "monero-bulletproofs" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "monero-bulletproofs-generators", @@ -6305,14 +6231,14 @@ dependencies = [ "monero-primitives", "rand_core 0.6.4", "std-shims", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "monero-bulletproofs-generators" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "monero-ed25519", @@ -6324,7 +6250,7 @@ dependencies = [ [[package]] name = "monero-clsag" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "group", @@ -6334,14 +6260,14 @@ dependencies = [ "rand_core 0.6.4", "std-shims", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "monero-daemon-rpc" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "hex", "monero-address", @@ -6356,7 +6282,7 @@ dependencies = [ [[package]] name = "monero-ed25519" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "crypto-bigint", "curve25519-dalek", @@ -6371,7 +6297,7 @@ dependencies = [ [[package]] name = "monero-epee" version = "0.2.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" [[package]] name = "monero-harness" @@ -6384,7 +6310,7 @@ dependencies = [ "monero-simple-request-rpc", "monero-sys", "rand 0.8.5", - "reqwest 0.12.25", + "reqwest 0.12.28", "testcontainers", "tokio", "tracing", @@ -6394,19 +6320,19 @@ dependencies = [ [[package]] name = "monero-interface" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "hex", "monero-oxide", "std-shims", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "monero-io" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "std-shims", ] @@ -6414,20 +6340,20 @@ dependencies = [ [[package]] name = "monero-mlsag" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "monero-ed25519", "monero-io", "std-shims", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "monero-oxide" version = "0.1.4-alpha" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "hex-literal", @@ -6451,7 +6377,7 @@ dependencies = [ "curve25519-dalek-ng", "hex", "monero-address", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "serde", "typeshare", ] @@ -6459,7 +6385,7 @@ dependencies = [ [[package]] name = "monero-primitives" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "sha3", ] @@ -6472,7 +6398,7 @@ dependencies = [ "arti-client", "axum", "chrono", - "clap 4.5.53", + "clap 4.5.54", "crossbeam", "cuprate-epee-encoding", "futures", @@ -6511,7 +6437,7 @@ dependencies = [ [[package]] name = "monero-simple-request-rpc" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "digest_auth", "hex", @@ -6543,7 +6469,7 @@ dependencies = [ "sqlx", "swap-serde", "tempfile", - "thiserror 2.0.17", + "thiserror 2.0.18", "throttle", "tokio", "tracing", @@ -6565,7 +6491,7 @@ dependencies = [ "monero-oxide-ext", "monero-simple-request-rpc", "monero-sys", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "monero-wallet-ng", "testcontainers", "tokio", @@ -6588,7 +6514,7 @@ dependencies = [ "monero-oxide-ext", "monero-simple-request-rpc", "monero-sys", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "monero-wallet-ng", "swap-core", "throttle", @@ -6602,7 +6528,7 @@ dependencies = [ [[package]] name = "monero-wallet" version = "0.1.0" -source = "git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite#1a8662faf352e0b7a7b11e157286c0fdb4a65db4" +source = "git+https://github.com/kayabaNerve/monero-oxide.git#c8be5d3d1287669946a83fbfcb296ce2a8852e47" dependencies = [ "curve25519-dalek", "hex", @@ -6616,7 +6542,7 @@ dependencies = [ "rand_distr", "std-shims", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "zeroize", ] @@ -6632,7 +6558,7 @@ dependencies = [ "monero-interface", "monero-oxide", "monero-simple-request-rpc", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "serde", "serde_json", "thiserror 1.0.69", @@ -6643,9 +6569,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" dependencies = [ "num-traits", "pxfm", @@ -6668,7 +6594,7 @@ dependencies = [ "once_cell", "png 0.17.16", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "windows-sys 0.60.2", ] @@ -6737,7 +6663,7 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.6", "openssl-sys", "schannel", "security-framework 2.11.1", @@ -6823,17 +6749,17 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "netlink-sys" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +checksum = "cd6c30ed10fa69cc491d491b85cc971f6bdeb8e7367b7cde2ee6cc878d583fae" dependencies = [ "bytes", - "futures", + "futures-util", "libc", "log", "tokio", @@ -6875,7 +6801,6 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", - "memoffset", ] [[package]] @@ -6934,15 +6859,18 @@ dependencies = [ [[package]] name = "notify-types" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.10.0", +] [[package]] name = "ntapi" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" dependencies = [ "winapi", ] @@ -6984,9 +6912,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -7047,7 +6975,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7378,7 +7306,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7387,6 +7315,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "openssl-sys" version = "0.9.111" @@ -7454,7 +7388,7 @@ dependencies = [ "objc2-osa-kit", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -7623,9 +7557,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.4" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" dependencies = [ "memchr", "ucd-trie", @@ -7633,9 +7567,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.4" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f" +checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" dependencies = [ "pest", "pest_generator", @@ -7643,22 +7577,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.4" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625" +checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "pest_meta" -version = "2.8.4" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82" +checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" dependencies = [ "pest", "sha2", @@ -7672,7 +7606,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap 2.12.1", + "indexmap 2.13.0", ] [[package]] @@ -7800,7 +7734,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7813,7 +7747,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7869,7 +7803,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7929,8 +7863,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", - "indexmap 2.12.1", - "quick-xml 0.38.4", + "indexmap 2.13.0", + "quick-xml", "serde", "time", ] @@ -8028,9 +7962,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "postage" @@ -8064,9 +7998,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppmd-rust" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" +checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" [[package]] name = "ppv-lite86" @@ -8099,7 +8033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93980406f12d9f8140ed5abe7155acb10bb1e69ea55c88960b9c2f117445ef96" dependencies = [ "equivalent", - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", ] @@ -8129,7 +8063,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.9", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -8175,7 +8109,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8186,9 +8120,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -8213,7 +8147,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8264,7 +8198,7 @@ dependencies = [ "derive-deftly", "libc", "paste", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8323,15 +8257,6 @@ dependencies = [ "unsigned-varint 0.8.0", ] -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quick-xml" version = "0.38.4" @@ -8360,7 +8285,7 @@ checksum = "f71ee38b42f8459a88d3362be6f9b841ad2d5421844f61eb1c59c11bff3ac14a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8376,9 +8301,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.35", - "socket2 0.6.1", - "thiserror 2.0.17", + "rustls 0.23.36", + "socket2 0.6.2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -8396,10 +8321,10 @@ dependencies = [ "rand 0.9.2", "ring 0.17.14", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.36", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -8414,16 +8339,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.2", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -8482,7 +8407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -8512,7 +8437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -8530,14 +8455,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -8568,7 +8493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16df48f071248e67b8fc5e866d9448d45c08ad8b672baaaf796e2f15e606ff0" dependencies = [ "libc", - "rand_core 0.9.3", + "rand_core 0.9.5", "winapi", ] @@ -8587,7 +8512,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -8655,13 +8580,22 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags 2.10.0", +] + [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] @@ -8672,9 +8606,9 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8694,7 +8628,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8797,15 +8731,15 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.25" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", - "h2 0.4.12", + "h2 0.4.13", "http 1.4.0", "http-body 1.0.1", "http-body-util", @@ -8817,8 +8751,8 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", "rustls-pki-types", "serde", "serde_json", @@ -8835,7 +8769,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.4", + "webpki-roots 1.0.5", ] [[package]] @@ -8861,11 +8795,10 @@ dependencies = [ [[package]] name = "rfd" -version = "0.15.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" dependencies = [ - "ashpd", "block2", "dispatch2", "glib-sys", @@ -8881,7 +8814,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -8907,7 +8840,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted 0.9.0", "windows-sys 0.52.0", @@ -8915,9 +8848,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -8933,9 +8866,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -8950,9 +8883,9 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rsa" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest 0.10.7", @@ -9004,9 +8937,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.39.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ "arrayvec", "borsh", @@ -9044,9 +8977,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags 2.10.0", "errno", @@ -9094,16 +9027,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] @@ -9114,7 +9047,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ - "openssl-probe", + "openssl-probe 0.1.6", "rustls 0.19.1", "schannel", "security-framework 2.11.1", @@ -9122,11 +9055,11 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", "security-framework 3.5.1", @@ -9143,9 +9076,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -9162,10 +9095,10 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", "rustls-platform-verifier-android", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs 0.26.11", @@ -9190,9 +9123,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "aws-lc-rs", "ring 0.17.14", @@ -9253,20 +9186,20 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "safelog" version = "0.7.1" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "either", "fluid-let", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -9325,9 +9258,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -9344,15 +9277,9 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.111", + "syn 2.0.114", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -9644,7 +9571,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9655,7 +9582,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9670,15 +9597,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -9700,7 +9627,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9714,9 +9641,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ "serde_core", ] @@ -9753,9 +9680,9 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.1.0", + "schemars 1.2.0", "serde_core", "serde_json", "serde_with_macros 3.16.1", @@ -9783,7 +9710,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9792,7 +9719,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "ryu", "serde", @@ -9818,7 +9745,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9924,10 +9851,11 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -10026,7 +9954,7 @@ dependencies = [ "paste", "serde", "slotmap", - "thiserror 2.0.17", + "thiserror 2.0.18", "void", ] @@ -10068,9 +9996,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -10216,7 +10144,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.12.1", + "indexmap 2.13.0", "log", "memchr", "once_cell", @@ -10247,7 +10175,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -10270,7 +10198,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.111", + "syn 2.0.114", "tempfile", "tokio", "url", @@ -10553,7 +10481,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -10565,7 +10493,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -10616,9 +10544,9 @@ dependencies = [ "proptest", "rand 0.8.5", "regex", - "reqwest 0.12.25", + "reqwest 0.12.28", "rust_decimal", - "rustls 0.23.35", + "rustls 0.23.36", "semver", "serde", "serde_json", @@ -10667,9 +10595,9 @@ dependencies = [ "monero-address", "monero-rpc-pool", "monero-sys", - "reqwest 0.12.25", + "reqwest 0.12.28", "rust_decimal", - "rustls 0.23.35", + "rustls 0.23.36", "serde", "serde_json", "structopt", @@ -10691,7 +10619,7 @@ name = "swap-controller" version = "3.6.7" dependencies = [ "anyhow", - "clap 4.5.53", + "clap 4.5.54", "comfy-table", "jsonrpsee", "monero-oxide-ext", @@ -10726,7 +10654,7 @@ dependencies = [ "futures", "monero-address", "monero-oxide-ext", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "proptest", "rand 0.8.5", "rand_chacha 0.3.1", @@ -10763,7 +10691,7 @@ dependencies = [ "anyhow", "bitcoin 0.32.8", "config", - "console 0.16.1", + "console 0.16.2", "dialoguer", "libp2p", "monero-address", @@ -10773,7 +10701,7 @@ dependencies = [ "swap-serde", "thiserror 1.0.69", "time", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", "tracing", "url", ] @@ -10787,7 +10715,7 @@ dependencies = [ "bitcoin 0.32.8", "futures", "monero-oxide-ext", - "reqwest 0.12.25", + "reqwest 0.12.28", "rust_decimal", "serde", "serde_json", @@ -10847,7 +10775,7 @@ dependencies = [ "monero-address", "serde_yaml", "swap-env", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", "url", "vergen 8.3.2", ] @@ -10857,6 +10785,7 @@ name = "swap-p2p" version = "0.1.0" dependencies = [ "anyhow", + "arti-client", "async-trait", "asynchronous-codec 0.7.0", "backoff", @@ -10865,6 +10794,7 @@ dependencies = [ "bmrng", "futures", "libp2p", + "libp2p-tor", "monero-address", "rand 0.8.5", "rust_decimal", @@ -10878,7 +10808,9 @@ dependencies = [ "swap-serde", "thiserror 1.0.69", "tokio", + "tor-rtcompat", "tracing", + "tracing-subscriber", "typeshare", "unsigned-varint 0.8.0", "uuid", @@ -10904,7 +10836,7 @@ dependencies = [ "libp2p", "monero-address", "monero-oxide-ext", - "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git?branch=rpc-rewrite)", + "monero-wallet 0.1.0 (git+https://github.com/kayabaNerve/monero-oxide.git)", "serde", "serde_json", "thiserror 1.0.69", @@ -10935,9 +10867,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -10979,7 +10911,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -11105,7 +11037,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -11161,7 +11093,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.12.25", + "reqwest 0.12.28", "serde", "serde_json", "serde_repr", @@ -11172,7 +11104,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tray-icon", "url", @@ -11200,7 +11132,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", "walkdir", ] @@ -11222,9 +11154,9 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.111", + "syn 2.0.114", "tauri-utils", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "url", "uuid", @@ -11240,7 +11172,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "tauri-codegen", "tauri-utils", ] @@ -11258,7 +11190,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", "walkdir", ] @@ -11268,13 +11200,13 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28e78fb2c09a81546bcd376d34db4bda5769270d00990daa9f0d6e7ac1107e25" dependencies = [ - "clap 4.5.53", + "clap 4.5.54", "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -11289,14 +11221,14 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "tauri-plugin-dialog" -version = "2.4.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313f8138692ddc4a2127c4c9607d616a46f5c042e77b3722450866da0aad2f19" +checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" dependencies = [ "log", "raw-window-handle", @@ -11306,15 +11238,15 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", ] [[package]] name = "tauri-plugin-fs" -version = "2.4.4" +version = "2.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47df422695255ecbe7bac7012440eddaeefd026656171eac9559f5243d3230d9" +checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804" dependencies = [ "anyhow", "dunce", @@ -11327,16 +11259,16 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.17", - "toml 0.9.8", + "thiserror 2.0.18", + "toml 0.9.11+spec-1.1.0", "url", ] [[package]] name = "tauri-plugin-opener" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26b72571d25dee25667940027114e60f569fc3974f8cefbe50c2cbc5fd65e3b" +checksum = "fc624469b06f59f5a29f874bbc61a2ed737c0f9c23ef09855a292c389c42e83f" dependencies = [ "dunce", "glob", @@ -11348,7 +11280,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", "windows 0.61.3", "zbus", @@ -11366,14 +11298,14 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" -version = "2.3.6" +version = "2.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd707f8c86b4e3004e2c141fa24351f1909ba40ce1b8437e30d5ed5277dd3710" +checksum = "acba6b5ca527a96cdfcc96ae09b09ccb91ddff5e33978ca6873b96ea16bb404c" dependencies = [ "serde", "serde_json", "tauri", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "windows-sys 0.60.2", "zbus", @@ -11381,16 +11313,16 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a77036340a97eb5bbe1b3209c31e5f27f75e6f92a52fd9dd4b211ef08bf310" +checksum = "5ca1a8ff83c269b115e98726ffc13f9e548a10161544a92ad121d6d0a96e16ea" dependencies = [ "dunce", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", ] @@ -11411,7 +11343,7 @@ dependencies = [ "minisign-verify", "osakit", "percent-encoding", - "reqwest 0.12.25", + "reqwest 0.12.28", "semver", "serde", "serde_json", @@ -11419,7 +11351,7 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "url", @@ -11445,7 +11377,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", "webkit2gtk", "webview2-com", @@ -11510,8 +11442,8 @@ dependencies = [ "serde_json", "serde_with 3.16.1", "swift-rs", - "thiserror 2.0.17", - "toml 0.9.8", + "thiserror 2.0.18", + "toml 0.9.11+spec-1.1.0", "url", "urlpattern", "uuid", @@ -11526,14 +11458,14 @@ checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" dependencies = [ "dunce", "embed-resource", - "toml 0.9.8", + "toml 0.9.11+spec-1.1.0", ] [[package]] name = "tempfile" -version = "3.23.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", "getrandom 0.3.4", @@ -11599,11 +11531,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -11614,18 +11546,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -11660,9 +11592,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -11670,22 +11602,22 @@ dependencies = [ "num-conv", "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -11729,9 +11661,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", @@ -11739,9 +11671,8 @@ dependencies = [ "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.2", "tokio-macros", - "tracing", "windows-sys 0.61.2", ] @@ -11753,7 +11684,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -11783,15 +11714,15 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.36", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -11801,12 +11732,10 @@ dependencies = [ [[package]] name = "tokio-test" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +checksum = "3f6d24790a10a7af737693a3e8f1d03faef7e6ca0cc99aae5066f533766de545" dependencies = [ - "async-stream", - "bytes", "futures-core", "tokio", "tokio-stream", @@ -11831,9 +11760,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -11858,14 +11787,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.8" +version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde_core", - "serde_spanned 1.0.3", - "toml_datetime 0.7.3", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow 0.7.14", @@ -11882,9 +11811,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] @@ -11895,7 +11824,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "toml_datetime 0.6.3", "winnow 0.5.40", ] @@ -11906,7 +11835,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.3", @@ -11915,30 +11844,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.9" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.12.1", - "toml_datetime 0.7.3", + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow 0.7.14", ] [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow 0.7.14", ] [[package]] name = "toml_writer" -version = "1.0.4" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tor-async-utils" @@ -11951,7 +11880,7 @@ dependencies = [ "oneshot-fused-workaround", "pin-project", "postage", - "thiserror 2.0.17", + "thiserror 2.0.18", "void", ] @@ -11960,7 +11889,7 @@ name = "tor-basic-utils" version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ - "derive_more 2.1.0", + "derive_more 2.1.1", "hex", "itertools 0.14.0", "libc", @@ -11970,7 +11899,7 @@ dependencies = [ "serde", "slab", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -11984,7 +11913,7 @@ dependencies = [ "educe", "getrandom 0.3.4", "safelog", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-llcrypto", "zeroize", @@ -12000,13 +11929,13 @@ dependencies = [ "bytes", "caret", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "itertools 0.14.0", "paste", "rand 0.9.2", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-cert", @@ -12027,9 +11956,9 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "caret", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-checkable", "tor-error", @@ -12044,7 +11973,7 @@ dependencies = [ "async-trait", "caret", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "futures", "oneshot-fused-workaround", @@ -12052,7 +11981,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -12078,7 +12007,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "humantime", "signature", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-llcrypto", ] @@ -12092,7 +12021,7 @@ dependencies = [ "cfg-if", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "downcast-rs 2.0.2", "dyn-clone", "educe", @@ -12106,7 +12035,7 @@ dependencies = [ "retry-error", "safelog", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -12153,8 +12082,8 @@ dependencies = [ "serde-value", "serde_ignored", "strum 0.27.2", - "thiserror 2.0.17", - "toml 0.9.8", + "thiserror 2.0.18", + "toml 0.9.11+spec-1.1.0", "tor-basic-utils", "tor-error", "tor-rtcompat", @@ -12170,7 +12099,7 @@ dependencies = [ "directories", "serde", "shellexpand", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-general-addr", ] @@ -12182,7 +12111,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "digest 0.10.7", "hex", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-llcrypto", ] @@ -12193,7 +12122,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "async-compression", "base64ct", - "derive_more 2.1.0", + "derive_more 2.1.1", "futures", "hex", "http 1.4.0", @@ -12201,7 +12130,7 @@ dependencies = [ "httpdate", "itertools 0.14.0", "memchr", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-circmgr", "tor-error", "tor-hscrypto", @@ -12241,7 +12170,7 @@ dependencies = [ "async-trait", "base64ct", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "educe", "event-listener", @@ -12265,7 +12194,7 @@ dependencies = [ "signature", "static_assertions", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -12292,13 +12221,13 @@ name = "tor-error" version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ - "derive_more 2.1.0", + "derive_more 2.1.1", "futures", "paste", "retry-error", "static_assertions", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", "void", ] @@ -12308,8 +12237,8 @@ name = "tor-general-addr" version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ - "derive_more 2.1.0", - "thiserror 2.0.17", + "derive_more 2.1.1", + "thiserror 2.0.18", "void", ] @@ -12322,7 +12251,7 @@ dependencies = [ "base64ct", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "dyn-clone", "educe", "futures", @@ -12337,7 +12266,7 @@ dependencies = [ "safelog", "serde", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -12362,7 +12291,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "async-trait", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "either", "futures", @@ -12374,7 +12303,7 @@ dependencies = [ "safelog", "slotmap-careful", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -12406,7 +12335,7 @@ dependencies = [ "cipher", "data-encoding", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "hex", "humantime", @@ -12417,7 +12346,7 @@ dependencies = [ "serde", "signature", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-error", @@ -12440,7 +12369,7 @@ dependencies = [ "cfg-if", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "educe", "fs-mistrust", @@ -12454,13 +12383,13 @@ dependencies = [ "oneshot-fused-workaround", "postage", "rand 0.9.2", - "rand_core 0.9.3", + "rand_core 0.9.5", "retry-error", "safelog", "serde", "serde_with 3.16.1", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -12492,14 +12421,14 @@ version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "downcast-rs 2.0.2", "paste", "rand 0.9.2", "rsa", "signature", "ssh-key", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-cert", "tor-checkable", @@ -12517,7 +12446,7 @@ dependencies = [ "cfg-if", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "downcast-rs 2.0.2", "dyn-clone", "fs-mistrust", @@ -12530,7 +12459,7 @@ dependencies = [ "serde", "signature", "ssh-key", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-config", @@ -12556,14 +12485,14 @@ dependencies = [ "caret", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "hex", "itertools 0.14.0", "safelog", "serde", "serde_with 3.16.1", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-basic-utils", "tor-bytes", "tor-config", @@ -12583,7 +12512,7 @@ dependencies = [ "curve25519-dalek", "der-parser 10.0.0", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "ed25519-dalek", "educe", @@ -12592,7 +12521,7 @@ dependencies = [ "rand 0.9.2", "rand_chacha 0.9.0", "rand_core 0.6.4", - "rand_core 0.9.3", + "rand_core 0.9.5", "rand_jitter", "rdrand", "rsa", @@ -12603,7 +12532,7 @@ dependencies = [ "sha3", "signature", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-memquota", "visibility", @@ -12618,7 +12547,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "futures", "humantime", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-rtcompat", "tracing", @@ -12632,7 +12561,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "cfg-if", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "dyn-clone", "educe", "futures", @@ -12643,7 +12572,7 @@ dependencies = [ "slotmap-careful", "static_assertions", "sysinfo", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -12661,7 +12590,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "async-trait", "bitflags 2.10.0", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "futures", "hex", @@ -12671,7 +12600,7 @@ dependencies = [ "rand 0.9.2", "serde", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-basic-utils", "tor-error", @@ -12695,7 +12624,7 @@ dependencies = [ "cipher", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "educe", "enumset", @@ -12712,7 +12641,7 @@ dependencies = [ "smallvec", "strum 0.27.2", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tinystr", "tor-basic-utils", @@ -12738,7 +12667,7 @@ source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_art dependencies = [ "amplify", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "filetime", "fs-mistrust", "fslock", @@ -12750,7 +12679,7 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tor-async-utils", "tor-basic-utils", @@ -12775,7 +12704,7 @@ dependencies = [ "criterion-cycles-per-byte", "derive-deftly", "derive_builder_fork_arti", - "derive_more 2.1.0", + "derive_more 2.1.1", "digest 0.10.7", "educe", "enum_dispatch", @@ -12789,14 +12718,14 @@ dependencies = [ "pin-project", "postage", "rand 0.9.2", - "rand_core 0.9.3", + "rand_core 0.9.5", "safelog", "slotmap-careful", "smallvec", "static_assertions", "subtle", "sync_wrapper 1.0.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tor-async-utils", @@ -12832,7 +12761,7 @@ dependencies = [ "caret", "paste", "serde_with 3.16.1", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", ] @@ -12842,7 +12771,7 @@ version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "humantime", "tor-cert", "tor-checkable", @@ -12875,7 +12804,7 @@ dependencies = [ "async_executors", "asynchronous-codec 0.7.0", "coarsetime", - "derive_more 2.1.0", + "derive_more 2.1.1", "dyn-clone", "educe", "futures", @@ -12885,9 +12814,9 @@ dependencies = [ "paste", "pin-project", "rustls-pki-types", - "rustls-webpki 0.103.8", - "socket2 0.6.1", - "thiserror 2.0.17", + "rustls-webpki 0.103.9", + "socket2 0.6.2", + "thiserror 2.0.18", "tokio", "tokio-util", "tor-error", @@ -12905,7 +12834,7 @@ dependencies = [ "assert_matches", "async-trait", "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "educe", "futures", "humantime", @@ -12915,7 +12844,7 @@ dependencies = [ "priority-queue", "slotmap-careful", "strum 0.27.2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-error", "tor-general-addr", "tor-rtcompat", @@ -12935,7 +12864,7 @@ dependencies = [ "educe", "safelog", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-bytes", "tor-error", ] @@ -12946,17 +12875,17 @@ version = "0.37.0" source = "git+https://github.com/eigenwallet/arti?branch=downgraded_rusqlite_arti_1_8_0#2a5db5823e2a5eb413d8ad433a4d3aba902bac07" dependencies = [ "derive-deftly", - "derive_more 2.1.0", + "derive_more 2.1.1", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tor-memquota", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -13000,9 +12929,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -13017,7 +12946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" dependencies = [ "crossbeam-channel", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tracing-subscriber", ] @@ -13030,14 +12959,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -13113,14 +13042,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "tray-icon" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d5572781bee8e3f994d7467084e1b1fd7a93ce66bd480f8156ba89dee55a2b" +checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" dependencies = [ "crossbeam-channel", "dirs", @@ -13134,7 +13063,7 @@ dependencies = [ "once_cell", "png 0.17.16", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "windows-sys 0.60.2", ] @@ -13179,9 +13108,9 @@ dependencies = [ [[package]] name = "typed-index-collections" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5318ee4ce62a4e948a33915574021a7a953d83e84fba6e25c72ffcfd7dad35ff" +checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" dependencies = [ "bincode 2.0.1", "serde", @@ -13201,9 +13130,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "typeshare" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19be0f411120091e76e13e5a0186d8e2bcc3e7e244afdb70152197f1a8486ceb" +checksum = "da1bf9fe204f358ffea7f8f779b53923a20278b3ab8e8d97962c5e1b3a54edb7" dependencies = [ "chrono", "serde", @@ -13218,7 +13147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "621963e302416b389a1ec177397e9e62de849a78bd8205d428608553def75350" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -13308,9 +13237,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-bidi" @@ -13411,7 +13340,7 @@ name = "unstoppableswap-gui-rs" version = "3.6.7" dependencies = [ "dfx-swiss-sdk", - "rustls 0.23.35", + "rustls 0.23.36", "serde", "serde_json", "swap", @@ -13452,14 +13381,15 @@ checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -13494,9 +13424,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" dependencies = [ "getrandom 0.3.4", "js-sys", @@ -13537,15 +13467,15 @@ dependencies = [ [[package]] name = "vergen" -version = "9.0.6" +version = "9.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" +checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" dependencies = [ "anyhow", "derive_builder", "rustversion", "time", - "vergen-lib", + "vergen-lib 9.1.0", ] [[package]] @@ -13559,8 +13489,8 @@ dependencies = [ "git2", "rustversion", "time", - "vergen 9.0.6", - "vergen-lib", + "vergen 9.1.0", + "vergen-lib 0.1.6", ] [[package]] @@ -13574,6 +13504,17 @@ dependencies = [ "rustversion", ] +[[package]] +name = "vergen-lib" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + [[package]] name = "version-compare" version = "0.2.1" @@ -13600,7 +13541,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -13671,9 +13612,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] @@ -13686,18 +13627,18 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasix" -version = "0.12.21" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d" +checksum = "1757e0d1f8456693c7e5c6c629bdb54884e032aa0bb53c155f6a39f94440d332" dependencies = [ "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -13708,11 +13649,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -13721,9 +13663,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -13731,22 +13673,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] @@ -13766,23 +13708,22 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" dependencies = [ "cc", "downcast-rs 1.2.1", "rustix", - "scoped-tls", "smallvec", "wayland-sys", ] [[package]] name = "wayland-client" -version = "0.31.11" +version = "0.31.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" dependencies = [ "bitflags 2.10.0", "rustix", @@ -13792,9 +13733,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.9" +version = "0.32.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -13804,9 +13745,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" +checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -13817,23 +13758,21 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" +checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3" dependencies = [ "proc-macro2", - "quick-xml 0.37.5", + "quick-xml", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd" dependencies = [ - "dlib", - "log", "pkg-config", ] @@ -13845,9 +13784,9 @@ checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -13933,14 +13872,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.4", + "webpki-root-certs 1.0.5", ] [[package]] name = "webpki-root-certs" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" dependencies = [ "rustls-pki-types", ] @@ -13971,18 +13910,18 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.38.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", @@ -13994,22 +13933,22 @@ dependencies = [ [[package]] name = "webview2-com-macros" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "webview2-com-sys" -version = "0.38.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", "windows 0.61.3", "windows-core 0.61.2", ] @@ -14169,7 +14108,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -14180,7 +14119,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -14616,9 +14555,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "wl-clipboard-rs" @@ -14630,7 +14569,7 @@ dependencies = [ "log", "os_pipe", "rustix", - "thiserror 2.0.17", + "thiserror 2.0.18", "tree_magic_mini", "wayland-backend", "wayland-client", @@ -14678,7 +14617,7 @@ dependencies = [ "sha2", "soup3", "tao-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", "webkit2gtk", "webkit2gtk-sys", @@ -14872,15 +14811,15 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure 0.13.2", ] [[package]] name = "zbus" -version = "5.12.0" +version = "5.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" +checksum = "1bfeff997a0aaa3eb20c4652baf788d2dfa6d2839a0ead0b3ff69ce2f9c4bdd1" dependencies = [ "async-broadcast", "async-executor", @@ -14896,11 +14835,11 @@ dependencies = [ "futures-core", "futures-lite", "hex", - "nix 0.30.1", + "libc", "ordered-stream", + "rustix", "serde", "serde_repr", - "tokio", "tracing", "uds_windows", "uuid", @@ -14913,14 +14852,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.12.0" +version = "5.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" +checksum = "0bbd5a90dbe8feee5b13def448427ae314ccd26a49cac47905cafefb9ff846f1" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "zbus_names", "zvariant", "zvariant_utils", @@ -14928,34 +14867,33 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.2.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" dependencies = [ "serde", - "static_assertions", "winnow 0.7.14", "zvariant", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -14975,7 +14913,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure 0.13.2", ] @@ -14990,13 +14928,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -15030,7 +14968,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -15048,7 +14986,7 @@ dependencies = [ "flate2", "getrandom 0.3.4", "hmac", - "indexmap 2.12.1", + "indexmap 2.13.0", "liblzma", "memchr", "pbkdf2", @@ -15062,9 +15000,15 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f936044d677be1a1168fae1d03b583a285a5dd9d8cbf7b24c23aa1fc775235" +checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" + +[[package]] +name = "zmij" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" [[package]] name = "zopfli" @@ -15123,14 +15067,13 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.8.0" +version = "5.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" +checksum = "68b64ef4f40c7951337ddc7023dd03528a57a3ce3408ee9da5e948bd29b232c4" dependencies = [ "endi", "enumflags2", "serde", - "url", "winnow 0.7.14", "zvariant_derive", "zvariant_utils", @@ -15138,26 +15081,26 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.8.0" +version = "5.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" +checksum = "484d5d975eb7afb52cc6b929c13d3719a20ad650fea4120e6310de3fc55e415c" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.111", + "syn 2.0.114", "winnow 0.7.14", ] diff --git a/Cargo.toml b/Cargo.toml index 27bbbe56cd..e47eacde4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,12 +40,12 @@ bdk_wallet = "2.0.0" bitcoin = { version = "0.32", features = ["rand", "serde"] } # monero-oxide -monero-address = { git = "https://github.com/kayabaNerve/monero-oxide.git", branch = "rpc-rewrite" } -monero-daemon-rpc = { git = "https://github.com/kayabaNerve/monero-oxide.git", branch = "rpc-rewrite" } -monero-interface = { git = "https://github.com/kayabaNerve/monero-oxide.git", branch = "rpc-rewrite" } -monero-oxide = { git = "https://github.com/kayabaNerve/monero-oxide.git", branch = "rpc-rewrite" } -monero-oxide-wallet = { git = "https://github.com/kayabaNerve/monero-oxide.git", package = "monero-wallet", branch = "rpc-rewrite" } -monero-simple-request-rpc = { git = "https://github.com/kayabaNerve/monero-oxide.git", branch = "rpc-rewrite" } +monero-address = { git = "https://github.com/kayabaNerve/monero-oxide.git" } +monero-daemon-rpc = { git = "https://github.com/kayabaNerve/monero-oxide.git" } +monero-interface = { git = "https://github.com/kayabaNerve/monero-oxide.git" } +monero-oxide = { git = "https://github.com/kayabaNerve/monero-oxide.git" } +monero-oxide-wallet = { git = "https://github.com/kayabaNerve/monero-oxide.git", package = "monero-wallet" } +monero-simple-request-rpc = { git = "https://github.com/kayabaNerve/monero-oxide.git" } # Cryptography curve25519-dalek = { version = "4", package = "curve25519-dalek", features = ["rand_core", "serde"] } @@ -101,6 +101,7 @@ tor-cell = { git = "https://github.com/eigenwallet/arti", branch = "downgraded_r tor-hsservice = { git = "https://github.com/eigenwallet/arti", branch = "downgraded_rusqlite_arti_1_8_0" } tor-proto = { git = "https://github.com/eigenwallet/arti", branch = "downgraded_rusqlite_arti_1_8_0" } tor-rtcompat = { git = "https://github.com/eigenwallet/arti", branch = "downgraded_rusqlite_arti_1_8_0" } +libp2p-tor = { path = "./libp2p-tor" } # Terminal Utilities console = "0.16" diff --git a/monero-oxide-ext/src/lib.rs b/monero-oxide-ext/src/lib.rs index 0517cafcd0..67d61344de 100644 --- a/monero-oxide-ext/src/lib.rs +++ b/monero-oxide-ext/src/lib.rs @@ -254,6 +254,14 @@ impl Amount { self.0 } + /// Get the amount in Monero. + pub fn as_xmr(self) -> f64 { + // Inefficient, but most safe way: monero-rs does it this way, too + let mut buf = String::new(); + fmt_piconero_in_xmr(self.as_pico(), &mut buf).expect("string to be writable"); + buf.parse().expect("Monero amount is floating point number") + } + /// Create an [`Amount`] with monero precision and the given number of monero, string in the format `"1.2"` or `"1"`. pub fn parse_monero(xmr: &str) -> Result { if xmr.is_empty() { diff --git a/monero-sys/build.rs b/monero-sys/build.rs index d5f60c851c..13e2a26121 100644 --- a/monero-sys/build.rs +++ b/monero-sys/build.rs @@ -144,7 +144,7 @@ fn main() { .display() .to_string(); config.define("CMAKE_TOOLCHAIN_FILE", toolchain_file.clone()); - println!("cargo:warning=Using toolchain file: {toolchain_file}"); + println!("cargo:debug=Using toolchain file: {toolchain_file}"); let depends_lib_dir = contrib_depends_dir.join(format!("{target}/lib")); @@ -443,7 +443,7 @@ fn compile_dependencies( "aarch64-apple-ios-sim" => "aarch64-apple-iossimulator".to_string(), _ => target, }; - println!("cargo:warning=Building for target: {target}"); + println!("cargo:debug=Building for target: {target}"); match target.as_str() { "x86_64-apple-darwin" @@ -459,7 +459,7 @@ fn compile_dependencies( _ => panic!("target unsupported: {target}"), } - println!("cargo:warning=Running make HOST={target} in contrib/depends",); + println!("cargo:debug=Running make HOST={target} in contrib/depends",); // Copy monero-depends to out_dir/depends in order to build the dependencies there match fs_extra::copy_items( @@ -554,7 +554,7 @@ fn apply_patches() -> Result<(), Box> { for embedded in EMBEDDED_PATCHES { println!( - "cargo:warning=Processing embedded patch: {} ({})", + "cargo:debug=Processing embedded patch: {} ({})", embedded.name, embedded.description ); @@ -567,14 +567,14 @@ fn apply_patches() -> Result<(), Box> { } println!( - "cargo:warning=Found {} file(s) in patch {}", + "cargo:debug=Found {} file(s) in patch {}", file_patches.len(), embedded.name ); // Apply each file patch individually for (file_path, patch_content) in file_patches { - println!("cargo:warning=Applying patch to file: {file_path}"); + println!("cargo:debug=Applying patch to file: {file_path}"); // Parse the individual file patch let patch = diffy::Patch::from_str(&patch_content) @@ -591,7 +591,7 @@ fn apply_patches() -> Result<(), Box> { // Check if patch is already applied by trying to reverse it if diffy::apply(¤t, &patch.reverse()).is_ok() { - println!("cargo:warning=Patch for {file_path} already applied – skipping",); + println!("cargo:debug=Patch for {file_path} already applied – skipping",); continue; } @@ -601,11 +601,11 @@ fn apply_patches() -> Result<(), Box> { fs::write(&target_path, patched) .map_err(|e| format!("Failed to write {file_path}: {e}"))?; - println!("cargo:warning=Successfully applied patch to: {file_path}"); + println!("cargo:debug=Successfully applied patch to: {file_path}"); } println!( - "cargo:warning=Successfully applied all file patches for: {} ({})", + "cargo:debug=Successfully applied all file patches for: {} ({})", embedded.name, embedded.description ); } diff --git a/monero-tests/Cargo.toml b/monero-tests/Cargo.toml index d3e25d28c5..9b83fb1e2a 100644 --- a/monero-tests/Cargo.toml +++ b/monero-tests/Cargo.toml @@ -3,6 +3,7 @@ name = "monero-tests" version = "0.1.0" edition = "2024" + [dev-dependencies] monero-address = { workspace = true } monero-daemon-rpc = { workspace = true } @@ -22,5 +23,7 @@ tracing-subscriber = { workspace = true } uuid = { workspace = true } zeroize = { workspace = true } -[lints] -workspace = true +# Each test counts as a seperate crate, and would individually get +# warnigns for "unused" dependencies. This silences them +[lints.rust] +unused_crate_dependencies = "allow" diff --git a/monero-tests/tests/subaddresses.rs b/monero-tests/tests/subaddresses.rs index 29e5704f10..a8a2ae4ded 100644 --- a/monero-tests/tests/subaddresses.rs +++ b/monero-tests/tests/subaddresses.rs @@ -53,16 +53,16 @@ async fn subaddress_methods_and_balances() -> anyhow::Result<()> { ); // Mine a block to confirm the transaction and make funds visible - monero.generate_block().await?; + monero.generate_blocks().await?; // Import tx keys so Alice scans this transaction explicitly let sa1_txkey = tx_receipt .tx_keys - .get(&alice_sa1) + .get(&alice_sa1.to_string()) .context("tx key not found for alice subaddress 1")?; let sa2_txkey = tx_receipt .tx_keys - .get(&alice_sa2) + .get(&alice_sa2.to_string()) .context("tx key not found for alice subaddress 2")?; tracing::info!("Importing tx keys for Alice subaddresses"); @@ -82,7 +82,7 @@ async fn subaddress_methods_and_balances() -> anyhow::Result<()> { let bal_sa1 = per_sub.get(&1).copied().unwrap_or(0); let bal_sa2 = per_sub.get(&2).copied().unwrap_or(0); - tracing::info!(bal_sa1=%monero::Amount::from_pico(bal_sa1), bal_sa2=%monero::Amount::from_pico(bal_sa2), "Per-subaddress balances"); + tracing::info!(bal_sa1=%monero_oxide_ext::Amount::from_pico(bal_sa1), bal_sa2=%monero_oxide_ext::Amount::from_pico(bal_sa2), "Per-subaddress balances"); assert!(bal_sa1 > 0, "Subaddress 1 expected to have received funds"); assert!(bal_sa2 > 0, "Subaddress 2 expected to have received funds"); diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index c22cfdf026..39d5062c11 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -80,7 +80,8 @@ macro_rules! generate_command_handlers { get_context_status, get_monero_subaddresses, create_monero_subaddress, - set_monero_subaddress_label + set_monero_subaddress_label, + refresh_p2p ] }; } diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index f5439183e2..d68e2f58c5 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -94,13 +94,14 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { table.add_row(["No swaps found"]); } else { for swap in &swaps { - let xmr = monero:Amount::from_pico(swap.xmr_amount); + let xmr = monero_oxide_ext::Amount::from_pico(swap.xmr_amount); table.add_row([ &swap.swap_id, &swap.start_date, &swap.state, &swap.btc_lock_txid, &swap.btc_amount.to_string(), + // Floating point may introduce very small inaccuracies here &format!("{:.12} XMR", xmr.as_xmr()), &swap.exchange_rate.to_string(), &swap.peer_id, diff --git a/swap-core/src/monero/primitives.rs b/swap-core/src/monero/primitives.rs index dde35855b7..beac72791c 100644 --- a/swap-core/src/monero/primitives.rs +++ b/swap-core/src/monero/primitives.rs @@ -443,7 +443,6 @@ pub struct OverflowError(pub String); #[cfg(test)] mod tests { use super::*; - use crate::compat::IntoDalekNg; #[test] fn display_monero_min() { diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 6b63dc2e35..c76fc1bd98 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use crate::common::{CROSS_CURVE_PROOF_SYSTEM, Message0, Message1, Message2, Message3, Message4}; -use anyhow::{Context, Result, anyhow, bail}; +use anyhow::{Context, Result, bail}; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; @@ -13,9 +13,9 @@ use swap_core::bitcoin::{ TxRefundAmnesty, TxRefundBurn, Txid, current_epoch, }; use swap_core::compat::{IntoDalek, IntoDalekNg, IntoMoneroOxide}; -use swap_core::monero; use swap_core::monero::ScalarExt; use swap_core::monero::primitives::{AmountExt, BlockHeight, TransferProof, TransferRequest}; +use swap_core::monero::{self, Scalar}; use swap_env::env::Config; use uuid::Uuid; @@ -850,16 +850,14 @@ impl State3 { &self, signed_partial_refund_tx: Arc, ) -> Result { - Ok(monero::PrivateKey::from_scalar( - self.tx_partial_refund()? - .extract_monero_private_key( - signed_partial_refund_tx, - self.s_a, - self.a.clone(), - self.S_b_bitcoin, - )? - .into_dalek_ng(), - )) + Ok(monero::PrivateKey::from_scalar(Scalar::from( + self.tx_partial_refund()?.extract_monero_private_key( + signed_partial_refund_tx, + self.s_a.into(), + self.a.clone(), + self.S_b_bitcoin, + )?, + ))) } pub async fn check_for_tx_cancel( diff --git a/swap-machine/src/lib.rs b/swap-machine/src/lib.rs index b3017577fc..27c9130b1a 100644 --- a/swap-machine/src/lib.rs +++ b/swap-machine/src/lib.rs @@ -11,7 +11,6 @@ mod tests { use monero_oxide_ext::PrivateKey; use rand::rngs::OsRng; use swap_core::bitcoin::*; - use swap_core::compat::IntoDalekNg; use swap_core::monero::{Scalar, TransferProof}; use swap_env::env::{GetConfig, Regtest}; use uuid::Uuid; diff --git a/swap-orchestrator/tests/spec.rs b/swap-orchestrator/tests/spec.rs index 94a874945e..a24a882031 100644 --- a/swap-orchestrator/tests/spec.rs +++ b/swap-orchestrator/tests/spec.rs @@ -1,3 +1,5 @@ +#![allow(unused_crate_dependencies)] + use swap_orchestrator::compose::{ IntoSpec, OrchestratorDirectories, OrchestratorImage, OrchestratorImages, OrchestratorInput, OrchestratorNetworks, OrchestratorPorts, diff --git a/swap-p2p/Cargo.toml b/swap-p2p/Cargo.toml index 913c3452d7..3c61b73963 100644 --- a/swap-p2p/Cargo.toml +++ b/swap-p2p/Cargo.toml @@ -16,6 +16,7 @@ swap-serde = { path = "../swap-serde" } async-trait = { workspace = true, optional = true } libp2p = { workspace = true, features = ["serde", "request-response", "rendezvous", "cbor", "json", "ping", "identify"] } + # Serialization asynchronous-codec = "0.7.0" serde = { workspace = true } @@ -57,5 +58,11 @@ test-support = ["libp2p/noise", "libp2p/tcp", "libp2p/yamux", "libp2p/tokio", "l async-trait = { workspace = true } libp2p = { workspace = true, features = ["serde", "request-response", "rendezvous", "cbor", "json", "ping", "identify", "noise", "tcp", "yamux", "tokio", "dns"] } +# Networking (for the example) +libp2p-tor = { workspace = true } +tor-rtcompat = { workspace = true } +arti-client = {workspace = true } +tracing-subscriber = { workspace = true } + [lints] workspace = true diff --git a/swap-p2p/examples/fetch_quotes.rs b/swap-p2p/examples/fetch_quotes.rs index 23a0a5ba58..5ebdf7d283 100644 --- a/swap-p2p/examples/fetch_quotes.rs +++ b/swap-p2p/examples/fetch_quotes.rs @@ -1,22 +1,20 @@ +#![allow(unused_crate_dependencies)] + use anyhow::Result; -use arti_client::{config::TorClientConfigBuilder, TorClient}; +use arti_client::{TorClient, config::TorClientConfigBuilder}; use futures::StreamExt; use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::transport::Boxed; use libp2p::core::upgrade::Version; -use libp2p::multiaddr::Protocol; -use libp2p::swarm::dial_opts::DialOpts; use libp2p::swarm::NetworkBehaviour; +use libp2p::{PeerId, SwarmBuilder, Transport, identity, yamux}; use libp2p::{dns, tcp}; -use libp2p::{identify, noise, ping, request_response}; -use libp2p::{identity, yamux, Multiaddr, PeerId, SwarmBuilder, Transport}; +use libp2p::{identify, noise, ping}; use libp2p_tor::{AddressConversion, TorTransport}; -use std::collections::{HashMap, VecDeque}; use std::sync::Arc; use std::time::Duration; use swap_p2p::libp2p_ext::MultiAddrExt; -use swap_p2p::protocols::quote::BidQuote; -use swap_p2p::protocols::{quote, quotes_cached, rendezvous}; +use swap_p2p::protocols::{quotes_cached, rendezvous}; use tor_rtcompat::tokio::TokioRustlsRuntime; const USE_TOR: bool = true; @@ -130,7 +128,7 @@ async fn main() -> Result<()> { match event { libp2p::swarm::SwarmEvent::Behaviour(event) => match event { BehaviourEvent::Rendezvous(event) => match event { - rendezvous::discovery::Event::DiscoveredPeer { peer_id } => {} + rendezvous::discovery::Event::DiscoveredPeer { .. } => {} }, BehaviourEvent::Quote(quotes_cached::Event::CachedQuotes { quotes }) => { println!("================"); @@ -150,7 +148,7 @@ async fn main() -> Result<()> { } _ => {} }, - libp2p::swarm::SwarmEvent::ConnectionEstablished { peer_id, .. } => {} + libp2p::swarm::SwarmEvent::ConnectionEstablished { .. } => {} _ => {} } } diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index e96fd5192a..53427b7c7e 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -505,7 +505,7 @@ async fn run_swap_setup( let unlocked = wallet_snapshot.unlocked_balance; let needed_balance = xmr + wallet_snapshot.lock_fee.into(); - if unlocked.as_piconero() < needed_balance.as_pico() { + if unlocked.as_pico() < needed_balance.as_pico() { tracing::warn!( unlocked_balance = %unlocked, needed_balance = %needed_balance, diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 474c838693..a6b0e014f9 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -13,7 +13,6 @@ use crate::protocol::alice::swap::has_already_processed_enc_sig; use crate::protocol::alice::{AliceState, State3, Swap, TipConfig}; use crate::protocol::{Database, State}; use anyhow::{anyhow, Context, Result}; -use bdk::bitcoin::hashes::sha1; use bitcoin_wallet::BitcoinWallet; use futures::future; use futures::future::{BoxFuture, FutureExt}; diff --git a/swap/src/asb/rpc/server.rs b/swap/src/asb/rpc/server.rs index cd044ebaaa..e8aeb94c52 100644 --- a/swap/src/asb/rpc/server.rs +++ b/swap/src/asb/rpc/server.rs @@ -199,7 +199,7 @@ impl AsbApiServer for RpcImpl { state: current_alice.to_string(), btc_lock_txid: state3.tx_lock.txid().to_string(), btc_amount: state3.btc, - xmr_amount: state3.xmr.as_piconero(), + xmr_amount: state3.xmr.as_pico(), exchange_rate, peer_id: peer_id.to_string(), completed: is_complete(¤t_alice), diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index b91673e27f..cc368c8d6d 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -2,7 +2,6 @@ pub mod harness; use std::time::Duration; -use harness::alice_run_until::{is_btc_refund_burn_confirmed, is_xmr_lock_transaction_sent}; use harness::FastAmnestyConfig; use rust_decimal::Decimal; use swap::asb::FixedRate; @@ -12,7 +11,7 @@ use swap_controller_api::AsbApiClient; use swap_env::config::RefundPolicy; use swap_machine::bob::BobState; -use crate::harness::alice_run_until::{is_btc_partially_refunded, is_xmr_refunded}; +use crate::harness::alice_run_until::is_xmr_refunded; use crate::harness::bob_run_until; /// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial @@ -48,7 +47,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { // Wait for bob to partially refund - stop here such that he doesn't publish amnesty // TODO: fix regtest blocktimes instead - let bob_state = bob_state.await??; + let _bob_state = bob_state.await??; let alice_state = alice_swap.await??; assert!(matches!(alice_state, AliceState::XmrRefunded { .. })); From 4fd84d2ac69a26235ea06c54d6412a14cb062993 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 26 Jan 2026 10:26:01 +0100 Subject: [PATCH 099/146] move to yarn@4 again --- src-gui/package.json | 3 +- src-gui/yarn.lock | 6605 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 6607 insertions(+), 1 deletion(-) create mode 100644 src-gui/yarn.lock diff --git a/src-gui/package.json b/src-gui/package.json index 7b537185ea..6efda81102 100644 --- a/src-gui/package.json +++ b/src-gui/package.json @@ -76,5 +76,6 @@ "vite-plugin-watch": "^0.3.1", "vite-tsconfig-paths": "^4.3.2", "vitest": "^2.1.1" - } + }, + "packageManager": "yarn@4.12.0" } diff --git a/src-gui/yarn.lock b/src-gui/yarn.lock new file mode 100644 index 0000000000..8f4abf9b8e --- /dev/null +++ b/src-gui/yarn.lock @@ -0,0 +1,6605 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/code-frame@npm:7.27.1" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.27.1" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/5dd9a18baa5fce4741ba729acc3a3272c49c25cb8736c4b18e113099520e7ef7b545a4096a26d600e4416157e63e87d66db46aa3fbf0a5f2286da2705c12da00 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.27.2": + version: 7.28.5 + resolution: "@babel/compat-data@npm:7.28.5" + checksum: 10c0/702a25de73087b0eba325c1d10979eed7c9b6662677386ba7b5aa6eace0fc0676f78343bae080a0176ae26f58bd5535d73b9d0fbb547fef377692e8b249353a7 + languageName: node + linkType: hard + +"@babel/core@npm:^7.24.4, @babel/core@npm:^7.28.0": + version: 7.28.5 + resolution: "@babel/core@npm:7.28.5" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.5" + "@babel/helper-compilation-targets": "npm:^7.27.2" + "@babel/helper-module-transforms": "npm:^7.28.3" + "@babel/helpers": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.5" + "@babel/template": "npm:^7.27.2" + "@babel/traverse": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/535f82238027621da6bdffbdbe896ebad3558b311d6f8abc680637a9859b96edbf929ab010757055381570b29cf66c4a295b5618318d27a4273c0e2033925e72 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/generator@npm:7.28.5" + dependencies: + "@babel/parser": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/9f219fe1d5431b6919f1a5c60db8d5d34fe546c0d8f5a8511b32f847569234ffc8032beb9e7404649a143f54e15224ecb53a3d11b6bb85c3203e573d91fca752 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/helper-compilation-targets@npm:7.27.2" + dependencies: + "@babel/compat-data": "npm:^7.27.2" + "@babel/helper-validator-option": "npm:^7.27.1" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/f338fa00dcfea931804a7c55d1a1c81b6f0a09787e528ec580d5c21b3ecb3913f6cb0f361368973ce953b824d910d3ac3e8a8ee15192710d3563826447193ad1 + languageName: node + linkType: hard + +"@babel/helper-globals@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/helper-globals@npm:7.28.0" + checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-module-imports@npm:7.27.1" + dependencies: + "@babel/traverse": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/e00aace096e4e29290ff8648455c2bc4ed982f0d61dbf2db1b5e750b9b98f318bf5788d75a4f974c151bd318fd549e81dbcab595f46b14b81c12eda3023f51e8 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/helper-module-transforms@npm:7.28.3" + dependencies: + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.3" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-plugin-utils@npm:7.27.1" + checksum: 10c0/94cf22c81a0c11a09b197b41ab488d416ff62254ce13c57e62912c85700dc2e99e555225787a4099ff6bae7a1812d622c80fbaeda824b79baa10a6c5ac4cf69b + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-option@npm:7.27.1" + checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/helpers@npm:7.28.4" + dependencies: + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + checksum: 10c0/aaa5fb8098926dfed5f223adf2c5e4c7fbba4b911b73dfec2d7d3083f8ba694d201a206db673da2d9b3ae8c01793e795767654558c450c8c14b4c2175b4fcb44 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/parser@npm:7.28.5" + dependencies: + "@babel/types": "npm:^7.28.5" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/5bbe48bf2c79594ac02b490a41ffde7ef5aa22a9a88ad6bcc78432a6ba8a9d638d531d868bd1f104633f1f6bba9905746e15185b8276a3756c42b765d131b1ef + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-self@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.26.9, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.28.4 + resolution: "@babel/runtime@npm:7.28.4" + checksum: 10c0/792ce7af9750fb9b93879cc9d1db175701c4689da890e6ced242ea0207c9da411ccf16dc04e689cc01158b28d7898c40d75598f4559109f761c12ce01e959bf7 + languageName: node + linkType: hard + +"@babel/template@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/template@npm:7.27.2" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.2" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/ed9e9022651e463cc5f2cc21942f0e74544f1754d231add6348ff1b472985a3b3502041c0be62dc99ed2d12cfae0c51394bf827452b98a2f8769c03b87aadc81 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/traverse@npm:7.28.5" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.5" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/parser": "npm:^7.28.5" + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.5" + debug: "npm:^4.3.1" + checksum: 10c0/f6c4a595993ae2b73f2d4cd9c062f2e232174d293edd4abe1d715bd6281da8d99e47c65857e8d0917d9384c65972f4acdebc6749a7c40a8fcc38b3c7fb3e706f + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.26.0, @babel/types@npm:^7.27.1, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/types@npm:7.28.5" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10c0/a5a483d2100befbf125793640dec26b90b95fd233a94c19573325898a5ce1e52cdfa96e495c7dcc31b5eca5b66ce3e6d4a0f5a4a62daec271455959f208ab08a + languageName: node + linkType: hard + +"@emotion/babel-plugin@npm:^11.13.5": + version: 11.13.5 + resolution: "@emotion/babel-plugin@npm:11.13.5" + dependencies: + "@babel/helper-module-imports": "npm:^7.16.7" + "@babel/runtime": "npm:^7.18.3" + "@emotion/hash": "npm:^0.9.2" + "@emotion/memoize": "npm:^0.9.0" + "@emotion/serialize": "npm:^1.3.3" + babel-plugin-macros: "npm:^3.1.0" + convert-source-map: "npm:^1.5.0" + escape-string-regexp: "npm:^4.0.0" + find-root: "npm:^1.1.0" + source-map: "npm:^0.5.7" + stylis: "npm:4.2.0" + checksum: 10c0/8ccbfec7defd0e513cb8a1568fa179eac1e20c35fda18aed767f6c59ea7314363ebf2de3e9d2df66c8ad78928dc3dceeded84e6fa8059087cae5c280090aeeeb + languageName: node + linkType: hard + +"@emotion/cache@npm:^11.14.0": + version: 11.14.0 + resolution: "@emotion/cache@npm:11.14.0" + dependencies: + "@emotion/memoize": "npm:^0.9.0" + "@emotion/sheet": "npm:^1.4.0" + "@emotion/utils": "npm:^1.4.2" + "@emotion/weak-memoize": "npm:^0.4.0" + stylis: "npm:4.2.0" + checksum: 10c0/3fa3e7a431ab6f8a47c67132a00ac8358f428c1b6c8421d4b20de9df7c18e95eec04a5a6ff5a68908f98d3280044f247b4965ac63df8302d2c94dba718769724 + languageName: node + linkType: hard + +"@emotion/hash@npm:^0.9.2": + version: 0.9.2 + resolution: "@emotion/hash@npm:0.9.2" + checksum: 10c0/0dc254561a3cc0a06a10bbce7f6a997883fd240c8c1928b93713f803a2e9153a257a488537012efe89dbe1246f2abfe2add62cdb3471a13d67137fcb808e81c2 + languageName: node + linkType: hard + +"@emotion/is-prop-valid@npm:^1.3.0": + version: 1.4.0 + resolution: "@emotion/is-prop-valid@npm:1.4.0" + dependencies: + "@emotion/memoize": "npm:^0.9.0" + checksum: 10c0/5f857814ec7d8c7e727727346dfb001af6b1fb31d621a3ce9c3edf944a484d8b0d619546c30899ae3ade2f317c76390ba4394449728e9bf628312defc2c41ac3 + languageName: node + linkType: hard + +"@emotion/memoize@npm:^0.9.0": + version: 0.9.0 + resolution: "@emotion/memoize@npm:0.9.0" + checksum: 10c0/13f474a9201c7f88b543e6ea42f55c04fb2fdc05e6c5a3108aced2f7e7aa7eda7794c56bba02985a46d8aaa914fcdde238727a98341a96e2aec750d372dadd15 + languageName: node + linkType: hard + +"@emotion/react@npm:^11.14.0": + version: 11.14.0 + resolution: "@emotion/react@npm:11.14.0" + dependencies: + "@babel/runtime": "npm:^7.18.3" + "@emotion/babel-plugin": "npm:^11.13.5" + "@emotion/cache": "npm:^11.14.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" + "@emotion/utils": "npm:^1.4.2" + "@emotion/weak-memoize": "npm:^0.4.0" + hoist-non-react-statics: "npm:^3.3.1" + peerDependencies: + react: ">=16.8.0" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d0864f571a9f99ec643420ef31fde09e2006d3943a6aba079980e4d5f6e9f9fecbcc54b8f617fe003c00092ff9d5241179149ffff2810cb05cf72b4620cfc031 + languageName: node + linkType: hard + +"@emotion/serialize@npm:^1.3.3": + version: 1.3.3 + resolution: "@emotion/serialize@npm:1.3.3" + dependencies: + "@emotion/hash": "npm:^0.9.2" + "@emotion/memoize": "npm:^0.9.0" + "@emotion/unitless": "npm:^0.10.0" + "@emotion/utils": "npm:^1.4.2" + csstype: "npm:^3.0.2" + checksum: 10c0/b28cb7de59de382021de2b26c0c94ebbfb16967a1b969a56fdb6408465a8993df243bfbd66430badaa6800e1834724e84895f5a6a9d97d0d224de3d77852acb4 + languageName: node + linkType: hard + +"@emotion/sheet@npm:^1.4.0": + version: 1.4.0 + resolution: "@emotion/sheet@npm:1.4.0" + checksum: 10c0/3ca72d1650a07d2fbb7e382761b130b4a887dcd04e6574b2d51ce578791240150d7072a9bcb4161933abbcd1e38b243a6fb4464a7fe991d700c17aa66bb5acc7 + languageName: node + linkType: hard + +"@emotion/styled@npm:^11.14.0": + version: 11.14.1 + resolution: "@emotion/styled@npm:11.14.1" + dependencies: + "@babel/runtime": "npm:^7.18.3" + "@emotion/babel-plugin": "npm:^11.13.5" + "@emotion/is-prop-valid": "npm:^1.3.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" + "@emotion/utils": "npm:^1.4.2" + peerDependencies: + "@emotion/react": ^11.0.0-rc.0 + react: ">=16.8.0" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/2bbf8451df49c967e41fbcf8111a7f6dafe6757f0cc113f2f6e287206c45ac1d54dc8a95a483b7c0cee8614b8a8d08155bded6453d6721de1f8cc8d5b9216963 + languageName: node + linkType: hard + +"@emotion/unitless@npm:^0.10.0": + version: 0.10.0 + resolution: "@emotion/unitless@npm:0.10.0" + checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49 + languageName: node + linkType: hard + +"@emotion/use-insertion-effect-with-fallbacks@npm:^1.2.0": + version: 1.2.0 + resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" + peerDependencies: + react: ">=16.8.0" + checksum: 10c0/074dbc92b96bdc09209871070076e3b0351b6b47efefa849a7d9c37ab142130767609ca1831da0055988974e3b895c1de7606e4c421fecaa27c3e56a2afd3b08 + languageName: node + linkType: hard + +"@emotion/utils@npm:^1.4.2": + version: 1.4.2 + resolution: "@emotion/utils@npm:1.4.2" + checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a + languageName: node + linkType: hard + +"@emotion/weak-memoize@npm:^0.4.0": + version: 0.4.0 + resolution: "@emotion/weak-memoize@npm:0.4.0" + checksum: 10c0/64376af11f1266042d03b3305c30b7502e6084868e33327e944b539091a472f089db307af69240f7188f8bc6b319276fd7b141a36613f1160d73d12a60f6ca1a + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/aix-ppc64@npm:0.21.5" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm64@npm:0.21.5" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm@npm:0.21.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-x64@npm:0.21.5" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-arm64@npm:0.21.5" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-x64@npm:0.21.5" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-arm64@npm:0.21.5" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-x64@npm:0.21.5" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm64@npm:0.21.5" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm@npm:0.21.5" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ia32@npm:0.21.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-loong64@npm:0.21.5" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-mips64el@npm:0.21.5" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ppc64@npm:0.21.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-riscv64@npm:0.21.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-s390x@npm:0.21.5" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-x64@npm:0.21.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/netbsd-x64@npm:0.21.5" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/openbsd-x64@npm:0.21.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/sunos-x64@npm:0.21.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-arm64@npm:0.21.5" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-ia32@npm:0.21.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-x64@npm:0.21.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.7.0, @eslint-community/eslint-utils@npm:^4.8.0": + version: 4.9.0 + resolution: "@eslint-community/eslint-utils@npm:4.9.0" + dependencies: + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.1": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.21.1": + version: 0.21.1 + resolution: "@eslint/config-array@npm:0.21.1" + dependencies: + "@eslint/object-schema": "npm:^2.1.7" + debug: "npm:^4.3.1" + minimatch: "npm:^3.1.2" + checksum: 10c0/2f657d4edd6ddcb920579b72e7a5b127865d4c3fb4dda24f11d5c4f445a93ca481aebdbd6bf3291c536f5d034458dbcbb298ee3b698bc6c9dd02900fe87eec3c + languageName: node + linkType: hard + +"@eslint/config-helpers@npm:^0.4.2": + version: 0.4.2 + resolution: "@eslint/config-helpers@npm:0.4.2" + dependencies: + "@eslint/core": "npm:^0.17.0" + checksum: 10c0/92efd7a527b2d17eb1a148409d71d80f9ac160b565ac73ee092252e8bf08ecd08670699f46b306b94f13d22e88ac88a612120e7847570dd7cdc72f234d50dcb4 + languageName: node + linkType: hard + +"@eslint/core@npm:^0.17.0": + version: 0.17.0 + resolution: "@eslint/core@npm:0.17.0" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/9a580f2246633bc752298e7440dd942ec421860d1946d0801f0423830e67887e4aeba10ab9a23d281727a978eb93d053d1922a587d502942a713607f40ed704e + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^3.3.1": + version: 3.3.3 + resolution: "@eslint/eslintrc@npm:3.3.3" + dependencies: + ajv: "npm:^6.12.4" + debug: "npm:^4.3.2" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" + ignore: "npm:^5.2.0" + import-fresh: "npm:^3.2.1" + js-yaml: "npm:^4.1.1" + minimatch: "npm:^3.1.2" + strip-json-comments: "npm:^3.1.1" + checksum: 10c0/532c7acc7ddd042724c28b1f020bd7bf148fcd4653bb44c8314168b5f772508c842ce4ee070299cac51c5c5757d2124bdcfcef5551c8c58ff9986e3e17f2260d + languageName: node + linkType: hard + +"@eslint/js@npm:9.39.2, @eslint/js@npm:^9.9.0": + version: 9.39.2 + resolution: "@eslint/js@npm:9.39.2" + checksum: 10c0/00f51c52b04ac79faebfaa65a9652b2093b9c924e945479f1f3945473f78aee83cbc76c8d70bbffbf06f7024626575b16d97b66eab16182e1d0d39daff2f26f5 + languageName: node + linkType: hard + +"@eslint/object-schema@npm:^2.1.7": + version: 2.1.7 + resolution: "@eslint/object-schema@npm:2.1.7" + checksum: 10c0/936b6e499853d1335803f556d526c86f5fe2259ed241bc665000e1d6353828edd913feed43120d150adb75570cae162cf000b5b0dfc9596726761c36b82f4e87 + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.4.1": + version: 0.4.1 + resolution: "@eslint/plugin-kit@npm:0.4.1" + dependencies: + "@eslint/core": "npm:^0.17.0" + levn: "npm:^0.4.1" + checksum: 10c0/51600f78b798f172a9915dffb295e2ffb44840d583427bc732baf12ecb963eb841b253300e657da91d890f4b323d10a1bd12934bf293e3018d8bb66fdce5217b + languageName: node + linkType: hard + +"@fontsource/roboto@npm:^5.1.0": + version: 5.2.9 + resolution: "@fontsource/roboto@npm:5.2.9" + checksum: 10c0/8280ab6504ab7da105c77afc1231236be86f7cd02a708e25b6cfc2871975699a44be7a42491e59934f2a84c874a8109bb2babfbc6b1986bcad9f3ac1de3980ca + languageName: node + linkType: hard + +"@humanfs/core@npm:^0.19.1": + version: 0.19.1 + resolution: "@humanfs/core@npm:0.19.1" + checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 + languageName: node + linkType: hard + +"@humanfs/node@npm:^0.16.6": + version: 0.16.7 + resolution: "@humanfs/node@npm:0.16.7" + dependencies: + "@humanfs/core": "npm:^0.19.1" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30 + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + languageName: node + linkType: hard + +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 + languageName: node + linkType: hard + +"@isaacs/balanced-match@npm:^4.0.1": + version: 4.0.1 + resolution: "@isaacs/balanced-match@npm:4.0.1" + checksum: 10c0/7da011805b259ec5c955f01cee903da72ad97c5e6f01ca96197267d3f33103d5b2f8a1af192140f3aa64526c593c8d098ae366c2b11f7f17645d12387c2fd420 + languageName: node + linkType: hard + +"@isaacs/brace-expansion@npm:^5.0.0": + version: 5.0.0 + resolution: "@isaacs/brace-expansion@npm:5.0.0" + dependencies: + "@isaacs/balanced-match": "npm:^4.0.1" + checksum: 10c0/b4d4812f4be53afc2c5b6c545001ff7a4659af68d4484804e9d514e183d20269bb81def8682c01a22b17c4d6aed14292c8494f7d2ac664e547101c1a905aa977 + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b + languageName: node + linkType: hard + +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5": + version: 1.5.5 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" + checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + +"@mui/core-downloads-tracker@npm:^7.3.6": + version: 7.3.6 + resolution: "@mui/core-downloads-tracker@npm:7.3.6" + checksum: 10c0/32eefa674df2717b18422f0e7468d7c584f2da93c219b98d29d4d873e9418152e3ae242aecd34ea19ea927dff50632b0d85022b99632d55ab02b84ee03d59078 + languageName: node + linkType: hard + +"@mui/icons-material@npm:^7.1.1": + version: 7.3.6 + resolution: "@mui/icons-material@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + peerDependencies: + "@mui/material": ^7.3.6 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/ec0286beb22a7070566d6242410b75f4106e15b2ead7b5d5115f00e1c7fc70d44d47289a1d27059781d56907cf291e53261868dafd7dba2843245abe18799d65 + languageName: node + linkType: hard + +"@mui/material@npm:^7.1.1": + version: 7.3.6 + resolution: "@mui/material@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/core-downloads-tracker": "npm:^7.3.6" + "@mui/system": "npm:^7.3.6" + "@mui/types": "npm:^7.4.9" + "@mui/utils": "npm:^7.3.6" + "@popperjs/core": "npm:^2.11.8" + "@types/react-transition-group": "npm:^4.4.12" + clsx: "npm:^2.1.1" + csstype: "npm:^3.1.3" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.0" + react-transition-group: "npm:^4.4.5" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@mui/material-pigment-css": ^7.3.6 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@mui/material-pigment-css": + optional: true + "@types/react": + optional: true + checksum: 10c0/8bc88277eea82897a0011f5d1efdccf048a1626e9bcfbf97e1c03ae4b6d1413d240a061a3af7ba10329d9d8e1b1cb296b9d3693978b47e9186d96704ff56c333 + languageName: node + linkType: hard + +"@mui/private-theming@npm:^7.3.6": + version: 7.3.6 + resolution: "@mui/private-theming@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/utils": "npm:^7.3.6" + prop-types: "npm:^15.8.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/c342d81e9499015267d4963423b1b2ce7931d1c6eb25090b4d5a32095c3bebd8c85b9ac87bfc5f4d70be7d772704d8d093c68f477b72a130e5c9dbf510165a45 + languageName: node + linkType: hard + +"@mui/styled-engine@npm:^7.3.6": + version: 7.3.6 + resolution: "@mui/styled-engine@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@emotion/cache": "npm:^11.14.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/sheet": "npm:^1.4.0" + csstype: "npm:^3.1.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.4.1 + "@emotion/styled": ^11.3.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + checksum: 10c0/7c6cb484a21fe238a2f86bcc5ef9b2ee4ea9bbf270dad3ef898b4019211f180740e8b0a37682d2e5baa0d46910231c3b9640231431ba454c0a02ff19f80e046e + languageName: node + linkType: hard + +"@mui/system@npm:^7.3.6": + version: 7.3.6 + resolution: "@mui/system@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/private-theming": "npm:^7.3.6" + "@mui/styled-engine": "npm:^7.3.6" + "@mui/types": "npm:^7.4.9" + "@mui/utils": "npm:^7.3.6" + clsx: "npm:^2.1.1" + csstype: "npm:^3.1.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@types/react": + optional: true + checksum: 10c0/03ae9f9b3ede2aaaf89c95d1097aaadc0fb7ae4e5747ffafb528a184bf6bffd9f01fe55b77cb26af3f7101de6dc743d975c06a9777e02ed849f6a83beca88ae5 + languageName: node + linkType: hard + +"@mui/types@npm:^7.4.9": + version: 7.4.9 + resolution: "@mui/types@npm:7.4.9" + dependencies: + "@babel/runtime": "npm:^7.28.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/ed371a08af12a712fb5985547162b99fc58b5d451ea1101927a6d2f2c005087eb25603553d2c4242ee3a34359333b917432052148c93ed7dded5d80042fec504 + languageName: node + linkType: hard + +"@mui/utils@npm:^7.3.5, @mui/utils@npm:^7.3.6": + version: 7.3.6 + resolution: "@mui/utils@npm:7.3.6" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/types": "npm:^7.4.9" + "@types/prop-types": "npm:^15.7.15" + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/0af5f65a022028fa25b6a331443c44fdfd9060355495fd10849807f7aee9c9a4f776592cfe427b3c478f4ee4bf96349d9e84d1a035d5e31ba84d821748b4f185 + languageName: node + linkType: hard + +"@mui/x-date-pickers@npm:^8.8.0": + version: 8.23.0 + resolution: "@mui/x-date-pickers@npm:8.23.0" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/utils": "npm:^7.3.5" + "@mui/x-internals": "npm:8.23.0" + "@types/react-transition-group": "npm:^4.4.12" + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + react-transition-group: "npm:^4.4.5" + peerDependencies: + "@emotion/react": ^11.9.0 + "@emotion/styled": ^11.8.1 + "@mui/material": ^5.15.14 || ^6.0.0 || ^7.0.0 + "@mui/system": ^5.15.14 || ^6.0.0 || ^7.0.0 + date-fns: ^2.25.0 || ^3.2.0 || ^4.0.0 + date-fns-jalali: ^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0 + dayjs: ^1.10.7 + luxon: ^3.0.2 + moment: ^2.29.4 + moment-hijri: ^2.1.2 || ^3.0.0 + moment-jalaali: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + date-fns: + optional: true + date-fns-jalali: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + moment-hijri: + optional: true + moment-jalaali: + optional: true + checksum: 10c0/a5e86d30f07b8f852bd4015deee73e8509e7058a28383a5cc0920dfecb9d03b80b6fcfa30a05d13568aa63d9224877396f4566584fecfd6f6872ceabf1eb5c40 + languageName: node + linkType: hard + +"@mui/x-internals@npm:8.23.0": + version: 8.23.0 + resolution: "@mui/x-internals@npm:8.23.0" + dependencies: + "@babel/runtime": "npm:^7.28.4" + "@mui/utils": "npm:^7.3.5" + reselect: "npm:^5.1.1" + use-sync-external-store: "npm:^1.6.0" + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/3195746a3ace98ecc67ed8992cd1d1cb8f6794236cbe60ddab55157d9cbb193023e78de7097047ada47c543305082a6a90240600edaaf3db3d1f00bcf0c55bf4 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/agent@npm:4.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^11.2.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^5.0.0": + version: 5.0.0 + resolution: "@npmcli/fs@npm:5.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/26e376d780f60ff16e874a0ac9bc3399186846baae0b6e1352286385ac134d900cc5dafaded77f38d77f86898fc923ae1cee9d7399f0275b1aa24878915d722b + languageName: node + linkType: hard + +"@popperjs/core@npm:^2.11.8": + version: 2.11.8 + resolution: "@popperjs/core@npm:2.11.8" + checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 + languageName: node + linkType: hard + +"@redux-devtools/core@npm:^4.1.1": + version: 4.1.1 + resolution: "@redux-devtools/core@npm:4.1.1" + dependencies: + "@babel/runtime": "npm:^7.26.9" + "@redux-devtools/instrument": "npm:^2.2.0" + peerDependencies: + react: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-redux: ^7.0.0 || ^8.0.0 || ^9.0.0 + redux: ^3.5.2 || ^4.0.0 || ^5.0.0 + checksum: 10c0/02a436c3c3f46a29e03f12b2659ed48c3952b8ee984fb997401b0fdf84e3df12f65b6fe73679a4d45efa12eff8e202460da1d68e981502514507c0b5abae4676 + languageName: node + linkType: hard + +"@redux-devtools/instrument@npm:^2.2.0": + version: 2.2.0 + resolution: "@redux-devtools/instrument@npm:2.2.0" + dependencies: + "@babel/runtime": "npm:^7.23.2" + lodash: "npm:^4.17.21" + peerDependencies: + redux: ^3.4.0 || ^4.0.0 || ^5.0.0 + checksum: 10c0/266cd15f1ef144bbb4a2ea472c096d2a4fa72341c4c892827d633a3c85b62d1240a35aaeab71a29020f1da4da0ab2f778c176fb30c35546f6a5020a26ba1c56a + languageName: node + linkType: hard + +"@redux-devtools/remote@npm:^0.9.5": + version: 0.9.5 + resolution: "@redux-devtools/remote@npm:0.9.5" + dependencies: + "@babel/runtime": "npm:^7.26.9" + "@redux-devtools/instrument": "npm:^2.2.0" + "@redux-devtools/utils": "npm:^3.1.1" + jsan: "npm:^3.1.14" + rn-host-detect: "npm:^1.2.0" + socketcluster-client: "npm:^19.2.3" + peerDependencies: + redux: ^3.5.2 || ^4.0.0 || ^5.0.0 + checksum: 10c0/ecb13fe01008afe25d860221c505a97774e43c81f04c2e381ec9a56e2f64c6ee3eb204ad34142f7d9149db8b64be1607e824d82a79eea3e5d99fe399b9805236 + languageName: node + linkType: hard + +"@redux-devtools/serialize@npm:^0.4.2": + version: 0.4.2 + resolution: "@redux-devtools/serialize@npm:0.4.2" + dependencies: + "@babel/runtime": "npm:^7.23.2" + jsan: "npm:^3.1.14" + peerDependencies: + immutable: ^4.0.0 + checksum: 10c0/9906d5fea1214ed82cb453d9a06b76c31fb9ddeea1f5fab18220af721f82c0efce6764353865cced3c481f0e421bfdd45701f2aea19a7678db07c56a5cdd5ad8 + languageName: node + linkType: hard + +"@redux-devtools/utils@npm:^3.1.1": + version: 3.1.1 + resolution: "@redux-devtools/utils@npm:3.1.1" + dependencies: + "@babel/runtime": "npm:^7.26.9" + "@redux-devtools/core": "npm:^4.1.1" + "@redux-devtools/serialize": "npm:^0.4.2" + "@types/get-params": "npm:^0.1.2" + get-params: "npm:^0.1.2" + immutable: "npm:^4.3.7" + jsan: "npm:^3.1.14" + nanoid: "npm:^5.1.2" + redux: "npm:^5.0.1" + peerDependencies: + "@redux-devtools/core": ^4.1.1 + immutable: ^4.3.7 + redux: ^4.0.0 || ^5.0.0 + checksum: 10c0/ea03fee3e633329d0d8cb84d7fb3aa739302b5e190fed23987e0663de4654e1d26be1ea01a61082b7497b8ac11a029fc4516a9f26d7aa057b5056e53fff170a0 + languageName: node + linkType: hard + +"@reduxjs/toolkit@npm:^2.3.0": + version: 2.11.2 + resolution: "@reduxjs/toolkit@npm:2.11.2" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + "@standard-schema/utils": "npm:^0.3.0" + immer: "npm:^11.0.0" + redux: "npm:^5.0.1" + redux-thunk: "npm:^3.1.0" + reselect: "npm:^5.1.0" + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + checksum: 10c0/4d388b96dc4b12a577af23607c252b3647c1b3b5136dbb0212e1dbbef9bb309e93d3ba6a95795ee165e87e4286453025cd67a98b5b3bb6d244b93ea487dd1ac0 + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:1.0.0-beta.27": + version: 1.0.0-beta.27 + resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27" + checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c + languageName: node + linkType: hard + +"@rollup/plugin-virtual@npm:^3.0.2": + version: 3.0.2 + resolution: "@rollup/plugin-virtual@npm:3.0.2" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/7115edb7989096d1ce334939fcf6e1ba365586b487bf61b2dd4f915386197f350db70904030342c0720fe58f5a52828975c645c4d415c1d432d9b1b6760a22ef + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.54.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-android-arm64@npm:4.54.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.54.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.54.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.54.0" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.54.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.54.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.54.0" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.54.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.54.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.54.0" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.54.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.54.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.54.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.54.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.54.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.54.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.54.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.54.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.54.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.54.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.54.0": + version: 4.54.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.54.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rtsao/scc@npm:^1.1.0": + version: 1.1.0 + resolution: "@rtsao/scc@npm:1.1.0" + checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b + languageName: node + linkType: hard + +"@standard-schema/spec@npm:^1.0.0": + version: 1.1.0 + resolution: "@standard-schema/spec@npm:1.1.0" + checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526 + languageName: node + linkType: hard + +"@standard-schema/utils@npm:^0.3.0": + version: 0.3.0 + resolution: "@standard-schema/utils@npm:0.3.0" + checksum: 10c0/6eb74cd13e52d5fc74054df51e37d947ef53f3ab9e02c085665dcca3c38c60ece8d735cebbdf18fbb13c775fbcb9becb3f53109b0e092a63f0f7389ce0993fd0 + languageName: node + linkType: hard + +"@swc/core-darwin-arm64@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-darwin-arm64@npm:1.15.7" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-darwin-x64@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-darwin-x64@npm:1.15.7" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@swc/core-linux-arm-gnueabihf@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.7" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@swc/core-linux-arm64-gnu@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-linux-arm64-gnu@npm:1.15.7" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-arm64-musl@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-linux-arm64-musl@npm:1.15.7" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-linux-x64-gnu@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-linux-x64-gnu@npm:1.15.7" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-x64-musl@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-linux-x64-musl@npm:1.15.7" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-win32-arm64-msvc@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-win32-arm64-msvc@npm:1.15.7" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-win32-ia32-msvc@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-win32-ia32-msvc@npm:1.15.7" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@swc/core-win32-x64-msvc@npm:1.15.7": + version: 1.15.7 + resolution: "@swc/core-win32-x64-msvc@npm:1.15.7" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@swc/core@npm:^1.12.14": + version: 1.15.7 + resolution: "@swc/core@npm:1.15.7" + dependencies: + "@swc/core-darwin-arm64": "npm:1.15.7" + "@swc/core-darwin-x64": "npm:1.15.7" + "@swc/core-linux-arm-gnueabihf": "npm:1.15.7" + "@swc/core-linux-arm64-gnu": "npm:1.15.7" + "@swc/core-linux-arm64-musl": "npm:1.15.7" + "@swc/core-linux-x64-gnu": "npm:1.15.7" + "@swc/core-linux-x64-musl": "npm:1.15.7" + "@swc/core-win32-arm64-msvc": "npm:1.15.7" + "@swc/core-win32-ia32-msvc": "npm:1.15.7" + "@swc/core-win32-x64-msvc": "npm:1.15.7" + "@swc/counter": "npm:^0.1.3" + "@swc/types": "npm:^0.1.25" + peerDependencies: + "@swc/helpers": ">=0.5.17" + dependenciesMeta: + "@swc/core-darwin-arm64": + optional: true + "@swc/core-darwin-x64": + optional: true + "@swc/core-linux-arm-gnueabihf": + optional: true + "@swc/core-linux-arm64-gnu": + optional: true + "@swc/core-linux-arm64-musl": + optional: true + "@swc/core-linux-x64-gnu": + optional: true + "@swc/core-linux-x64-musl": + optional: true + "@swc/core-win32-arm64-msvc": + optional: true + "@swc/core-win32-ia32-msvc": + optional: true + "@swc/core-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 10c0/ae1d20db777bfe0404f2c840d8fa66da0664bca1f88ac8727cbe4c0cb04ee28505009b55caf345f1e790b96410f9bcf66d0178372e9c6505a9da76e7562a06bf + languageName: node + linkType: hard + +"@swc/counter@npm:^0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 + languageName: node + linkType: hard + +"@swc/types@npm:^0.1.25": + version: 0.1.25 + resolution: "@swc/types@npm:0.1.25" + dependencies: + "@swc/counter": "npm:^0.1.3" + checksum: 10c0/847a5b20b131281f89d640a7ed4887fb65724807d53d334b230e84b98c21097aa10cd28a074f9ed287a6ce109e443dd4bafbe7dcfb62333d7806c4ea3e7f8aca + languageName: node + linkType: hard + +"@swc/wasm@npm:^1.12.14": + version: 1.15.7 + resolution: "@swc/wasm@npm:1.15.7" + checksum: 10c0/306722f4841cf88da75a5a46f65987655ee704573cb6f0bac52e7b5b7a481423a1f71f2d8c8e3343438f234d7e5a2d8650ec051c0a2b7b0631ea772f99a13110 + languageName: node + linkType: hard + +"@tauri-apps/api@npm:^2.6.0, @tauri-apps/api@npm:^2.8.0": + version: 2.9.1 + resolution: "@tauri-apps/api@npm:2.9.1" + checksum: 10c0/18c76ec58b579860bfde5cd5b5ea6c3b13019d356c17d436bf395cafdf15dd1f277364cacd24cc94e5d4aa3816f39698f231773d2a18625e98702295ab0c2c8f + languageName: node + linkType: hard + +"@tauri-apps/cli-darwin-arm64@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-darwin-arm64@npm:2.9.6" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@tauri-apps/cli-darwin-x64@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-darwin-x64@npm:2.9.6" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-arm-gnueabihf@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-arm-gnueabihf@npm:2.9.6" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-arm64-gnu@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-arm64-gnu@npm:2.9.6" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-arm64-musl@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-arm64-musl@npm:2.9.6" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-riscv64-gnu@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-riscv64-gnu@npm:2.9.6" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-x64-gnu@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-x64-gnu@npm:2.9.6" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@tauri-apps/cli-linux-x64-musl@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-linux-x64-musl@npm:2.9.6" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@tauri-apps/cli-win32-arm64-msvc@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-win32-arm64-msvc@npm:2.9.6" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@tauri-apps/cli-win32-ia32-msvc@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-win32-ia32-msvc@npm:2.9.6" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@tauri-apps/cli-win32-x64-msvc@npm:2.9.6": + version: 2.9.6 + resolution: "@tauri-apps/cli-win32-x64-msvc@npm:2.9.6" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@tauri-apps/cli@npm:^2.0.0": + version: 2.9.6 + resolution: "@tauri-apps/cli@npm:2.9.6" + dependencies: + "@tauri-apps/cli-darwin-arm64": "npm:2.9.6" + "@tauri-apps/cli-darwin-x64": "npm:2.9.6" + "@tauri-apps/cli-linux-arm-gnueabihf": "npm:2.9.6" + "@tauri-apps/cli-linux-arm64-gnu": "npm:2.9.6" + "@tauri-apps/cli-linux-arm64-musl": "npm:2.9.6" + "@tauri-apps/cli-linux-riscv64-gnu": "npm:2.9.6" + "@tauri-apps/cli-linux-x64-gnu": "npm:2.9.6" + "@tauri-apps/cli-linux-x64-musl": "npm:2.9.6" + "@tauri-apps/cli-win32-arm64-msvc": "npm:2.9.6" + "@tauri-apps/cli-win32-ia32-msvc": "npm:2.9.6" + "@tauri-apps/cli-win32-x64-msvc": "npm:2.9.6" + dependenciesMeta: + "@tauri-apps/cli-darwin-arm64": + optional: true + "@tauri-apps/cli-darwin-x64": + optional: true + "@tauri-apps/cli-linux-arm-gnueabihf": + optional: true + "@tauri-apps/cli-linux-arm64-gnu": + optional: true + "@tauri-apps/cli-linux-arm64-musl": + optional: true + "@tauri-apps/cli-linux-riscv64-gnu": + optional: true + "@tauri-apps/cli-linux-x64-gnu": + optional: true + "@tauri-apps/cli-linux-x64-musl": + optional: true + "@tauri-apps/cli-win32-arm64-msvc": + optional: true + "@tauri-apps/cli-win32-ia32-msvc": + optional: true + "@tauri-apps/cli-win32-x64-msvc": + optional: true + bin: + tauri: tauri.js + checksum: 10c0/f8aed97b4dec2ad99720315d8bf392624e5db13eff30e89340849d14b17020a3f65af847f1ebdad88f187ccb0f00512e77a17af8c607350fc9a7c68c05414b8b + languageName: node + linkType: hard + +"@tauri-apps/plugin-cli@npm:^2.4.0": + version: 2.4.1 + resolution: "@tauri-apps/plugin-cli@npm:2.4.1" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/3da30cce5fb527972243c28bb226349301328f98cf5afaef757a4c931452f71779a3c62530874d09dff9f18dffa9a8f3652ef9ba46c52e14194f2181818590e9 + languageName: node + linkType: hard + +"@tauri-apps/plugin-clipboard-manager@npm:^2.3.0": + version: 2.3.2 + resolution: "@tauri-apps/plugin-clipboard-manager@npm:2.3.2" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/26ba8814bdd51c35d80fd0911643eee3862eac241352c70203c9f7fcc3d2dcf68e5efed63315f0d80b8446c16b0e9f80aa040da340461614034c00881ec246d6 + languageName: node + linkType: hard + +"@tauri-apps/plugin-dialog@npm:^2.0.0": + version: 2.4.2 + resolution: "@tauri-apps/plugin-dialog@npm:2.4.2" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/2950a5aa07727710b5395491e9b80886c13cbefd05445a84412819128e90bdaec751795c47ed39dd80fb5181c4e21ee7aaaae6152551dbf1ddc02aa3eac59b37 + languageName: node + linkType: hard + +"@tauri-apps/plugin-opener@npm:^2.5.0": + version: 2.5.2 + resolution: "@tauri-apps/plugin-opener@npm:2.5.2" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/b10c39063c59ca71e5a5c43bb93da34387a7e707d1baf65a53110141f1a973ce2b73f19be9f63d9312c030760ba2b876ad3069b9a123abb4883e025059a15c3f + languageName: node + linkType: hard + +"@tauri-apps/plugin-process@npm:^2.3.0": + version: 2.3.1 + resolution: "@tauri-apps/plugin-process@npm:2.3.1" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/2e5086898f1c9f25f6426a752404c788727237142bbb7c8f418b97c76c5360874d06203150d136e51114df9e720022e4fa3681fd1d4cb6f777dc83c3553f8670 + languageName: node + linkType: hard + +"@tauri-apps/plugin-store@npm:^2.4.0": + version: 2.4.1 + resolution: "@tauri-apps/plugin-store@npm:2.4.1" + dependencies: + "@tauri-apps/api": "npm:^2.8.0" + checksum: 10c0/69af5e6f6ee81b86525b5510aff2f4f5a3ec3dff26b028f191bd5ecdf1d838721cac0942fb9838ec4c293687bfc2238e2c71493f500a5781dbe7c14001fb5660 + languageName: node + linkType: hard + +"@tauri-apps/plugin-updater@npm:^2.9.0": + version: 2.9.0 + resolution: "@tauri-apps/plugin-updater@npm:2.9.0" + dependencies: + "@tauri-apps/api": "npm:^2.6.0" + checksum: 10c0/72ce83d1c241308a13b9929f0900e4d33453875877009166e3998e3e75a1003ac48c3641086b4d3230f0f18c64f475ad6c3556d1603fc641ca50dc9c18d61866 + languageName: node + linkType: hard + +"@testing-library/react@npm:^16.0.1": + version: 16.3.1 + resolution: "@testing-library/react@npm:16.3.1" + dependencies: + "@babel/runtime": "npm:^7.12.5" + peerDependencies: + "@testing-library/dom": ^10.0.0 + "@types/react": ^18.0.0 || ^19.0.0 + "@types/react-dom": ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/5a26ceaa4ab1d065be722d93e3b019883864ae038f9fd1c974f5b8a173f5f35a25768ecb2baa02a783299f009cbcd09fa7ee0b8b3d360d1c0f81535436358b28 + languageName: node + linkType: hard + +"@testing-library/user-event@npm:^14.5.2": + version: 14.6.1 + resolution: "@testing-library/user-event@npm:14.6.1" + peerDependencies: + "@testing-library/dom": ">=7.21.4" + checksum: 10c0/75fea130a52bf320d35d46ed54f3eec77e71a56911b8b69a3fe29497b0b9947b2dc80d30f04054ad4ce7f577856ae3e5397ea7dff0ef14944d3909784c7a93fe + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.20.5": + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" + dependencies: + "@babel/parser": "npm:^7.20.7" + "@babel/types": "npm:^7.20.7" + "@types/babel__generator": "npm:*" + "@types/babel__template": "npm:*" + "@types/babel__traverse": "npm:*" + checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff + languageName: node + linkType: hard + +"@types/babel__generator@npm:*": + version: 7.27.0 + resolution: "@types/babel__generator@npm:7.27.0" + dependencies: + "@babel/types": "npm:^7.0.0" + checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd + languageName: node + linkType: hard + +"@types/babel__template@npm:*": + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" + dependencies: + "@babel/parser": "npm:^7.1.0" + "@babel/types": "npm:^7.0.0" + checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b + languageName: node + linkType: hard + +"@types/babel__traverse@npm:*": + version: 7.28.0 + resolution: "@types/babel__traverse@npm:7.28.0" + dependencies: + "@babel/types": "npm:^7.28.2" + checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + +"@types/get-params@npm:^0.1.2": + version: 0.1.2 + resolution: "@types/get-params@npm:0.1.2" + checksum: 10c0/7138af23d6acf0737d462263b8d2e5decfd282f1164aa7e2783c2fc9aeb2ec6aa10f6288605740356a916ecc4d27e01c1d8e6ad4c4fd0cd92790b8f482063cf6 + languageName: node + linkType: hard + +"@types/hoist-non-react-statics@npm:^3.3.0": + version: 3.3.7 + resolution: "@types/hoist-non-react-statics@npm:3.3.7" + dependencies: + hoist-non-react-statics: "npm:^3.3.0" + peerDependencies: + "@types/react": "*" + checksum: 10c0/ed8f4e88338f7d021d0f956adf6089d2a12b2e254a03c05292324f2e986d2376eb9efdb8a4f04596823e8fca88c9d06361d20dab4a2a00dc935fb36ac911de55 + languageName: node + linkType: hard + +"@types/humanize-duration@npm:^3.27.4": + version: 3.27.4 + resolution: "@types/humanize-duration@npm:3.27.4" + checksum: 10c0/0d92b036ac284c4ae248dca6efa826f9d397e7369f2d5e11de1813e05b32fd44e3d696f999acdc5a7eb412efc33668b8a68f6ad671392c0bbcf797a6329d674f + languageName: node + linkType: hard + +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/json5@npm:^0.0.29": + version: 0.0.29 + resolution: "@types/json5@npm:0.0.29" + checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac + languageName: node + linkType: hard + +"@types/lodash@npm:^4.17.6": + version: 4.17.21 + resolution: "@types/lodash@npm:4.17.21" + checksum: 10c0/73cb006e047d8871e9d63f3a165543bf16c44a5b6fe3f9f6299e37cb8d67a7b1d55ac730959a81f9def510fd07232ff7e30e05413e5d5a12793baad84ebe36c3 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 25.0.3 + resolution: "@types/node@npm:25.0.3" + dependencies: + undici-types: "npm:~7.16.0" + checksum: 10c0/b7568f0d765d9469621615e2bb257c7fd1953d95e9acbdb58dffb6627a2c4150d405a4600aa1ad8a40182a94fe5f903cafd3c0a2f5132814debd0e3bfd61f835 + languageName: node + linkType: hard + +"@types/node@npm:^22.15.29": + version: 22.19.3 + resolution: "@types/node@npm:22.19.3" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10c0/a30a75d503da795ddbd5f8851014f3e91925c2a63fa3f14128d54c998f25d682dfba96dc9589c73cf478b87a16d88beb790b11697bb8cd5bee913079237a58f2 + languageName: node + linkType: hard + +"@types/parse-json@npm:^4.0.0": + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 + languageName: node + linkType: hard + +"@types/prop-types@npm:^15.7.15": + version: 15.7.15 + resolution: "@types/prop-types@npm:15.7.15" + checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2 + languageName: node + linkType: hard + +"@types/react-dom@npm:^19.1.5": + version: 19.2.3 + resolution: "@types/react-dom@npm:19.2.3" + peerDependencies: + "@types/react": ^19.2.0 + checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1 + languageName: node + linkType: hard + +"@types/react-redux@npm:^7.1.34": + version: 7.1.34 + resolution: "@types/react-redux@npm:7.1.34" + dependencies: + "@types/hoist-non-react-statics": "npm:^3.3.0" + "@types/react": "npm:*" + hoist-non-react-statics: "npm:^3.3.0" + redux: "npm:^4.0.0" + checksum: 10c0/6750964ec656eb6973b0e4fda787549aee5dbc266a0f0e78fc9efb417b4965c0b060d10b99a7b7fa0c8812b8a0a07d97a1ef46d094bf64fee07144e8bbad781a + languageName: node + linkType: hard + +"@types/react-transition-group@npm:^4.4.12": + version: 4.4.12 + resolution: "@types/react-transition-group@npm:4.4.12" + peerDependencies: + "@types/react": "*" + checksum: 10c0/0441b8b47c69312c89ec0760ba477ba1a0808a10ceef8dc1c64b1013ed78517332c30f18681b0ec0b53542731f1ed015169fed1d127cc91222638ed955478ec7 + languageName: node + linkType: hard + +"@types/react@npm:*, @types/react@npm:^19.1.6": + version: 19.2.7 + resolution: "@types/react@npm:19.2.7" + dependencies: + csstype: "npm:^3.2.2" + checksum: 10c0/a7b75f1f9fcb34badd6f84098be5e35a0aeca614bc91f93d2698664c0b2ba5ad128422bd470ada598238cebe4f9e604a752aead7dc6f5a92261d0c7f9b27cfd1 + languageName: node + linkType: hard + +"@types/semver@npm:^7.5.8": + version: 7.7.1 + resolution: "@types/semver@npm:7.7.1" + checksum: 10c0/c938aef3bf79a73f0f3f6037c16e2e759ff40c54122ddf0b2583703393d8d3127130823facb880e694caa324eb6845628186aac1997ee8b31dc2d18fafe26268 + languageName: node + linkType: hard + +"@types/use-sync-external-store@npm:^0.0.6": + version: 0.0.6 + resolution: "@types/use-sync-external-store@npm:0.0.6" + checksum: 10c0/77c045a98f57488201f678b181cccd042279aff3da34540ad242f893acc52b358bd0a8207a321b8ac09adbcef36e3236944390e2df4fcedb556ce7bb2a88f2a8 + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.50.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.50.1" + "@typescript-eslint/type-utils": "npm:8.50.1" + "@typescript-eslint/utils": "npm:8.50.1" + "@typescript-eslint/visitor-keys": "npm:8.50.1" + ignore: "npm:^7.0.0" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + "@typescript-eslint/parser": ^8.50.1 + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/cae56cec414dc5d8347f1ff9fc01ec7b82c7988bcca9597569564b69e1715594e044487805a72ce7a9b4e6e81c3632db92c3d4b6b991874dafa402e1fcb508d5 + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/parser@npm:8.50.1" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.50.1" + "@typescript-eslint/types": "npm:8.50.1" + "@typescript-eslint/typescript-estree": "npm:8.50.1" + "@typescript-eslint/visitor-keys": "npm:8.50.1" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/60a2591745650b35cd8d425bb1959ef40d598245481bdfdc2654ed1f7878364c2c442ba70ca7105b650d0df2b6109727dd43214be76045667de0d32a221f3955 + languageName: node + linkType: hard + +"@typescript-eslint/project-service@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/project-service@npm:8.50.1" + dependencies: + "@typescript-eslint/tsconfig-utils": "npm:^8.50.1" + "@typescript-eslint/types": "npm:^8.50.1" + debug: "npm:^4.3.4" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/50fee0882188c2d704deddfb39f5283618adf7e5f72418143e9f69a8f3771233d55a3e0fc2673fa09c62e230ec53e500f95c0f1ed331ffac5f6a7f8e7b7a2e8c + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/scope-manager@npm:8.50.1" + dependencies: + "@typescript-eslint/types": "npm:8.50.1" + "@typescript-eslint/visitor-keys": "npm:8.50.1" + checksum: 10c0/ef0df092745f5d4e3684a3d770dc47735ab3195456de4ac5825931aeed1857a7e8d7cec14cc9c78c5ed049b3d83b0f8ac43b9463c5032ba548558a06bebb5539 + languageName: node + linkType: hard + +"@typescript-eslint/tsconfig-utils@npm:8.50.1, @typescript-eslint/tsconfig-utils@npm:^8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.50.1" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/6a1ffb0cd2d9e820ed0c7555a43ebb21438ca80f26c9632e0753bd09e764d9b8e9a352215e4ae60f6d570ab1e77751c9460a00515648b9a2f13f56c56a068a94 + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/type-utils@npm:8.50.1" + dependencies: + "@typescript-eslint/types": "npm:8.50.1" + "@typescript-eslint/typescript-estree": "npm:8.50.1" + "@typescript-eslint/utils": "npm:8.50.1" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/e4bfd3dd2459e936f7b6d9ee4b60fdedbf4b8f6b3d832e11d3cb1b58c1ce6da098880daafe3b65b2d33e2f79aba0e75c4b6eafdfa2a66c6e00a9ad3132b8e90d + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:8.50.1, @typescript-eslint/types@npm:^8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/types@npm:8.50.1" + checksum: 10c0/04e3c296d81293e370578762be6736fccd1581476f9d534938d42fe93968571fcaf26d7d8c3de52ed63a5af2c0b2da922b8ee2011fa5fb9fb401fc7f0916367a + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.50.1" + dependencies: + "@typescript-eslint/project-service": "npm:8.50.1" + "@typescript-eslint/tsconfig-utils": "npm:8.50.1" + "@typescript-eslint/types": "npm:8.50.1" + "@typescript-eslint/visitor-keys": "npm:8.50.1" + debug: "npm:^4.3.4" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.1.0" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/697b53fd3355619271a7bf543c5880731670b96567da63f554a3c3cd4d746feb8153628ec912c8a2df95e3123472e9a77df43c32fad72946b69ace89c2cf8b7e + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/utils@npm:8.50.1" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.7.0" + "@typescript-eslint/scope-manager": "npm:8.50.1" + "@typescript-eslint/types": "npm:8.50.1" + "@typescript-eslint/typescript-estree": "npm:8.50.1" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/66b19a9c8981b0b601af3a477fdcabdd110b0805591f28eefa11b32bbb88518d80b928e49eaa4c40d42ea8d71605bf5cd2ee5e39802022d1daec2800f1b198df + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:8.50.1": + version: 8.50.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.50.1" + dependencies: + "@typescript-eslint/types": "npm:8.50.1" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/b23839d04b2e5e7964a4006317d75cdc3cf76e56f4c5fde1e0bcd23f3bb78dca910e3dcadca80606f76a09ff9e44b3363ee1e1d6394e3f7479da74a641a8870f + languageName: node + linkType: hard + +"@vitejs/plugin-react@npm:^4.2.1": + version: 4.7.0 + resolution: "@vitejs/plugin-react@npm:4.7.0" + dependencies: + "@babel/core": "npm:^7.28.0" + "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" + "@rolldown/pluginutils": "npm:1.0.0-beta.27" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.17.0" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253 + languageName: node + linkType: hard + +"@vitest/expect@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/expect@npm:2.1.9" + dependencies: + "@vitest/spy": "npm:2.1.9" + "@vitest/utils": "npm:2.1.9" + chai: "npm:^5.1.2" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/98d1cf02917316bebef9e4720723e38298a1c12b3c8f3a81f259bb822de4288edf594e69ff64f0b88afbda6d04d7a4f0c2f720f3fec16b4c45f5e2669f09fdbb + languageName: node + linkType: hard + +"@vitest/mocker@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/mocker@npm:2.1.9" + dependencies: + "@vitest/spy": "npm:2.1.9" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.12" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10c0/f734490d8d1206a7f44dfdfca459282f5921d73efa72935bb1dc45307578defd38a4131b14853316373ec364cbe910dbc74594ed4137e0da35aa4d9bb716f190 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.1.9, @vitest/pretty-format@npm:^2.1.9": + version: 2.1.9 + resolution: "@vitest/pretty-format@npm:2.1.9" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/155f9ede5090eabed2a73361094bb35ed4ec6769ae3546d2a2af139166569aec41bb80e031c25ff2da22b71dd4ed51e5468e66a05e6aeda5f14b32e30bc18f00 + languageName: node + linkType: hard + +"@vitest/runner@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/runner@npm:2.1.9" + dependencies: + "@vitest/utils": "npm:2.1.9" + pathe: "npm:^1.1.2" + checksum: 10c0/e81f176badb12a815cbbd9bd97e19f7437a0b64e8934d680024b0f768d8670d59cad698ef0e3dada5241b6731d77a7bb3cd2c7cb29f751fd4dd35eb11c42963a + languageName: node + linkType: hard + +"@vitest/snapshot@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/snapshot@npm:2.1.9" + dependencies: + "@vitest/pretty-format": "npm:2.1.9" + magic-string: "npm:^0.30.12" + pathe: "npm:^1.1.2" + checksum: 10c0/394974b3a1fe96186a3c87f933b2f7f1f7b7cc42f9c781d80271dbb4c987809bf035fecd7398b8a3a2d54169e3ecb49655e38a0131d0e7fea5ce88960613b526 + languageName: node + linkType: hard + +"@vitest/spy@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/spy@npm:2.1.9" + dependencies: + tinyspy: "npm:^3.0.2" + checksum: 10c0/12a59b5095e20188b819a1d797e0a513d991b4e6a57db679927c43b362a3eff52d823b34e855a6dd9e73c9fa138dcc5ef52210841a93db5cbf047957a60ca83c + languageName: node + linkType: hard + +"@vitest/utils@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/utils@npm:2.1.9" + dependencies: + "@vitest/pretty-format": "npm:2.1.9" + loupe: "npm:^3.1.2" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/81a346cd72b47941f55411f5df4cc230e5f740d1e97e0d3f771b27f007266fc1f28d0438582f6409ea571bc0030ed37f684c64c58d1947d6298d770c21026fdf + languageName: node + linkType: hard + +"abbrev@npm:^4.0.0": + version: 4.0.0 + resolution: "abbrev@npm:4.0.0" + checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.15.0": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" + bin: + acorn: bin/acorn + checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec + languageName: node + linkType: hard + +"ag-auth@npm:^2.1.0": + version: 2.1.1 + resolution: "ag-auth@npm:2.1.1" + dependencies: + jsonwebtoken: "npm:^9.0.2" + sc-errors: "npm:^3.0.0" + checksum: 10c0/c8c15b751deae509020e28bc266d3a5d0a04adb7da5677d932afaf73c5193dfbd41f0b6bbf1ba771d0543bea9cf7c49ba0aaa8362e14160c240d7b586113750d + languageName: node + linkType: hard + +"ag-channel@npm:^5.0.0": + version: 5.0.0 + resolution: "ag-channel@npm:5.0.0" + dependencies: + consumable-stream: "npm:^2.0.0" + checksum: 10c0/54dcac553a21f28687c99beef8287c3c6bdebd23585fa9e1a54205eb46e8bf5bcd204c78ca5753ab0d5b01330576b49462cec6e8fdcfcf0f1478162439536ec4 + languageName: node + linkType: hard + +"ag-request@npm:^1.1.0": + version: 1.1.0 + resolution: "ag-request@npm:1.1.0" + dependencies: + sc-errors: "npm:^3.0.0" + checksum: 10c0/7a7a53252e66cab1a0e4ea422df83214ed9f277e895692c543aa2499184bc8812a65e3c8b4941c78ff949ecdff0fb8e8a12879e14c20e12057187cf801de2471 + languageName: node + linkType: hard + +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe + languageName: node + linkType: hard + +"ajv@npm:^6.12.4": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + languageName: node + linkType: hard + +"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": + version: 1.0.2 + resolution: "array-buffer-byte-length@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + is-array-buffer: "npm:^3.0.5" + checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d + languageName: node + linkType: hard + +"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8, array-includes@npm:^3.1.9": + version: 3.1.9 + resolution: "array-includes@npm:3.1.9" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.24.0" + es-object-atoms: "npm:^1.1.1" + get-intrinsic: "npm:^1.3.0" + is-string: "npm:^1.1.1" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856 + languageName: node + linkType: hard + +"array.prototype.findlast@npm:^1.2.5": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 + languageName: node + linkType: hard + +"array.prototype.findlastindex@npm:^1.2.6": + version: 1.2.6 + resolution: "array.prototype.findlastindex@npm:1.2.6" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.9" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + es-shim-unscopables: "npm:^1.1.0" + checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956 + languageName: node + linkType: hard + +"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.3": + version: 1.3.3 + resolution: "array.prototype.flat@npm:1.3.3" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.3": + version: 1.3.3 + resolution: "array.prototype.flatmap@npm:1.3.3" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54 + languageName: node + linkType: hard + +"array.prototype.tosorted@npm:^1.1.4": + version: 1.1.4 + resolution: "array.prototype.tosorted@npm:1.1.4" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.3" + es-errors: "npm:^1.3.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943 + languageName: node + linkType: hard + +"arraybuffer.prototype.slice@npm:^1.0.4": + version: 1.0.4 + resolution: "arraybuffer.prototype.slice@npm:1.0.4" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + is-array-buffer: "npm:^3.0.4" + checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06 + languageName: node + linkType: hard + +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 + languageName: node + linkType: hard + +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 + languageName: node + linkType: hard + +"async-generator-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-generator-function@npm:1.0.0" + checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186 + languageName: node + linkType: hard + +"async-stream-emitter@npm:^7.0.1": + version: 7.0.1 + resolution: "async-stream-emitter@npm:7.0.1" + dependencies: + stream-demux: "npm:^10.0.1" + checksum: 10c0/0e8d1daaca584f741dd10375748fa11bb7a52282d88c5b4ddcefeba776edf60dc3d4aa4820cdc0d162519b0838085ec250d427dd3e3b7f0926a91d95da320473 + languageName: node + linkType: hard + +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 + languageName: node + linkType: hard + +"babel-plugin-macros@npm:^3.1.0": + version: 3.1.0 + resolution: "babel-plugin-macros@npm:3.1.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + cosmiconfig: "npm:^7.0.0" + resolve: "npm:^1.19.0" + checksum: 10c0/c6dfb15de96f67871d95bd2e8c58b0c81edc08b9b087dc16755e7157f357dc1090a8dc60ebab955e92587a9101f02eba07e730adc253a1e4cf593ca3ebd3839c + languageName: node + linkType: hard + +"babel-plugin-react-compiler@npm:^1.0.0": + version: 1.0.0 + resolution: "babel-plugin-react-compiler@npm:1.0.0" + dependencies: + "@babel/types": "npm:^7.26.0" + checksum: 10c0/9406267ada8d7dbdfe8906b40ecadb816a5f4cee2922bee23f7729293b369624ee135b5a9b0f263851c263c9787522ac5d97016c9a2b82d1668300e42b18aff8 + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf + languageName: node + linkType: hard + +"baseline-browser-mapping@npm:^2.9.0": + version: 2.9.11 + resolution: "baseline-browser-mapping@npm:2.9.11" + bin: + baseline-browser-mapping: dist/cli.js + checksum: 10c0/eba49fcc1b33ab994aeeb73a4848f2670e06a0886dd5b903689ae6f60d47e7f1bea9262dbb2548c48179e858f7eda2b82ddf941ae783b862f4dcc51085a246f2 + languageName: node + linkType: hard + +"bl@npm:^1.2.1": + version: 1.2.3 + resolution: "bl@npm:1.2.3" + dependencies: + readable-stream: "npm:^2.3.5" + safe-buffer: "npm:^5.1.1" + checksum: 10c0/ee6478864d3b1295614f269f3fbabeb2362a2f2fc7f8dc2f6c1f944a278d84e0572ecefd6d0b0736d7418763f98dc3b2738253191ea9e98e4b08de211cfac0a6 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf + languageName: node + linkType: hard + +"browserslist@npm:^4.24.0": + version: 4.28.1 + resolution: "browserslist@npm:4.28.1" + dependencies: + baseline-browser-mapping: "npm:^2.9.0" + caniuse-lite: "npm:^1.0.30001759" + electron-to-chromium: "npm:^1.5.263" + node-releases: "npm:^2.0.27" + update-browserslist-db: "npm:^1.2.0" + bin: + browserslist: cli.js + checksum: 10c0/545a5fa9d7234e3777a7177ec1e9134bb2ba60a69e6b95683f6982b1473aad347c77c1264ccf2ac5dea609a9731fbfbda6b85782bdca70f80f86e28a402504bd + languageName: node + linkType: hard + +"buffer-equal-constant-time@npm:^1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 10c0/fb2294e64d23c573d0dd1f1e7a466c3e978fe94a4e0f8183937912ca374619773bef8e2aceb854129d2efecbbc515bbd0cc78d2734a3e3031edb0888531bbc8e + languageName: node + linkType: hard + +"buffer@npm:^5.2.1": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.1.13" + checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + languageName: node + linkType: hard + +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 + languageName: node + linkType: hard + +"cacache@npm:^20.0.1": + version: 20.0.3 + resolution: "cacache@npm:20.0.3" + dependencies: + "@npmcli/fs": "npm:^5.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^13.0.0" + lru-cache: "npm:^11.1.0" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^13.0.0" + unique-filename: "npm:^5.0.0" + checksum: 10c0/c7da1ca694d20e8f8aedabd21dc11518f809a7d2b59aa76a1fc655db5a9e62379e465c157ddd2afe34b19230808882288effa6911b2de26a088a6d5645123462 + languageName: node + linkType: hard + +"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + languageName: node + linkType: hard + +"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": + version: 1.0.8 + resolution: "call-bind@npm:1.0.8" + dependencies: + call-bind-apply-helpers: "npm:^1.0.0" + es-define-property: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.2" + checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4 + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 + languageName: node + linkType: hard + +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001759": + version: 1.0.30001761 + resolution: "caniuse-lite@npm:1.0.30001761" + checksum: 10c0/8ea4158ccd507b9c73c03b9b3b1b897e75d095c5753a131d0f36ef9b64c19a049174467842dd9e8bebe886ac27ed7a5b1d5adcaae5fe887716b07fc1103e100b + languageName: node + linkType: hard + +"canvas-renderer@npm:~2.2.0": + version: 2.2.1 + resolution: "canvas-renderer@npm:2.2.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/436f2f516723cf2cac03dcb189907b282249cc33446c6bce7760fb3ebd22689b0a4a27b3a3ab077a2c8204bd597a5e923da505520735b00cd839a790e6bdda50 + languageName: node + linkType: hard + +"chai@npm:^5.1.2": + version: 5.3.3 + resolution: "chai@npm:5.3.3" + dependencies: + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10c0/b360fd4d38861622e5010c2f709736988b05c7f31042305fa3f4e9911f6adb80ccfb4e302068bf8ed10e835c2e2520cba0f5edc13d878b886987e5aa62483f53 + languageName: node + linkType: hard + +"chalk@npm:^4.0.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + languageName: node + linkType: hard + +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + +"clone-deep@npm:^4.0.1": + version: 4.0.1 + resolution: "clone-deep@npm:4.0.1" + dependencies: + is-plain-object: "npm:^2.0.4" + kind-of: "npm:^6.0.2" + shallow-clone: "npm:^3.0.0" + checksum: 10c0/637753615aa24adf0f2d505947a1bb75e63964309034a1cf56ba4b1f30af155201edd38d26ffe26911adaae267a3c138b344a4947d39f5fc1b6d6108125aa758 + languageName: node + linkType: hard + +"clsx@npm:^1.1.0": + version: 1.2.1 + resolution: "clsx@npm:1.2.1" + checksum: 10c0/34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27 + languageName: node + linkType: hard + +"clsx@npm:^2.1.1": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f + languageName: node + linkType: hard + +"consumable-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "consumable-stream@npm:2.0.0" + checksum: 10c0/4276ac662d254ef17e38daeaf280584801906a661ab215bde5cc3a37e6bd3def428c19abd8db601527a1582c065529ad9608466f09619ba3d1dcd89abcfadaea + languageName: node + linkType: hard + +"consumable-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "consumable-stream@npm:3.0.0" + checksum: 10c0/a6e9a7f29666aa135e898628edf3671d92b6fe061dcab1eff6f8eadb35438ea0f6eb2d782b9ca8320bb05ae2e73706986a17392f2c6bcd5e5c6826745d353fcb + languageName: node + linkType: hard + +"convert-source-map@npm:^1.5.0": + version: 1.9.0 + resolution: "convert-source-map@npm:1.9.0" + checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + +"cookie@npm:^1.0.1": + version: 1.1.1 + resolution: "cookie@npm:1.1.1" + checksum: 10c0/79c4ddc0fcad9c4f045f826f42edf54bcc921a29586a4558b0898277fa89fb47be95bc384c2253f493af7b29500c830da28341274527328f18eba9f58afa112c + languageName: node + linkType: hard + +"core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 + languageName: node + linkType: hard + +"cosmiconfig@npm:^7.0.0": + version: 7.1.0 + resolution: "cosmiconfig@npm:7.1.0" + dependencies: + "@types/parse-json": "npm:^4.0.0" + import-fresh: "npm:^3.2.1" + parse-json: "npm:^5.0.0" + path-type: "npm:^4.0.0" + yaml: "npm:^1.10.0" + checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + +"csstype@npm:^3.0.10, csstype@npm:^3.0.2, csstype@npm:^3.1.3, csstype@npm:^3.2.2": + version: 3.2.3 + resolution: "csstype@npm:3.2.3" + checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce + languageName: node + linkType: hard + +"data-view-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "data-view-buffer@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.2" + checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c + languageName: node + linkType: hard + +"data-view-byte-length@npm:^1.0.2": + version: 1.0.2 + resolution: "data-view-byte-length@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.2" + checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55 + languageName: node + linkType: hard + +"data-view-byte-offset@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-offset@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4 + languageName: node + linkType: hard + +"dayjs@npm:^1.11.13": + version: 1.11.19 + resolution: "dayjs@npm:1.11.19" + checksum: 10c0/7d8a6074a343f821f81ea284d700bd34ea6c7abbe8d93bce7aba818948957c1b7f56131702e5e890a5622cdfc05dcebe8aed0b8313bdc6838a594d7846b0b000 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + +"debug@npm:^3.2.7": + version: 3.2.7 + resolution: "debug@npm:3.2.7" + dependencies: + ms: "npm:^2.1.1" + checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a + languageName: node + linkType: hard + +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 + languageName: node + linkType: hard + +"deep-is@npm:^0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c + languageName: node + linkType: hard + +"default-gateway@npm:^6.0.3": + version: 6.0.3 + resolution: "default-gateway@npm:6.0.3" + dependencies: + execa: "npm:^5.0.0" + checksum: 10c0/5184f9e6e105d24fb44ade9e8741efa54bb75e84625c1ea78c4ef8b81dff09ca52d6dbdd1185cf0dc655bb6b282a64fffaf7ed2dd561b8d9ad6f322b1f039aba + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 + languageName: node + linkType: hard + +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" + dependencies: + define-data-property: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 + languageName: node + linkType: hard + +"dns-over-http-resolver@npm:^1.2.3": + version: 1.2.3 + resolution: "dns-over-http-resolver@npm:1.2.3" + dependencies: + debug: "npm:^4.3.1" + native-fetch: "npm:^3.0.0" + receptacle: "npm:^1.3.2" + checksum: 10c0/231435742246115aeb4f153721effc4d995ab8f22572240b27d85e1be4123345cbe503e9922bc46b36caaa86307fbcf65ba252302dc7a4794f330aa6d6f920b8 + languageName: node + linkType: hard + +"doctrine@npm:^2.1.0": + version: 2.1.0 + resolution: "doctrine@npm:2.1.0" + dependencies: + esutils: "npm:^2.0.2" + checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac + languageName: node + linkType: hard + +"dom-helpers@npm:^5.0.1": + version: 5.2.1 + resolution: "dom-helpers@npm:5.2.1" + dependencies: + "@babel/runtime": "npm:^7.8.7" + csstype: "npm:^3.0.2" + checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c + languageName: node + linkType: hard + +"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 + languageName: node + linkType: hard + +"ecdsa-sig-formatter@npm:1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 10c0/ebfbf19d4b8be938f4dd4a83b8788385da353d63307ede301a9252f9f7f88672e76f2191618fd8edfc2f24679236064176fab0b78131b161ee73daa37125408c + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.263": + version: 1.5.267 + resolution: "electron-to-chromium@npm:1.5.267" + checksum: 10c0/0732bdb891b657f2e43266a3db8cf86fff6cecdcc8d693a92beff214e136cb5c2ee7dc5945ed75fa1db16e16bad0c38695527a020d15f39e79084e0b2e447621 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 + languageName: node + linkType: hard + +"err-code@npm:^3.0.1": + version: 3.0.1 + resolution: "err-code@npm:3.0.1" + checksum: 10c0/78b1c50500adebde6699b8d27b8ce4728c132dcaad75b5d18ba44f6ccb28769d1fff8368ae1164be4559dac8b95d4e26bb15b480ba9999e0cd0f0c64beaf1b24 + languageName: node + linkType: hard + +"error-ex@npm:^1.3.1": + version: 1.3.4 + resolution: "error-ex@npm:1.3.4" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664 + languageName: node + linkType: hard + +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0, es-abstract@npm:^1.24.1": + version: 1.24.1 + resolution: "es-abstract@npm:1.24.1" + dependencies: + array-buffer-byte-length: "npm:^1.0.2" + arraybuffer.prototype.slice: "npm:^1.0.4" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + data-view-buffer: "npm:^1.0.2" + data-view-byte-length: "npm:^1.0.2" + data-view-byte-offset: "npm:^1.0.1" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + es-set-tostringtag: "npm:^2.1.0" + es-to-primitive: "npm:^1.3.0" + function.prototype.name: "npm:^1.1.8" + get-intrinsic: "npm:^1.3.0" + get-proto: "npm:^1.0.1" + get-symbol-description: "npm:^1.1.0" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.2.0" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + internal-slot: "npm:^1.1.0" + is-array-buffer: "npm:^3.0.5" + is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.2" + is-negative-zero: "npm:^2.0.3" + is-regex: "npm:^1.2.1" + is-set: "npm:^2.0.3" + is-shared-array-buffer: "npm:^1.0.4" + is-string: "npm:^1.1.1" + is-typed-array: "npm:^1.1.15" + is-weakref: "npm:^1.1.1" + math-intrinsics: "npm:^1.1.0" + object-inspect: "npm:^1.13.4" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.7" + own-keys: "npm:^1.0.1" + regexp.prototype.flags: "npm:^1.5.4" + safe-array-concat: "npm:^1.1.3" + safe-push-apply: "npm:^1.0.0" + safe-regex-test: "npm:^1.1.0" + set-proto: "npm:^1.0.0" + stop-iteration-iterator: "npm:^1.1.0" + string.prototype.trim: "npm:^1.2.10" + string.prototype.trimend: "npm:^1.0.9" + string.prototype.trimstart: "npm:^1.0.8" + typed-array-buffer: "npm:^1.0.3" + typed-array-byte-length: "npm:^1.0.3" + typed-array-byte-offset: "npm:^1.0.4" + typed-array-length: "npm:^1.0.7" + unbox-primitive: "npm:^1.1.0" + which-typed-array: "npm:^1.1.19" + checksum: 10c0/fca062ef8b5daacf743732167d319a212d45cb655b0bb540821d38d715416ae15b04b84fc86da9e2c89135aa7b337337b6c867f84dcde698d75d55688d5d765c + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 + languageName: node + linkType: hard + +"es-iterator-helpers@npm:^1.2.1": + version: 1.2.2 + resolution: "es-iterator-helpers@npm:1.2.2" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.24.1" + es-errors: "npm:^1.3.0" + es-set-tostringtag: "npm:^2.1.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.3.0" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.2.0" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + internal-slot: "npm:^1.1.0" + iterator.prototype: "npm:^1.1.5" + safe-array-concat: "npm:^1.1.3" + checksum: 10c0/1ced8abf845a45e660dd77b5f3a64358421df70e4a0bd1897d5ddfefffed8409a6a2ca21241b9367e639df9eca74abc1c678b3020bffe6bee1f1826393658ddb + languageName: node + linkType: hard + +"es-module-lexer@npm:^1.5.4": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": + version: 1.1.0 + resolution: "es-shim-unscopables@npm:1.1.0" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb + languageName: node + linkType: hard + +"es-to-primitive@npm:^1.3.0": + version: 1.3.0 + resolution: "es-to-primitive@npm:1.3.0" + dependencies: + is-callable: "npm:^1.2.7" + is-date-object: "npm:^1.0.5" + is-symbol: "npm:^1.0.4" + checksum: 10c0/c7e87467abb0b438639baa8139f701a06537d2b9bc758f23e8622c3b42fd0fdb5bde0f535686119e446dd9d5e4c0f238af4e14960f4771877cf818d023f6730b + languageName: node + linkType: hard + +"esbuild@npm:^0.21.3": + version: 0.21.5 + resolution: "esbuild@npm:0.21.5" + dependencies: + "@esbuild/aix-ppc64": "npm:0.21.5" + "@esbuild/android-arm": "npm:0.21.5" + "@esbuild/android-arm64": "npm:0.21.5" + "@esbuild/android-x64": "npm:0.21.5" + "@esbuild/darwin-arm64": "npm:0.21.5" + "@esbuild/darwin-x64": "npm:0.21.5" + "@esbuild/freebsd-arm64": "npm:0.21.5" + "@esbuild/freebsd-x64": "npm:0.21.5" + "@esbuild/linux-arm": "npm:0.21.5" + "@esbuild/linux-arm64": "npm:0.21.5" + "@esbuild/linux-ia32": "npm:0.21.5" + "@esbuild/linux-loong64": "npm:0.21.5" + "@esbuild/linux-mips64el": "npm:0.21.5" + "@esbuild/linux-ppc64": "npm:0.21.5" + "@esbuild/linux-riscv64": "npm:0.21.5" + "@esbuild/linux-s390x": "npm:0.21.5" + "@esbuild/linux-x64": "npm:0.21.5" + "@esbuild/netbsd-x64": "npm:0.21.5" + "@esbuild/openbsd-x64": "npm:0.21.5" + "@esbuild/sunos-x64": "npm:0.21.5" + "@esbuild/win32-arm64": "npm:0.21.5" + "@esbuild/win32-ia32": "npm:0.21.5" + "@esbuild/win32-x64": "npm:0.21.5" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/fa08508adf683c3f399e8a014a6382a6b65542213431e26206c0720e536b31c09b50798747c2a105a4bbba1d9767b8d3615a74c2f7bf1ddf6d836cd11eb672de + languageName: node + linkType: hard + +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 + languageName: node + linkType: hard + +"eslint-import-resolver-node@npm:^0.3.9": + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" + dependencies: + debug: "npm:^3.2.7" + is-core-module: "npm:^2.13.0" + resolve: "npm:^1.22.4" + checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 + languageName: node + linkType: hard + +"eslint-module-utils@npm:^2.12.1": + version: 2.12.1 + resolution: "eslint-module-utils@npm:2.12.1" + dependencies: + debug: "npm:^3.2.7" + peerDependenciesMeta: + eslint: + optional: true + checksum: 10c0/6f4efbe7a91ae49bf67b4ab3644cb60bc5bd7db4cb5521de1b65be0847ffd3fb6bce0dd68f0995e1b312d137f768e2a1f842ee26fe73621afa05f850628fdc40 + languageName: node + linkType: hard + +"eslint-plugin-import@npm:^2.32.0": + version: 2.32.0 + resolution: "eslint-plugin-import@npm:2.32.0" + dependencies: + "@rtsao/scc": "npm:^1.1.0" + array-includes: "npm:^3.1.9" + array.prototype.findlastindex: "npm:^1.2.6" + array.prototype.flat: "npm:^1.3.3" + array.prototype.flatmap: "npm:^1.3.3" + debug: "npm:^3.2.7" + doctrine: "npm:^2.1.0" + eslint-import-resolver-node: "npm:^0.3.9" + eslint-module-utils: "npm:^2.12.1" + hasown: "npm:^2.0.2" + is-core-module: "npm:^2.16.1" + is-glob: "npm:^4.0.3" + minimatch: "npm:^3.1.2" + object.fromentries: "npm:^2.0.8" + object.groupby: "npm:^1.0.3" + object.values: "npm:^1.2.1" + semver: "npm:^6.3.1" + string.prototype.trimend: "npm:^1.0.9" + tsconfig-paths: "npm:^3.15.0" + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + checksum: 10c0/bfb1b8fc8800398e62ddfefbf3638d185286edfed26dfe00875cc2846d954491b4f5112457831588b757fa789384e1ae585f812614c4797f0499fa234fd4a48b + languageName: node + linkType: hard + +"eslint-plugin-react-hooks@npm:^7.0.1": + version: 7.0.1 + resolution: "eslint-plugin-react-hooks@npm:7.0.1" + dependencies: + "@babel/core": "npm:^7.24.4" + "@babel/parser": "npm:^7.24.4" + hermes-parser: "npm:^0.25.1" + zod: "npm:^3.25.0 || ^4.0.0" + zod-validation-error: "npm:^3.5.0 || ^4.0.0" + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + checksum: 10c0/1e711d1a9d1fa9cfc51fa1572500656577201199c70c795c6a27adfc1df39e5c598f69aab6aa91117753d23cc1f11388579a2bed14921cf9a4efe60ae8618496 + languageName: node + linkType: hard + +"eslint-plugin-react@npm:^7.35.0": + version: 7.37.5 + resolution: "eslint-plugin-react@npm:7.37.5" + dependencies: + array-includes: "npm:^3.1.8" + array.prototype.findlast: "npm:^1.2.5" + array.prototype.flatmap: "npm:^1.3.3" + array.prototype.tosorted: "npm:^1.1.4" + doctrine: "npm:^2.1.0" + es-iterator-helpers: "npm:^1.2.1" + estraverse: "npm:^5.3.0" + hasown: "npm:^2.0.2" + jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" + minimatch: "npm:^3.1.2" + object.entries: "npm:^1.1.9" + object.fromentries: "npm:^2.0.8" + object.values: "npm:^1.2.1" + prop-types: "npm:^15.8.1" + resolve: "npm:^2.0.0-next.5" + semver: "npm:^6.3.1" + string.prototype.matchall: "npm:^4.0.12" + string.prototype.repeat: "npm:^1.0.0" + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 + languageName: node + linkType: hard + +"eslint-scope@npm:^8.4.0": + version: 8.4.0 + resolution: "eslint-scope@npm:8.4.0" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 + languageName: node + linkType: hard + +"eslint@npm:^9.9.0": + version: 9.39.2 + resolution: "eslint@npm:9.39.2" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.1" + "@eslint/config-array": "npm:^0.21.1" + "@eslint/config-helpers": "npm:^0.4.2" + "@eslint/core": "npm:^0.17.0" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:9.39.2" + "@eslint/plugin-kit": "npm:^0.4.1" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + ajv: "npm:^6.12.4" + chalk: "npm:^4.0.0" + cross-spawn: "npm:^7.0.6" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^8.4.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" + esquery: "npm:^1.5.0" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^8.0.0" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + lodash.merge: "npm:^4.6.2" + minimatch: "npm:^3.1.2" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + bin: + eslint: bin/eslint.js + checksum: 10c0/bb88ca8fd16bb7e1ac3e13804c54d41c583214460c0faa7b3e7c574e69c5600c7122295500fb4b0c06067831111db740931e98da1340329527658e1cf80073d3 + languageName: node + linkType: hard + +"espree@npm:^10.0.1, espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" + dependencies: + acorn: "npm:^8.15.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b + languageName: node + linkType: hard + +"esquery@npm:^1.5.0": + version: 1.6.0 + resolution: "esquery@npm:1.6.0" + dependencies: + estraverse: "npm:^5.1.0" + checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + languageName: node + linkType: hard + +"execa@npm:^5.0.0": + version: 5.1.1 + resolution: "execa@npm:5.1.1" + dependencies: + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^6.0.0" + human-signals: "npm:^2.1.0" + is-stream: "npm:^2.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^4.0.1" + onetime: "npm:^5.1.2" + signal-exit: "npm:^3.0.3" + strip-final-newline: "npm:^2.0.0" + checksum: 10c0/c8e615235e8de4c5addf2fa4c3da3e3aa59ce975a3e83533b4f6a71750fb816a2e79610dc5f1799b6e28976c9ae86747a36a606655bf8cb414a74d8d507b304f + languageName: node + linkType: hard + +"expect-type@npm:^1.1.0": + version: 1.3.0 + resolution: "expect-type@npm:1.3.0" + checksum: 10c0/8412b3fe4f392c420ab41dae220b09700e4e47c639a29ba7ba2e83cc6cffd2b4926f7ac9e47d7e277e8f4f02acda76fd6931cb81fd2b382fa9477ef9ada953fd + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + languageName: node + linkType: hard + +"fast-levenshtein@npm:^2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 + languageName: node + linkType: hard + +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" + dependencies: + flat-cache: "npm:^4.0.0" + checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 + languageName: node + linkType: hard + +"find-root@npm:^1.1.0": + version: 1.1.0 + resolution: "find-root@npm:1.1.0" + checksum: 10c0/1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa + languageName: node + linkType: hard + +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a + languageName: node + linkType: hard + +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" + dependencies: + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.4" + checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc + languageName: node + linkType: hard + +"flatted@npm:^3.2.9": + version: 3.3.3 + resolution: "flatted@npm:3.3.3" + checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 + languageName: node + linkType: hard + +"for-each@npm:^0.3.3, for-each@npm:^0.3.5": + version: 0.3.5 + resolution: "for-each@npm:0.3.5" + dependencies: + is-callable: "npm:^1.2.7" + checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 + languageName: node + linkType: hard + +"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": + version: 1.1.8 + resolution: "function.prototype.name@npm:1.1.8" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + functions-have-names: "npm:^1.2.3" + hasown: "npm:^2.0.2" + is-callable: "npm:^1.2.7" + checksum: 10c0/e920a2ab52663005f3cbe7ee3373e3c71c1fb5558b0b0548648cdf3e51961085032458e26c71ff1a8c8c20e7ee7caeb03d43a5d1fa8610c459333323a2e71253 + languageName: node + linkType: hard + +"functions-have-names@npm:^1.2.3": + version: 1.2.3 + resolution: "functions-have-names@npm:1.2.3" + checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca + languageName: node + linkType: hard + +"generator-function@npm:^2.0.0": + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 + languageName: node + linkType: hard + +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": + version: 1.3.1 + resolution: "get-intrinsic@npm:1.3.1" + dependencies: + async-function: "npm:^1.0.0" + async-generator-function: "npm:^1.0.0" + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + function-bind: "npm:^1.1.2" + generator-function: "npm:^2.0.0" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d + languageName: node + linkType: hard + +"get-params@npm:^0.1.2": + version: 0.1.2 + resolution: "get-params@npm:0.1.2" + checksum: 10c0/bf83ed37d2c5e9d9cf04b0d9d380fa3f29997e4c4c5cbbcda0112747a43148111ab5a054e1681819aeb24b98726053196b183830ad9a4b246bdc5f79af5792f7 + languageName: node + linkType: hard + +"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c + languageName: node + linkType: hard + +"get-stream@npm:^6.0.0": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.1.0": + version: 1.1.0 + resolution: "get-symbol-description@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + languageName: node + linkType: hard + +"glob@npm:^13.0.0": + version: 13.0.0 + resolution: "glob@npm:13.0.0" + dependencies: + minimatch: "npm:^10.1.1" + minipass: "npm:^7.1.2" + path-scurry: "npm:^2.0.0" + checksum: 10c0/8e2f5821f3f7c312dd102e23a15b80c79e0837a9872784293ba2e15ec73b3f3749a49a42a31bfcb4e52c84820a474e92331c2eebf18819d20308f5c33876630a + languageName: node + linkType: hard + +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d + languageName: node + linkType: hard + +"globals@npm:^15.9.0": + version: 15.15.0 + resolution: "globals@npm:15.15.0" + checksum: 10c0/f9ae80996392ca71316495a39bec88ac43ae3525a438b5626cd9d5ce9d5500d0a98a266409605f8cd7241c7acf57c354a48111ea02a767ba4f374b806d6861fe + languageName: node + linkType: hard + +"globalthis@npm:^1.0.4": + version: 1.0.4 + resolution: "globalthis@npm:1.0.4" + dependencies: + define-properties: "npm:^1.2.1" + gopd: "npm:^1.0.1" + checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 + languageName: node + linkType: hard + +"globrex@npm:^0.1.2": + version: 0.1.2 + resolution: "globrex@npm:0.1.2" + checksum: 10c0/a54c029520cf58bda1d8884f72bd49b4cd74e977883268d931fd83bcbd1a9eb96d57c7dbd4ad80148fb9247467ebfb9b215630b2ed7563b2a8de02e1ff7f89d1 + languageName: node + linkType: hard + +"goober@npm:^2.0.33": + version: 2.1.18 + resolution: "goober@npm:2.1.18" + peerDependencies: + csstype: ^3.0.10 + checksum: 10c0/de9bf7b6f57417900afac81a479b85d8c0bcb0322ba8b174f9287d10e7891ba7e33db5fe2b0cdd75281c69130e76eb0c694345acf45ea57e4e4a2db8e4c4f021 + languageName: node + linkType: hard + +"gopd@npm:^1.0.1, gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"has-bigints@npm:^1.0.2": + version: 1.1.0 + resolution: "has-bigints@npm:1.1.0" + checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + languageName: node + linkType: hard + +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: "npm:^1.0.0" + checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 + languageName: node + linkType: hard + +"has-proto@npm:^1.2.0": + version: 1.2.0 + resolution: "has-proto@npm:1.2.0" + dependencies: + dunder-proto: "npm:^1.0.0" + checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95 + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e + languageName: node + linkType: hard + +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 + languageName: node + linkType: hard + +"hermes-estree@npm:0.25.1": + version: 0.25.1 + resolution: "hermes-estree@npm:0.25.1" + checksum: 10c0/48be3b2fa37a0cbc77a112a89096fa212f25d06de92781b163d67853d210a8a5c3784fac23d7d48335058f7ed283115c87b4332c2a2abaaccc76d0ead1a282ac + languageName: node + linkType: hard + +"hermes-parser@npm:^0.25.1": + version: 0.25.1 + resolution: "hermes-parser@npm:0.25.1" + dependencies: + hermes-estree: "npm:0.25.1" + checksum: 10c0/3abaa4c6f1bcc25273f267297a89a4904963ea29af19b8e4f6eabe04f1c2c7e9abd7bfc4730ddb1d58f2ea04b6fee74053d8bddb5656ec6ebf6c79cc8d14202c + languageName: node + linkType: hard + +"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1": + version: 3.3.2 + resolution: "hoist-non-react-statics@npm:3.3.2" + dependencies: + react-is: "npm:^16.7.0" + checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac + languageName: node + linkType: hard + +"human-signals@npm:^2.1.0": + version: 2.1.0 + resolution: "human-signals@npm:2.1.0" + checksum: 10c0/695edb3edfcfe9c8b52a76926cd31b36978782062c0ed9b1192b36bebc75c4c87c82e178dfcb0ed0fc27ca59d434198aac0bd0be18f5781ded775604db22304a + languageName: node + linkType: hard + +"humanize-duration@npm:^3.32.1": + version: 3.33.2 + resolution: "humanize-duration@npm:3.33.2" + checksum: 10c0/eae493c113f1c11c96e42195002e8016ab7c08bfcc3414ba5459027da4faaa2df012429bc4eae200873a65d0a86b7cc6a9656783aa45705ffe6106b5256af973 + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + languageName: node + linkType: hard + +"ignore@npm:^5.2.0": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + +"ignore@npm:^7.0.0": + version: 7.0.5 + resolution: "ignore@npm:7.0.5" + checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d + languageName: node + linkType: hard + +"immer@npm:^11.0.0": + version: 11.1.0 + resolution: "immer@npm:11.1.0" + checksum: 10c0/cc1f14037534802a662f0113d80b4695685d789b84ab4a56a241a384df32f57f12332d1643fa3b3cc7a2504b076efb07aead08732796c8e019569d95b8b7f1cd + languageName: node + linkType: hard + +"immutable@npm:^4.3.7": + version: 4.3.7 + resolution: "immutable@npm:4.3.7" + checksum: 10c0/9b099197081b22f6433003e34929da8ecddbbdc1474cdc8aa3b7669dee4adda349c06143de22def36016d1b6de5322b043eccd7a11db1dad2ca85dad4fff5435 + languageName: node + linkType: hard + +"import-fresh@npm:^3.2.1": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" + dependencies: + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + languageName: node + linkType: hard + +"inherits@npm:~2.0.3": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + +"internal-ip@npm:^7.0.0": + version: 7.0.0 + resolution: "internal-ip@npm:7.0.0" + dependencies: + default-gateway: "npm:^6.0.3" + ipaddr.js: "npm:^2.0.1" + is-ip: "npm:^3.1.0" + p-event: "npm:^4.2.0" + checksum: 10c0/22eb24ad1e1c5eb9c3742cfb4ce7c85b3328632aee8f595e5587e699c386b46b44c6655141135187ed09c60a19e7357188f2cf306ee569711f23f8a8cf56f359 + languageName: node + linkType: hard + +"internal-slot@npm:^1.1.0": + version: 1.1.0 + resolution: "internal-slot@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.2" + side-channel: "npm:^1.1.0" + checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7 + languageName: node + linkType: hard + +"ip-address@npm:^10.0.1": + version: 10.1.0 + resolution: "ip-address@npm:10.1.0" + checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 + languageName: node + linkType: hard + +"ip-regex@npm:^4.0.0": + version: 4.3.0 + resolution: "ip-regex@npm:4.3.0" + checksum: 10c0/f9ef1f5d0df05b9133a882974e572ae525ccd205260cb103dae337f1fc7451ed783391acc6ad688e56dd2598f769e8e72ecbb650ec34763396af822a91768562 + languageName: node + linkType: hard + +"ipaddr.js@npm:^2.0.1": + version: 2.3.0 + resolution: "ipaddr.js@npm:2.3.0" + checksum: 10c0/084bab99e2f6875d7a62adc3325e1c64b038a12c9521e35fb967b5e263a8b3afb1b8884dd77c276092331f5d63298b767491e10997ef147c62da01b143780bbd + languageName: node + linkType: hard + +"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": + version: 3.0.5 + resolution: "is-array-buffer@npm:3.0.5" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d + languageName: node + linkType: hard + +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + languageName: node + linkType: hard + +"is-async-function@npm:^2.0.0": + version: 2.1.1 + resolution: "is-async-function@npm:2.1.1" + dependencies: + async-function: "npm:^1.0.0" + call-bound: "npm:^1.0.3" + get-proto: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298 + languageName: node + linkType: hard + +"is-bigint@npm:^1.1.0": + version: 1.1.0 + resolution: "is-bigint@npm:1.1.0" + dependencies: + has-bigints: "npm:^1.0.2" + checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4 + languageName: node + linkType: hard + +"is-boolean-object@npm:^1.2.1": + version: 1.2.2 + resolution: "is-boolean-object@npm:1.2.2" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e + languageName: node + linkType: hard + +"is-callable@npm:^1.2.7": + version: 1.2.7 + resolution: "is-callable@npm:1.2.7" + checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f + languageName: node + linkType: hard + +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": + version: 2.16.1 + resolution: "is-core-module@npm:2.16.1" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd + languageName: node + linkType: hard + +"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": + version: 1.0.2 + resolution: "is-data-view@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.6" + is-typed-array: "npm:^1.1.13" + checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153 + languageName: node + linkType: hard + +"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0": + version: 1.1.0 + resolution: "is-date-object@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + +"is-finalizationregistry@npm:^1.1.0": + version: 1.1.1 + resolution: "is-finalizationregistry@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97 + languageName: node + linkType: hard + +"is-generator-function@npm:^1.0.10": + version: 1.1.2 + resolution: "is-generator-function@npm:1.1.2" + dependencies: + call-bound: "npm:^1.0.4" + generator-function: "npm:^2.0.0" + get-proto: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/83da102e89c3e3b71d67b51d47c9f9bc862bceb58f87201727e27f7fa19d1d90b0ab223644ecaee6fc6e3d2d622bb25c966fbdaf87c59158b01ce7c0fe2fa372 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + languageName: node + linkType: hard + +"is-ip@npm:^3.1.0": + version: 3.1.0 + resolution: "is-ip@npm:3.1.0" + dependencies: + ip-regex: "npm:^4.0.0" + checksum: 10c0/4cb643c831314b8fc72770c93a795c0d3dde339f36c8430544c36727956027e2cb329641ace73c5951085ecf93ac608c898859d3d4f7b117d405e1e13c703c76 + languageName: node + linkType: hard + +"is-map@npm:^2.0.3": + version: 2.0.3 + resolution: "is-map@npm:2.0.3" + checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc + languageName: node + linkType: hard + +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e + languageName: node + linkType: hard + +"is-number-object@npm:^1.1.1": + version: 1.1.1 + resolution: "is-number-object@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53 + languageName: node + linkType: hard + +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: "npm:^3.0.1" + checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 + languageName: node + linkType: hard + +"is-regex@npm:^1.2.1": + version: 1.2.1 + resolution: "is-regex@npm:1.2.1" + dependencies: + call-bound: "npm:^1.0.2" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04 + languageName: node + linkType: hard + +"is-set@npm:^2.0.3": + version: 2.0.3 + resolution: "is-set@npm:2.0.3" + checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 + languageName: node + linkType: hard + +"is-shared-array-buffer@npm:^1.0.4": + version: 1.0.4 + resolution: "is-shared-array-buffer@npm:1.0.4" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db + languageName: node + linkType: hard + +"is-stream@npm:^2.0.0": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 + languageName: node + linkType: hard + +"is-string@npm:^1.1.1": + version: 1.1.1 + resolution: "is-string@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d + languageName: node + linkType: hard + +"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1": + version: 1.1.1 + resolution: "is-symbol@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.2" + has-symbols: "npm:^1.1.0" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e + languageName: node + linkType: hard + +"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": + version: 1.1.15 + resolution: "is-typed-array@npm:1.1.15" + dependencies: + which-typed-array: "npm:^1.1.16" + checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4 + languageName: node + linkType: hard + +"is-weakmap@npm:^2.0.2": + version: 2.0.2 + resolution: "is-weakmap@npm:2.0.2" + checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 + languageName: node + linkType: hard + +"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": + version: 1.1.1 + resolution: "is-weakref@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b + languageName: node + linkType: hard + +"is-weakset@npm:^2.0.3": + version: 2.0.4 + resolution: "is-weakset@npm:2.0.4" + dependencies: + call-bound: "npm:^1.0.3" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647 + languageName: node + linkType: hard + +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd + languageName: node + linkType: hard + +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 + languageName: node + linkType: hard + +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db + languageName: node + linkType: hard + +"iterator.prototype@npm:^1.1.5": + version: 1.1.5 + resolution: "iterator.prototype@npm:1.1.5" + dependencies: + define-data-property: "npm:^1.1.4" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.6" + get-proto: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" + set-function-name: "npm:^2.0.2" + checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0 + languageName: node + linkType: hard + +"jdenticon@npm:^3.3.0": + version: 3.3.0 + resolution: "jdenticon@npm:3.3.0" + dependencies: + canvas-renderer: "npm:~2.2.0" + bin: + jdenticon: bin/jdenticon.js + checksum: 10c0/be2642fe3a9a9013d56ced80ec76a2ae6990363d7c2d92470125fc3d646fe711ba8a8695e49cd5bd696b84574fab4e93f3694414fdb95e150c5ce340c385d9e1 + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"js-yaml@npm:^4.1.1": + version: 4.1.1 + resolution: "js-yaml@npm:4.1.1" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7 + languageName: node + linkType: hard + +"jsan@npm:^3.1.14": + version: 3.1.14 + resolution: "jsan@npm:3.1.14" + checksum: 10c0/86b6738e90769d8e717849f7bd9ba4742a4ffb1edfa28354521e0c8f106a3addd15eb79d723b47dc9867c70ed06245e4ee14cb2a10c99b91ea612071688137dc + languageName: node + linkType: hard + +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + languageName: node + linkType: hard + +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 + languageName: node + linkType: hard + +"json5@npm:^1.0.2": + version: 1.0.2 + resolution: "json5@npm:1.0.2" + dependencies: + minimist: "npm:^1.2.0" + bin: + json5: lib/cli.js + checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f + languageName: node + linkType: hard + +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + languageName: node + linkType: hard + +"jsonwebtoken@npm:^9.0.2": + version: 9.0.3 + resolution: "jsonwebtoken@npm:9.0.3" + dependencies: + jws: "npm:^4.0.1" + lodash.includes: "npm:^4.3.0" + lodash.isboolean: "npm:^3.0.3" + lodash.isinteger: "npm:^4.0.4" + lodash.isnumber: "npm:^3.0.3" + lodash.isplainobject: "npm:^4.0.6" + lodash.isstring: "npm:^4.0.1" + lodash.once: "npm:^4.0.0" + ms: "npm:^2.1.1" + semver: "npm:^7.5.4" + checksum: 10c0/6ca7f1e54886ea3bde7146a5a22b53847c46e25453c7f7307a69818b9a6ad48c390b2e59d5690fcfd03c529b01960060cc4bb0c686991d6edae2285dfd30f4ba + languageName: node + linkType: hard + +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": + version: 3.3.5 + resolution: "jsx-ast-utils@npm:3.3.5" + dependencies: + array-includes: "npm:^3.1.6" + array.prototype.flat: "npm:^1.3.1" + object.assign: "npm:^4.1.4" + object.values: "npm:^1.1.6" + checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 + languageName: node + linkType: hard + +"jwa@npm:^2.0.1": + version: 2.0.1 + resolution: "jwa@npm:2.0.1" + dependencies: + buffer-equal-constant-time: "npm:^1.0.1" + ecdsa-sig-formatter: "npm:1.0.11" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/ab3ebc6598e10dc11419d4ed675c9ca714a387481466b10e8a6f3f65d8d9c9237e2826f2505280a739cf4cbcf511cb288eeec22b5c9c63286fc5a2e4f97e78cf + languageName: node + linkType: hard + +"jws@npm:^4.0.1": + version: 4.0.1 + resolution: "jws@npm:4.0.1" + dependencies: + jwa: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/6be1ed93023aef570ccc5ea8d162b065840f3ef12f0d1bb3114cade844de7a357d5dc558201d9a65101e70885a6fa56b17462f520e6b0d426195510618a154d0 + languageName: node + linkType: hard + +"keyv@npm:^4.5.4": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e + languageName: node + linkType: hard + +"kind-of@npm:^6.0.2": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d + languageName: node + linkType: hard + +"linked-list@npm:^2.1.0": + version: 2.1.0 + resolution: "linked-list@npm:2.1.0" + checksum: 10c0/d039f664f847022be908460a06a7f63792aadcdfd3061f999726a92d89bf3a10688e7dfb98236f65d9980e2a175839028a374070e48e0676ab9e66122fca7063 + languageName: node + linkType: hard + +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: "npm:^5.0.0" + checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 + languageName: node + linkType: hard + +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b + languageName: node + linkType: hard + +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 + languageName: node + linkType: hard + +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d + languageName: node + linkType: hard + +"lodash.isplainobject@npm:^4.0.6": + version: 4.0.6 + resolution: "lodash.isplainobject@npm:4.0.6" + checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb + languageName: node + linkType: hard + +"lodash.isstring@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.isstring@npm:4.0.1" + checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 + languageName: node + linkType: hard + +"lodash.merge@npm:^4.6.2": + version: 4.6.2 + resolution: "lodash.merge@npm:4.6.2" + checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 + languageName: node + linkType: hard + +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 + languageName: node + linkType: hard + +"lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + languageName: node + linkType: hard + +"loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + +"loupe@npm:^3.1.0, loupe@npm:^3.1.2": + version: 3.2.1 + resolution: "loupe@npm:3.2.1" + checksum: 10c0/910c872cba291309664c2d094368d31a68907b6f5913e989d301b5c25f30e97d76d77f23ab3bf3b46d0f601ff0b6af8810c10c31b91d2c6b2f132809ca2cc705 + languageName: node + linkType: hard + +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": + version: 11.2.4 + resolution: "lru-cache@npm:11.2.4" + checksum: 10c0/4a24f9b17537619f9144d7b8e42cd5a225efdfd7076ebe7b5e7dc02b860a818455201e67fbf000765233fe7e339d3c8229fc815e9b58ee6ede511e07608c19b2 + languageName: node + linkType: hard + +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + +"magic-string@npm:^0.30.12": + version: 0.30.21 + resolution: "magic-string@npm:0.30.21" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a + languageName: node + linkType: hard + +"make-fetch-happen@npm:^15.0.0": + version: 15.0.3 + resolution: "make-fetch-happen@npm:15.0.3" + dependencies: + "@npmcli/agent": "npm:^4.0.0" + cacache: "npm:^20.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^5.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^6.0.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^13.0.0" + checksum: 10c0/525f74915660be60b616bcbd267c4a5b59481b073ba125e45c9c3a041bb1a47a2bd0ae79d028eb6f5f95bf9851a4158423f5068539c3093621abb64027e8e461 + languageName: node + linkType: hard + +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + languageName: node + linkType: hard + +"mimic-fn@npm:^2.1.0": + version: 2.1.0 + resolution: "mimic-fn@npm:2.1.0" + checksum: 10c0/b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4 + languageName: node + linkType: hard + +"minimatch@npm:^10.1.1": + version: 10.1.1 + resolution: "minimatch@npm:10.1.1" + dependencies: + "@isaacs/brace-expansion": "npm:^5.0.0" + checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902 + languageName: node + linkType: hard + +"minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + languageName: node + linkType: hard + +"minimatch@npm:^5.1.1": + version: 5.1.6 + resolution: "minimatch@npm:5.1.6" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + languageName: node + linkType: hard + +"minimist@npm:^1.2.0, minimist@npm:^1.2.6": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e + languageName: node + linkType: hard + +"minipass-fetch@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass-fetch@npm:5.0.0" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^3.0.1" + dependenciesMeta: + encoding: + optional: true + checksum: 10c0/9443aab5feab190972f84b64116e54e58dd87a58e62399cae0a4a7461b80568281039b7c3a38ba96453431ebc799d1e26999e548540156216729a4967cd5ef06 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c + languageName: node + linkType: hard + +"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + +"ms@npm:^2.1.1, ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"multiaddr@npm:^10.0.1": + version: 10.0.1 + resolution: "multiaddr@npm:10.0.1" + dependencies: + dns-over-http-resolver: "npm:^1.2.3" + err-code: "npm:^3.0.1" + is-ip: "npm:^3.1.0" + multiformats: "npm:^9.4.5" + uint8arrays: "npm:^3.0.0" + varint: "npm:^6.0.0" + checksum: 10c0/948d0c69d75992d754fd36154db4d4a435b977c56a617183a9d8c2075081e2cfcacda3bedb72bbd6759bb329956a45b216e804829e708af8d2f780f8152a4bf6 + languageName: node + linkType: hard + +"multiformats@npm:^9.4.2, multiformats@npm:^9.4.5": + version: 9.9.0 + resolution: "multiformats@npm:9.9.0" + checksum: 10c0/1fdb34fd2fb085142665e8bd402570659b50a5fae5994027e1df3add9e1ce1283ed1e0c2584a5c63ac0a58e871b8ee9665c4a99ca36ce71032617449d48aa975 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.11": + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b + languageName: node + linkType: hard + +"nanoid@npm:^5.1.2": + version: 5.1.6 + resolution: "nanoid@npm:5.1.6" + bin: + nanoid: bin/nanoid.js + checksum: 10c0/27b5b055ad8332cf4f0f9f6e2a494aa7e5ded89df4cab8c8490d4eabefe72c4423971d2745d22002868b1d50576a5e42b7b05214733b19f576382323282dd26e + languageName: node + linkType: hard + +"native-fetch@npm:^3.0.0": + version: 3.0.0 + resolution: "native-fetch@npm:3.0.0" + peerDependencies: + node-fetch: "*" + checksum: 10c0/737cdd209dd366df8b748dabac39340089d57a2bcc460ffc029ec145f30aeffea0c6a6f177013069d6f7f04ffc8c3e39cfb8e3825e7071a373c4f86b187ae1b5 + languageName: node + linkType: hard + +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 12.1.0 + resolution: "node-gyp@npm:12.1.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^15.0.0" + nopt: "npm:^9.0.0" + proc-log: "npm:^6.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.2" + tinyglobby: "npm:^0.2.12" + which: "npm:^6.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/f43efea8aaf0beb6b2f6184e533edad779b2ae38062953e21951f46221dd104006cc574154f2ad4a135467a5aae92c49e84ef289311a82e08481c5df0e8dc495 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.27": + version: 2.0.27 + resolution: "node-releases@npm:2.0.27" + checksum: 10c0/f1e6583b7833ea81880627748d28a3a7ff5703d5409328c216ae57befbced10ce2c991bea86434e8ec39003bd017f70481e2e5f8c1f7e0a7663241f81d6e00e2 + languageName: node + linkType: hard + +"nopt@npm:^9.0.0": + version: 9.0.0 + resolution: "nopt@npm:9.0.0" + dependencies: + abbrev: "npm:^4.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd + languageName: node + linkType: hard + +"notistack@npm:^3.0.1": + version: 3.0.2 + resolution: "notistack@npm:3.0.2" + dependencies: + clsx: "npm:^1.1.0" + goober: "npm:^2.0.33" + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/82a0270ee1b9e70bc1dfad4d7e1d2bbb6dc08ac887b920986dcfa58cc2aa975bd48b71f7cf3afc2e11badd142ba9ade5f708c858ee2080b9d4cd950b80c43811 + languageName: node + linkType: hard + +"npm-run-path@npm:^4.0.1": + version: 4.0.1 + resolution: "npm-run-path@npm:4.0.1" + dependencies: + path-key: "npm:^3.0.0" + checksum: 10c0/6f9353a95288f8455cf64cbeb707b28826a7f29690244c1e4bb61ec573256e021b6ad6651b394eb1ccfd00d6ec50147253aba2c5fe58a57ceb111fad62c519ac + languageName: node + linkType: hard + +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + languageName: node + linkType: hard + +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 + languageName: node + linkType: hard + +"object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d + languageName: node + linkType: hard + +"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": + version: 4.1.7 + resolution: "object.assign@npm:4.1.7" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc + languageName: node + linkType: hard + +"object.entries@npm:^1.1.9": + version: 1.1.9 + resolution: "object.entries@npm:1.1.9" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.1.1" + checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db + languageName: node + linkType: hard + +"object.fromentries@npm:^2.0.8": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b + languageName: node + linkType: hard + +"object.groupby@npm:^1.0.3": + version: 1.0.3 + resolution: "object.groupby@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c + languageName: node + linkType: hard + +"object.values@npm:^1.1.6, object.values@npm:^1.2.1": + version: 1.2.1 + resolution: "object.values@npm:1.2.1" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9 + languageName: node + linkType: hard + +"onetime@npm:^5.1.2": + version: 5.1.2 + resolution: "onetime@npm:5.1.2" + dependencies: + mimic-fn: "npm:^2.1.0" + checksum: 10c0/ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f + languageName: node + linkType: hard + +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" + dependencies: + deep-is: "npm:^0.1.3" + fast-levenshtein: "npm:^2.0.6" + levn: "npm:^0.4.1" + prelude-ls: "npm:^1.2.1" + type-check: "npm:^0.4.0" + word-wrap: "npm:^1.2.5" + checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 + languageName: node + linkType: hard + +"own-keys@npm:^1.0.1": + version: 1.0.1 + resolution: "own-keys@npm:1.0.1" + dependencies: + get-intrinsic: "npm:^1.2.6" + object-keys: "npm:^1.1.1" + safe-push-apply: "npm:^1.0.0" + checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a + languageName: node + linkType: hard + +"p-event@npm:^4.2.0": + version: 4.2.0 + resolution: "p-event@npm:4.2.0" + dependencies: + p-timeout: "npm:^3.1.0" + checksum: 10c0/f1b6a2fb13d47f2a8afc00150da5ece0d28940ce3d8fa562873e091d3337d298e78fee9cb18b768598ff1d11df608b2ae23868309ff6405b864a2451ccd6d25a + languageName: node + linkType: hard + +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 + languageName: node + linkType: hard + +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + languageName: node + linkType: hard + +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: "npm:^3.0.2" + checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a + languageName: node + linkType: hard + +"p-map@npm:^7.0.2": + version: 7.0.4 + resolution: "p-map@npm:7.0.4" + checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd + languageName: node + linkType: hard + +"p-timeout@npm:^3.1.0": + version: 3.2.0 + resolution: "p-timeout@npm:3.2.0" + dependencies: + p-finally: "npm:^1.0.0" + checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 + languageName: node + linkType: hard + +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 + languageName: node + linkType: hard + +"parse-json@npm:^5.0.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b + languageName: node + linkType: hard + +"path-key@npm:^3.0.0, path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + languageName: node + linkType: hard + +"path-scurry@npm:^2.0.0": + version: 2.0.1 + resolution: "path-scurry@npm:2.0.1" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/2a16ed0e81fbc43513e245aa5763354e25e787dab0d539581a6c3f0f967461a159ed6236b2559de23aa5b88e7dc32b469b6c47568833dd142a4b24b4f5cd2620 + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c + languageName: node + linkType: hard + +"pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 + languageName: node + linkType: hard + +"pathval@npm:^2.0.0": + version: 2.0.1 + resolution: "pathval@npm:2.0.1" + checksum: 10c0/460f4709479fbf2c45903a65655fc8f0a5f6d808f989173aeef5fdea4ff4f303dc13f7870303999add60ec49d4c14733895c0a869392e9866f1091fa64fd7581 + languageName: node + linkType: hard + +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^4.0.3": + version: 4.0.3 + resolution: "picomatch@npm:4.0.3" + checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2 + languageName: node + linkType: hard + +"possible-typed-array-names@npm:^1.0.0": + version: 1.1.0 + resolution: "possible-typed-array-names@npm:1.1.0" + checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196 + languageName: node + linkType: hard + +"postcss@npm:^8.4.43": + version: 8.5.6 + resolution: "postcss@npm:8.5.6" + dependencies: + nanoid: "npm:^3.3.11" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/5127cc7c91ed7a133a1b7318012d8bfa112da9ef092dddf369ae699a1f10ebbd89b1b9f25f3228795b84585c72aabd5ced5fc11f2ba467eedf7b081a66fad024 + languageName: node + linkType: hard + +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd + languageName: node + linkType: hard + +"proc-log@npm:^6.0.0": + version: 6.1.0 + resolution: "proc-log@npm:6.1.0" + checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 + languageName: node + linkType: hard + +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 + languageName: node + linkType: hard + +"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: "npm:^1.4.0" + object-assign: "npm:^4.1.1" + react-is: "npm:^16.13.1" + checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 + languageName: node + linkType: hard + +"qr.js@npm:0.0.0": + version: 0.0.0 + resolution: "qr.js@npm:0.0.0" + checksum: 10c0/1c6a4c7a58d04e52ec2fee99e39b680fdc5b2a510a981df42c36b716a8eac6634d130fc4d65af8f030f2a07dbf5fa046b97cdfa7456c250ebb50a73916efdcb5 + languageName: node + linkType: hard + +"react-dom@npm:^19.1.0": + version: 19.2.3 + resolution: "react-dom@npm:19.2.3" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.3 + checksum: 10c0/dc43f7ede06f46f3acc16ee83107c925530de9b91d1d0b3824583814746ff4c498ea64fd65cd83aba363205268adff52e2827c582634ae7b15069deaeabc4892 + languageName: node + linkType: hard + +"react-is@npm:^16.13.1, react-is@npm:^16.7.0": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 + languageName: node + linkType: hard + +"react-is@npm:^19.2.0": + version: 19.2.3 + resolution: "react-is@npm:19.2.3" + checksum: 10c0/2b54c422c21b8dbd68a435a1cce21ecd5b6f06f48659531f7d53dd7368365da5a67e946f352fb2010d11ca40658aa67bec90995f0f1ec5556c0f71dbffe54994 + languageName: node + linkType: hard + +"react-qr-code@npm:^2.0.15": + version: 2.0.18 + resolution: "react-qr-code@npm:2.0.18" + dependencies: + prop-types: "npm:^15.8.1" + qr.js: "npm:0.0.0" + peerDependencies: + react: "*" + checksum: 10c0/4e13b795cbb10f1dcf0e39d682bb59851e4c84010ba2be7225b2ad9d5c1ffea52d2d38f884ee26235b7002b8ca99e83b805f55e877663c39d67496764d975cf1 + languageName: node + linkType: hard + +"react-redux@npm:^9.2.0": + version: 9.2.0 + resolution: "react-redux@npm:9.2.0" + dependencies: + "@types/use-sync-external-store": "npm:^0.0.6" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + "@types/react": ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + redux: + optional: true + checksum: 10c0/00d485f9d9219ca1507b4d30dde5f6ff8fb68ba642458f742e0ec83af052f89e65cd668249b99299e1053cc6ad3d2d8ac6cb89e2f70d2ac5585ae0d7fa0ef259 + languageName: node + linkType: hard + +"react-refresh@npm:^0.17.0": + version: 0.17.0 + resolution: "react-refresh@npm:0.17.0" + checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c + languageName: node + linkType: hard + +"react-router-dom@npm:^7.6.1": + version: 7.11.0 + resolution: "react-router-dom@npm:7.11.0" + dependencies: + react-router: "npm:7.11.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + checksum: 10c0/0e8061fe0ef7915cc411dd92f5f41109f6343b6abef36571b08ff231365bf61f52364bea128d1c964e9b8eb19426c9bd21923df0b3e1bb993d21bd2b7440fb49 + languageName: node + linkType: hard + +"react-router@npm:7.11.0": + version: 7.11.0 + resolution: "react-router@npm:7.11.0" + dependencies: + cookie: "npm:^1.0.1" + set-cookie-parser: "npm:^2.6.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10c0/eb3693d63d1c52221a3449de5db170e2fa9e00536b011998b17f8a277f8b5e89b752d104dbbeb4ee3d474f8e4570167db00293b4510f63277e5e6658c5dab22b + languageName: node + linkType: hard + +"react-transition-group@npm:^4.4.5": + version: 4.4.5 + resolution: "react-transition-group@npm:4.4.5" + dependencies: + "@babel/runtime": "npm:^7.5.5" + dom-helpers: "npm:^5.0.1" + loose-envify: "npm:^1.4.0" + prop-types: "npm:^15.6.2" + peerDependencies: + react: ">=16.6.0" + react-dom: ">=16.6.0" + checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82 + languageName: node + linkType: hard + +"react@npm:^19.1.0": + version: 19.2.3 + resolution: "react@npm:19.2.3" + checksum: 10c0/094220b3ba3a76c1b668f972ace1dd15509b157aead1b40391d1c8e657e720c201d9719537375eff08f5e0514748c0319063392a6f000e31303aafc4471f1436 + languageName: node + linkType: hard + +"readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: "npm:~1.0.0" + inherits: "npm:~2.0.3" + isarray: "npm:~1.0.0" + process-nextick-args: "npm:~2.0.0" + safe-buffer: "npm:~5.1.1" + string_decoder: "npm:~1.1.1" + util-deprecate: "npm:~1.0.1" + checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + languageName: node + linkType: hard + +"receptacle@npm:^1.3.2": + version: 1.3.2 + resolution: "receptacle@npm:1.3.2" + dependencies: + ms: "npm:^2.1.1" + checksum: 10c0/213dc9e4e80969cde60c5877fae08d8438f0bf7dd10bf4ea47916a10c053ca05d6581bda374d8f22ce15e6b50739efe319d847362f5ec9e1a4cbdcbde3ddf355 + languageName: node + linkType: hard + +"redux-persist@npm:^6.0.0": + version: 6.0.0 + resolution: "redux-persist@npm:6.0.0" + peerDependencies: + redux: ">4.0.0" + checksum: 10c0/8242d265ab8d28bbc95cf2dc2a05b869eb67aa309b1ed08163c926f3af56dd8eb1ea62118286083461b8ef2024d3b349fd264e5a62a70eb2e74d068c832d5bf2 + languageName: node + linkType: hard + +"redux-thunk@npm:^3.1.0": + version: 3.1.0 + resolution: "redux-thunk@npm:3.1.0" + peerDependencies: + redux: ^5.0.0 + checksum: 10c0/21557f6a30e1b2e3e470933247e51749be7f1d5a9620069a3125778675ce4d178d84bdee3e2a0903427a5c429e3aeec6d4df57897faf93eb83455bc1ef7b66fd + languageName: node + linkType: hard + +"redux@npm:^4.0.0": + version: 4.2.1 + resolution: "redux@npm:4.2.1" + dependencies: + "@babel/runtime": "npm:^7.9.2" + checksum: 10c0/136d98b3d5dbed1cd6279c8c18a6a74c416db98b8a432a46836bdd668475de6279a2d4fd9d1363f63904e00f0678a8a3e7fa532c897163340baf1e71bb42c742 + languageName: node + linkType: hard + +"redux@npm:^5.0.1": + version: 5.0.1 + resolution: "redux@npm:5.0.1" + checksum: 10c0/b10c28357194f38e7d53b760ed5e64faa317cc63de1fb95bc5d9e127fab956392344368c357b8e7a9bedb0c35b111e7efa522210cfdc3b3c75e5074718e9069c + languageName: node + linkType: hard + +"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": + version: 1.0.10 + resolution: "reflect.getprototypeof@npm:1.0.10" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.9" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.7" + get-proto: "npm:^1.0.1" + which-builtin-type: "npm:^1.2.1" + checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac + languageName: node + linkType: hard + +"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": + version: 1.5.4 + resolution: "regexp.prototype.flags@npm:1.5.4" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-errors: "npm:^1.3.0" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + set-function-name: "npm:^2.0.2" + checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77 + languageName: node + linkType: hard + +"reselect@npm:^5.1.0, reselect@npm:^5.1.1": + version: 5.1.1 + resolution: "reselect@npm:5.1.1" + checksum: 10c0/219c30da122980f61853db3aebd173524a2accd4b3baec770e3d51941426c87648a125ca08d8c57daa6b8b086f2fdd2703cb035dd6231db98cdbe1176a71f489 + languageName: node + linkType: hard + +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 + languageName: node + linkType: hard + +"resolve@npm:^1.19.0, resolve@npm:^1.22.4": + version: 1.22.11 + resolution: "resolve@npm:1.22.11" + dependencies: + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409 + languageName: node + linkType: hard + +"resolve@npm:^2.0.0-next.5": + version: 2.0.0-next.5 + resolution: "resolve@npm:2.0.0-next.5" + dependencies: + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/a6c33555e3482ea2ec4c6e3d3bf0d78128abf69dca99ae468e64f1e30acaa318fd267fb66c8836b04d558d3e2d6ed875fe388067e7d8e0de647d3c21af21c43a + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": + version: 1.22.11 + resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": + version: 2.0.0-next.5 + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/78ad6edb8309a2bfb720c2c1898f7907a37f858866ce11a5974643af1203a6a6e05b2fa9c53d8064a673a447b83d42569260c306d43628bff5bb101969708355 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe + languageName: node + linkType: hard + +"rn-host-detect@npm:^1.2.0": + version: 1.2.0 + resolution: "rn-host-detect@npm:1.2.0" + checksum: 10c0/94067014566c738b3cb786d507a3cf4f4fab79b51b0d7c38bea0a48d536458c7218e01f259e03fa51cf1cf6f62ad4c01fcd36c6fa3b725a86eace02dd30d929f + languageName: node + linkType: hard + +"rollup@npm:^4.20.0": + version: 4.54.0 + resolution: "rollup@npm:4.54.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.54.0" + "@rollup/rollup-android-arm64": "npm:4.54.0" + "@rollup/rollup-darwin-arm64": "npm:4.54.0" + "@rollup/rollup-darwin-x64": "npm:4.54.0" + "@rollup/rollup-freebsd-arm64": "npm:4.54.0" + "@rollup/rollup-freebsd-x64": "npm:4.54.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.54.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.54.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.54.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.54.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.54.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.54.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.54.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.54.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.54.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.54.0" + "@rollup/rollup-linux-x64-musl": "npm:4.54.0" + "@rollup/rollup-openharmony-arm64": "npm:4.54.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.54.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.54.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.54.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.54.0" + "@types/estree": "npm:1.0.8" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/62e5fd5d43e72751ac631f13fd7e70bec0fc3809231d5e087c3c0811945e7b8f0956620c5bed4e0cd67085325324266989e5ea4d22985c2677119ac7809b6455 + languageName: node + linkType: hard + +"safe-array-concat@npm:^1.1.3": + version: 1.1.3 + resolution: "safe-array-concat@npm:1.1.3" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.6" + has-symbols: "npm:^1.1.0" + isarray: "npm:^2.0.5" + checksum: 10c0/43c86ffdddc461fb17ff8a17c5324f392f4868f3c7dd2c6a5d9f5971713bc5fd755667212c80eab9567595f9a7509cc2f83e590ddaebd1bd19b780f9c79f9a8d + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + +"safe-push-apply@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-push-apply@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + isarray: "npm:^2.0.5" + checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750 + languageName: node + linkType: hard + +"safe-regex-test@npm:^1.1.0": + version: 1.1.0 + resolution: "safe-regex-test@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + is-regex: "npm:^1.2.1" + checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"sc-errors@npm:^3.0.0": + version: 3.0.0 + resolution: "sc-errors@npm:3.0.0" + checksum: 10c0/d015423572cf0b68a6ddb5a9088cb7509da013cdb304691128443f6240e095b3de0e126e0d8e6c5fce14dc0973ad1c3f6ef9c77f4667599f2e99e5377c72a133 + languageName: node + linkType: hard + +"sc-formatter@npm:^4.0.0": + version: 4.0.0 + resolution: "sc-formatter@npm:4.0.0" + checksum: 10c0/1ef2e29bbfcd4ee17c9bbeaaa766169b8e0d210cecac6bcfd71341306438948536b59e060e1edd28ddee1ede1108c3ac1e1789813349d15aab677a5f64ea7cc9 + languageName: node + linkType: hard + +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 + languageName: node + linkType: hard + +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2": + version: 7.7.3 + resolution: "semver@npm:7.7.3" + bin: + semver: bin/semver.js + checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e + languageName: node + linkType: hard + +"set-cookie-parser@npm:^2.6.0": + version: 2.7.2 + resolution: "set-cookie-parser@npm:2.7.2" + checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45 + languageName: node + linkType: hard + +"set-function-length@npm:^1.2.2": + version: 1.2.2 + resolution: "set-function-length@npm:1.2.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c + languageName: node + linkType: hard + +"set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 + languageName: node + linkType: hard + +"set-proto@npm:^1.0.0": + version: 1.0.0 + resolution: "set-proto@npm:1.0.0" + dependencies: + dunder-proto: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a + languageName: node + linkType: hard + +"shallow-clone@npm:^3.0.0": + version: 3.0.1 + resolution: "shallow-clone@npm:3.0.1" + dependencies: + kind-of: "npm:^6.0.2" + checksum: 10c0/7bab09613a1b9f480c85a9823aebec533015579fa055ba6634aa56ba1f984380670eaf33b8217502931872aa1401c9fcadaa15f9f604d631536df475b05bcf1e + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 + languageName: node + linkType: hard + +"side-channel-list@npm:^1.0.0": + version: 1.0.0 + resolution: "side-channel-list@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + side-channel-list: "npm:^1.0.0" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 + languageName: node + linkType: hard + +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.3": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + languageName: node + linkType: hard + +"socketcluster-client@npm:^19.2.3": + version: 19.2.7 + resolution: "socketcluster-client@npm:19.2.7" + dependencies: + ag-auth: "npm:^2.1.0" + ag-channel: "npm:^5.0.0" + ag-request: "npm:^1.1.0" + async-stream-emitter: "npm:^7.0.1" + buffer: "npm:^5.2.1" + clone-deep: "npm:^4.0.1" + linked-list: "npm:^2.1.0" + sc-errors: "npm:^3.0.0" + sc-formatter: "npm:^4.0.0" + stream-demux: "npm:^10.0.1" + uuid: "npm:^8.3.2" + vinyl-buffer: "npm:^1.0.1" + ws: "npm:^8.18.0" + checksum: 10c0/58a333f2ac376043ea7bf38c42a473042258000e9ea8e56eec3d2ff3b6e85c04d8f710b2bd1f79436878bc802358259e3aa1dcc22241a1d7ae2600288fc75412 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.7 + resolution: "socks@npm:2.8.7" + dependencies: + ip-address: "npm:^10.0.1" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 + languageName: node + linkType: hard + +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + +"source-map@npm:^0.5.7": + version: 0.5.7 + resolution: "source-map@npm:0.5.7" + checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 + languageName: node + linkType: hard + +"ssri@npm:^13.0.0": + version: 13.0.0 + resolution: "ssri@npm:13.0.0" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/405f3a531cd98b013cecb355d63555dca42fd12c7bc6671738aaa9a82882ff41cdf0ef9a2b734ca4f9a760338f114c29d01d9238a65db3ccac27929bd6e6d4b2 + languageName: node + linkType: hard + +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 + languageName: node + linkType: hard + +"std-env@npm:^3.8.0": + version: 3.10.0 + resolution: "std-env@npm:3.10.0" + checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f + languageName: node + linkType: hard + +"stop-iteration-iterator@npm:^1.1.0": + version: 1.1.0 + resolution: "stop-iteration-iterator@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + internal-slot: "npm:^1.1.0" + checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09 + languageName: node + linkType: hard + +"stream-demux@npm:^10.0.1": + version: 10.0.1 + resolution: "stream-demux@npm:10.0.1" + dependencies: + consumable-stream: "npm:^3.0.0" + writable-consumable-stream: "npm:^4.1.0" + checksum: 10c0/9c6b42af758560ceab49b0fdae169599cfca95fcd6f234b45fa3e1465751c2576ad65fd86e54bf5365fda6152955d06d6e6957c506b51460343c4801260402cf + languageName: node + linkType: hard + +"string.prototype.matchall@npm:^4.0.12": + version: 4.0.12 + resolution: "string.prototype.matchall@npm:4.0.12" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.6" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.6" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + internal-slot: "npm:^1.1.0" + regexp.prototype.flags: "npm:^1.5.3" + set-function-name: "npm:^2.0.2" + side-channel: "npm:^1.1.0" + checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c + languageName: node + linkType: hard + +"string.prototype.repeat@npm:^1.0.0": + version: 1.0.0 + resolution: "string.prototype.repeat@npm:1.0.0" + dependencies: + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.17.5" + checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40 + languageName: node + linkType: hard + +"string.prototype.trim@npm:^1.2.10": + version: 1.2.10 + resolution: "string.prototype.trim@npm:1.2.10" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.2" + define-data-property: "npm:^1.1.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-object-atoms: "npm:^1.0.0" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/8a8854241c4b54a948e992eb7dd6b8b3a97185112deb0037a134f5ba57541d8248dd610c966311887b6c2fd1181a3877bffb14d873ce937a344535dabcc648f8 + languageName: node + linkType: hard + +"string.prototype.trimend@npm:^1.0.9": + version: 1.0.9 + resolution: "string.prototype.trimend@npm:1.0.9" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.2" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/59e1a70bf9414cb4c536a6e31bef5553c8ceb0cf44d8b4d0ed65c9653358d1c64dd0ec203b100df83d0413bbcde38b8c5d49e14bc4b86737d74adc593a0d35b6 + languageName: node + linkType: hard + +"string.prototype.trimstart@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimstart@npm:1.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 + languageName: node + linkType: hard + +"string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: "npm:~5.1.0" + checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + languageName: node + linkType: hard + +"strip-bom@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-bom@npm:3.0.0" + checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 + languageName: node + linkType: hard + +"strip-final-newline@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-final-newline@npm:2.0.0" + checksum: 10c0/bddf8ccd47acd85c0e09ad7375409d81653f645fda13227a9d459642277c253d877b68f2e5e4d819fe75733b0e626bac7e954c04f3236f6d196f79c94fa4a96f + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd + languageName: node + linkType: hard + +"stylis@npm:4.2.0": + version: 4.2.0 + resolution: "stylis@npm:4.2.0" + checksum: 10c0/a7128ad5a8ed72652c6eba46bed4f416521bc9745a460ef5741edc725252cebf36ee45e33a8615a7057403c93df0866ab9ee955960792db210bb80abd5ac6543 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 + languageName: node + linkType: hard + +"tar@npm:^7.5.2": + version: 7.5.2 + resolution: "tar@npm:7.5.2" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/a7d8b801139b52f93a7e34830db0de54c5aa45487c7cb551f6f3d44a112c67f1cb8ffdae856b05fd4f17b1749911f1c26f1e3a23bbe0279e17fd96077f13f467 + languageName: node + linkType: hard + +"through2@npm:^2.0.3": + version: 2.0.5 + resolution: "through2@npm:2.0.5" + dependencies: + readable-stream: "npm:~2.3.6" + xtend: "npm:~4.0.1" + checksum: 10c0/cbfe5b57943fa12b4f8c043658c2a00476216d79c014895cef1ac7a1d9a8b31f6b438d0e53eecbb81054b93128324a82ecd59ec1a4f91f01f7ac113dcb14eade + languageName: node + linkType: hard + +"tinybench@npm:^2.9.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c + languageName: node + linkType: hard + +"tinyexec@npm:^0.3.1": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + +"tinypool@npm:^1.0.1": + version: 1.1.1 + resolution: "tinypool@npm:1.1.1" + checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b + languageName: node + linkType: hard + +"tinyrainbow@npm:^1.2.0": + version: 1.2.0 + resolution: "tinyrainbow@npm:1.2.0" + checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192 + languageName: node + linkType: hard + +"tinyspy@npm:^3.0.2": + version: 3.0.2 + resolution: "tinyspy@npm:3.0.2" + checksum: 10c0/55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0 + languageName: node + linkType: hard + +"ts-api-utils@npm:^2.1.0": + version: 2.3.0 + resolution: "ts-api-utils@npm:2.3.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10c0/9f2aadb8ac55926c79db03e37ee3b014135923d1705f6868b9e787e6b8822d2fd8e19df2f9002563f4e6268c994425ddaad61df24d0dad833a4be9f26f789213 + languageName: node + linkType: hard + +"tsconfck@npm:^3.0.3": + version: 3.1.6 + resolution: "tsconfck@npm:3.1.6" + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + bin: + tsconfck: bin/tsconfck.js + checksum: 10c0/269c3c513540be44844117bb9b9258fe6f8aeab026d32aeebf458d5299125f330711429dbb556dbf125a0bc25f4a81e6c24ac96de2740badd295c3fb400f66c4 + languageName: node + linkType: hard + +"tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" + dependencies: + "@types/json5": "npm:^0.0.29" + json5: "npm:^1.0.2" + minimist: "npm:^1.2.6" + strip-bom: "npm:^3.0.0" + checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 + languageName: node + linkType: hard + +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: "npm:^1.2.1" + checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 + languageName: node + linkType: hard + +"typed-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-buffer@npm:1.0.3" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.14" + checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079 + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-byte-length@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.8" + for-each: "npm:^0.3.3" + gopd: "npm:^1.2.0" + has-proto: "npm:^1.2.0" + is-typed-array: "npm:^1.1.14" + checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.4": + version: 1.0.4 + resolution: "typed-array-byte-offset@npm:1.0.4" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + for-each: "npm:^0.3.3" + gopd: "npm:^1.2.0" + has-proto: "npm:^1.2.0" + is-typed-array: "npm:^1.1.15" + reflect.getprototypeof: "npm:^1.0.9" + checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53 + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.7": + version: 1.0.7 + resolution: "typed-array-length@npm:1.0.7" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + is-typed-array: "npm:^1.1.13" + possible-typed-array-names: "npm:^1.0.0" + reflect.getprototypeof: "npm:^1.0.6" + checksum: 10c0/e38f2ae3779584c138a2d8adfa8ecf749f494af3cd3cdafe4e688ce51418c7d2c5c88df1bd6be2bbea099c3f7cea58c02ca02ed438119e91f162a9de23f61295 + languageName: node + linkType: hard + +"typescript-eslint@npm:^8.1.0": + version: 8.50.1 + resolution: "typescript-eslint@npm:8.50.1" + dependencies: + "@typescript-eslint/eslint-plugin": "npm:8.50.1" + "@typescript-eslint/parser": "npm:8.50.1" + "@typescript-eslint/typescript-estree": "npm:8.50.1" + "@typescript-eslint/utils": "npm:8.50.1" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10c0/481095a249c48fa1d3551c50ceb8dcfba22413d6175f586ee802200342478a24b566b49d59e618c835631e4071ba1902d8549dc6467f47adb3079d00394d614f + languageName: node + linkType: hard + +"typescript@npm:^5.2.2": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 + languageName: node + linkType: hard + +"uint8arrays@npm:^3.0.0": + version: 3.1.1 + resolution: "uint8arrays@npm:3.1.1" + dependencies: + multiformats: "npm:^9.4.2" + checksum: 10c0/9946668e04f29b46bbb73cca3d190f63a2fbfe5452f8e6551ef4257d9d597b72da48fa895c15ef2ef772808a5335b3305f69da5f13a09f8c2924896b409565ff + languageName: node + linkType: hard + +"unbox-primitive@npm:^1.1.0": + version: 1.1.0 + resolution: "unbox-primitive@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.3" + has-bigints: "npm:^1.0.2" + has-symbols: "npm:^1.1.0" + which-boxed-primitive: "npm:^1.1.1" + checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982 + languageName: node + linkType: hard + +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 + languageName: node + linkType: hard + +"undici-types@npm:~7.16.0": + version: 7.16.0 + resolution: "undici-types@npm:7.16.0" + checksum: 10c0/3033e2f2b5c9f1504bdc5934646cb54e37ecaca0f9249c983f7b1fc2e87c6d18399ebb05dc7fd5419e02b2e915f734d872a65da2e3eeed1813951c427d33cc9a + languageName: node + linkType: hard + +"unique-filename@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-filename@npm:5.0.0" + dependencies: + unique-slug: "npm:^6.0.0" + checksum: 10c0/afb897e9cf4c2fb622ea716f7c2bb462001928fc5f437972213afdf1cc32101a230c0f1e9d96fc91ee5185eca0f2feb34127145874975f347be52eb91d6ccc2c + languageName: node + linkType: hard + +"unique-slug@npm:^6.0.0": + version: 6.0.0 + resolution: "unique-slug@npm:6.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10c0/da7ade4cb04eb33ad0499861f82fe95ce9c7c878b7139dc54d140ecfb6a6541c18a5c8dac16188b8b379fe62c0c1f1b710814baac910cde5f4fec06212126c6a + languageName: node + linkType: hard + +"unstoppableswap-gui-rs@workspace:.": + version: 0.0.0-use.local + resolution: "unstoppableswap-gui-rs@workspace:." + dependencies: + "@emotion/react": "npm:^11.14.0" + "@emotion/styled": "npm:^11.14.0" + "@eslint/js": "npm:^9.9.0" + "@fontsource/roboto": "npm:^5.1.0" + "@mui/icons-material": "npm:^7.1.1" + "@mui/material": "npm:^7.1.1" + "@mui/x-date-pickers": "npm:^8.8.0" + "@redux-devtools/remote": "npm:^0.9.5" + "@reduxjs/toolkit": "npm:^2.3.0" + "@tauri-apps/api": "npm:^2.8.0" + "@tauri-apps/cli": "npm:^2.0.0" + "@tauri-apps/plugin-cli": "npm:^2.4.0" + "@tauri-apps/plugin-clipboard-manager": "npm:^2.3.0" + "@tauri-apps/plugin-dialog": "npm:^2.0.0" + "@tauri-apps/plugin-opener": "npm:^2.5.0" + "@tauri-apps/plugin-process": "npm:^2.3.0" + "@tauri-apps/plugin-store": "npm:^2.4.0" + "@tauri-apps/plugin-updater": "npm:^2.9.0" + "@testing-library/react": "npm:^16.0.1" + "@testing-library/user-event": "npm:^14.5.2" + "@types/humanize-duration": "npm:^3.27.4" + "@types/lodash": "npm:^4.17.6" + "@types/node": "npm:^22.15.29" + "@types/react": "npm:^19.1.6" + "@types/react-dom": "npm:^19.1.5" + "@types/react-redux": "npm:^7.1.34" + "@types/semver": "npm:^7.5.8" + "@vitejs/plugin-react": "npm:^4.2.1" + babel-plugin-react-compiler: "npm:^1.0.0" + dayjs: "npm:^1.11.13" + eslint: "npm:^9.9.0" + eslint-plugin-import: "npm:^2.32.0" + eslint-plugin-react: "npm:^7.35.0" + eslint-plugin-react-hooks: "npm:^7.0.1" + globals: "npm:^15.9.0" + humanize-duration: "npm:^3.32.1" + internal-ip: "npm:^7.0.0" + jdenticon: "npm:^3.3.0" + lodash: "npm:^4.17.21" + multiaddr: "npm:^10.0.1" + notistack: "npm:^3.0.1" + react: "npm:^19.1.0" + react-dom: "npm:^19.1.0" + react-qr-code: "npm:^2.0.15" + react-redux: "npm:^9.2.0" + react-router-dom: "npm:^7.6.1" + redux-persist: "npm:^6.0.0" + semver: "npm:^7.6.2" + typescript: "npm:^5.2.2" + typescript-eslint: "npm:^8.1.0" + virtua: "npm:^0.33.2" + vite: "npm:^5.3.1" + vite-plugin-top-level-await: "npm:^1.4.4" + vite-plugin-watch: "npm:^0.3.1" + vite-tsconfig-paths: "npm:^4.3.2" + vitest: "npm:^2.1.1" + languageName: unknown + linkType: soft + +"update-browserslist-db@npm:^1.2.0": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + languageName: node + linkType: hard + +"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.6.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/35e1179f872a53227bdf8a827f7911da4c37c0f4091c29b76b1e32473d1670ebe7bcd880b808b7549ba9a5605c233350f800ffab963ee4a4ee346ee983b6019b + languageName: node + linkType: hard + +"util-deprecate@npm:~1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + languageName: node + linkType: hard + +"uuid@npm:10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10c0/eab18c27fe4ab9fb9709a5d5f40119b45f2ec8314f8d4cf12ce27e4c6f4ffa4a6321dc7db6c515068fa373c075b49691ba969f0010bf37f44c37ca40cd6bf7fe + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 + languageName: node + linkType: hard + +"varint@npm:^6.0.0": + version: 6.0.0 + resolution: "varint@npm:6.0.0" + checksum: 10c0/737fc37088a62ed3bd21466e318d21ca7ac4991d0f25546f518f017703be4ed0f9df1c5559f1dd533dddba4435a1b758fd9230e4772c1a930ef72b42f5c750fd + languageName: node + linkType: hard + +"vinyl-buffer@npm:^1.0.1": + version: 1.0.1 + resolution: "vinyl-buffer@npm:1.0.1" + dependencies: + bl: "npm:^1.2.1" + through2: "npm:^2.0.3" + checksum: 10c0/0dedb6bd3dbdd33ef77feae6535284d9fcd65be4826cb15c3afa91e77a0d384ff5c91a02768a96e6914671db5b65133c69ff44dd25b399494d2628dc71de259b + languageName: node + linkType: hard + +"virtua@npm:^0.33.2": + version: 0.33.7 + resolution: "virtua@npm:0.33.7" + peerDependencies: + react: ">=16.14.0" + react-dom: ">=16.14.0" + solid-js: ">=1.0" + svelte: ">=4.0" + vue: ">=3.2" + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + checksum: 10c0/bc42cd6fc5119c18f5bc83c9c887e40120e4cb4bbf4abf499cc2543ce790b2d23868815975dd472643b07da5804cc5e11919ac0026fc26f540608793aa3eefba + languageName: node + linkType: hard + +"vite-node@npm:2.1.9": + version: 2.1.9 + resolution: "vite-node@npm:2.1.9" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.3.7" + es-module-lexer: "npm:^1.5.4" + pathe: "npm:^1.1.2" + vite: "npm:^5.0.0" + bin: + vite-node: vite-node.mjs + checksum: 10c0/0d3589f9f4e9cff696b5b49681fdb75d1638c75053728be52b4013f70792f38cb0120a9c15e3a4b22bdd6b795ad7c2da13bcaf47242d439f0906049e73bdd756 + languageName: node + linkType: hard + +"vite-plugin-top-level-await@npm:^1.4.4": + version: 1.6.0 + resolution: "vite-plugin-top-level-await@npm:1.6.0" + dependencies: + "@rollup/plugin-virtual": "npm:^3.0.2" + "@swc/core": "npm:^1.12.14" + "@swc/wasm": "npm:^1.12.14" + uuid: "npm:10.0.0" + peerDependencies: + vite: ">=2.8" + checksum: 10c0/499054e67f38ce925b1bae270cc334e1ee42194d00cae084792a5a00c7f246f27f3fd7798e0d4cfe07510f1c7620288bcbcf463570e7650f57977ac0591bf8da + languageName: node + linkType: hard + +"vite-plugin-watch@npm:^0.3.1": + version: 0.3.1 + resolution: "vite-plugin-watch@npm:0.3.1" + dependencies: + minimatch: "npm:^5.1.1" + checksum: 10c0/a14998cb9d678b5e1b92d68af0e40164d7fb413a4b112edfe44f831bda701a46f44e4253d612bd8101933a55364e6448ee3c7899616c57b0b0477812ebbffa4e + languageName: node + linkType: hard + +"vite-tsconfig-paths@npm:^4.3.2": + version: 4.3.2 + resolution: "vite-tsconfig-paths@npm:4.3.2" + dependencies: + debug: "npm:^4.1.1" + globrex: "npm:^0.1.2" + tsconfck: "npm:^3.0.3" + peerDependencies: + vite: "*" + peerDependenciesMeta: + vite: + optional: true + checksum: 10c0/f390ac1d1c3992fc5ac50f9274c1090f8b55ab34a89ea88893db9a6924a3b26c9f64bc1163615150ad100749db73b6b2cf1d57f6cd60df6e762ceb5b8ad30024 + languageName: node + linkType: hard + +"vite@npm:^5.0.0, vite@npm:^5.3.1": + version: 5.4.21 + resolution: "vite@npm:5.4.21" + dependencies: + esbuild: "npm:^0.21.3" + fsevents: "npm:~2.3.3" + postcss: "npm:^8.4.43" + rollup: "npm:^4.20.0" + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/468336a1409f728b464160cbf02672e72271fb688d0e605e776b74a89d27e1029509eef3a3a6c755928d8011e474dbf234824d054d07960be5f23cd176bc72de + languageName: node + linkType: hard + +"vitest@npm:^2.1.1": + version: 2.1.9 + resolution: "vitest@npm:2.1.9" + dependencies: + "@vitest/expect": "npm:2.1.9" + "@vitest/mocker": "npm:2.1.9" + "@vitest/pretty-format": "npm:^2.1.9" + "@vitest/runner": "npm:2.1.9" + "@vitest/snapshot": "npm:2.1.9" + "@vitest/spy": "npm:2.1.9" + "@vitest/utils": "npm:2.1.9" + chai: "npm:^5.1.2" + debug: "npm:^4.3.7" + expect-type: "npm:^1.1.0" + magic-string: "npm:^0.30.12" + pathe: "npm:^1.1.2" + std-env: "npm:^3.8.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.1" + tinypool: "npm:^1.0.1" + tinyrainbow: "npm:^1.2.0" + vite: "npm:^5.0.0" + vite-node: "npm:2.1.9" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 2.1.9 + "@vitest/ui": 2.1.9 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10c0/e339e16dccacf4589ff43cb1f38c7b4d14427956ae8ef48702af6820a9842347c2b6c77356aeddb040329759ca508a3cb2b104ddf78103ea5bc98ab8f2c3a54e + languageName: node + linkType: hard + +"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": + version: 1.1.1 + resolution: "which-boxed-primitive@npm:1.1.1" + dependencies: + is-bigint: "npm:^1.1.0" + is-boolean-object: "npm:^1.2.1" + is-number-object: "npm:^1.1.1" + is-string: "npm:^1.1.1" + is-symbol: "npm:^1.1.1" + checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe + languageName: node + linkType: hard + +"which-builtin-type@npm:^1.2.1": + version: 1.2.1 + resolution: "which-builtin-type@npm:1.2.1" + dependencies: + call-bound: "npm:^1.0.2" + function.prototype.name: "npm:^1.1.6" + has-tostringtag: "npm:^1.0.2" + is-async-function: "npm:^2.0.0" + is-date-object: "npm:^1.1.0" + is-finalizationregistry: "npm:^1.1.0" + is-generator-function: "npm:^1.0.10" + is-regex: "npm:^1.2.1" + is-weakref: "npm:^1.0.2" + isarray: "npm:^2.0.5" + which-boxed-primitive: "npm:^1.1.0" + which-collection: "npm:^1.0.2" + which-typed-array: "npm:^1.1.16" + checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471 + languageName: node + linkType: hard + +"which-collection@npm:^1.0.2": + version: 1.0.2 + resolution: "which-collection@npm:1.0.2" + dependencies: + is-map: "npm:^2.0.3" + is-set: "npm:^2.0.3" + is-weakmap: "npm:^2.0.2" + is-weakset: "npm:^2.0.3" + checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19": + version: 1.1.19 + resolution: "which-typed-array@npm:1.1.19" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + for-each: "npm:^0.3.5" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/702b5dc878addafe6c6300c3d0af5983b175c75fcb4f2a72dfc3dd38d93cf9e89581e4b29c854b16ea37e50a7d7fca5ae42ece5c273d8060dcd603b2404bbb3f + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^6.0.0": + version: 6.0.0 + resolution: "which@npm:6.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10c0/fe9d6463fe44a76232bb6e3b3181922c87510a5b250a98f1e43a69c99c079b3f42ddeca7e03d3e5f2241bf2d334f5a7657cfa868b97c109f3870625842f4cc15 + languageName: node + linkType: hard + +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 + languageName: node + linkType: hard + +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 + languageName: node + linkType: hard + +"writable-consumable-stream@npm:^4.1.0": + version: 4.2.0 + resolution: "writable-consumable-stream@npm:4.2.0" + dependencies: + consumable-stream: "npm:^3.0.0" + checksum: 10c0/d674d68c52025f988fa18c717e8ea56b3fd10c54fcb04c9716ad1ca45dbaaaf0d027b3b1e6e0e67d495d267ffc6b95ccf37cb62d15daefeec0c942bdae2f616b + languageName: node + linkType: hard + +"ws@npm:^8.18.0": + version: 8.18.3 + resolution: "ws@npm:8.18.3" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/eac918213de265ef7cb3d4ca348b891a51a520d839aa51cdb8ca93d4fa7ff9f6ccb339ccee89e4075324097f0a55157c89fa3f7147bde9d8d7e90335dc087b53 + languageName: node + linkType: hard + +"xtend@npm:~4.0.1": + version: 4.0.2 + resolution: "xtend@npm:4.0.2" + checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard + +"yaml@npm:^1.10.0": + version: 1.10.2 + resolution: "yaml@npm:1.10.2" + checksum: 10c0/5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f + languageName: node + linkType: hard + +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f + languageName: node + linkType: hard + +"zod-validation-error@npm:^3.5.0 || ^4.0.0": + version: 4.0.2 + resolution: "zod-validation-error@npm:4.0.2" + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + checksum: 10c0/0ccfec48c46de1be440b719cd02044d4abb89ed0e14c13e637cd55bf29102f67ccdba373f25def0fc7130e5f15025be4d557a7edcc95d5a3811599aade689e1b + languageName: node + linkType: hard + +"zod@npm:^3.25.0 || ^4.0.0": + version: 4.2.1 + resolution: "zod@npm:4.2.1" + checksum: 10c0/ecb5219bddf76a42d092a843fb98ad4cb78f1e1077082772b03ef032ee5cbc80790a4051836b962d26fb4af854323bc784d628bd1b8d9898149eba7af21c5560 + languageName: node + linkType: hard From ae09bb1e50856d2510160b79553cd5d65561a96a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 26 Jan 2026 12:19:05 +0100 Subject: [PATCH 100/146] state-machine(alice+bob): rename states to match new transaction names Rename the states as follows: - RemainingRefundTimelock -> ReclaimTimelock - RefundBurn -> Withhold - RefundAmnesty -> Reclaim - FinalAmnesty -> Mercy --- swap-db/src/alice.rs | 91 ++++++++----------- swap-db/src/bob.rs | 76 +++++++--------- swap-machine/src/bob/mod.rs | 54 +++++------ swap/src/cli/cancel_and_refund.rs | 36 ++++---- swap/src/protocol/bob/swap.rs | 42 ++++----- swap/tests/harness/mod.rs | 19 ++-- ...rtial_refund_alice_grants_final_amnesty.rs | 6 +- 7 files changed, 150 insertions(+), 174 deletions(-) diff --git a/swap-db/src/alice.rs b/swap-db/src/alice.rs index e3cc963c35..7462068f0a 100644 --- a/swap-db/src/alice.rs +++ b/swap-db/src/alice.rs @@ -89,6 +89,9 @@ pub enum Alice { #[serde(with = "swap_serde::monero::private_key")] spend_key: monero::PrivateKey, }, + BtcWithholdPublished { + state3: alice::State3, + }, Done(AliceEndState), } @@ -107,19 +110,16 @@ pub enum AliceEndState { state3: alice::State3, transfer_proof: TransferProof, }, - BtcRefundBurnPublished { + BtcWithheld { state3: alice::State3, }, - BtcRefundBurnConfirmed { + BtcMercyGranted { state3: alice::State3, }, - BtcFinalAmnestyGranted { + BtcMercyPublished { state3: alice::State3, }, - BtcRefundFinalAmnestyPublished { - state3: alice::State3, - }, - BtcRefundFinalAmnestyConfirmed { + BtcMercyConfirmed { state3: alice::State3, }, } @@ -127,15 +127,11 @@ pub enum AliceEndState { impl From for Alice { fn from(alice_state: AliceState) -> Self { match alice_state { - AliceState::Started { state3 } => Alice::Started { - state3: *state3, - }, - AliceState::BtcLockTransactionSeen { state3 } => Alice::BtcLockTransactionSeen { - state3: *state3, - }, - AliceState::BtcLocked { state3 } => Alice::BtcLocked { - state3: *state3, - }, + AliceState::Started { state3 } => Alice::Started { state3: *state3 }, + AliceState::BtcLockTransactionSeen { state3 } => { + Alice::BtcLockTransactionSeen { state3: *state3 } + } + AliceState::BtcLocked { state3 } => Alice::BtcLocked { state3: *state3 }, AliceState::XmrLockTransactionSent { monero_wallet_restore_blockheight, transfer_proof, @@ -224,12 +220,12 @@ impl From for Alice { state3: *state3, spend_key, }, - AliceState::BtcEarlyRefundable { state3 } => Alice::BtcEarlyRefundable { - state3: *state3, - }, - AliceState::BtcEarlyRefunded(state3) => Alice::Done(AliceEndState::BtcEarlyRefunded { - state3: *state3, - }), + AliceState::BtcEarlyRefundable { state3 } => { + Alice::BtcEarlyRefundable { state3: *state3 } + } + AliceState::BtcEarlyRefunded(state3) => { + Alice::Done(AliceEndState::BtcEarlyRefunded { state3: *state3 }) + } AliceState::BtcPunishable { monero_wallet_restore_blockheight, transfer_proof, @@ -243,29 +239,19 @@ impl From for Alice { state3: state3.map(|s| s.as_ref().clone()), }), AliceState::BtcRefundBurnPublished { state3 } => { - Alice::Done(AliceEndState::BtcRefundBurnPublished { - state3: *state3, - }) + Alice::BtcWithholdPublished { state3: *state3 } } AliceState::BtcRefundBurnConfirmed { state3 } => { - Alice::Done(AliceEndState::BtcRefundBurnConfirmed { - state3: *state3, - }) + Alice::Done(AliceEndState::BtcWithheld { state3: *state3 }) } AliceState::BtcFinalAmnestyGranted { state3 } => { - Alice::Done(AliceEndState::BtcFinalAmnestyGranted { - state3: *state3, - }) + Alice::Done(AliceEndState::BtcMercyGranted { state3: *state3 }) } AliceState::BtcRefundFinalAmnestyPublished { state3 } => { - Alice::Done(AliceEndState::BtcRefundFinalAmnestyPublished { - state3: *state3, - }) + Alice::Done(AliceEndState::BtcMercyPublished { state3: *state3 }) } AliceState::BtcRefundFinalAmnestyConfirmed { state3 } => { - Alice::Done(AliceEndState::BtcRefundFinalAmnestyConfirmed { - state3: *state3, - }) + Alice::Done(AliceEndState::BtcMercyConfirmed { state3: *state3 }) } AliceState::WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight, @@ -426,6 +412,9 @@ impl From for AliceState { spend_key, state3: Box::new(state3), }, + Alice::BtcWithholdPublished { state3 } => AliceState::BtcRefundBurnPublished { + state3: Box::new(state3), + }, Alice::Done(end_state) => match end_state { AliceEndState::SafelyAborted => AliceState::SafelyAborted, AliceEndState::BtcRedeemed => AliceState::BtcRedeemed, @@ -442,27 +431,18 @@ impl From for AliceState { AliceEndState::BtcEarlyRefunded { state3 } => { AliceState::BtcEarlyRefunded(Box::new(state3)) } - AliceEndState::BtcRefundBurnPublished { state3 } => { - AliceState::BtcRefundBurnPublished { - state3: Box::new(state3), - } - } - AliceEndState::BtcRefundBurnConfirmed { state3 } => { - AliceState::BtcRefundBurnConfirmed { - state3: Box::new(state3), - } - } - AliceEndState::BtcFinalAmnestyGranted { state3 } => { - AliceState::BtcFinalAmnestyGranted { - state3: Box::new(state3), - } - } - AliceEndState::BtcRefundFinalAmnestyPublished { state3 } => { + AliceEndState::BtcWithheld { state3 } => AliceState::BtcRefundBurnConfirmed { + state3: Box::new(state3), + }, + AliceEndState::BtcMercyGranted { state3 } => AliceState::BtcFinalAmnestyGranted { + state3: Box::new(state3), + }, + AliceEndState::BtcMercyPublished { state3 } => { AliceState::BtcRefundFinalAmnestyPublished { state3: Box::new(state3), } } - AliceEndState::BtcRefundFinalAmnestyConfirmed { state3 } => { + AliceEndState::BtcMercyConfirmed { state3 } => { AliceState::BtcRefundFinalAmnestyConfirmed { state3: Box::new(state3), } @@ -499,6 +479,9 @@ impl fmt::Display for Alice { Alice::BtcPartiallyRefunded { .. } => f.write_str("Monero refundable"), Alice::BtcEarlyRefundable { .. } => f.write_str("Bitcoin early refundable"), Alice::XmrRefundable { .. } => f.write_str("Bitcoin early refundable"), + Alice::BtcWithholdPublished { .. } => { + f.write_str("Bitcoin withhold transaction published") + } Alice::Done(end_state) => write!(f, "Done: {}", end_state), } } diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 362cd011b8..1c382afb87 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -55,12 +55,12 @@ pub enum Bob { BtcEarlyRefundPublished(bob::State6), BtcPartialRefundPublished(bob::State6), BtcPartiallyRefunded(bob::State6), - BtcAmnestyPublished(bob::State6), - WaitingForRemainingRefundTimelockExpiration(bob::State6), - RemainingRefundTimelockExpired(bob::State6), - BtcRefundBurnPublished(bob::State6), - BtcRefundBurnt(bob::State6), - BtcFinalAmnestyPublished(bob::State6), + WaitingForReclaimTimelockExpiration(bob::State6), + ReclaimTimelockExpired(bob::State6), + BtcReclaimPublished(bob::State6), + BtcWithholdPublished(bob::State6), + BtcWithheld(bob::State6), + BtcMercyPublished(bob::State6), Done(BobEndState), } @@ -70,8 +70,8 @@ pub enum BobEndState { XmrRedeemed { tx_lock_id: bitcoin::Txid }, BtcRefunded(Box), BtcEarlyRefunded(Box), - BtcAmnestyConfirmed(Box), - BtcFinalAmnestyConfirmed(Box), + BtcReclaimConfirmed(Box), + BtcMercyConfirmed(Box), } impl From for Bob { @@ -145,21 +145,19 @@ impl From for Bob { Bob::Done(BobEndState::BtcEarlyRefunded(Box::new(state6))) } BobState::BtcPartiallyRefunded(state6) => Bob::BtcPartiallyRefunded(state6), - BobState::BtcAmnestyPublished(state6) => Bob::BtcAmnestyPublished(state6), - BobState::BtcAmnestyConfirmed(state6) => { - Bob::Done(BobEndState::BtcAmnestyConfirmed(Box::new(state6))) + BobState::BtcReclaimPublished(state6) => Bob::BtcReclaimPublished(state6), + BobState::BtcReclaimConfirmed(state6) => { + Bob::Done(BobEndState::BtcReclaimConfirmed(Box::new(state6))) } - BobState::WaitingForRemainingRefundTimelockExpiration(state6) => { - Bob::WaitingForRemainingRefundTimelockExpiration(state6) + BobState::WaitingForReclaimTimelockExpiration(state6) => { + Bob::WaitingForReclaimTimelockExpiration(state6) } - BobState::RemainingRefundTimelockExpired(state6) => { - Bob::RemainingRefundTimelockExpired(state6) - } - BobState::BtcRefundBurnPublished(state6) => Bob::BtcRefundBurnPublished(state6), - BobState::BtcRefundBurnt(state6) => Bob::BtcRefundBurnt(state6), - BobState::BtcFinalAmnestyPublished(state6) => Bob::BtcFinalAmnestyPublished(state6), - BobState::BtcFinalAmnestyConfirmed(state6) => { - Bob::Done(BobEndState::BtcFinalAmnestyConfirmed(Box::new(state6))) + BobState::ReclaimTimelockExpired(state6) => Bob::ReclaimTimelockExpired(state6), + BobState::BtcWithholdPublished(state6) => Bob::BtcWithholdPublished(state6), + BobState::BtcWithheld(state6) => Bob::BtcWithheld(state6), + BobState::BtcMercyPublished(state6) => Bob::BtcMercyPublished(state6), + BobState::BtcMercyConfirmed(state6) => { + Bob::Done(BobEndState::BtcMercyConfirmed(Box::new(state6))) } BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted), } @@ -228,27 +226,23 @@ impl From for BobState { Bob::BtcRefundPublished(state6) => BobState::BtcRefundPublished(state6), Bob::BtcPartialRefundPublished(state6) => BobState::BtcPartialRefundPublished(state6), Bob::BtcPartiallyRefunded(state6) => BobState::BtcPartiallyRefunded(state6), - Bob::BtcAmnestyPublished(state6) => BobState::BtcAmnestyPublished(state6), + Bob::BtcReclaimPublished(state6) => BobState::BtcReclaimPublished(state6), Bob::BtcEarlyRefundPublished(state6) => BobState::BtcEarlyRefundPublished(state6), Bob::BtcPunished { state, tx_lock_id } => BobState::BtcPunished { state, tx_lock_id }, - Bob::WaitingForRemainingRefundTimelockExpiration(state6) => { - BobState::WaitingForRemainingRefundTimelockExpiration(state6) - } - Bob::RemainingRefundTimelockExpired(state6) => { - BobState::RemainingRefundTimelockExpired(state6) + Bob::WaitingForReclaimTimelockExpiration(state6) => { + BobState::WaitingForReclaimTimelockExpiration(state6) } - Bob::BtcRefundBurnPublished(state6) => BobState::BtcRefundBurnPublished(state6), - Bob::BtcRefundBurnt(state6) => BobState::BtcRefundBurnt(state6), - Bob::BtcFinalAmnestyPublished(state6) => BobState::BtcFinalAmnestyPublished(state6), + Bob::ReclaimTimelockExpired(state6) => BobState::ReclaimTimelockExpired(state6), + Bob::BtcWithholdPublished(state6) => BobState::BtcWithholdPublished(state6), + Bob::BtcWithheld(state6) => BobState::BtcWithheld(state6), + Bob::BtcMercyPublished(state6) => BobState::BtcMercyPublished(state6), Bob::Done(end_state) => match end_state { BobEndState::SafelyAborted => BobState::SafelyAborted, BobEndState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id }, BobEndState::BtcRefunded(state6) => BobState::BtcRefunded(*state6), BobEndState::BtcEarlyRefunded(state6) => BobState::BtcEarlyRefunded(*state6), - BobEndState::BtcAmnestyConfirmed(state6) => BobState::BtcAmnestyConfirmed(*state6), - BobEndState::BtcFinalAmnestyConfirmed(state6) => { - BobState::BtcFinalAmnestyConfirmed(*state6) - } + BobEndState::BtcReclaimConfirmed(state6) => BobState::BtcReclaimConfirmed(*state6), + BobEndState::BtcMercyConfirmed(state6) => BobState::BtcMercyConfirmed(*state6), }, } } @@ -281,16 +275,14 @@ impl fmt::Display for Bob { Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"), Bob::BtcPunished { .. } => f.write_str("Bitcoin punished"), Bob::BtcPartiallyRefunded { .. } => f.write_str("Bitcoin partially refunded"), - Bob::BtcAmnestyPublished { .. } => f.write_str("Bitcoin amnesty published"), - Bob::WaitingForRemainingRefundTimelockExpiration { .. } => { + Bob::BtcReclaimPublished { .. } => f.write_str("Bitcoin amnesty published"), + Bob::WaitingForReclaimTimelockExpiration { .. } => { f.write_str("Waiting for remaining refund timelock to expire") } - Bob::RemainingRefundTimelockExpired { .. } => { - f.write_str("Remaining refund timelock expired") - } - Bob::BtcRefundBurnPublished { .. } => f.write_str("Bitcoin refund burn published"), - Bob::BtcRefundBurnt { .. } => f.write_str("Bitcoin refund burnt"), - Bob::BtcFinalAmnestyPublished { .. } => f.write_str("Bitcoin final amnesty published"), + Bob::ReclaimTimelockExpired { .. } => f.write_str("Remaining refund timelock expired"), + Bob::BtcWithholdPublished { .. } => f.write_str("Bitcoin refund burn published"), + Bob::BtcWithheld { .. } => f.write_str("Bitcoin refund burnt"), + Bob::BtcMercyPublished { .. } => f.write_str("Bitcoin final amnesty published"), } } } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index a4b2743867..87439de93d 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -78,24 +78,26 @@ pub enum BobState { BtcRefunded(State6), BtcEarlyRefunded(State6), BtcPartiallyRefunded(State6), - BtcAmnestyPublished(State6), - BtcAmnestyConfirmed(State6), /// Waiting for RemainingRefundTimelock to expire after partial refund confirmed. /// During this time, Alice may publish TxRefundBurn. - WaitingForRemainingRefundTimelockExpiration(State6), + WaitingForReclaimTimelockExpiration(State6), /// RemainingRefundTimelock has expired, we can now publish TxRefundAmnesty. - RemainingRefundTimelockExpired(State6), + ReclaimTimelockExpired(State6), /// Alice published TxRefundBurn before we could publish TxRefundAmnesty. - BtcRefundBurnPublished(State6), + BtcWithholdPublished(State6), /// TxRefundBurn has been confirmed. The amnesty output is now burnt. - BtcRefundBurnt(State6), + BtcWithheld(State6), + BtcReclaimPublished(State6), + BtcReclaimConfirmed(State6), /// Alice published TxFinalAmnesty (using our presigned signature) to refund us. - BtcFinalAmnestyPublished(State6), + BtcMercyPublished(State6), /// TxFinalAmnesty has been confirmed. We received the burnt funds back. - BtcFinalAmnestyConfirmed(State6), + BtcMercyConfirmed(State6), XmrRedeemed { tx_lock_id: bitcoin::Txid, }, + /// If we do not refund within `PUNISH_TIMELOCK` blocks of either us or alice publishing + /// [TxCancel], then alice may punish us by forcibly redeeming the BTC. BtcPunished { state: State6, // TODO: This attribute is redundant and unused @@ -181,20 +183,20 @@ impl fmt::Display for BobState { BobState::BtcPunished { .. } => write!(f, "btc is punished"), BobState::BtcEarlyRefunded { .. } => write!(f, "btc is early refunded"), BobState::BtcPartiallyRefunded { .. } => write!(f, "btc is partially refunded"), - BobState::BtcAmnestyPublished { .. } => write!(f, "btc amnesty is published"), - BobState::BtcAmnestyConfirmed { .. } => write!(f, "btc amnesty is confirmed"), - BobState::WaitingForRemainingRefundTimelockExpiration { .. } => { + BobState::BtcReclaimPublished { .. } => write!(f, "btc amnesty is published"), + BobState::BtcReclaimConfirmed { .. } => write!(f, "btc amnesty is confirmed"), + BobState::WaitingForReclaimTimelockExpiration { .. } => { write!(f, "waiting for remaining refund timelock to expire") } - BobState::RemainingRefundTimelockExpired { .. } => { + BobState::ReclaimTimelockExpired { .. } => { write!(f, "remaining refund timelock expired") } - BobState::BtcRefundBurnPublished { .. } => write!(f, "btc refund burn is published"), - BobState::BtcRefundBurnt { .. } => write!(f, "btc refund is burnt"), - BobState::BtcFinalAmnestyPublished { .. } => { + BobState::BtcWithholdPublished { .. } => write!(f, "btc refund burn is published"), + BobState::BtcWithheld { .. } => write!(f, "btc refund is burnt"), + BobState::BtcMercyPublished { .. } => { write!(f, "btc final amnesty is published") } - BobState::BtcFinalAmnestyConfirmed { .. } => { + BobState::BtcMercyConfirmed { .. } => { write!(f, "btc final amnesty is confirmed") } BobState::SafelyAborted => write!(f, "safely aborted"), @@ -240,17 +242,17 @@ impl BobState { | BobState::BtcEarlyRefundPublished(state) | BobState::BtcPartialRefundPublished(state) | BobState::BtcPartiallyRefunded(state) - | BobState::BtcAmnestyPublished(state) - | BobState::BtcAmnestyConfirmed(state) - | BobState::WaitingForRemainingRefundTimelockExpiration(state) - | BobState::RemainingRefundTimelockExpired(state) - | BobState::BtcRefundBurnPublished(state) - | BobState::BtcRefundBurnt(state) - | BobState::BtcFinalAmnestyPublished(state) => { + | BobState::BtcReclaimPublished(state) + | BobState::BtcReclaimConfirmed(state) + | BobState::WaitingForReclaimTimelockExpiration(state) + | BobState::ReclaimTimelockExpired(state) + | BobState::BtcWithholdPublished(state) + | BobState::BtcWithheld(state) + | BobState::BtcMercyPublished(state) => { Some(state.expired_timelock(bitcoin_wallet.as_ref()).await?) } BobState::BtcPunished { .. } => Some(ExpiredTimelocks::Punish), - BobState::BtcFinalAmnestyConfirmed(_) => Some(ExpiredTimelocks::RemainingRefund), + BobState::BtcMercyConfirmed(_) => Some(ExpiredTimelocks::RemainingRefund), BobState::BtcRefunded(_) | BobState::BtcEarlyRefunded { .. } | BobState::BtcRedeemed(_) @@ -264,8 +266,8 @@ pub fn is_complete(state: &BobState) -> bool { state, BobState::BtcRefunded(..) | BobState::BtcEarlyRefunded { .. } - | BobState::BtcAmnestyConfirmed { .. } - | BobState::BtcFinalAmnestyConfirmed { .. } + | BobState::BtcReclaimConfirmed { .. } + | BobState::BtcMercyConfirmed { .. } | BobState::XmrRedeemed { .. } | BobState::SafelyAborted ) diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 58722febcc..252671e529 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -74,20 +74,20 @@ pub async fn cancel( BobState::BtcEarlyRefundPublished(state6) => state6, BobState::BtcPartialRefundPublished(state6) => state6, BobState::BtcPartiallyRefunded(state6) => state6, - BobState::BtcAmnestyConfirmed(state6) => state6, - BobState::BtcAmnestyPublished(state6) => state6, - BobState::WaitingForRemainingRefundTimelockExpiration(state6) => state6, - BobState::RemainingRefundTimelockExpired(state6) => state6, - BobState::BtcRefundBurnPublished(state6) => state6, - BobState::BtcFinalAmnestyPublished(state6) => state6, + BobState::BtcReclaimConfirmed(state6) => state6, + BobState::BtcReclaimPublished(state6) => state6, + BobState::WaitingForReclaimTimelockExpiration(state6) => state6, + BobState::ReclaimTimelockExpired(state6) => state6, + BobState::BtcWithholdPublished(state6) => state6, + BobState::BtcMercyPublished(state6) => state6, BobState::Started { .. } | BobState::BtcRedeemed(_) | BobState::XmrRedeemed { .. } | BobState::BtcPunished { .. } | BobState::BtcEarlyRefunded { .. } - | BobState::BtcRefundBurnt { .. } - | BobState::BtcFinalAmnestyConfirmed { .. } + | BobState::BtcWithheld { .. } + | BobState::BtcMercyConfirmed { .. } | BobState::SafelyAborted => bail!( "Cannot cancel swap {} because it is in state {} which is not cancellable.", swap_id, @@ -212,20 +212,20 @@ pub async fn refund( BobState::BtcEarlyRefundPublished(state6) => state6, BobState::BtcPartialRefundPublished(state6) => state6, BobState::BtcPartiallyRefunded(state6) => state6, - BobState::BtcAmnestyPublished(state6) => state6, - BobState::BtcAmnestyConfirmed(state6) => state6, - BobState::WaitingForRemainingRefundTimelockExpiration(state6) => state6, - BobState::RemainingRefundTimelockExpired(state6) => state6, - BobState::BtcRefundBurnPublished(state6) => state6, - BobState::BtcFinalAmnestyPublished(state6) => state6, + BobState::BtcReclaimPublished(state6) => state6, + BobState::BtcReclaimConfirmed(state6) => state6, + BobState::WaitingForReclaimTimelockExpiration(state6) => state6, + BobState::ReclaimTimelockExpired(state6) => state6, + BobState::BtcWithholdPublished(state6) => state6, + BobState::BtcMercyPublished(state6) => state6, BobState::Started { .. } | BobState::SwapSetupCompleted(_) | BobState::BtcRedeemed(_) | BobState::BtcEarlyRefunded { .. } | BobState::XmrRedeemed { .. } | BobState::BtcPunished { .. } - | BobState::BtcRefundBurnt { .. } - | BobState::BtcFinalAmnestyConfirmed { .. } + | BobState::BtcWithheld { .. } + | BobState::BtcMercyConfirmed { .. } | BobState::SafelyAborted => bail!( "Cannot refund swap {} because it is in state {} which is not refundable.", swap_id, @@ -308,7 +308,9 @@ pub async fn refund( } Ok(ExpiredTimelocks::RemainingRefund) => { // TODO: Try to publish TxRefundAmnesty here instead of just reporting the state - bail!(bitcoin_publication_err.context("Amnesty timelock has expired. TxRefundAmnesty can be published.")); + bail!(bitcoin_publication_err.context( + "Amnesty timelock has expired. TxRefundAmnesty can be published." + )); } Err(e) => { bail!(bitcoin_publication_err diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 576d698b96..5ffefa348f 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -51,7 +51,7 @@ pub fn has_already_processed_transfer_proof(state: &BobState) -> bool { // // The same is true for the BtcRefundBurnt. pub fn is_run_at_most_once(state: &BobState) -> bool { - matches!(state, BobState::BtcPunished { .. } | BobState::BtcRefundBurnt(..)) + matches!(state, BobState::BtcPunished { .. } | BobState::BtcWithheld(..)) } #[allow(clippy::too_many_arguments)] @@ -1066,7 +1066,7 @@ async fn next_state( // Transition to waiting state where we race remaining_refund_timelock // against Alice potentially publishing TxRefundBurn - BobState::WaitingForRemainingRefundTimelockExpiration(state) + BobState::WaitingForReclaimTimelockExpiration(state) } BobState::BtcRefunded(state) => { event_emitter.emit_swap_progress_event( @@ -1078,7 +1078,7 @@ async fn next_state( BobState::BtcRefunded(state) } - BobState::BtcAmnestyPublished(state) => { + BobState::BtcReclaimPublished(state) => { // Here we just wait for the amnesty transaction to be confirmed let tx_amnesty = state.construct_tx_amnesty().context("Couldn't construct Bitcoin amnesty transaction")?; @@ -1109,7 +1109,7 @@ async fn next_state( }, ); - Ok(BobState::BtcAmnestyConfirmed(state.clone())) + Ok(BobState::BtcReclaimConfirmed(state.clone())) }, None, None) .await .context("Failed to wait for Bitcoin amnesty transaction to be confirmed")? @@ -1252,15 +1252,15 @@ async fn next_state( }); BobState::BtcEarlyRefunded(state) }, - BobState::BtcAmnestyConfirmed(state) => { + BobState::BtcReclaimConfirmed(state) => { event_emitter.emit_swap_progress_event(swap_id, TauriSwapProgressEvent::BtcAmnestyReceived { btc_amnesty_txid: state.construct_tx_amnesty()?.txid(), btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }); - BobState::BtcAmnestyConfirmed(state) + BobState::BtcReclaimConfirmed(state) }, - BobState::WaitingForRemainingRefundTimelockExpiration(state) => { + BobState::WaitingForReclaimTimelockExpiration(state) => { // Race between: // - Remaining refund timelock expiring (so we can publish TxRefundAmnesty) // - Alice publishing TxRefundBurn (burns the amnesty output) @@ -1309,16 +1309,16 @@ async fn next_state( result = timelock_expired_future => { result?; tracing::info!("Remaining refund timelock expired, can now publish TxRefundAmnesty"); - BobState::RemainingRefundTimelockExpired(state) + BobState::ReclaimTimelockExpired(state) } // Watch for Alice publishing TxRefundBurn _ = tx_refund_burn_status.wait_until_seen() => { tracing::info!("Alice published TxRefundBurn, amnesty output is being burnt"); - BobState::BtcRefundBurnPublished(state) + BobState::BtcWithholdPublished(state) } } } - BobState::RemainingRefundTimelockExpired(state) => { + BobState::ReclaimTimelockExpired(state) => { // TODO: We should retry this and the check // First check if TxRefundBurn was seen (we may have missed it while offline) let tx_refund_burn = state.construct_tx_refund_burn()?; @@ -1326,7 +1326,7 @@ async fn next_state( if tx_refund_burn_status.has_been_seen() { tracing::info!("TxRefundBurn was already published, transitioning to BtcRefundBurnPublished"); - return Ok(BobState::BtcRefundBurnPublished(state)); + return Ok(BobState::BtcWithholdPublished(state)); } // TxRefundBurn not published, we can publish TxRefundAmnesty @@ -1336,9 +1336,9 @@ async fn next_state( bitcoin_wallet.ensure_broadcasted(transaction, "amnesty") .await .context("Couldn't ensure broadcast of Bitcoin amnesty transaction")?; - BobState::BtcAmnestyPublished(state) + BobState::BtcReclaimPublished(state) } - BobState::BtcRefundBurnPublished(state) => { + BobState::BtcWithholdPublished(state) => { // Wait for TxRefundBurn confirmation let tx_refund_burn = state.construct_tx_refund_burn()?; event_emitter.emit_swap_progress_event( @@ -1353,9 +1353,9 @@ async fn next_state( subscription.wait_until_final().await?; tracing::info!("TxRefundBurn confirmed, amnesty output is burnt"); - BobState::BtcRefundBurnt(state) + BobState::BtcWithheld(state) } - BobState::BtcRefundBurnt(state) => { + BobState::BtcWithheld(state) => { // Watch for Alice publishing TxFinalAmnesty // Alice may grant final amnesty after burning our refund // However, we don't expect Alice to publish the tx at once, if at all. @@ -1376,12 +1376,12 @@ async fn next_state( let final_amnesty_status = bitcoin_wallet.status_of_script(&tx_final_amnesty).await.context("Failed to check TxFinalAmnesty status")?; if final_amnesty_status.has_been_seen() { - BobState::BtcFinalAmnestyPublished(state) + BobState::BtcMercyPublished(state) } else { - BobState::BtcRefundBurnt(state) + BobState::BtcWithheld(state) } } - BobState::BtcFinalAmnestyPublished(state) => { + BobState::BtcMercyPublished(state) => { // Wait for TxFinalAmnesty confirmation let tx_final_amnesty = state.construct_tx_final_amnesty()?; event_emitter.emit_swap_progress_event( @@ -1396,9 +1396,9 @@ async fn next_state( subscription.wait_until_final().await?; tracing::info!("TxFinalAmnesty confirmed, received burnt funds back"); - BobState::BtcFinalAmnestyConfirmed(state) + BobState::BtcMercyConfirmed(state) } - BobState::BtcFinalAmnestyConfirmed(state) => { + BobState::BtcMercyConfirmed(state) => { // Terminal state - we received the burnt funds back let tx_final_amnesty = state.construct_tx_final_amnesty()?; event_emitter.emit_swap_progress_event( @@ -1409,7 +1409,7 @@ async fn next_state( btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); - BobState::BtcFinalAmnestyConfirmed(state) + BobState::BtcMercyConfirmed(state) } BobState::SafelyAborted => BobState::SafelyAborted, BobState::XmrRedeemed { tx_lock_id } => { diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 14dbaefebd..c6cac73f5e 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -1034,7 +1034,7 @@ impl TestContext { self.bob_bitcoin_wallet.sync().await.unwrap(); let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_fee) = match state { - BobState::BtcAmnestyConfirmed(state6) => ( + BobState::BtcReclaimConfirmed(state6) => ( state6.tx_lock_id(), state6.tx_cancel_fee, state6.tx_partial_refund_fee.expect("partial refund fee"), @@ -1063,7 +1063,7 @@ impl TestContext { self.bob_bitcoin_wallet.sync().await.unwrap(); let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_amount) = match state { - BobState::BtcRefundBurnt(state6) => ( + BobState::BtcWithheld(state6) => ( state6.tx_lock_id(), state6.tx_cancel_fee, state6.tx_partial_refund_fee.expect("partial refund fee"), @@ -1092,7 +1092,7 @@ impl TestContext { self.bob_bitcoin_wallet.sync().await.unwrap(); let (lock_tx_id, cancel_fee, partial_refund_fee, final_amnesty_fee) = match state { - BobState::BtcFinalAmnestyConfirmed(state6) => ( + BobState::BtcMercyConfirmed(state6) => ( state6.tx_lock_id(), state6.tx_cancel_fee, state6.tx_partial_refund_fee.expect("partial refund fee"), @@ -1476,26 +1476,23 @@ pub mod bob_run_until { } pub fn is_waiting_for_remaining_refund_timelock(state: &BobState) -> bool { - matches!( - state, - BobState::WaitingForRemainingRefundTimelockExpiration(..) - ) + matches!(state, BobState::WaitingForReclaimTimelockExpiration(..)) } pub fn is_remaining_refund_timelock_expired(state: &BobState) -> bool { - matches!(state, BobState::RemainingRefundTimelockExpired(..)) + matches!(state, BobState::ReclaimTimelockExpired(..)) } pub fn is_btc_amnesty_confirmed(state: &BobState) -> bool { - matches!(state, BobState::BtcAmnestyConfirmed(..)) + matches!(state, BobState::BtcReclaimConfirmed(..)) } pub fn is_btc_refund_burnt(state: &BobState) -> bool { - matches!(state, BobState::BtcRefundBurnt(..)) + matches!(state, BobState::BtcWithheld(..)) } pub fn is_btc_final_amnesty_confirmed(state: &BobState) -> bool { - matches!(state, BobState::BtcFinalAmnestyConfirmed(..)) + matches!(state, BobState::BtcMercyConfirmed(..)) } } diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index cc368c8d6d..080f37bfca 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -75,7 +75,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { )); let bob_state = bob_state.await??; - assert!(matches!(bob_state, BobState::BtcRefundBurnt(..))); + assert!(matches!(bob_state, BobState::BtcWithheld(..))); // Simulate alice's controller sending the final amnesty command via `controller` cli ctx.restart_alice().await; @@ -87,7 +87,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { let (bob_swap, _) = ctx .stop_and_resume_bob_from_db(bob_app_handle, swap_id) .await; - assert!(matches!(bob_swap.state, BobState::BtcRefundBurnt(..))); + assert!(matches!(bob_swap.state, BobState::BtcWithheld(..))); let alice_state = alice_swap.await??; // Only start bob again after alice published the tx. otherwise bob immediately @@ -104,7 +104,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { "Actual state: {alice_state}" ); assert!( - matches!(bob_state, bob::BobState::BtcFinalAmnestyConfirmed(..)), + matches!(bob_state, bob::BobState::BtcMercyConfirmed(..)), "Actual state: {bob_state}" ); From c956efb839cf6e6b12b22e0445d94183f4212457 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 26 Jan 2026 12:26:51 +0100 Subject: [PATCH 101/146] bitcoin(transaction): rename partial refund TXs --- swap-core/src/bitcoin.rs | 14 +++++------ .../bitcoin/{final_amnesty.rs => mercy.rs} | 10 ++++---- .../bitcoin/{refund_amnesty.rs => reclaim.rs} | 6 ++--- .../bitcoin/{refund_burn.rs => withhold.rs} | 6 ++--- swap-machine/src/alice/mod.rs | 22 ++++++++--------- swap-machine/src/bob/mod.rs | 24 +++++++++---------- swap/src/asb/event_loop.rs | 8 +++---- swap/src/protocol/bob/swap.rs | 6 ++--- 8 files changed, 47 insertions(+), 49 deletions(-) rename swap-core/src/bitcoin/{final_amnesty.rs => mercy.rs} (96%) rename swap-core/src/bitcoin/{refund_amnesty.rs => reclaim.rs} (97%) rename swap-core/src/bitcoin/{refund_burn.rs => withhold.rs} (98%) diff --git a/swap-core/src/bitcoin.rs b/swap-core/src/bitcoin.rs index 9dd4cc52b2..4ccd6fc34d 100644 --- a/swap-core/src/bitcoin.rs +++ b/swap-core/src/bitcoin.rs @@ -2,32 +2,32 @@ mod cancel; mod early_refund; -mod final_amnesty; mod full_refund; mod lock; +mod mercy; mod partial_refund; mod punish; +mod reclaim; mod redeem; -mod refund_amnesty; -mod refund_burn; mod timelocks; +mod withhold; pub use crate::bitcoin::cancel::TxCancel; pub use crate::bitcoin::early_refund::TxEarlyRefund; -pub use crate::bitcoin::final_amnesty::TxFinalAmnesty; pub use crate::bitcoin::full_refund::TxFullRefund; pub use crate::bitcoin::lock::TxLock; +pub use crate::bitcoin::mercy::TxMercy; pub use crate::bitcoin::partial_refund::TxPartialRefund; pub use crate::bitcoin::punish::TxPunish; +pub use crate::bitcoin::reclaim::TxReclaim; pub use crate::bitcoin::redeem::TxRedeem; -pub use crate::bitcoin::refund_amnesty::TxRefundAmnesty; -pub use crate::bitcoin::refund_burn::TxRefundBurn; pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks}; pub use crate::bitcoin::timelocks::{CancelTimelock, PunishTimelock, RemainingRefundTimelock}; -pub use bitcoin_wallet::ScriptStatus; +pub use crate::bitcoin::withhold::TxWithhold; pub use ::bitcoin::amount::Amount; pub use ::bitcoin::psbt::Psbt as PartiallySignedTransaction; pub use ::bitcoin::{Address, AddressType, Network, Transaction, Txid}; +pub use bitcoin_wallet::ScriptStatus; pub use ecdsa_fun::Signature; pub use ecdsa_fun::adaptor::EncryptedSignature; pub use ecdsa_fun::fun::Scalar; diff --git a/swap-core/src/bitcoin/final_amnesty.rs b/swap-core/src/bitcoin/mercy.rs similarity index 96% rename from swap-core/src/bitcoin/final_amnesty.rs rename to swap-core/src/bitcoin/mercy.rs index 98b99674d7..ce54735944 100644 --- a/swap-core/src/bitcoin/final_amnesty.rs +++ b/swap-core/src/bitcoin/mercy.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use crate::bitcoin::refund_burn::TxRefundBurn; +use crate::bitcoin::withhold::TxWithhold; use crate::bitcoin::{self, Address, Amount, PublicKey, Transaction}; use ::bitcoin::sighash::SighashCache; use ::bitcoin::{EcdsaSighashType, Txid, sighash::SegwitV0Sighash as Sighash}; @@ -19,16 +19,16 @@ use std::collections::HashMap; /// her signature private until she decides to cooperate (e.g., if Bob contacts /// her to request the refund). #[derive(Debug, Clone)] -pub struct TxFinalAmnesty { +pub struct TxMercy { inner: Transaction, digest: Sighash, burn_output_descriptor: Descriptor<::bitcoin::PublicKey>, watch_script: ScriptBuf, } -impl TxFinalAmnesty { +impl TxMercy { pub fn new( - tx_refund_burn: &TxRefundBurn, + tx_refund_burn: &TxWithhold, refund_address: &Address, spending_fee: Amount, ) -> Self { @@ -135,7 +135,7 @@ impl TxFinalAmnesty { } } -impl Watchable for TxFinalAmnesty { +impl Watchable for TxMercy { fn id(&self) -> Txid { self.txid() } diff --git a/swap-core/src/bitcoin/refund_amnesty.rs b/swap-core/src/bitcoin/reclaim.rs similarity index 97% rename from swap-core/src/bitcoin/refund_amnesty.rs rename to swap-core/src/bitcoin/reclaim.rs index c6e726ecfa..79ce2425a3 100644 --- a/swap-core/src/bitcoin/refund_amnesty.rs +++ b/swap-core/src/bitcoin/reclaim.rs @@ -12,14 +12,14 @@ use std::collections::HashMap; use super::timelocks::RemainingRefundTimelock; #[derive(Debug, Clone)] -pub struct TxRefundAmnesty { +pub struct TxReclaim { inner: Transaction, digest: Sighash, amensty_output_descriptor: Descriptor<::bitcoin::PublicKey>, watch_script: ScriptBuf, } -impl TxRefundAmnesty { +impl TxReclaim { pub fn new( tx_refund: &TxPartialRefund, refund_address: &Address, @@ -127,7 +127,7 @@ impl TxRefundAmnesty { } } -impl Watchable for TxRefundAmnesty { +impl Watchable for TxReclaim { fn id(&self) -> Txid { self.txid() } diff --git a/swap-core/src/bitcoin/refund_burn.rs b/swap-core/src/bitcoin/withhold.rs similarity index 98% rename from swap-core/src/bitcoin/refund_burn.rs rename to swap-core/src/bitcoin/withhold.rs index bcc577ad63..9a75fc38c8 100644 --- a/swap-core/src/bitcoin/refund_burn.rs +++ b/swap-core/src/bitcoin/withhold.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; /// Unlike TxRefundAmnesty, this transaction has no timelock - Alice can publish /// it immediately after TxPartialRefund is confirmed. #[derive(Debug, Clone)] -pub struct TxRefundBurn { +pub struct TxWithhold { inner: Transaction, digest: Sighash, amnesty_output_descriptor: Descriptor<::bitcoin::PublicKey>, @@ -29,7 +29,7 @@ pub struct TxRefundBurn { watch_script: ScriptBuf, } -impl TxRefundBurn { +impl TxWithhold { pub fn new( tx_partial_refund: &TxPartialRefund, A: PublicKey, @@ -195,7 +195,7 @@ impl TxRefundBurn { } } -impl Watchable for TxRefundBurn { +impl Watchable for TxWithhold { fn id(&self) -> Txid { self.txid() } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index c76fc1bd98..2ba8e65fd0 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -9,8 +9,8 @@ use std::fmt::{self, Debug}; use std::sync::Arc; use swap_core::bitcoin::{ CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, - TxCancel, TxEarlyRefund, TxFinalAmnesty, TxFullRefund, TxPartialRefund, TxPunish, TxRedeem, - TxRefundAmnesty, TxRefundBurn, Txid, current_epoch, + TxCancel, TxEarlyRefund, TxFullRefund, TxMercy, TxPartialRefund, TxPunish, TxReclaim, TxRedeem, + TxWithhold, Txid, current_epoch, }; use swap_core::compat::{IntoDalek, IntoDalekNg, IntoMoneroOxide}; use swap_core::monero::ScalarExt; @@ -478,7 +478,7 @@ impl State2 { let tx_partial_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); // Construct and sign TxRefundAmnesty - let tx_refund_amnesty = swap_core::bitcoin::TxRefundAmnesty::new( + let tx_refund_amnesty = swap_core::bitcoin::TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee @@ -589,7 +589,7 @@ impl State2 { .context("missing tx_partial_refund_fee")?, ) .context("Couldn't construct TxPartialRefund")?; - let tx_refund_amnesty = TxRefundAmnesty::new( + let tx_refund_amnesty = TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee @@ -607,7 +607,7 @@ impl State2 { .context("Failed to verify refund amnesty transaction")?; // Create TxRefundBurn ourself - let tx_refund_burn = TxRefundBurn::new( + let tx_refund_burn = TxWithhold::new( &tx_partial_refund, self.a.public(), self.B, @@ -624,7 +624,7 @@ impl State2 { .context("Failed to verify refund burn transaction")?; // Create TxFinalAmnesty ourself - let tx_final_amnesty = TxFinalAmnesty::new( + let tx_final_amnesty = TxMercy::new( &tx_refund_burn, &self.refund_address, self.tx_final_amnesty_fee @@ -899,7 +899,7 @@ impl State3 { pub fn signed_bitcoin_amnesty_transaction(&self) -> Result { let tx_partial_refund = self.tx_partial_refund()?; - let tx_amnesty = TxRefundAmnesty::new( + let tx_amnesty = TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee @@ -923,8 +923,8 @@ impl State3 { } /// Construct TxRefundBurn from tx_partial_refund output. - pub fn tx_refund_burn(&self) -> Result { - TxRefundBurn::new( + pub fn tx_refund_burn(&self) -> Result { + TxWithhold::new( &self.tx_partial_refund()?, self.a.public(), self.B, @@ -947,8 +947,8 @@ impl State3 { } /// Construct TxFinalAmnesty from tx_refund_burn output. - pub fn tx_final_amnesty(&self) -> Result { - Ok(TxFinalAmnesty::new( + pub fn tx_final_amnesty(&self) -> Result { + Ok(TxMercy::new( &self.tx_refund_burn()?, &self.refund_address, self.tx_final_amnesty_fee diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 87439de93d..8f535115c9 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -15,8 +15,8 @@ use std::fmt; use std::sync::Arc; use swap_core::bitcoin::{ self, CancelTimelock, ExpiredTimelocks, PunishTimelock, RemainingRefundTimelock, Transaction, - TxCancel, TxFinalAmnesty, TxFullRefund, TxLock, TxPartialRefund, TxRefundAmnesty, TxRefundBurn, - Txid, current_epoch, + TxCancel, TxFullRefund, TxLock, TxMercy, TxPartialRefund, TxReclaim, TxWithhold, Txid, + current_epoch, }; use swap_core::compat::{IntoDalekNg, IntoMoneroOxide}; use swap_core::monero; @@ -512,7 +512,7 @@ impl State1 { &tx_partial_refund_encsig, )?; - let tx_refund_amnesty = TxRefundAmnesty::new( + let tx_refund_amnesty = TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee @@ -645,7 +645,7 @@ impl State2 { .context("missing tx_partial_refund_fee")?, ) .context("Couldn't construct TxPartialRefund")?; - let tx_refund_amnesty = TxRefundAmnesty::new( + let tx_refund_amnesty = TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee @@ -655,7 +655,7 @@ impl State2 { )?; let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); - let tx_refund_burn = TxRefundBurn::new( + let tx_refund_burn = TxWithhold::new( &tx_partial_refund, self.A, self.b.public(), @@ -664,7 +664,7 @@ impl State2 { )?; let tx_refund_burn_sig = self.b.sign(tx_refund_burn.digest()); - let tx_final_amnesty = TxFinalAmnesty::new( + let tx_final_amnesty = TxMercy::new( &tx_refund_burn, &self.refund_address, self.tx_final_amnesty_fee @@ -1317,10 +1317,10 @@ impl State6 { Ok(signed_tx_amnesty) } - pub fn construct_tx_amnesty(&self) -> Result { + pub fn construct_tx_amnesty(&self) -> Result { let tx_partial_refund = self.construct_tx_partial_refund()?; - bitcoin::TxRefundAmnesty::new( + bitcoin::TxReclaim::new( &tx_partial_refund, &self.refund_address, self.tx_refund_amnesty_fee.context( @@ -1332,9 +1332,9 @@ impl State6 { ) } - pub fn construct_tx_refund_burn(&self) -> Result { + pub fn construct_tx_refund_burn(&self) -> Result { let tx_partial_refund = self.construct_tx_partial_refund()?; - bitcoin::TxRefundBurn::new( + bitcoin::TxWithhold::new( &tx_partial_refund, self.A, self.b.public(), @@ -1343,9 +1343,9 @@ impl State6 { ) } - pub fn construct_tx_final_amnesty(&self) -> Result { + pub fn construct_tx_final_amnesty(&self) -> Result { let tx_refund_burn = self.construct_tx_refund_burn()?; - Ok(bitcoin::TxFinalAmnesty::new( + Ok(bitcoin::TxMercy::new( &tx_refund_burn, &self.refund_address, self.tx_final_amnesty_fee.context( diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index a6b0e014f9..efb70e6d36 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -71,8 +71,7 @@ where /// Stores where to send burn-on-refund instructions to /// The corresponding receiver is stored in the EventLoopHandle /// Uses watch channel to allow multiple updates before consumption - recv_burn_on_refund_instruction: - HashMap>>, + recv_burn_on_refund_instruction: HashMap>>, /// Once we receive an [`EncryptedSignature`] from Bob, we forward it to the EventLoopHandle. /// Once the EventLoopHandle acknowledges the receipt of the [`EncryptedSignature`], we need to confirm this to Bob. @@ -786,8 +785,7 @@ pub struct EventLoopHandle { peer: PeerId, recv_encrypted_signature: tokio::sync::Mutex>>, - recv_burn_on_refund_instruction: - tokio::sync::Mutex>>, + recv_burn_on_refund_instruction: tokio::sync::Mutex>>, #[allow(clippy::type_complexity)] transfer_proof_sender: tokio::sync::Mutex< Option< @@ -1000,7 +998,7 @@ async fn capture_wallet_snapshot( .estimate_fee(bitcoin::TxPunish::weight(), Some(transfer_amount)) .await?; let refund_burn_fee = bitcoin_wallet - .estimate_fee(bitcoin::TxRefundBurn::weight(), Some(transfer_amount)) + .estimate_fee(bitcoin::TxWithhold::weight(), Some(transfer_amount)) .await?; Ok(WalletSnapshot::new( diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 5ffefa348f..b1173a9df3 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -17,7 +17,7 @@ use anyhow::{Context as AnyContext, Result, anyhow}; use std::sync::Arc; use std::time::Duration; use swap_core::bitcoin::{ - ExpiredTimelocks, TxCancel, TxFinalAmnesty, TxFullRefund, TxPartialRefund, TxRefundAmnesty, + ExpiredTimelocks, TxCancel, TxMercy, TxFullRefund, TxPartialRefund, TxReclaim, }; use swap_core::monero::BlockHeight; use swap_env::env; @@ -130,10 +130,10 @@ async fn next_state( .estimate_fee(TxPartialRefund::weight(), Some(btc_amount)) .await?; let tx_refund_amnesty_fee = bitcoin_wallet - .estimate_fee(TxRefundAmnesty::weight(), Some(btc_amount)) + .estimate_fee(TxReclaim::weight(), Some(btc_amount)) .await?; let tx_final_amnesty_fee = bitcoin_wallet - .estimate_fee(TxFinalAmnesty::weight(), Some(btc_amount)) + .estimate_fee(TxMercy::weight(), Some(btc_amount)) .await?; // Emit an event to tauri that we are negotiating with the maker to lock the Bitcoin From 97dbf4c2ad91af7ecd0642719a0ee0c266bb809f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 26 Jan 2026 12:46:32 +0100 Subject: [PATCH 102/146] asb(config)+protocol(quote): anti_spam_deposit_ratio instead of taker_guaranteed_refund --- swap-core/src/bitcoin/partial_refund.rs | 20 +++++++++---------- swap-core/src/bitcoin/reclaim.rs | 8 ++------ swap-core/src/bitcoin/withhold.rs | 8 ++++---- swap-env/src/config.rs | 20 +++++++++++-------- swap-p2p/src/protocols/quote.rs | 9 +++++---- swap/src/asb/event_loop.rs | 14 ++++++------- swap/tests/partial_refund_alice_burns.rs | 4 ++-- ...artial_refund_alice_burns_after_command.rs | 4 ++-- ...rtial_refund_alice_grants_final_amnesty.rs | 4 ++-- .../partial_refund_bob_claims_amnesty.rs | 4 ++-- 10 files changed, 47 insertions(+), 48 deletions(-) diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 40406ee776..78a184b987 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -76,15 +76,15 @@ impl TxPartialRefund { self.digest } - pub fn amnesty_amount(&self) -> Amount { + pub fn anti_spam_deposit(&self) -> Amount { self.inner.output[1].value } - pub fn amnesty_outpoint(&self) -> ::bitcoin::OutPoint { + pub fn ani_spam_deposit_outpoint(&self) -> ::bitcoin::OutPoint { ::bitcoin::OutPoint::new(self.txid(), 1) } - pub fn build_amnesty_spend_transaction( + pub fn build_reclaim_transaction( &self, refund_address: &Address, spending_fee: Amount, @@ -96,7 +96,7 @@ impl TxPartialRefund { }; let tx_in = TxIn { - previous_output: self.amnesty_outpoint(), + previous_output: self.ani_spam_deposit_outpoint(), script_sig: Default::default(), sequence: Sequence(remaining_refund_timelock.0), witness: Default::default(), @@ -104,7 +104,7 @@ impl TxPartialRefund { let tx_out = TxOut { value: self - .amnesty_amount() + .anti_spam_deposit() .checked_sub(spending_fee) .context("btc amnesty amount is less than spending fee")?, script_pubkey: refund_address.script_pubkey(), @@ -121,7 +121,7 @@ impl TxPartialRefund { /// Build a transaction that spends the amnesty output to a new 2-of-2 multisig (burn output). /// This is used by TxRefundBurn to "burn" the amnesty by moving it to another multisig. /// Unlike `build_amnesty_spend_transaction`, this has no timelock. - pub fn build_burn_spend_transaction( + pub fn build_withhold_transaction( &self, burn_output_descriptor: &Descriptor<::bitcoin::PublicKey>, spending_fee: Amount, @@ -133,21 +133,21 @@ impl TxPartialRefund { // TODO: Handle case where fee >= amnesty_amount more gracefully assert!( - self.amnesty_amount() > spending_fee, + self.anti_spam_deposit() > spending_fee, "Burn spend fee ({}) must be less than amnesty amount ({})", spending_fee, - self.amnesty_amount() + self.anti_spam_deposit() ); let tx_in = TxIn { - previous_output: self.amnesty_outpoint(), + previous_output: self.ani_spam_deposit_outpoint(), script_sig: Default::default(), sequence: Sequence(0xFFFF_FFFF), // No timelock witness: Default::default(), }; let tx_out = TxOut { - value: self.amnesty_amount() - spending_fee, + value: self.anti_spam_deposit() - spending_fee, script_pubkey: burn_output_descriptor.script_pubkey(), }; diff --git a/swap-core/src/bitcoin/reclaim.rs b/swap-core/src/bitcoin/reclaim.rs index 79ce2425a3..66228ad8f6 100644 --- a/swap-core/src/bitcoin/reclaim.rs +++ b/swap-core/src/bitcoin/reclaim.rs @@ -27,11 +27,7 @@ impl TxReclaim { remaining_refund_timelock: RemainingRefundTimelock, ) -> Result { let tx_refund_amnesty = tx_refund - .build_amnesty_spend_transaction( - refund_address, - spending_fee, - remaining_refund_timelock, - ) + .build_reclaim_transaction(refund_address, spending_fee, remaining_refund_timelock) .context("Couldn't build tx refund amnesty")?; let digest = SighashCache::new(&tx_refund_amnesty) @@ -41,7 +37,7 @@ impl TxReclaim { .amnesty_output_descriptor .script_code() .expect("scriptcode"), - tx_refund.amnesty_amount(), + tx_refund.anti_spam_deposit(), EcdsaSighashType::All, ) .expect("sighash"); diff --git a/swap-core/src/bitcoin/withhold.rs b/swap-core/src/bitcoin/withhold.rs index 9a75fc38c8..cb26c185d9 100644 --- a/swap-core/src/bitcoin/withhold.rs +++ b/swap-core/src/bitcoin/withhold.rs @@ -39,16 +39,16 @@ impl TxWithhold { // TODO: Handle case where fee >= amnesty_amount more gracefully // For now, assert to catch this during development assert!( - tx_partial_refund.amnesty_amount() > spending_fee, + tx_partial_refund.anti_spam_deposit() > spending_fee, "TxRefundBurn fee ({}) must be less than amnesty amount ({})", spending_fee, - tx_partial_refund.amnesty_amount() + tx_partial_refund.anti_spam_deposit() ); let burn_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; let tx_refund_burn = - tx_partial_refund.build_burn_spend_transaction(&burn_output_descriptor, spending_fee); + tx_partial_refund.build_withhold_transaction(&burn_output_descriptor, spending_fee); let digest = SighashCache::new(&tx_refund_burn) .p2wsh_signature_hash( @@ -57,7 +57,7 @@ impl TxWithhold { .amnesty_output_descriptor .script_code() .expect("scriptcode"), - tx_partial_refund.amnesty_amount(), + tx_partial_refund.anti_spam_deposit(), EcdsaSighashType::All, ) .expect("sighash"); diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index 59dac31de5..f8f73321df 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -124,20 +124,20 @@ pub struct RefundPolicy { /// Takers will only receive this percentage of their Bitcoin back by default. /// Maker can still issue "amnesty" to refund the rest. /// This protects the maker against griefing attacks. - #[serde(default = "default_taker_refund_ratio")] - pub taker_refund_ratio: Decimal, + #[serde(default = "default_anti_spam_deposit_ratio")] + pub anti_spam_deposit_ratio: Decimal, /// If true, Alice will publish TxRefundBurn after refunding her XMR, /// denying Bob access to the amnesty output. Alice can later grant /// final amnesty to return the funds to Bob. - #[serde(default)] - pub burn_on_refund: bool, + #[serde(default = "default_always_withhold_deposit")] + pub always_withhold_deposit: bool, } impl Default for RefundPolicy { fn default() -> Self { Self { - taker_refund_ratio: default_taker_refund_ratio(), - burn_on_refund: false, + anti_spam_deposit_ratio: default_anti_spam_deposit_ratio(), + always_withhold_deposit: false, } } } @@ -158,8 +158,12 @@ fn default_developer_tip() -> Decimal { Decimal::ZERO } -fn default_taker_refund_ratio() -> Decimal { - Decimal::ONE +fn default_anti_spam_deposit_ratio() -> Decimal { + Decimal::ZERO +} + +fn default_always_withhold_deposit() -> bool { + false } impl Config { diff --git a/swap-p2p/src/protocols/quote.rs b/swap-p2p/src/protocols/quote.rs index bcd9fef6b9..430a6652d7 100644 --- a/swap-p2p/src/protocols/quote.rs +++ b/swap-p2p/src/protocols/quote.rs @@ -24,19 +24,20 @@ pub enum RefundPolicyWire { /// Taker receives a partial refund; the remainder goes to an amnesty output /// that the maker may or may not release later. PartialRefund { - /// Ratio (0.0-1.0) of Bitcoin the taker receives immediately. + /// Ratio (0.0-1.0) of Bitcoin that goes into the anti-spam deposit + /// and may be withheld by the maker. #[typeshare(serialized_as = "number")] - taker_refund_ratio: Decimal, + anti_spam_deposit_ratio: Decimal, }, } impl From for RefundPolicyWire { fn from(policy: RefundPolicy) -> Self { - if policy.taker_refund_ratio == Decimal::ONE { + if policy.anti_spam_deposit_ratio == Decimal::ONE { RefundPolicyWire::FullRefund } else { RefundPolicyWire::PartialRefund { - taker_refund_ratio: policy.taker_refund_ratio, + anti_spam_deposit_ratio: policy.anti_spam_deposit_ratio, } } } diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index efb70e6d36..05e2430b1a 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -944,16 +944,14 @@ fn apply_bitcoin_amnesty_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, ) -> Result<(bitcoin::Amount, bool)> { - let should_burn_on_refund = refund_policy.burn_on_refund; + let should_always_withhold = refund_policy.always_withhold_deposit; - // When ratio is 1.0, no amnesty - use full refund path - if refund_policy.taker_refund_ratio == Decimal::ONE { - return Ok((bitcoin::Amount::ZERO, should_burn_on_refund)); + // When ratio is 0.0, no amnesty - use full refund path for fewer fees + if refund_policy.anti_spam_deposit_ratio == Decimal::ZERO { + return Ok((bitcoin::Amount::ZERO, should_always_withhold)); } - let btc_amnesty_ratio = Decimal::ONE - .checked_sub(refund_policy.taker_refund_ratio) - .context("can't have refund ration > 1")?; + let btc_amnesty_ratio = refund_policy.anti_spam_deposit_ratio; let amount_sats = swap_amount.to_sat(); let amount_decimal = @@ -969,7 +967,7 @@ fn apply_bitcoin_amnesty_policy( Ok(( bitcoin::Amount::from_sat(btc_amnesty_sats), - should_burn_on_refund, + should_always_withhold, )) } diff --git a/swap/tests/partial_refund_alice_burns.rs b/swap/tests/partial_refund_alice_burns.rs index d32651c43d..344089794b 100644 --- a/swap/tests/partial_refund_alice_burns.rs +++ b/swap/tests/partial_refund_alice_burns.rs @@ -19,8 +19,8 @@ async fn given_partial_refund_alice_burns_the_amnesty() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty // Alice burns the amnesty let refund_policy = Some(RefundPolicy { - taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% - burn_on_refund: true, + anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + always_withhold_deposit: true, }); harness::setup_test( diff --git a/swap/tests/partial_refund_alice_burns_after_command.rs b/swap/tests/partial_refund_alice_burns_after_command.rs index a02629474e..45d37fa7a4 100644 --- a/swap/tests/partial_refund_alice_burns_after_command.rs +++ b/swap/tests/partial_refund_alice_burns_after_command.rs @@ -20,8 +20,8 @@ async fn given_partial_refund_alice_burns_after_command() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty // Alice does NOT burn by default - burn_on_refund is false let refund_policy = Some(RefundPolicy { - taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% - burn_on_refund: false, // Do not burn by default + anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + always_withhold_deposit: false, // Do not burn by default }); harness::setup_test( diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index 080f37bfca..2dede6bbbe 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -23,8 +23,8 @@ async fn given_partial_refund_alice_grants_final_amnesty() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty // Alice burns the amnesty, then grants final amnesty let refund_policy = Some(RefundPolicy { - taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% - burn_on_refund: true, + anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + always_withhold_deposit: true, }); harness::setup_test( diff --git a/swap/tests/partial_refund_bob_claims_amnesty.rs b/swap/tests/partial_refund_bob_claims_amnesty.rs index a37eb4afae..9ccd078e7a 100644 --- a/swap/tests/partial_refund_bob_claims_amnesty.rs +++ b/swap/tests/partial_refund_bob_claims_amnesty.rs @@ -15,8 +15,8 @@ async fn given_partial_refund_bob_claims_amnesty_after_timelock() { // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty // Alice does NOT burn - Bob can claim amnesty after timelock let refund_policy = Some(RefundPolicy { - taker_refund_ratio: Decimal::new(95, 2), // 0.95 = 95% - burn_on_refund: false, + anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + always_withhold_deposit: false, }); harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { From f9d67494238809a7489be99fc9e5c8ab619dcf14 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 2 Feb 2026 15:55:53 +0100 Subject: [PATCH 103/146] update terminology accross state machines, commands, etc --- swap-controller-api/src/lib.rs | 7 +-- swap-controller/src/cli.rs | 8 +-- swap-controller/src/main.rs | 17 ++++--- swap-db/src/alice.rs | 50 +++++++++---------- swap-db/src/bob.rs | 12 ++--- swap-machine/src/alice/mod.rs | 28 +++++------ swap/src/asb/event_loop.rs | 4 +- swap/src/asb/recovery/cancel.rs | 10 ++-- swap/src/asb/recovery/grant_final_amnesty.rs | 4 +- swap/src/asb/recovery/punish.rs | 10 ++-- swap/src/asb/recovery/redeem.rs | 10 ++-- swap/src/asb/recovery/refund.rs | 10 ++-- swap/src/asb/recovery/safely_abort.rs | 10 ++-- swap/src/asb/rpc/server.rs | 12 +++-- swap/src/protocol/alice/swap.rs | 22 ++++---- swap/tests/harness/mod.rs | 8 +-- ...artial_refund_alice_burns_after_command.rs | 2 +- ...rtial_refund_alice_grants_final_amnesty.rs | 6 +-- 18 files changed, 116 insertions(+), 114 deletions(-) diff --git a/swap-controller-api/src/lib.rs b/swap-controller-api/src/lib.rs index a22103f773..339c70d6c5 100644 --- a/swap-controller-api/src/lib.rs +++ b/swap-controller-api/src/lib.rs @@ -120,7 +120,8 @@ pub trait AsbApi { #[method(name = "registration_status")] async fn registration_status(&self) -> Result; #[method(name = "set_burn_on_refund")] - async fn set_burn_on_refund(&self, swap_id: Uuid, burn: bool) -> Result<(), ErrorObjectOwned>; - #[method(name = "grant_final_amnesty")] - async fn grant_final_amnesty(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned>; + async fn set_withhold_deposit(&self, swap_id: Uuid, burn: bool) + -> Result<(), ErrorObjectOwned>; + #[method(name = "grant_mercy")] + async fn grant_mercy(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned>; } diff --git a/swap-controller/src/cli.rs b/swap-controller/src/cli.rs index 384502336e..1e458d7df5 100644 --- a/swap-controller/src/cli.rs +++ b/swap-controller/src/cli.rs @@ -39,15 +39,15 @@ pub enum Cmd { /// Show rendezvous registration status RegistrationStatus, /// Set whether to burn Bitcoin on refund for a swap - SetBurnOnRefund { + SetWithholdDeposit { /// The swap ID swap_id: Uuid, /// Whether to burn the Bitcoin (true or false) #[arg(action = clap::ArgAction::Set)] - burn: bool, + withhold: bool, }, - /// Grant final amnesty for a swap in BtcRefundBurnConfirmed state - GrantFinalAmnesty { + /// Grant mercy (release the anti-spam deposit) for a swap in BtcWithheld state + GrantMercy { /// The swap ID swap_id: Uuid, }, diff --git a/swap-controller/src/main.rs b/swap-controller/src/main.rs index d68e2f58c5..3aefe3e195 100644 --- a/swap-controller/src/main.rs +++ b/swap-controller/src/main.rs @@ -131,17 +131,20 @@ async fn dispatch(cmd: Cmd, client: impl AsbApiClient) -> anyhow::Result<()> { } } } - Cmd::SetBurnOnRefund { swap_id, burn } => { - client.set_burn_on_refund(swap_id, burn).await?; + Cmd::SetWithholdDeposit { + swap_id, + withhold: burn, + } => { + client.set_withhold_deposit(swap_id, burn).await?; if burn { - println!("Burn on refund enabled for swap {swap_id}"); + println!("Withholding deposit should the taker refund for swap {swap_id}"); } else { - println!("Burn on refund disabled for swap {swap_id}"); + println!("Not withholding deposit should the taker refund for swap {swap_id}"); } } - Cmd::GrantFinalAmnesty { swap_id } => { - client.grant_final_amnesty(swap_id).await?; - println!("Final amnesty granted for swap {swap_id}"); + Cmd::GrantMercy { swap_id } => { + client.grant_mercy(swap_id).await?; + println!("Mercy granted for swap {swap_id}"); } } Ok(()) diff --git a/swap-db/src/alice.rs b/swap-db/src/alice.rs index 7462068f0a..8d4183ba71 100644 --- a/swap-db/src/alice.rs +++ b/swap-db/src/alice.rs @@ -92,6 +92,12 @@ pub enum Alice { BtcWithholdPublished { state3: alice::State3, }, + BtcMercyGranted { + state3: alice::State3, + }, + BtcMercyPublished { + state3: alice::State3, + }, Done(AliceEndState), } @@ -113,12 +119,6 @@ pub enum AliceEndState { BtcWithheld { state3: alice::State3, }, - BtcMercyGranted { - state3: alice::State3, - }, - BtcMercyPublished { - state3: alice::State3, - }, BtcMercyConfirmed { state3: alice::State3, }, @@ -238,19 +238,17 @@ impl From for Alice { AliceState::XmrRefunded { state3 } => Alice::Done(AliceEndState::XmrRefunded { state3: state3.map(|s| s.as_ref().clone()), }), - AliceState::BtcRefundBurnPublished { state3 } => { + AliceState::BtcWithholdPublished { state3 } => { Alice::BtcWithholdPublished { state3: *state3 } } - AliceState::BtcRefundBurnConfirmed { state3 } => { + AliceState::BtcWithholdConfirmed { state3 } => { Alice::Done(AliceEndState::BtcWithheld { state3: *state3 }) } - AliceState::BtcFinalAmnestyGranted { state3 } => { - Alice::Done(AliceEndState::BtcMercyGranted { state3: *state3 }) - } - AliceState::BtcRefundFinalAmnestyPublished { state3 } => { - Alice::Done(AliceEndState::BtcMercyPublished { state3: *state3 }) + AliceState::BtcMercyGranted { state3 } => Alice::BtcMercyGranted { state3: *state3 }, + AliceState::BtcMercyPublished { state3 } => { + Alice::BtcMercyPublished { state3: *state3 } } - AliceState::BtcRefundFinalAmnestyConfirmed { state3 } => { + AliceState::BtcMercyConfirmed { state3 } => { Alice::Done(AliceEndState::BtcMercyConfirmed { state3: *state3 }) } AliceState::WaitingForCancelTimelockExpiration { @@ -412,7 +410,13 @@ impl From for AliceState { spend_key, state3: Box::new(state3), }, - Alice::BtcWithholdPublished { state3 } => AliceState::BtcRefundBurnPublished { + Alice::BtcWithholdPublished { state3 } => AliceState::BtcWithholdPublished { + state3: Box::new(state3), + }, + Alice::BtcMercyGranted { state3 } => AliceState::BtcMercyGranted { + state3: Box::new(state3), + }, + Alice::BtcMercyPublished { state3 } => AliceState::BtcMercyPublished { state3: Box::new(state3), }, Alice::Done(end_state) => match end_state { @@ -431,22 +435,12 @@ impl From for AliceState { AliceEndState::BtcEarlyRefunded { state3 } => { AliceState::BtcEarlyRefunded(Box::new(state3)) } - AliceEndState::BtcWithheld { state3 } => AliceState::BtcRefundBurnConfirmed { + AliceEndState::BtcWithheld { state3 } => AliceState::BtcWithholdConfirmed { state3: Box::new(state3), }, - AliceEndState::BtcMercyGranted { state3 } => AliceState::BtcFinalAmnestyGranted { + AliceEndState::BtcMercyConfirmed { state3 } => AliceState::BtcMercyConfirmed { state3: Box::new(state3), }, - AliceEndState::BtcMercyPublished { state3 } => { - AliceState::BtcRefundFinalAmnestyPublished { - state3: Box::new(state3), - } - } - AliceEndState::BtcMercyConfirmed { state3 } => { - AliceState::BtcRefundFinalAmnestyConfirmed { - state3: Box::new(state3), - } - } }, } } @@ -482,6 +476,8 @@ impl fmt::Display for Alice { Alice::BtcWithholdPublished { .. } => { f.write_str("Bitcoin withhold transaction published") } + Alice::BtcMercyGranted { .. } => f.write_str("Bitcoin mercy initiated"), + Alice::BtcMercyPublished { .. } => f.write_str("Bitcoin mercy published"), Alice::Done(end_state) => write!(f, "Done: {}", end_state), } } diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 1c382afb87..91e77a52a1 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -275,14 +275,14 @@ impl fmt::Display for Bob { Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"), Bob::BtcPunished { .. } => f.write_str("Bitcoin punished"), Bob::BtcPartiallyRefunded { .. } => f.write_str("Bitcoin partially refunded"), - Bob::BtcReclaimPublished { .. } => f.write_str("Bitcoin amnesty published"), + Bob::BtcReclaimPublished { .. } => f.write_str("Bitcoin reclaim transaction published"), Bob::WaitingForReclaimTimelockExpiration { .. } => { - f.write_str("Waiting for remaining refund timelock to expire") + f.write_str("Waiting for reclaim timelock to expire") } - Bob::ReclaimTimelockExpired { .. } => f.write_str("Remaining refund timelock expired"), - Bob::BtcWithholdPublished { .. } => f.write_str("Bitcoin refund burn published"), - Bob::BtcWithheld { .. } => f.write_str("Bitcoin refund burnt"), - Bob::BtcMercyPublished { .. } => f.write_str("Bitcoin final amnesty published"), + Bob::ReclaimTimelockExpired { .. } => f.write_str("Reclaim timelock expired"), + Bob::BtcWithholdPublished { .. } => f.write_str("Bitcoin withhold published"), + Bob::BtcWithheld { .. } => f.write_str("Bitcoin withheld"), + Bob::BtcMercyPublished { .. } => f.write_str("Bitcoin mercy published"), } } } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 2ba8e65fd0..c83de4eb7a 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -90,21 +90,21 @@ pub enum AliceState { XmrRefunded { state3: Option>, }, - BtcRefundBurnPublished { + BtcWithholdPublished { state3: Box, }, - BtcRefundBurnConfirmed { + BtcWithholdConfirmed { state3: Box, }, /// Operator has decided to grant final amnesty to Bob. /// This state will publish TxFinalAmnesty and transition to BtcRefundFinalAmnestyPublished. - BtcFinalAmnestyGranted { + BtcMercyGranted { state3: Box, }, - BtcRefundFinalAmnestyPublished { + BtcMercyPublished { state3: Box, }, - BtcRefundFinalAmnestyConfirmed { + BtcMercyConfirmed { state3: Box, }, WaitingForCancelTimelockExpiration { @@ -140,8 +140,8 @@ pub fn is_complete(state: &AliceState) -> bool { | AliceState::BtcPunished { .. } | AliceState::SafelyAborted | AliceState::BtcEarlyRefunded(_) - | AliceState::BtcRefundBurnConfirmed { .. } - | AliceState::BtcRefundFinalAmnestyConfirmed { .. } => true, + | AliceState::BtcWithholdConfirmed { .. } + | AliceState::BtcMercyConfirmed { .. } => true, _ => false, } } @@ -170,14 +170,14 @@ impl fmt::Display for AliceState { AliceState::SafelyAborted => write!(f, "safely aborted"), AliceState::BtcPunishable { .. } => write!(f, "btc is punishable"), AliceState::XmrRefunded { .. } => write!(f, "xmr is refunded"), - AliceState::BtcRefundBurnPublished { .. } => write!(f, "btc refund burn published"), - AliceState::BtcRefundBurnConfirmed { .. } => write!(f, "btc refund burn confirmed"), - AliceState::BtcFinalAmnestyGranted { .. } => write!(f, "btc final amnesty granted"), - AliceState::BtcRefundFinalAmnestyPublished { .. } => { - write!(f, "btc final amnesty published") + AliceState::BtcWithholdPublished { .. } => write!(f, "btc withhold published"), + AliceState::BtcWithholdConfirmed { .. } => write!(f, "btc withheld"), + AliceState::BtcMercyGranted { .. } => write!(f, "btc mercy granted"), + AliceState::BtcMercyPublished { .. } => { + write!(f, "btc mercy published") } - AliceState::BtcRefundFinalAmnestyConfirmed { .. } => { - write!(f, "btc final amnesty confirmed") + AliceState::BtcMercyConfirmed { .. } => { + write!(f, "btc mercy confirmed") } AliceState::WaitingForCancelTimelockExpiration { .. } => { write!(f, "waiting for cancel timelock expiration") diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 05e2430b1a..162568d2a1 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -1085,7 +1085,7 @@ mod service { /// /// This can be called multiple times to update the decision before /// the swap state machine polls for it. - pub async fn set_burn_on_refund(&self, swap_id: Uuid, burn: bool) -> anyhow::Result<()> { + pub async fn set_withhold_deposit(&self, swap_id: Uuid, burn: bool) -> anyhow::Result<()> { let (tx, rx) = oneshot::channel(); self.sender .send(EventLoopRequest::SetBurnOnRefund { @@ -1102,7 +1102,7 @@ mod service { /// /// This transitions the swap to BtcFinalAmnestyGranted and resumes /// the swap state machine to publish the final amnesty transaction. - pub async fn grant_final_amnesty(&self, swap_id: Uuid) -> anyhow::Result<()> { + pub async fn grant_mercy(&self, swap_id: Uuid) -> anyhow::Result<()> { let (tx, rx) = oneshot::channel(); self.sender .send(EventLoopRequest::GrantFinalAmnesty { diff --git a/swap/src/asb/recovery/cancel.rs b/swap/src/asb/recovery/cancel.rs index 9cc8a29cb4..f99118ad5b 100644 --- a/swap/src/asb/recovery/cancel.rs +++ b/swap/src/asb/recovery/cancel.rs @@ -42,11 +42,11 @@ pub async fn cancel( // Alice already in final state | AliceState::BtcRedeemed | AliceState::XmrRefunded { .. } - | AliceState::BtcRefundBurnPublished { .. } - | AliceState::BtcRefundBurnConfirmed { .. } - | AliceState::BtcFinalAmnestyGranted { .. } - | AliceState::BtcRefundFinalAmnestyPublished { .. } - | AliceState::BtcRefundFinalAmnestyConfirmed { .. } + | AliceState::BtcWithholdPublished { .. } + | AliceState::BtcWithholdConfirmed { .. } + | AliceState::BtcMercyGranted { .. } + | AliceState::BtcMercyPublished { .. } + | AliceState::BtcMercyConfirmed { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) | AliceState::BtcPunished { .. } diff --git a/swap/src/asb/recovery/grant_final_amnesty.rs b/swap/src/asb/recovery/grant_final_amnesty.rs index 5a31cdbace..4f5b898607 100644 --- a/swap/src/asb/recovery/grant_final_amnesty.rs +++ b/swap/src/asb/recovery/grant_final_amnesty.rs @@ -12,8 +12,8 @@ pub async fn grant_final_amnesty( let state = db.get_state(swap_id).await?.try_into()?; match state { - AliceState::BtcRefundBurnConfirmed { state3 } => { - let new_state = AliceState::BtcFinalAmnestyGranted { state3 }; + AliceState::BtcWithholdConfirmed { state3 } => { + let new_state = AliceState::BtcMercyGranted { state3 }; db.insert_latest_state(swap_id, new_state.clone().into()) .await?; diff --git a/swap/src/asb/recovery/punish.rs b/swap/src/asb/recovery/punish.rs index d585564d1d..07657ce96a 100644 --- a/swap/src/asb/recovery/punish.rs +++ b/swap/src/asb/recovery/punish.rs @@ -43,11 +43,11 @@ pub async fn punish( | AliceState::BtcLocked { .. } | AliceState::BtcRedeemed { .. } | AliceState::XmrRefunded { .. } - | AliceState::BtcRefundBurnPublished { .. } - | AliceState::BtcRefundBurnConfirmed { .. } - | AliceState::BtcFinalAmnestyGranted { .. } - | AliceState::BtcRefundFinalAmnestyPublished { .. } - | AliceState::BtcRefundFinalAmnestyConfirmed { .. } + | AliceState::BtcWithholdPublished { .. } + | AliceState::BtcWithholdConfirmed { .. } + | AliceState::BtcMercyGranted { .. } + | AliceState::BtcMercyPublished { .. } + | AliceState::BtcMercyConfirmed { .. } | AliceState::BtcPunished { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) diff --git a/swap/src/asb/recovery/redeem.rs b/swap/src/asb/recovery/redeem.rs index 48dcbf00ef..406bb6eb91 100644 --- a/swap/src/asb/recovery/redeem.rs +++ b/swap/src/asb/recovery/redeem.rs @@ -93,11 +93,11 @@ pub async fn redeem( | AliceState::BtcPunishable { .. } | AliceState::BtcRedeemed | AliceState::XmrRefunded { .. } - | AliceState::BtcRefundBurnPublished { .. } - | AliceState::BtcRefundBurnConfirmed { .. } - | AliceState::BtcFinalAmnestyGranted { .. } - | AliceState::BtcRefundFinalAmnestyPublished { .. } - | AliceState::BtcRefundFinalAmnestyConfirmed { .. } + | AliceState::BtcWithholdPublished { .. } + | AliceState::BtcWithholdConfirmed { .. } + | AliceState::BtcMercyGranted { .. } + | AliceState::BtcMercyPublished { .. } + | AliceState::BtcMercyConfirmed { .. } | AliceState::XmrRefundable { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) diff --git a/swap/src/asb/recovery/refund.rs b/swap/src/asb/recovery/refund.rs index 22ba86f6de..1c46c307e2 100644 --- a/swap/src/asb/recovery/refund.rs +++ b/swap/src/asb/recovery/refund.rs @@ -61,11 +61,11 @@ pub async fn refund( AliceState::BtcRedeemTransactionPublished { .. } | AliceState::BtcRedeemed | AliceState::XmrRefunded { .. } - | AliceState::BtcRefundBurnPublished { .. } - | AliceState::BtcRefundBurnConfirmed { .. } - | AliceState::BtcFinalAmnestyGranted { .. } - | AliceState::BtcRefundFinalAmnestyPublished { .. } - | AliceState::BtcRefundFinalAmnestyConfirmed { .. } + | AliceState::BtcWithholdPublished { .. } + | AliceState::BtcWithholdConfirmed { .. } + | AliceState::BtcMercyGranted { .. } + | AliceState::BtcMercyPublished { .. } + | AliceState::BtcMercyConfirmed { .. } | AliceState::BtcEarlyRefundable { .. } | AliceState::BtcEarlyRefunded(_) | AliceState::BtcPunished { .. } diff --git a/swap/src/asb/recovery/safely_abort.rs b/swap/src/asb/recovery/safely_abort.rs index aed7c14d4c..779bf65033 100644 --- a/swap/src/asb/recovery/safely_abort.rs +++ b/swap/src/asb/recovery/safely_abort.rs @@ -34,11 +34,11 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc) -> Result Result<(), ErrorObjectOwned> { + async fn set_withhold_deposit( + &self, + swap_id: Uuid, + burn: bool, + ) -> Result<(), ErrorObjectOwned> { self.event_loop_service - .set_burn_on_refund(swap_id, burn) + .set_withhold_deposit(swap_id, burn) .await .into_json_rpc_result()?; Ok(()) } - async fn grant_final_amnesty(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned> { + async fn grant_mercy(&self, swap_id: Uuid) -> Result<(), ErrorObjectOwned> { self.event_loop_service - .grant_final_amnesty(swap_id) + .grant_mercy(swap_id) .await .into_json_rpc_result()?; diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 5cc834d31c..f38cde10ea 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -802,9 +802,9 @@ where .await .context("Couldn't publish TxRefundBurn")?; - AliceState::BtcRefundBurnPublished { state3 } + AliceState::BtcWithholdPublished { state3 } } - AliceState::BtcRefundBurnPublished { state3 } => { + AliceState::BtcWithholdPublished { state3 } => { let tx_refund_burn = state3 .tx_refund_burn() .context("Can't construct TxRefundBurn even though we published it")?; @@ -816,13 +816,13 @@ where .await .context("Failed to wait for TxRefundBurn to be confirmed")?; - AliceState::BtcRefundBurnConfirmed { state3 } + AliceState::BtcWithholdConfirmed { state3 } } - AliceState::BtcRefundBurnConfirmed { state3 } => { + AliceState::BtcWithholdConfirmed { state3 } => { // Nothing to do here. Final amnesty is triggered manually. - AliceState::BtcRefundBurnConfirmed { state3 } + AliceState::BtcWithholdConfirmed { state3 } } - AliceState::BtcFinalAmnestyGranted { state3 } => { + AliceState::BtcMercyGranted { state3 } => { // Operator has decided to grant final amnesty to Bob let signed_tx = state3 .signed_final_amnesty_transaction() @@ -835,9 +835,9 @@ where tracing::info!("TxFinalAmnesty published successfully"); - AliceState::BtcRefundFinalAmnestyPublished { state3 } + AliceState::BtcMercyPublished { state3 } } - AliceState::BtcRefundFinalAmnestyPublished { state3 } => { + AliceState::BtcMercyPublished { state3 } => { // Wait for TxFinalAmnesty to be confirmed let tx_final_amnesty = state3 .tx_final_amnesty() @@ -852,11 +852,9 @@ where .await .context("Failed to wait for TxFinalAmnesty to be confirmed")?; - AliceState::BtcRefundFinalAmnestyConfirmed { state3 } - } - AliceState::BtcRefundFinalAmnestyConfirmed { state3 } => { - AliceState::BtcRefundFinalAmnestyConfirmed { state3 } + AliceState::BtcMercyConfirmed { state3 } } + AliceState::BtcMercyConfirmed { state3 } => AliceState::BtcMercyConfirmed { state3 }, AliceState::BtcRedeemed => AliceState::BtcRedeemed, AliceState::BtcPunished { state3, diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index c6cac73f5e..27bba95e37 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -855,7 +855,7 @@ impl TestContext { } pub async fn assert_alice_refund_burn_confirmed(&mut self, state: AliceState) { - assert!(matches!(state, AliceState::BtcRefundBurnConfirmed { .. })); + assert!(matches!(state, AliceState::BtcWithholdConfirmed { .. })); // Same as refunded - Alice still has her XMR back assert_eventual_balance( @@ -878,7 +878,7 @@ impl TestContext { pub async fn assert_alice_final_amnesty_confirmed(&mut self, state: AliceState) { assert!(matches!( state, - AliceState::BtcRefundFinalAmnestyConfirmed { .. } + AliceState::BtcMercyConfirmed { .. } )); // Same as refunded - Alice still has her XMR back @@ -1444,11 +1444,11 @@ pub mod alice_run_until { } pub fn is_btc_refund_burn_confirmed(state: &AliceState) -> bool { - matches!(state, AliceState::BtcRefundBurnConfirmed { .. }) + matches!(state, AliceState::BtcWithholdConfirmed { .. }) } pub fn is_btc_final_amnesty_confirmed(state: &AliceState) -> bool { - matches!(state, AliceState::BtcRefundFinalAmnestyConfirmed { .. }) + matches!(state, AliceState::BtcMercyConfirmed { .. }) } } diff --git a/swap/tests/partial_refund_alice_burns_after_command.rs b/swap/tests/partial_refund_alice_burns_after_command.rs index 45d37fa7a4..68c876a14e 100644 --- a/swap/tests/partial_refund_alice_burns_after_command.rs +++ b/swap/tests/partial_refund_alice_burns_after_command.rs @@ -63,7 +63,7 @@ async fn given_partial_refund_alice_burns_after_command() { // Send RPC command to Alice to burn this swap's amnesty // Must be done AFTER restart (so EventLoopHandle exists) but BEFORE running the swap ctx.alice_rpc_client - .set_burn_on_refund(alice_swap_id, true) + .set_withhold_deposit(alice_swap_id, true) .await .expect("Failed to send burn command to Alice"); diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index 2dede6bbbe..bc95767f8f 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -71,7 +71,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { let alice_state = alice_swap.await??; assert!(matches!( alice_state, - AliceState::BtcRefundBurnConfirmed { .. } + AliceState::BtcWithholdConfirmed { .. } )); let bob_state = bob_state.await??; @@ -79,7 +79,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { // Simulate alice's controller sending the final amnesty command via `controller` cli ctx.restart_alice().await; - ctx.alice_rpc_client.grant_final_amnesty(swap_id).await?; + ctx.alice_rpc_client.grant_mercy(swap_id).await?; let alice_swap = ctx.alice_next_swap().await; let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); @@ -99,7 +99,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { assert!( matches!( alice_state, - AliceState::BtcRefundFinalAmnestyConfirmed { .. } + AliceState::BtcMercyConfirmed { .. } ), "Actual state: {alice_state}" ); From 97a332dbb518a4f81c73ac20a922bf4351969c9f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Feb 2026 14:11:11 +0100 Subject: [PATCH 104/146] try to fix stackoverflow when selecting offer --- .cargo/config.toml | 3 +++ .helix/ignore | 2 ++ Cargo.toml | 2 ++ bitcoin-wallet/src/wallet.rs | 2 +- justfile | 4 ++-- swap/src/cli/api/tauri_bindings.rs | 16 +++++++++++----- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index e27705d7a3..9b0737155b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,6 +10,9 @@ linker = "arm-linux-gnueabihf-gcc" [target.'cfg(all(windows, target_env = "msvc"))'] rustflags = ["-C", "link-arg=/STACK:8388608"] +[target.'cfg(macos)'] +rustflags = ["-C", "link-arg=-Wl,stack_size,41943040"] + # For the GNU/MinGW tool-chain [target.'cfg(all(windows, target_env = "gnu"))'] linker = "x86_64-w64-mingw32-g++" # Use g++ driver so -lstdc++ gets pulled in automatically diff --git a/.helix/ignore b/.helix/ignore index 47f73afa1a..a53623a692 100644 --- a/.helix/ignore +++ b/.helix/ignore @@ -1,2 +1,4 @@ src-tauri/gen/ +monero-sys/monero/ +monero-sys/monero-depends/ diff --git a/Cargo.toml b/Cargo.toml index e47eacde4a..8cb6fb6f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,6 +123,8 @@ crunchy = { git = "https://github.com/eira-fransham/crunchy", rev = "ba7b86cea6b [workspace.lints] rust.unused_crate_dependencies = "warn" +# prevents accidental infinite recursion when implementing a trait method by calling a method with the same name +rust.unconditional_recusion = "deny" [profile.release] codegen-units = 1 diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index fb317d935f..fb0cc7eb68 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -2237,7 +2237,7 @@ impl EstimateFeeRate for Client { } async fn min_relay_fee(&self) -> Result { - self.min_relay_fee().await + Client::min_relay_fee(self).await } } diff --git a/justfile b/justfile index e9f7279a79..a561eee619 100644 --- a/justfile +++ b/justfile @@ -30,10 +30,10 @@ test-ffi-address: # Start the Tauri app tauri: - cd src-tauri && cargo tauri dev --no-watch -- -vv -- --testnet + cd src-tauri && RUST_MIN_STACK=41943040 RUST_BACKTRACE=1 cargo tauri dev --no-watch -- -vv -- --testnet tauri-mainnet: - cd src-tauri && cargo tauri dev --no-watch -- -vv + cd src-tauri && RUST_BACKTRACE=1 cargo tauri dev --no-watch -- -vv # Install the GUI dependencies gui_install: diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index d1b227baf8..64f312f7b2 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -481,10 +481,13 @@ impl bitcoin_wallet::BitcoinTauriBackgroundTask for TauriBackgroundProgressHandle { fn update(&self, consumed: u64, total: u64) { - self.update(TauriBitcoinFullScanProgress::Known { - current_index: consumed, - assumed_total: total, - }); + TauriBackgroundProgressHandle::update( + self, + TauriBitcoinFullScanProgress::Known { + current_index: consumed, + assumed_total: total, + }, + ); } fn finish(&self) { @@ -496,7 +499,10 @@ impl bitcoin_wallet::BitcoinTauriBackgroundTask for TauriBackgroundProgressHandle { fn update(&self, consumed: u64, total: u64) { - self.update(TauriBitcoinSyncProgress::Known { consumed, total }); + TauriBackgroundProgressHandle::update( + self, + TauriBitcoinSyncProgress::Known { consumed, total }, + ); } fn finish(&self) { From deeb8ff7871cb37ed489ff396a6e68e93d81b0a6 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 15:05:55 +0100 Subject: [PATCH 105/146] fix: electrum pool bug preventing btc tx publishing In get_script_history we treated _any_ error returned by any of the nodes as a total error if the script history returned by the other nodes is empty. This specifically causes the publishing of tx lock to fail/be falsely recognized as failed when at least one of the nodes is unreachable or errors for some other reason. We now accept the result if at least one of the node returns a script history. --- bitcoin-wallet/Cargo.toml | 2 +- bitcoin-wallet/src/wallet.rs | 16 +++++++++------- swap/src/cli/api/request.rs | 19 +++++++++++++------ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/bitcoin-wallet/Cargo.toml b/bitcoin-wallet/Cargo.toml index dd4f62af4a..430dc56e6b 100644 --- a/bitcoin-wallet/Cargo.toml +++ b/bitcoin-wallet/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bitcoin-wallet" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] anyhow = { workspace = true } diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index fb0cc7eb68..7776a140ab 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -1773,11 +1773,15 @@ impl Client { // Collect all successful history entries from all servers. let mut all_history_items: Vec = Vec::new(); + let mut any_success = false; let mut first_error = None; for result in results { match result { - Ok(history) => all_history_items.extend(history), + Ok(history) => { + any_success = true; + all_history_items.extend(history); + } Err(e) => { if first_error.is_none() { first_error = Some(e); @@ -1786,12 +1790,10 @@ impl Client { } } - // If we got no history items at all, and there was an error, propagate it. - // Otherwise, it's valid for a script to have no history. - if all_history_items.is_empty() { - if let Some(err) = first_error { - return Err(err.into()); - } + // If any of the calls succeeded, that is fine. Only if none + // succeeded we return the error. + if !any_success && let Some(err) = first_error { + return Err(err.into()); } // Use a map to find the best (highest confirmation) entry for each transaction. diff --git a/swap/src/cli/api/request.rs b/swap/src/cli/api/request.rs index 1e86fa26b8..a9fca0aba7 100644 --- a/swap/src/cli/api/request.rs +++ b/swap/src/cli/api/request.rs @@ -1796,13 +1796,20 @@ impl CheckElectrumNodeArgs { return Ok(CheckElectrumNodeResponse { available: false }); }; - // Check if the node is available - let res = - bitcoin_wallet::Client::new(&[url.as_str().to_string()], Duration::from_secs(60)).await; + // Check if the node is available by performing a lightweight RPC call. + // This forces a real connection and TLS handshake (for ssl:// URLs). + let mut client = + match bitcoin_wallet::Client::new(&[url.as_str().to_string()], Duration::from_secs(60)) + .await + { + Ok(client) => client, + Err(_) => return Ok(CheckElectrumNodeResponse { available: false }), + }; - Ok(CheckElectrumNodeResponse { - available: res.is_ok(), - }) + // Force a rpc call for blockchain height. + let available = client.update_state(true).await.is_ok(); + + Ok(CheckElectrumNodeResponse { available }) } } From 7fa10dcabbe4b4a1d24eaa8dff8366cc319b9957 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 16:33:54 +0100 Subject: [PATCH 106/146] update transaction weights, field names in mockSwapEvents --- src-gui/src/dev/mockSwapEvents.ts | 2 +- .../deposit_and_choose_offer/MakerOfferItem.tsx | 6 +++--- swap-core/src/bitcoin/mercy.rs | 1 - swap-core/src/bitcoin/partial_refund.rs | 3 +-- swap-core/src/bitcoin/withhold.rs | 3 +-- swap/src/asb/event_loop.rs | 14 +++++++------- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index 071c408bba..56e05ce917 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -61,7 +61,7 @@ const MOCK_QUOTE_PARTIAL_REFUND: BidQuote = { price: 0.0068, min_quantity: 5_000_000, max_quantity: 200_000_000, - refund_policy: { type: "PartialRefund", content: { taker_refund_ratio: 0.98 } }, + refund_policy: { type: "PartialRefund", content: { anti_spam_deposit_ratio: 0.02 } }, }; const MOCK_QUOTE_WITH_ADDRESS_PARTIAL: QuoteWithAddress = { diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index 1cc3e06b36..0a6eff34a4 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -16,7 +16,7 @@ function getRefundPercentage(policy: RefundPolicyWire): number { if (policy.type === "FullRefund") { return 100; } - return policy.content.taker_refund_ratio * 100; + return policy.content.anti_spam_deposit_ratio * 100; } export default function MakerOfferItem({ @@ -192,10 +192,10 @@ export default function MakerOfferItem({ } function EarnestDepositChip(quote: BidQuote) { - const full_refund: boolean = quote.refund_policy.type === "FullRefund" ? true : quote.refund_policy.content.taker_refund_ratio === 1; + const full_refund: boolean = quote.refund_policy.type === "FullRefund" ? true : quote.refund_policy.content.anti_spam_deposit_ratio === 0; // Rounded to 0.001 precision const earnest_deposit_ratio = Math.round( - (quote.refund_policy.type === "FullRefund" ? 0 : 1 - quote.refund_policy.content?.taker_refund_ratio) + (quote.refund_policy.type === "FullRefund" ? 0 : quote.refund_policy.content?.anti_spam_deposit_ratio) * 1000 ) / 1000; const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `If the swap is refunded, the maker may choose to freeze ${earnest_deposit_ratio * 100}% of your refund. This is allows them to protect themselves against griefing.`; diff --git a/swap-core/src/bitcoin/mercy.rs b/swap-core/src/bitcoin/mercy.rs index ce54735944..1630c621cf 100644 --- a/swap-core/src/bitcoin/mercy.rs +++ b/swap-core/src/bitcoin/mercy.rs @@ -129,7 +129,6 @@ impl TxMercy { Ok(tx) } - // TODO: calculate actual weight pub fn weight() -> Weight { Weight::from_wu(548) } diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index 78a184b987..b45861cdd6 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -255,9 +255,8 @@ impl TxPartialRefund { Ok(sig) } - // TODO: calculate actual weight pub fn weight() -> Weight { - Weight::from_wu(548) + Weight::from_wu(720) } } diff --git a/swap-core/src/bitcoin/withhold.rs b/swap-core/src/bitcoin/withhold.rs index cb26c185d9..ddc39be5e3 100644 --- a/swap-core/src/bitcoin/withhold.rs +++ b/swap-core/src/bitcoin/withhold.rs @@ -189,9 +189,8 @@ impl TxWithhold { } } - // TODO: calculate actual weight pub fn weight() -> Weight { - Weight::from_wu(548) + Weight::from_wu(596) } } diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 162568d2a1..b72b8c9848 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -259,7 +259,7 @@ where }; // TODO: propagate error to the swap_setup routine instead of swallowing it - let (btc_amnesty_amount, should_publish_tx_refund_burn )= match apply_bitcoin_amnesty_policy(btc, &self.refund_policy) { + let (btc_amnesty_amount, should_publish_tx_refund_burn )= match apply_anti_spam_policy(btc, &self.refund_policy) { Ok(amount) => amount, Err(error) => { tracing::error!("Swap request will be ignored because we were unable to create wallet snapshot for swap: {:#}", error); @@ -937,10 +937,10 @@ impl EventLoopHandle { } /// For a new swap of `swap_amount`, this function calculates how much -/// Bitcoin should go into the amnesty-lock incase of a refund. -/// Returns ZERO when taker_refund_ratio is 1.0 (100%), indicating full refund. -/// Also returns whether or not to burn the the amnesty output if the taker refunds. -fn apply_bitcoin_amnesty_policy( +/// Bitcoin should go into the anti spam deposit incase of a refund. +/// Returns ZERO when anti_spam_deposit_ratio is 0, indicating immediate and full refund. +/// Also returns whether or not to always withhold the the anti spam deposit output if the taker refunds. +fn apply_anti_spam_policy( swap_amount: bitcoin::Amount, refund_policy: &RefundPolicy, ) -> Result<(bitcoin::Amount, bool)> { @@ -951,14 +951,14 @@ fn apply_bitcoin_amnesty_policy( return Ok((bitcoin::Amount::ZERO, should_always_withhold)); } - let btc_amnesty_ratio = refund_policy.anti_spam_deposit_ratio; + let btc_anti_spam_deposit_ratio = refund_policy.anti_spam_deposit_ratio; let amount_sats = swap_amount.to_sat(); let amount_decimal = Decimal::from_u64(amount_sats).context("Decimal overflowed by Bitcoin sats")?; let btc_amnesty_decimal = amount_decimal - .checked_mul(btc_amnesty_ratio) + .checked_mul(btc_anti_spam_deposit_ratio) .context("Decimal overflow when computing amnesty amount in sats")? .floor(); let btc_amnesty_sats = btc_amnesty_decimal From 0cc15ad734699348bb5c49bc9c600f127ee07fdb Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 17:51:24 +0100 Subject: [PATCH 107/146] alice: sanity check for anti spam deposit ratio alice+bob: sanity check anti spam deposit (greater than fees) --- swap-asb/src/main.rs | 17 +++-------------- swap-env/src/config.rs | 34 ++++++++++++++++++++++++++++++++++ swap-machine/src/alice/mod.rs | 25 +++++++++++++++++++++++++ swap-machine/src/bob/mod.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/swap-asb/src/main.rs b/swap-asb/src/main.rs index 94644153b0..859214a64a 100644 --- a/swap-asb/src/main.rs +++ b/swap-asb/src/main.rs @@ -38,7 +38,8 @@ use swap::protocol::alice::{run, AliceState, TipConfig}; use swap::protocol::{Database, State}; use swap::seed::Seed; use swap_env::config::{ - initial_setup, query_user_for_initial_config, read_config, Config, ConfigNotInitialized, + initial_setup, query_user_for_initial_config, read_config, validate_config, Config, + ConfigNotInitialized, }; use swap_feed; use swap_machine::alice::is_complete; @@ -140,19 +141,7 @@ pub async fn main() -> Result<()> { // Initialize tracing initialize_tracing(json, &config, trace)?; - // Check for conflicting env / config values - if config.monero.network != env_config.monero_network { - bail!(format!( - "Expected monero network in config file to be {:?} but was {:?}", - env_config.monero_network, config.monero.network - )); - } - if config.bitcoin.network != env_config.bitcoin_network { - bail!(format!( - "Expected bitcoin network in config file to be {:?} but was {:?}", - env_config.bitcoin_network, config.bitcoin.network - )); - } + validate_config(&config, env_config)?; let seed = Seed::from_file_or_generate(&config.data.dir) .await diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index f8f73321df..a2bbe3c3e8 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -214,6 +214,40 @@ pub fn read_config(config_path: PathBuf) -> Result Result<()> { + if config.monero.network != env_config.monero_network { + bail!( + "Expected monero network in config file to be {:?} but was {:?}", + env_config.monero_network, + config.monero.network + ); + } + if config.bitcoin.network != env_config.bitcoin_network { + bail!( + "Expected bitcoin network in config file to be {:?} but was {:?}", + env_config.bitcoin_network, + config.bitcoin.network + ); + } + + let ratio = config.maker.refund_policy.anti_spam_deposit_ratio; + if ratio < Decimal::ZERO || ratio > Decimal::ONE { + bail!("anti_spam_deposit_ratio must be between 0 and 1, got {ratio}"); + } + if ratio > MAX_ANTI_SPAM_DEPOSIT_RATIO { + bail!( + "anti_spam_deposit_ratio of {ratio} exceeds maximum of {MAX_ANTI_SPAM_DEPOSIT_RATIO}. \ + Such a high deposit ratio is implausible and likely a misconfiguration." + ); + } + + Ok(()) +} + pub fn initial_setup(config_path: PathBuf, config: Config) -> Result<()> { let toml = toml::to_string(&config)?; diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index c83de4eb7a..37301e8e07 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -271,6 +271,31 @@ impl State0 { bail!("Bob's dleq proof doesn't verify") } + let amnesty_amount = self + .btc_amnesty_amount + .context("btc_amnesty_amount missing for new swap")?; + + if amnesty_amount > bitcoin::Amount::ZERO { + let tx_refund_burn_fee = self + .tx_refund_burn_fee + .context("tx_refund_burn_fee missing for new swap")?; + + let min_amnesty = msg.tx_partial_refund_fee + + msg.tx_refund_amnesty_fee + + tx_refund_burn_fee + + msg.tx_final_amnesty_fee; + if amnesty_amount < min_amnesty { + bail!( + "Amnesty amount ({amnesty_amount}) is less than the combined fees \ + for TxPartialRefund ({}), TxReclaim ({}), TxWithhold ({tx_refund_burn_fee}), \ + and TxMercy ({}). The deposit would be consumed by fees.", + msg.tx_partial_refund_fee, + msg.tx_refund_amnesty_fee, + msg.tx_final_amnesty_fee, + ); + } + } + let v = self.v_a + msg.v_b; Ok(( diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 8f535115c9..d8b78701af 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -386,6 +386,33 @@ impl State0 { bail!("Alice's dleq proof doesn't verify") } + if msg.amnesty_amount > bitcoin::Amount::ZERO { + let tx_partial_refund_fee = self + .tx_partial_refund_fee + .context("tx_partial_refund_fee missing for new swap")?; + let tx_refund_amnesty_fee = self + .tx_refund_amnesty_fee + .context("tx_refund_amnesty_fee missing for new swap")?; + let tx_final_amnesty_fee = self + .tx_final_amnesty_fee + .context("tx_final_amnesty_fee missing for new swap")?; + + let min_amnesty = tx_partial_refund_fee + + tx_refund_amnesty_fee + + msg.tx_refund_burn_fee + + tx_final_amnesty_fee; + if msg.amnesty_amount < min_amnesty { + bail!( + "Amnesty amount ({}) is less than the combined fees \ + for TxPartialRefund ({tx_partial_refund_fee}), TxReclaim ({tx_refund_amnesty_fee}), \ + TxWithhold ({}), and TxMercy ({tx_final_amnesty_fee}). \ + The deposit would be consumed by fees.", + msg.amnesty_amount, + msg.tx_refund_burn_fee, + ); + } + } + let tx_lock = swap_core::bitcoin::TxLock::new( wallet, self.btc, From f7ced4edec1b37399c0aced9481d5bdd81f171dd Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 18:22:56 +0100 Subject: [PATCH 108/146] alice+bob: add sanity checks for amnesty amount Alice and Bob now check at swap setup that the amnesty amount is either zero or at least greather than the sum of the fees of TxPartialRefund, TxReclaim, TxWithhold and TxMercy. An upper bound (currently 20% of the lock amount) is also introduced. --- Cargo.lock | 1 + bitcoin-wallet/src/wallet.rs | 3 +- swap-env/src/config.rs | 2 +- swap-machine/Cargo.toml | 1 + swap-machine/src/alice/mod.rs | 31 ++++------ swap-machine/src/bob/mod.rs | 24 +++----- swap-machine/src/common/mod.rs | 105 ++++++++++++++++++++++++++++++++- 7 files changed, 129 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fff222ecce..6838f36ab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10751,6 +10751,7 @@ dependencies = [ "monero-oxide-ext", "rand 0.8.5", "rand_chacha 0.3.1", + "rust_decimal", "serde", "sha2", "sigma_fun", diff --git a/bitcoin-wallet/src/wallet.rs b/bitcoin-wallet/src/wallet.rs index 7776a140ab..fd63abe8b9 100644 --- a/bitcoin-wallet/src/wallet.rs +++ b/bitcoin-wallet/src/wallet.rs @@ -82,7 +82,8 @@ pub trait BitcoinWalletSeed { const TWENTY_PERCENT: Decimal = Decimal::from_parts(20, 0, 0, false, 2); pub const MAX_RELATIVE_TX_FEE: Decimal = TWENTY_PERCENT; pub const MAX_ABSOLUTE_TX_FEE: Amount = Amount::from_sat(100_000); -pub const MIN_ABSOLUTE_TX_FEE: Amount = Amount::from_sat(1000); +pub const MIN_ABSOLUTE_TX_FEE_SATS: u64 = 1000; +pub const MIN_ABSOLUTE_TX_FEE: Amount = Amount::from_sat(MIN_ABSOLUTE_TX_FEE_SATS); pub const DUST_AMOUNT: Amount = Amount::from_sat(546); /// This is our wrapper around a bdk wallet and a corresponding diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index a2bbe3c3e8..8f73ed73eb 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -216,7 +216,7 @@ pub fn read_config(config_path: PathBuf) -> Result Result<()> { if config.monero.network != env_config.monero_network { diff --git a/swap-machine/Cargo.toml b/swap-machine/Cargo.toml index f9714c621f..9f4f70da2c 100644 --- a/swap-machine/Cargo.toml +++ b/swap-machine/Cargo.toml @@ -14,6 +14,7 @@ libp2p = { workspace = true } monero-address = { workspace = true } monero-oxide-ext = { path = "../monero-oxide-ext" } rand = { workspace = true } +rust_decimal = { workspace = true } rand_chacha = { workspace = true } serde = { workspace = true } sha2 = { workspace = true } diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index 37301e8e07..d9bf8c4f61 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -274,27 +274,18 @@ impl State0 { let amnesty_amount = self .btc_amnesty_amount .context("btc_amnesty_amount missing for new swap")?; + let tx_refund_burn_fee = self + .tx_refund_burn_fee + .context("tx_refund_burn_fee missing for new swap")?; - if amnesty_amount > bitcoin::Amount::ZERO { - let tx_refund_burn_fee = self - .tx_refund_burn_fee - .context("tx_refund_burn_fee missing for new swap")?; - - let min_amnesty = msg.tx_partial_refund_fee - + msg.tx_refund_amnesty_fee - + tx_refund_burn_fee - + msg.tx_final_amnesty_fee; - if amnesty_amount < min_amnesty { - bail!( - "Amnesty amount ({amnesty_amount}) is less than the combined fees \ - for TxPartialRefund ({}), TxReclaim ({}), TxWithhold ({tx_refund_burn_fee}), \ - and TxMercy ({}). The deposit would be consumed by fees.", - msg.tx_partial_refund_fee, - msg.tx_refund_amnesty_fee, - msg.tx_final_amnesty_fee, - ); - } - } + crate::common::sanity_check_amnesty_amount( + self.btc, + amnesty_amount, + msg.tx_partial_refund_fee, + msg.tx_refund_amnesty_fee, + tx_refund_burn_fee, + msg.tx_final_amnesty_fee, + )?; let v = self.v_a + msg.v_b; diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index d8b78701af..6f36f1e1c1 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -386,7 +386,7 @@ impl State0 { bail!("Alice's dleq proof doesn't verify") } - if msg.amnesty_amount > bitcoin::Amount::ZERO { + { let tx_partial_refund_fee = self .tx_partial_refund_fee .context("tx_partial_refund_fee missing for new swap")?; @@ -397,20 +397,14 @@ impl State0 { .tx_final_amnesty_fee .context("tx_final_amnesty_fee missing for new swap")?; - let min_amnesty = tx_partial_refund_fee - + tx_refund_amnesty_fee - + msg.tx_refund_burn_fee - + tx_final_amnesty_fee; - if msg.amnesty_amount < min_amnesty { - bail!( - "Amnesty amount ({}) is less than the combined fees \ - for TxPartialRefund ({tx_partial_refund_fee}), TxReclaim ({tx_refund_amnesty_fee}), \ - TxWithhold ({}), and TxMercy ({tx_final_amnesty_fee}). \ - The deposit would be consumed by fees.", - msg.amnesty_amount, - msg.tx_refund_burn_fee, - ); - } + crate::common::sanity_check_amnesty_amount( + self.btc, + msg.amnesty_amount, + tx_partial_refund_fee, + tx_refund_amnesty_fee, + msg.tx_refund_burn_fee, + tx_final_amnesty_fee, + )?; } let tx_lock = swap_core::bitcoin::TxLock::new( diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index f1c09e3670..d3d2424e4b 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -2,7 +2,8 @@ use crate::alice::AliceState; use crate::alice::is_complete as alice_is_complete; use crate::bob::BobState; use crate::bob::is_complete as bob_is_complete; -use anyhow::Result; +use anyhow::{Result, bail}; +use rust_decimal::prelude::FromPrimitive; use async_trait::async_trait; use libp2p::{Multiaddr, PeerId}; use serde::{Deserialize, Serialize}; @@ -91,6 +92,53 @@ pub struct Message4 { pub tx_final_amnesty_sig: Option, } +/// Validates that the amnesty amount is within sane bounds. +/// +/// - If amnesty is zero, this is a full-refund swap and no checks are needed. +/// - Otherwise, the amnesty must cover all transaction fees that could be spent +/// from it (TxPartialRefund, TxReclaim, TxWithhold, TxMercy). +/// - The amnesty ratio (amnesty / lock amount) must not exceed +/// [`swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO`]. +pub fn sanity_check_amnesty_amount( + lock_amount: bitcoin::Amount, + amnesty_amount: bitcoin::Amount, + tx_partial_refund_fee: bitcoin::Amount, + tx_reclaim_fee: bitcoin::Amount, + tx_withhold_fee: bitcoin::Amount, + tx_mercy_fee: bitcoin::Amount, +) -> Result<()> { + if amnesty_amount == bitcoin::Amount::ZERO { + return Ok(()); + } + + let min_amnesty = + tx_partial_refund_fee + tx_reclaim_fee + tx_withhold_fee + tx_mercy_fee; + if amnesty_amount < min_amnesty { + bail!( + "Amnesty amount ({amnesty_amount}) is less than the combined fees \ + for TxPartialRefund ({tx_partial_refund_fee}), TxReclaim ({tx_reclaim_fee}), \ + TxWithhold ({tx_withhold_fee}), and TxMercy ({tx_mercy_fee}). \ + The deposit would be consumed by fees.", + ); + } + + let amnesty_sats = rust_decimal::Decimal::from_u64(amnesty_amount.to_sat()) + .expect("amnesty sats to fit in Decimal"); + let lock_sats = rust_decimal::Decimal::from_u64(lock_amount.to_sat()) + .expect("lock sats to fit in Decimal"); + let ratio = amnesty_sats / lock_sats; + + if ratio > swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO { + bail!( + "Amnesty ratio ({ratio}) exceeds maximum allowed ratio of {}. \ + The requested deposit is unreasonably high.", + swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO, + ); + } + + Ok(()) +} + #[allow(clippy::large_enum_variant)] #[derive(Clone, Debug, PartialEq)] pub enum State { @@ -199,3 +247,58 @@ pub trait Database { ) -> Result>; async fn has_swap(&self, swap_id: Uuid) -> Result; } + +#[cfg(test)] +mod tests { + use super::*; + use bitcoin_wallet::{MIN_ABSOLUTE_TX_FEE, MIN_ABSOLUTE_TX_FEE_SATS}; + + /// 1 BTC lock amount. + const LOCK: bitcoin::Amount = bitcoin::Amount::from_sat(100_000_000); + const FEE: bitcoin::Amount = MIN_ABSOLUTE_TX_FEE; + /// Sum of all 4 fees (the lower bound). + const FEE_FLOOR: u64 = MIN_ABSOLUTE_TX_FEE_SATS * 4; + /// 20% of LOCK (the upper bound). + const RATIO_CEILING: u64 = 20_000_000; + + #[test] + fn zero_amnesty_always_passes() { + sanity_check_amnesty_amount(LOCK, bitcoin::Amount::ZERO, FEE, FEE, FEE, FEE) + .expect("zero amnesty should always pass"); + } + + #[test] + fn reject_amnesty_below_fee_floor() { + let amnesty = bitcoin::Amount::from_sat(FEE_FLOOR - 1); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect_err("amnesty below fee floor should be rejected"); + } + + #[test] + fn pass_amnesty_at_fee_floor() { + let amnesty = bitcoin::Amount::from_sat(FEE_FLOOR); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect("amnesty exactly at fee floor should pass"); + } + + #[test] + fn pass_medium_amnesty() { + let amnesty = bitcoin::Amount::from_sat(10_000_000); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect("10% amnesty should pass"); + } + + #[test] + fn pass_amnesty_at_ratio_ceiling() { + let amnesty = bitcoin::Amount::from_sat(RATIO_CEILING); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect("amnesty exactly at 20% ratio should pass"); + } + + #[test] + fn reject_amnesty_above_ratio_ceiling() { + let amnesty = bitcoin::Amount::from_sat(RATIO_CEILING + 1); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect_err("amnesty above 20% ratio should be rejected"); + } +} From 492fb4625028d2b325d26ac376538e12bd9e40fd Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 19:26:34 +0100 Subject: [PATCH 109/146] swap: delete unit tests regarding buy-xmr (which was removed) --- swap/src/cli/command.rs | 110 ---------------------------------------- 1 file changed, 110 deletions(-) diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 3185caa949..383afae150 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -397,7 +397,6 @@ mod tests { use super::*; use crate::cli::api::api_test::*; - use swap_serde::monero::address::MoneroAddressNetworkMismatch; const BINARY_NAME: &str = "swap"; const ARGS_DATA_DIR: &str = "/tmp/dir/"; @@ -416,53 +415,6 @@ mod tests { .unwrap(); } - #[tokio::test] - async fn given_buy_xmr_on_mainnet_with_testnet_address_then_fails() { - let raw_ars = [ - BINARY_NAME, - "buy-xmr", - "--receive-address", - MONERO_STAGENET_ADDRESS, - "--change-address", - BITCOIN_TESTNET_ADDRESS, - "--seller", - MULTI_ADDRESS, - ]; - - let err = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); - assert_eq!( - err.downcast_ref::().unwrap(), - &MoneroAddressNetworkMismatch { - expected: monero_address::Network::Mainnet, - actual: monero_address::Network::Stagenet - } - ); - } - - #[tokio::test] - async fn given_buy_xmr_on_testnet_with_mainnet_address_then_fails() { - let raw_ars = [ - BINARY_NAME, - "--testnet", - "buy-xmr", - "--receive-address", - MONERO_MAINNET_ADDRESS, - "--change-address", - BITCOIN_MAINNET_ADDRESS, - "--seller", - MULTI_ADDRESS, - ]; - - let err = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); - assert_eq!( - err.downcast_ref::().unwrap(), - &MoneroAddressNetworkMismatch { - expected: monero_address::Network::Stagenet, - actual: monero_address::Network::Mainnet - } - ); - } - #[tokio::test] async fn given_resume_on_mainnet_then_defaults_to_mainnet() { let raw_ars = [BINARY_NAME, "resume", "--swap-id", SWAP_ID]; @@ -602,66 +554,4 @@ mod tests { simple_positive(&raw_ars, (true, true, None), cli_cmd).await; } - #[tokio::test] - async fn only_bech32_addresses_mainnet_are_allowed() { - // TODO: not apply defaults - let mut raw_ars = [ - BINARY_NAME, - "buy-xmr", - "--change-address", - "", - "--receive-address", - MONERO_MAINNET_ADDRESS, - "--seller", - MULTI_ADDRESS, - ]; - raw_ars[3] = "1A5btpLKZjgYm8R22rJAhdbTFVXgSRA2Mp"; - parse_args_and_custom(raw_ars, async |_, _, _| unreachable!()) - .await - .unwrap_err(); - - raw_ars[3] = "36vn4mFhmTXn7YcNwELFPxTXhjorw2ppu2"; - parse_args_and_custom(raw_ars, async |_, _, _| unreachable!()) - .await - .unwrap_err(); - - raw_ars[3] = "bc1qh4zjxrqe3trzg7s6m7y67q2jzrw3ru5mx3z7j3"; - let ParseResult::Success(_) = parse_args_and_custom(raw_ars, async |_, _, _| Ok(())) - .await - .unwrap() - else { - panic!() - }; - } - - #[tokio::test] - async fn only_bech32_addresses_testnet_are_allowed() { - let mut raw_ars = [ - BINARY_NAME, - "--testnet", - "buy-xmr", - "--change-address", - "", - "--receive-address", - MONERO_STAGENET_ADDRESS, - "--seller", - MULTI_ADDRESS, - ]; - raw_ars[4] = "n2czxyeFCQp9e8WRyGpy4oL4YfQAeKkkUH"; - parse_args_and_custom(raw_ars, async |_, _, _| unreachable!()) - .await - .unwrap_err(); - raw_ars[4] = "2ND9a4xmQG89qEWG3ETRuytjKpLmGrW7Jvf"; - parse_args_and_custom(raw_ars, async |_, _, _| unreachable!()) - .await - .unwrap_err(); - - raw_ars[4] = "tb1q958vfh3wkdp232pktq8zzvmttyxeqnj80zkz3v"; - let ParseResult::Success(_) = parse_args_and_custom(raw_ars, async |_, _, _| Ok(())) - .await - .unwrap() - else { - panic!() - }; - } } From db2858f14d827e1dea8ebe121df7cf35d09d2ebe Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 19:50:47 +0100 Subject: [PATCH 110/146] add some code style guidelines to CONTRIBUTING.md --- AGENTS.md | 1 + CONTRIBUTING.md | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 4fcf62b2ca..5b5c206e31 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,4 @@ + - Read CONTRIBUTING.md and the code style guidelines! - When asked about libp2p, check if a rust-libp2p folder exists which contains the cloned rust libp2p codebase. Read through to figure out what the best response it. If its a question about best practice when implementing protocols read @rust-libp2p/protocols/ specificially. - Never do `cargo clean`. Building `monero-sys` takes ages, and cleaning the build cache will cause a full rebuilt (horrible). `cargo clean` has never fixed a build problem. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 779e37b085..d50ba6b8dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,7 @@ Thank you for wanting to contribute to this project! There are a couple of things we are going to look out for in PRs and knowing them upfront is going to reduce the number of times we will be going back and forth, making things more efficient. +0. **Read and comply with our [AI Policy](AI_POLICY.md)** 1. We have CI checks in place that validate formatting and code style. Make sure the branch is building with `--all-features` and `--all-targets` without errors and all tests are passed. @@ -21,3 +22,22 @@ There are a couple of things we are going to look out for in PRs and knowing the When contributing a feature request, please focus on your _problem_ as much as possible. It is okay to include ideas on how the feature should be implemented but they should be 2nd nature of your request. +## Code style + +### General + + - File structure + - The content of each file should be ordered in terms of importance / level of abstraction + - Public `struct`s, `enum`s and important constants should be at the top + - `impl` blocks should be below the type declarations + - Both the type declaration part and the implementation part of the file should be internally ordered by level of abstraction/ importance + - For example, `fn main` should always be at least at the top of the implementation + - Prefer early returns over nested `if`/`match` statements + - Don't use fallback values or silent failures + +### Rust + + - Use `cargo fmt` for formatting + - Make use of the powerful `if let` and `let ... else` pattern to enable early returns + - Make use of anyhows `.context` method and the `?` operator for concise error reporting + From 2a9fa9a688fe97960cfc5b1ef23ed375d89ba13c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 19:51:44 +0100 Subject: [PATCH 111/146] fix typo - actually enable deny(unconditioned_recursion) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8cb6fb6f0a..0ebd9f497b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,7 +124,7 @@ crunchy = { git = "https://github.com/eira-fransham/crunchy", rev = "ba7b86cea6b [workspace.lints] rust.unused_crate_dependencies = "warn" # prevents accidental infinite recursion when implementing a trait method by calling a method with the same name -rust.unconditional_recusion = "deny" +rust.unconditional_recursion = "deny" [profile.release] codegen-units = 1 From 53675cb20b6620ae97d574e7f805164dc6a0c389 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 19:52:09 +0100 Subject: [PATCH 112/146] update unit tests --- swap-core/proptest-regressions/bitcoin.txt | 7 +++ swap-machine/src/common/mod.rs | 9 ++- swap/src/asb/event_loop.rs | 31 ++++++++- swap/src/protocol/alice/swap.rs | 73 ++++++++++++++++++++-- 4 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 swap-core/proptest-regressions/bitcoin.txt diff --git a/swap-core/proptest-regressions/bitcoin.txt b/swap-core/proptest-regressions/bitcoin.txt new file mode 100644 index 0000000000..29be8f4aca --- /dev/null +++ b/swap-core/proptest-regressions/bitcoin.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc dd09112d3bef8c0fb013a7fc8a1e2bb68e9a5db3041b954c7b7723e8fcace068 # shrinks to funding_amount = 3000, num_utxos = 1, sats_per_vb = 1, key = Xpriv { network: Test, depth: 0, parent_fingerprint: 00000000, child_number: Normal { index: 0 }, private_key: SecretKey(#dc659542f09c329f), chain_code: c94a49bbee951f7f7401c801db73c23cf17b0b3aa2f6246a8616fe2205a6ca51 }, alice = Point(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798), bob = Point(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5) diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index d3d2424e4b..61a5f900a6 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -3,9 +3,9 @@ use crate::alice::is_complete as alice_is_complete; use crate::bob::BobState; use crate::bob::is_complete as bob_is_complete; use anyhow::{Result, bail}; -use rust_decimal::prelude::FromPrimitive; use async_trait::async_trait; use libp2p::{Multiaddr, PeerId}; +use rust_decimal::prelude::FromPrimitive; use serde::{Deserialize, Serialize}; use sha2::Sha256; use sigma_fun::HashTranscript; @@ -111,8 +111,7 @@ pub fn sanity_check_amnesty_amount( return Ok(()); } - let min_amnesty = - tx_partial_refund_fee + tx_reclaim_fee + tx_withhold_fee + tx_mercy_fee; + let min_amnesty = tx_partial_refund_fee + tx_reclaim_fee + tx_withhold_fee + tx_mercy_fee; if amnesty_amount < min_amnesty { bail!( "Amnesty amount ({amnesty_amount}) is less than the combined fees \ @@ -124,8 +123,8 @@ pub fn sanity_check_amnesty_amount( let amnesty_sats = rust_decimal::Decimal::from_u64(amnesty_amount.to_sat()) .expect("amnesty sats to fit in Decimal"); - let lock_sats = rust_decimal::Decimal::from_u64(lock_amount.to_sat()) - .expect("lock sats to fit in Decimal"); + let lock_sats = + rust_decimal::Decimal::from_u64(lock_amount.to_sat()).expect("lock sats to fit in Decimal"); let ratio = amnesty_sats / lock_sats; if ratio > swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO { diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index b72b8c9848..4e8957a032 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -1671,7 +1671,36 @@ mod tests { #[tokio::test] async fn test_make_quote_with_developer_tip() { - todo!("implement once unit tests compile again") + let min_buy = bitcoin::Amount::from_sat(100_000); + let max_buy = bitcoin::Amount::from_sat(5_000_000); // High enough to be balance-limited + let rate = FixedRate::default(); + let balance = monero::Amount::parse_monero("1.0").unwrap(); + let reserved_items: Vec = vec![]; + let developer_tip = Decimal::new(5, 2); // 0.05 = 5% + + let result = make_quote( + min_buy, + max_buy, + rate.clone(), + || async { Ok(balance) }, + || async { Ok(reserved_items) }, + || async { Err(anyhow::anyhow!("no reserve proof")) }, + developer_tip, + RefundPolicyWire::FullRefund, + ) + .await + .unwrap(); + + // Compute expected max: effective balance is reduced by the tip multiplier + let unreserved = unreserved_monero_balance(balance, std::iter::empty(), developer_tip); + let expected_max = unreserved + .max_bitcoin_for_price(rate.value().ask().unwrap()) + .unwrap(); + + assert_eq!(result.min_quantity, min_buy); + assert_eq!(result.max_quantity, expected_max); + // The tip should have reduced max_quantity below max_buy + assert!(result.max_quantity < max_buy); } // Mock struct for testing diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index f38cde10ea..b2f5a5cbfe 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -997,28 +997,91 @@ pub(crate) fn has_already_processed_enc_sig(state: &AliceState) -> bool { #[cfg(test)] mod tests { + use super::build_transfer_destinations; + use crate::protocol::alice::TipConfig; + use rust_decimal::Decimal; + + const TEST_ADDRESS_STR: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a"; + + fn test_address() -> monero_address::MoneroAddress { + monero_address::MoneroAddress::from_str_with_unchecked_network(TEST_ADDRESS_STR).unwrap() + } + #[test] fn test_build_transfer_destinations_without_tip() { - todo!("implement once unit tests compile again") + let lock_amount = monero_oxide_ext::Amount::from_pico(1_000_000_000_000); // 1 XMR + let tip = TipConfig { + ratio: Decimal::ZERO, + address: test_address(), + }; + + let result = build_transfer_destinations(test_address(), lock_amount, tip).unwrap(); + + assert_eq!(result.len(), 1); + assert_eq!(result[0].1, lock_amount); } #[test] fn test_build_transfer_destinations_with_tip() { - todo!("implement once unit tests compile again") + let lock_amount = monero_oxide_ext::Amount::from_pico(10_000_000_000_000); // 10 XMR + let tip = TipConfig { + ratio: Decimal::new(1, 2), // 0.01 = 1% + address: test_address(), + }; + + let result = build_transfer_destinations(test_address(), lock_amount, tip).unwrap(); + + // Tip = 10 XMR * 0.01 = 0.1 XMR = 100_000_000_000 pico >> 30_000_000 threshold + assert_eq!(result.len(), 2); + assert_eq!(result[0].1, lock_amount); + assert_eq!(result[1].1, monero_oxide_ext::Amount::from_pico(100_000_000_000)); } #[test] fn test_build_transfer_destinations_with_small_tip() { - todo!("implement once unit tests compile again") + // ratio * amount < 30_000_000 piconero threshold + let lock_amount = monero_oxide_ext::Amount::from_pico(2_000_000_000); // 0.002 XMR + let tip = TipConfig { + ratio: Decimal::new(1, 2), // 0.01 + address: test_address(), + }; + + let result = build_transfer_destinations(test_address(), lock_amount, tip).unwrap(); + + // Tip = 0.002 XMR * 0.01 = 20_000_000 piconero < 30_000_000 threshold + assert_eq!(result.len(), 1); + assert_eq!(result[0].1, lock_amount); } #[test] fn test_build_transfer_destinations_with_zero_tip() { - todo!("implement once unit tests compile again") + // Nonzero ratio but tiny lock amount → effective tip rounds to near-zero + let lock_amount = monero_oxide_ext::Amount::from_pico(100); + let tip = TipConfig { + ratio: Decimal::new(1, 1), // 0.1 = 10% + address: test_address(), + }; + + let result = build_transfer_destinations(test_address(), lock_amount, tip).unwrap(); + + // Tip = 100 * 0.1 = 10 piconero << 30_000_000 threshold + assert_eq!(result.len(), 1); + assert_eq!(result[0].1, lock_amount); } #[test] fn test_build_transfer_destinations_with_fractional_tip() { - todo!("implement once unit tests compile again") + let lock_amount = monero_oxide_ext::Amount::from_pico(1_000_000_000_000); // 1 XMR + let tip = TipConfig { + ratio: Decimal::new(5, 3), // 0.005 = 0.5% + address: test_address(), + }; + + let result = build_transfer_destinations(test_address(), lock_amount, tip).unwrap(); + + // Tip = 1 XMR * 0.005 = 0.005 XMR = 5_000_000_000 pico >> 30_000_000 threshold + assert_eq!(result.len(), 2); + assert_eq!(result[0].1, lock_amount); + assert_eq!(result[1].1, monero_oxide_ext::Amount::from_pico(5_000_000_000)); } } From 8a72769cda9970c9fd00672797473a50b32d8158 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 6 Feb 2026 22:22:43 +0100 Subject: [PATCH 113/146] ci: fix typo -> build and unit tests run again --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e33b3c1202..08d072f790 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,14 +87,14 @@ jobs: - target: x86_64-pc-windows-gnu os: ubuntu-22.04 - runs-on: ${{ matrix.host }} + runs-on: ${{ matrix.os }} if: github.event_name == 'push' || !github.event.pull_request.draft steps: - uses: actions/checkout@v4 - name: Setup build environment (cli tools, dependencies) uses: ./.github/actions/setup-build-environment with: - host: ${{ matrix.host }} + host: ${{ matrix.os }} target: ${{ matrix.target }} - name: Build binary @@ -117,21 +117,21 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-15] - runs-on: ${{ matrix.host }} + runs-on: ${{ matrix.os }} if: github.event_name == 'push' || !github.event.pull_request.draft steps: - uses: actions/checkout@v4 - name: Setup build environment (cli tools, dependencies) uses: ./.github/actions/setup-build-environment with: - host: ${{ matrix.host }} + host: ${{ matrix.os }} - name: Run monero-harness tests - if: matrix.host == 'ubuntu-22.04' + if: matrix.os == 'ubuntu-22.04' run: cargo test --package monero-harness --all-features - - name: Run library tests for swap - run: cargo test --package swap --lib + - name: Run library tests + run: cargo test --lib docker_tests: strategy: From 04cfb28b3e2d961e3bbae2b8b8bb47722731e017 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 13 Feb 2026 18:37:13 -0600 Subject: [PATCH 114/146] bump version to 4.0.0 --- Cargo.lock | 28 ++++++++++++++-------------- swap-asb/Cargo.toml | 2 +- swap-controller-api/Cargo.toml | 2 +- swap-controller/Cargo.toml | 2 +- swap-core/Cargo.toml | 2 +- swap-db/Cargo.toml | 2 +- swap-env/Cargo.toml | 2 +- swap-feed/Cargo.toml | 2 +- swap-fs/Cargo.toml | 2 +- swap-machine/Cargo.toml | 2 +- swap-machine/src/common/mod.rs | 23 +++++++++++++++++++++++ swap-orchestrator/Cargo.toml | 2 +- swap-p2p/Cargo.toml | 2 +- swap-proptest/Cargo.toml | 2 +- swap-serde/Cargo.toml | 2 +- swap/Cargo.toml | 2 +- 16 files changed, 51 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6838f36ab3..1bc8febb02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10510,7 +10510,7 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "swap" -version = "3.6.7" +version = "4.0.0" dependencies = [ "anyhow", "arti-client", @@ -10585,7 +10585,7 @@ dependencies = [ [[package]] name = "swap-asb" -version = "3.6.7" +version = "4.0.0" dependencies = [ "anyhow", "bitcoin 0.32.8", @@ -10616,7 +10616,7 @@ dependencies = [ [[package]] name = "swap-controller" -version = "3.6.7" +version = "4.0.0" dependencies = [ "anyhow", "clap 4.5.54", @@ -10632,7 +10632,7 @@ dependencies = [ [[package]] name = "swap-controller-api" -version = "0.1.0" +version = "4.0.0" dependencies = [ "bitcoin 0.32.8", "jsonrpsee", @@ -10642,7 +10642,7 @@ dependencies = [ [[package]] name = "swap-core" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "bdk_wallet", @@ -10674,7 +10674,7 @@ dependencies = [ [[package]] name = "swap-db" -version = "0.1.0" +version = "4.0.0" dependencies = [ "bitcoin 0.32.8", "serde", @@ -10686,7 +10686,7 @@ dependencies = [ [[package]] name = "swap-env" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "bitcoin 0.32.8", @@ -10708,7 +10708,7 @@ dependencies = [ [[package]] name = "swap-feed" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "backoff", @@ -10729,7 +10729,7 @@ dependencies = [ [[package]] name = "swap-fs" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "directories-next", @@ -10738,7 +10738,7 @@ dependencies = [ [[package]] name = "swap-machine" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "async-trait", @@ -10766,7 +10766,7 @@ dependencies = [ [[package]] name = "swap-orchestrator" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "bitcoin 0.32.8", @@ -10783,7 +10783,7 @@ dependencies = [ [[package]] name = "swap-p2p" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "arti-client", @@ -10820,7 +10820,7 @@ dependencies = [ [[package]] name = "swap-proptest" -version = "0.1.0" +version = "4.0.0" dependencies = [ "bitcoin 0.32.8", "ecdsa_fun", @@ -10829,7 +10829,7 @@ dependencies = [ [[package]] name = "swap-serde" -version = "0.1.0" +version = "4.0.0" dependencies = [ "anyhow", "bitcoin 0.32.8", diff --git a/swap-asb/Cargo.toml b/swap-asb/Cargo.toml index 126ce5031c..e147323d23 100644 --- a/swap-asb/Cargo.toml +++ b/swap-asb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-asb" -version = "3.6.7" +version = "4.0.0" authors = ["The eigenwallet guys ", "The COMIT guys "] edition = "2021" description = "ASB (Automated Swap Backend) binary for XMR/BTC atomic swaps." diff --git a/swap-controller-api/Cargo.toml b/swap-controller-api/Cargo.toml index 06bf31f14a..346c17e77a 100644 --- a/swap-controller-api/Cargo.toml +++ b/swap-controller-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-controller-api" -version = "0.1.0" +version = "4.0.0" edition = "2021" [dependencies] diff --git a/swap-controller/Cargo.toml b/swap-controller/Cargo.toml index 518d69add5..cb59810b39 100644 --- a/swap-controller/Cargo.toml +++ b/swap-controller/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-controller" -version = "3.6.7" +version = "4.0.0" edition = "2021" [[bin]] diff --git a/swap-core/Cargo.toml b/swap-core/Cargo.toml index 53fe14c235..13b0a94baa 100644 --- a/swap-core/Cargo.toml +++ b/swap-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-core" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-db/Cargo.toml b/swap-db/Cargo.toml index 2a65aea576..64ffe841e1 100644 --- a/swap-db/Cargo.toml +++ b/swap-db/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-db" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-env/Cargo.toml b/swap-env/Cargo.toml index d5c3d95147..cbaa67850d 100644 --- a/swap-env/Cargo.toml +++ b/swap-env/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-env" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-feed/Cargo.toml b/swap-feed/Cargo.toml index d413c87027..7a187cbc7a 100644 --- a/swap-feed/Cargo.toml +++ b/swap-feed/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-feed" -version = "0.1.0" +version = "4.0.0" authors = ["The COMIT guys "] edition = "2021" description = "Price feed functionality for XMR/BTC atomic swaps" diff --git a/swap-fs/Cargo.toml b/swap-fs/Cargo.toml index 4f92c417ec..cc23fc7064 100644 --- a/swap-fs/Cargo.toml +++ b/swap-fs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-fs" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-machine/Cargo.toml b/swap-machine/Cargo.toml index 9f4f70da2c..28fe50239e 100644 --- a/swap-machine/Cargo.toml +++ b/swap-machine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-machine" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index 61a5f900a6..bfcee84df8 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -92,6 +92,29 @@ pub struct Message4 { pub tx_final_amnesty_sig: Option, } +/// Validates that a proposed transaction fee is between +/// [`bitcoin_wallet::MIN_ABSOLUTE_TX_FEE`] and 3× the `conservative_estimated_fee`. +pub fn sanity_check_transaction_fee( + fee: bitcoin::Amount, + conservative_estimated_fee: bitcoin::Amount, +) -> Result<()> { + if fee < bitcoin_wallet::MIN_ABSOLUTE_TX_FEE { + bail!( + "Fee ({fee}) is below the minimum relay fee ({})", + bitcoin_wallet::MIN_ABSOLUTE_TX_FEE, + ); + } + + let ceiling = conservative_estimated_fee.to_sat().saturating_mul(3); + if fee.to_sat() > ceiling { + bail!( + "Fee ({fee}) exceeds 3x the conservative estimate ({conservative_estimated_fee})", + ); + } + + Ok(()) +} + /// Validates that the amnesty amount is within sane bounds. /// /// - If amnesty is zero, this is a full-refund swap and no checks are needed. diff --git a/swap-orchestrator/Cargo.toml b/swap-orchestrator/Cargo.toml index d62ade629f..651de7f106 100644 --- a/swap-orchestrator/Cargo.toml +++ b/swap-orchestrator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-orchestrator" -version = "0.1.0" +version = "4.0.0" edition = "2024" [[bin]] diff --git a/swap-p2p/Cargo.toml b/swap-p2p/Cargo.toml index 3c61b73963..adf0ee152a 100644 --- a/swap-p2p/Cargo.toml +++ b/swap-p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-p2p" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-proptest/Cargo.toml b/swap-proptest/Cargo.toml index 3094ee5f58..7509e855ea 100644 --- a/swap-proptest/Cargo.toml +++ b/swap-proptest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-proptest" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap-serde/Cargo.toml b/swap-serde/Cargo.toml index 0b3960ac4b..4bc282b3c5 100644 --- a/swap-serde/Cargo.toml +++ b/swap-serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap-serde" -version = "0.1.0" +version = "4.0.0" edition = "2024" [dependencies] diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 42805db17c..a81e610965 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap" -version = "3.6.7" +version = "4.0.0" authors = ["The COMIT guys "] edition = "2021" description = "XMR/BTC trustless atomic swaps." From 86ccc09caa2ea24ac9922d68e3881485df5921c0 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Fri, 13 Feb 2026 19:43:20 -0600 Subject: [PATCH 115/146] update field names to match new tx names --- src-gui/src/dev/mockSwapEvents.ts | 34 +-- src-gui/src/models/tauriModelExt.ts | 32 +-- .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 26 +- .../modal/swap/SwapStateStepper.tsx | 8 +- .../pages/swap/swap/SwapStatePage.tsx | 34 +-- .../swap/done/BitcoinPartialRefundPage.tsx | 52 ++-- .../swap/swap/exited/ProcessExitedPage.tsx | 4 +- swap-asb/src/command.rs | 10 +- swap-asb/src/main.rs | 8 +- swap-core/src/bitcoin/mercy.rs | 24 +- swap-core/src/bitcoin/partial_refund.rs | 2 +- swap-core/src/bitcoin/reclaim.rs | 8 +- swap-core/src/bitcoin/withhold.rs | 20 +- swap-env/src/config.rs | 2 +- swap-machine/src/alice/mod.rs | 242 +++++++++--------- swap-machine/src/bob/mod.rs | 228 ++++++++--------- swap-machine/src/common/mod.rs | 14 +- swap-p2p/src/protocols/swap_setup/alice.rs | 8 +- swap-p2p/src/protocols/swap_setup/bob.rs | 8 +- swap/src/asb.rs | 2 +- swap/src/asb/event_loop.rs | 38 +-- swap/src/asb/recovery.rs | 2 +- ...{grant_final_amnesty.rs => grant_mercy.rs} | 4 +- swap/src/cli/api/tauri_bindings.rs | 24 +- swap/src/cli/cancel_and_refund.rs | 6 +- swap/src/protocol/alice/swap.rs | 60 ++--- swap/src/protocol/bob/swap.rs | 94 +++---- swap/tests/harness/mod.rs | 32 +-- swap/tests/partial_refund_alice_burns.rs | 24 +- ...artial_refund_alice_burns_after_command.rs | 30 +-- ...rtial_refund_alice_grants_final_amnesty.rs | 20 +- .../partial_refund_bob_claims_amnesty.rs | 6 +- 32 files changed, 553 insertions(+), 553 deletions(-) rename swap/src/asb/recovery/{grant_final_amnesty.rs => grant_mercy.rs} (81%) diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index 56e05ce917..a915d79a47 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -24,9 +24,9 @@ const MOCK_BTC_PARTIAL_REFUND_TXID = "f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3"; const MOCK_BTC_AMNESTY_TXID = "a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4"; -const MOCK_BTC_REFUND_BURN_TXID = +const MOCK_BTC_WITHHOLD_TXID = "b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5"; -const MOCK_BTC_FINAL_AMNESTY_TXID = +const MOCK_BTC_MERCY_TXID = "c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"; // Mock timelock blocks for earnest deposit @@ -236,17 +236,17 @@ const partialRefundWithBurn: TauriSwapProgressEvent[] = [ }, })), { - type: "BtcRefundBurnPublished", + type: "BtcWithholdPublished", content: { - btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_withhold_txid: MOCK_BTC_WITHHOLD_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, { - type: "BtcRefundBurnt", + type: "BtcWithheld", content: { - btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_withhold_txid: MOCK_BTC_WITHHOLD_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, @@ -254,7 +254,7 @@ const partialRefundWithBurn: TauriSwapProgressEvent[] = [ { type: "Released" }, ]; -const partialRefundWithBurnAndFinalAmnesty: TauriSwapProgressEvent[] = [ +const partialRefundWithWithholdAndMercy: TauriSwapProgressEvent[] = [ ...baseScenario, { type: "WaitingForCancelTimelockExpiration" }, { type: "CancelTimelockExpired" }, @@ -287,33 +287,33 @@ const partialRefundWithBurnAndFinalAmnesty: TauriSwapProgressEvent[] = [ }, })), { - type: "BtcRefundBurnPublished", + type: "BtcWithholdPublished", content: { - btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_withhold_txid: MOCK_BTC_WITHHOLD_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, { - type: "BtcRefundBurnt", + type: "BtcWithheld", content: { - btc_refund_burn_txid: MOCK_BTC_REFUND_BURN_TXID, + btc_withhold_txid: MOCK_BTC_WITHHOLD_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, { - type: "BtcFinalAmnestyPublished", + type: "BtcMercyPublished", content: { - btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID, + btc_mercy_txid: MOCK_BTC_MERCY_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, }, { - type: "BtcFinalAmnestyConfirmed", + type: "BtcMercyConfirmed", content: { - btc_final_amnesty_txid: MOCK_BTC_FINAL_AMNESTY_TXID, + btc_mercy_txid: MOCK_BTC_MERCY_TXID, btc_lock_amount: MOCK_BTC_LOCK_AMOUNT, btc_amnesty_amount: MOCK_BTC_AMNESTY_AMOUNT, }, @@ -328,7 +328,7 @@ export const scenarios: Record = { earlyRefund, partialRefundWithAmnesty, partialRefundWithBurn, - partialRefundWithBurnAndFinalAmnesty, + partialRefundWithWithholdAndMercy, }; export type MockScenario = keyof typeof scenarios; @@ -360,7 +360,7 @@ const MOCK_LOCK_BITCOIN_DETAILS_FULL: LockBitcoinDetails = { const PARTIAL_REFUND_SCENARIOS: MockScenario[] = [ "partialRefundWithAmnesty", "partialRefundWithBurn", - "partialRefundWithBurnAndFinalAmnesty", + "partialRefundWithWithholdAndMercy", ]; export function isPartialRefundScenario(scenario: MockScenario): boolean { diff --git a/src-gui/src/models/tauriModelExt.ts b/src-gui/src/models/tauriModelExt.ts index f3c9efdaaa..f22faa4ff1 100644 --- a/src-gui/src/models/tauriModelExt.ts +++ b/src-gui/src/models/tauriModelExt.ts @@ -58,10 +58,10 @@ export enum BobStateName { BtcPartiallyRefunded = "btc is partially refunded", BtcAmnestyPublished = "btc amnesty is published", BtcAmnestyReceived = "btc amnesty is confirmed", - BtcRefundBurnPublished = "btc refund burn is published", - BtcRefundBurnt = "btc refund is burnt", - BtcFinalAmnestyPublished = "btc final amnesty is published", - BtcFinalAmnestyConfirmed = "btc final amnesty is confirmed", + BtcWithholdPublished = "btc withhold is published", + BtcWithheld = "btc is withheld", + BtcMercyPublished = "btc mercy is published", + BtcMercyConfirmed = "btc mercy is confirmed", XmrRedeemed = "xmr is redeemed", BtcPunished = "btc is punished", SafelyAborted = "safely aborted", @@ -107,14 +107,14 @@ export function bobStateNameToHumanReadable(stateName: BobStateName): string { return "Bitcoin partially refunded"; case BobStateName.BtcAmnestyReceived: return "Bitcoin amnesty was received"; - case BobStateName.BtcRefundBurnPublished: - return "Bitcoin refund burn published"; - case BobStateName.BtcRefundBurnt: - return "Bitcoin refund is burnt"; - case BobStateName.BtcFinalAmnestyPublished: - return "Bitcoin final amnesty published"; - case BobStateName.BtcFinalAmnestyConfirmed: - return "Bitcoin final amnesty received"; + case BobStateName.BtcWithholdPublished: + return "Bitcoin withhold published"; + case BobStateName.BtcWithheld: + return "Bitcoin withheld"; + case BobStateName.BtcMercyPublished: + return "Bitcoin mercy published"; + case BobStateName.BtcMercyConfirmed: + return "Bitcoin mercy received"; case BobStateName.XmrRedeemed: return "Monero redeemed"; case BobStateName.BtcPunished: @@ -178,8 +178,8 @@ export type BobStateNameRunningSwap = Exclude< | BobStateName.BtcAmnestyReceived | BobStateName.BtcRefunded | BobStateName.BtcEarlyRefunded - | BobStateName.BtcRefundBurnt - | BobStateName.BtcFinalAmnestyConfirmed + | BobStateName.BtcWithheld + | BobStateName.BtcMercyConfirmed | BobStateName.BtcPunished | BobStateName.SafelyAborted | BobStateName.XmrRedeemed @@ -198,8 +198,8 @@ export function isBobStateNameRunningSwap( BobStateName.BtcRefunded, BobStateName.BtcEarlyRefunded, BobStateName.BtcAmnestyReceived, - BobStateName.BtcRefundBurnt, - BobStateName.BtcFinalAmnestyConfirmed, + BobStateName.BtcWithheld, + BobStateName.BtcMercyConfirmed, BobStateName.BtcPunished, BobStateName.SafelyAborted, BobStateName.XmrRedeemed, diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 22a17dbded..622d32a6bc 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -204,29 +204,29 @@ function RemainingRefundTimelockExpiredAlert() { } /** - * Sub-component for alerts when the maker has burnt the amnesty output. + * Sub-component for alerts when the maker has withheld the amnesty output. */ -function BtcRefundBurnPublishedAlert() { +function BtcWithholdPublishedAlert() { return ( ); } /** - * Sub-component for alerts when the maker has published the final amnesty transaction. + * Sub-component for alerts when the maker has published the mercy transaction. */ -function BtcFinalAmnestyPublishedAlert() { +function BtcMercyPublishedAlert() { return ( ); @@ -317,11 +317,11 @@ export function StateAlert({ } return null; - case BobStateName.BtcRefundBurnPublished: - return ; + case BobStateName.BtcWithholdPublished: + return ; - case BobStateName.BtcFinalAmnestyPublished: - return ; + case BobStateName.BtcMercyPublished: + return ; case BobStateName.BtcAmnestyPublished: // Amnesty tx published, waiting for confirmation - no specific alert needed diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index 7a9b27a846..da3794b16b 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -134,16 +134,16 @@ function getActiveStep(state: SwapState | null): PathStep | null { case "BtcAmnestyReceived": return [PathType.RECOVERY_PATH, 3, false, RecoveryScenario.PARTIAL_REFUND]; - case "BtcRefundBurnPublished": + case "BtcWithholdPublished": return [PathType.RECOVERY_PATH, 2, true, RecoveryScenario.PARTIAL_REFUND]; - case "BtcRefundBurnt": + case "BtcWithheld": return [PathType.RECOVERY_PATH, 2, true, RecoveryScenario.PARTIAL_REFUND]; - case "BtcFinalAmnestyPublished": + case "BtcMercyPublished": return [PathType.RECOVERY_PATH, 2, isReleased, RecoveryScenario.PARTIAL_REFUND]; - case "BtcFinalAmnestyConfirmed": + case "BtcMercyConfirmed": return [PathType.RECOVERY_PATH, 3, false, RecoveryScenario.PARTIAL_REFUND]; // Recovery Path States - Cooperative Redeem (after punishment) diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index 9243ab5aed..818a7aadd3 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -14,10 +14,10 @@ import { WaitingForEarnestDepositTimelockExpirationPage, BitcoinAmnestyPublished, BitcoinAmnestyReceived, - BitcoinRefundBurnPublished, - BitcoinRefundBurnt, - BitcoinFinalAmnestyPublished, - BitcoinFinalAmnestyConfirmed, + BitcoinWithholdPublished, + BitcoinWithheld, + BitcoinMercyPublished, + BitcoinMercyConfirmed, } from "./done/BitcoinPartialRefundPage"; import XmrRedeemInMempoolPage from "./done/XmrRedeemInMempoolPage"; import ProcessExitedPage from "./exited/ProcessExitedPage"; @@ -164,25 +164,25 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { } break; - //// 4 different types of refund burn / final amnesty states - case "BtcRefundBurnPublished": - if (state.curr.type === "BtcRefundBurnPublished") { - return ; + //// 4 different types of withhold / mercy states + case "BtcWithholdPublished": + if (state.curr.type === "BtcWithholdPublished") { + return ; } break; - case "BtcRefundBurnt": - if (state.curr.type === "BtcRefundBurnt") { - return ; + case "BtcWithheld": + if (state.curr.type === "BtcWithheld") { + return ; } break; - case "BtcFinalAmnestyPublished": - if (state.curr.type === "BtcFinalAmnestyPublished") { - return ; + case "BtcMercyPublished": + if (state.curr.type === "BtcMercyPublished") { + return ; } break; - case "BtcFinalAmnestyConfirmed": - if (state.curr.type === "BtcFinalAmnestyConfirmed") { - return ; + case "BtcMercyConfirmed": + if (state.curr.type === "BtcMercyConfirmed") { + return ; } break; diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 9b3dcc4aa4..7e6624e451 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -7,9 +7,9 @@ * 1. BtcPartialRefundPublished - TxPartialRefund is published * 2. BtcPartiallyRefunded - TxPartialRefund is confirmed * 3. Either: - * a. BtcAmnestyPublished -> BtcAmnestyReceived (Bob claims amnesty via TxRefundAmnesty) - * b. BtcRefundBurnPublished -> BtcRefundBurnt (Alice burns amnesty via TxRefundBurn) - * -> optionally BtcFinalAmnestyPublished -> BtcFinalAmnestyConfirmed (Alice grants final amnesty) + * a. BtcAmnestyPublished -> BtcAmnestyReceived (Bob claims amnesty via TxReclaim) + * b. BtcWithholdPublished -> BtcWithheld (Alice withholds amnesty via TxWithhold) + * -> optionally BtcMercyPublished -> BtcMercyConfirmed (Alice grants mercy) */ import { Alert, Box, Button, DialogContentText, Typography } from "@mui/material"; @@ -186,18 +186,18 @@ function AmnestyPage({ ); } -// Refund Burn pages - The maker actively withheld the remaining Bitcoin (bad outcome) +// Withhold pages - The maker actively withheld the remaining Bitcoin (bad outcome) // Note: By default, the user would have received the remaining Bitcoin after a timelock. -// If we're in this state, it means the maker actively published TxBurn to revoke it. +// If we're in this state, it means the maker actively published TxWithhold to revoke it. -export function BitcoinRefundBurnPublished({ - btc_refund_burn_txid, +export function BitcoinWithholdPublished({ + btc_withhold_txid, btc_lock_amount, btc_amnesty_amount, -}: TauriSwapProgressEventContent<"BtcRefundBurnPublished">) { +}: TauriSwapProgressEventContent<"BtcWithholdPublished">) { return ( - ) { +}: TauriSwapProgressEventContent<"BtcWithheld">) { return ( - ) { - return ; +export function BitcoinMercyPublished({ + btc_mercy_txid, +}: TauriSwapProgressEventContent<"BtcMercyPublished">) { + return ; } -export function BitcoinFinalAmnestyConfirmed({ - btc_final_amnesty_txid, -}: TauriSwapProgressEventContent<"BtcFinalAmnestyConfirmed">) { - return ; +export function BitcoinMercyConfirmed({ + btc_mercy_txid, +}: TauriSwapProgressEventContent<"BtcMercyConfirmed">) { + return ; } -function FinalAmnestyPage({ +function MercyPage({ txid, confirmed, }: { diff --git a/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx index 18c94d1b59..acee82ea82 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/exited/ProcessExitedPage.tsx @@ -22,8 +22,8 @@ export default function ProcessExitedPage({ prevState.type === "BtcRefunded" || prevState.type === "BtcPunished" || prevState.type === "CooperativeRedeemRejected" || - prevState.type === "BtcRefundBurnt" || - prevState.type === "BtcFinalAmnestyConfirmed" || + prevState.type === "BtcWithheld" || + prevState.type === "BtcMercyConfirmed" || prevState.type === "BtcAmnestyReceived") ) { return ( diff --git a/swap-asb/src/command.rs b/swap-asb/src/command.rs index d6bb2b3afa..5730d097a4 100644 --- a/swap-asb/src/command.rs +++ b/swap-asb/src/command.rs @@ -177,13 +177,13 @@ where env_config: env_config(testnet), cmd: Command::SafelyAbort { swap_id }, }, - RawCommand::ManualRecovery(ManualRecovery::GrantFinalAmnesty { swap_id }) => Arguments { + RawCommand::ManualRecovery(ManualRecovery::GrantMercy { swap_id }) => Arguments { testnet, json, trace, config_path: config_path(config, testnet)?, env_config: env_config(testnet), - cmd: Command::GrantFinalAmnesty { swap_id }, + cmd: Command::GrantMercy { swap_id }, }, }; @@ -257,7 +257,7 @@ pub enum Command { SafelyAbort { swap_id: Uuid, }, - GrantFinalAmnesty { + GrantMercy { swap_id: Uuid, }, ExportBitcoinWallet, @@ -423,9 +423,9 @@ pub enum ManualRecovery { swap_id: Uuid, }, #[structopt( - about = "Grant final amnesty to a swap in BtcRefundBurnConfirmed state, allowing the taker to claim the remaining funds." + about = "Grant mercy to a swap in BtcWithholdConfirmed state, allowing the taker to claim the remaining funds." )] - GrantFinalAmnesty { + GrantMercy { #[structopt( long = "swap-id", help = "The swap id can be retrieved using the history subcommand" diff --git a/swap-asb/src/main.rs b/swap-asb/src/main.rs index 859214a64a..87259daaa1 100644 --- a/swap-asb/src/main.rs +++ b/swap-asb/src/main.rs @@ -26,7 +26,7 @@ use structopt::clap::ErrorKind; mod command; use command::{parse_args, Arguments, Command}; use swap::asb::rpc::RpcServer; -use swap::asb::{cancel, grant_final_amnesty, punish, redeem, refund, safely_abort, EventLoop, ExchangeRate, Finality}; +use swap::asb::{cancel, grant_mercy, punish, redeem, refund, safely_abort, EventLoop, ExchangeRate, Finality}; use swap::common::tor::{bootstrap_tor_client, create_tor_client}; use swap::common::tracing_util::Format; use swap::common::{self, get_logs, warn_if_outdated}; @@ -473,12 +473,12 @@ pub async fn main() -> Result<()> { tracing::info!("Swap safely aborted"); } - Command::GrantFinalAmnesty { swap_id } => { + Command::GrantMercy { swap_id } => { let db = open_db(db_file, AccessMode::ReadWrite, None).await?; - grant_final_amnesty(swap_id, db).await?; + grant_mercy(swap_id, db).await?; - tracing::info!("Final amnesty granted for swap {}", swap_id); + tracing::info!("Mercy granted for swap {}", swap_id); } Command::Redeem { swap_id, diff --git a/swap-core/src/bitcoin/mercy.rs b/swap-core/src/bitcoin/mercy.rs index 1630c621cf..75a3f1942e 100644 --- a/swap-core/src/bitcoin/mercy.rs +++ b/swap-core/src/bitcoin/mercy.rs @@ -11,7 +11,7 @@ use bitcoin_wallet::primitives::Watchable; use ecdsa_fun::Signature; use std::collections::HashMap; -/// TxFinalAmnesty spends the burn output of TxRefundBurn and sends it to +/// TxMercy spends the burn output of TxWithhold and sends it to /// Bob's refund address. This allows Alice to voluntarily refund Bob even /// after she has "burnt" the amnesty output. /// @@ -28,36 +28,36 @@ pub struct TxMercy { impl TxMercy { pub fn new( - tx_refund_burn: &TxWithhold, + tx_withhold: &TxWithhold, refund_address: &Address, spending_fee: Amount, ) -> Self { // TODO: Handle case where fee >= burn amount more gracefully assert!( - tx_refund_burn.amount() > spending_fee, - "TxFinalAmnesty fee ({}) must be less than burn amount ({})", + tx_withhold.amount() > spending_fee, + "TxMercy fee ({}) must be less than burn amount ({})", spending_fee, - tx_refund_burn.amount() + tx_withhold.amount() ); - let tx_final_amnesty = tx_refund_burn.build_spend_transaction(refund_address, spending_fee); + let tx_mercy = tx_withhold.build_spend_transaction(refund_address, spending_fee); - let digest = SighashCache::new(&tx_final_amnesty) + let digest = SighashCache::new(&tx_mercy) .p2wsh_signature_hash( - 0, // Only one input: burn output from tx_refund_burn - &tx_refund_burn + 0, // Only one input: burn output from tx_withhold + &tx_withhold .burn_output_descriptor .script_code() .expect("scriptcode"), - tx_refund_burn.amount(), + tx_withhold.amount(), EcdsaSighashType::All, ) .expect("sighash"); Self { - inner: tx_final_amnesty, + inner: tx_mercy, digest, - burn_output_descriptor: tx_refund_burn.burn_output_descriptor.clone(), + burn_output_descriptor: tx_withhold.burn_output_descriptor.clone(), watch_script: refund_address.script_pubkey(), } } diff --git a/swap-core/src/bitcoin/partial_refund.rs b/swap-core/src/bitcoin/partial_refund.rs index b45861cdd6..9ec2817ca7 100644 --- a/swap-core/src/bitcoin/partial_refund.rs +++ b/swap-core/src/bitcoin/partial_refund.rs @@ -119,7 +119,7 @@ impl TxPartialRefund { } /// Build a transaction that spends the amnesty output to a new 2-of-2 multisig (burn output). - /// This is used by TxRefundBurn to "burn" the amnesty by moving it to another multisig. + /// This is used by TxWithhold to "burn" the amnesty by moving it to another multisig. /// Unlike `build_amnesty_spend_transaction`, this has no timelock. pub fn build_withhold_transaction( &self, diff --git a/swap-core/src/bitcoin/reclaim.rs b/swap-core/src/bitcoin/reclaim.rs index 66228ad8f6..0e9ba83ac1 100644 --- a/swap-core/src/bitcoin/reclaim.rs +++ b/swap-core/src/bitcoin/reclaim.rs @@ -26,11 +26,11 @@ impl TxReclaim { spending_fee: Amount, remaining_refund_timelock: RemainingRefundTimelock, ) -> Result { - let tx_refund_amnesty = tx_refund + let tx_reclaim = tx_refund .build_reclaim_transaction(refund_address, spending_fee, remaining_refund_timelock) - .context("Couldn't build tx refund amnesty")?; + .context("Couldn't build tx reclaim")?; - let digest = SighashCache::new(&tx_refund_amnesty) + let digest = SighashCache::new(&tx_reclaim) .p2wsh_signature_hash( 0, // Only one input: amnesty box from tx_refund &tx_refund @@ -43,7 +43,7 @@ impl TxReclaim { .expect("sighash"); Ok(Self { - inner: tx_refund_amnesty, + inner: tx_reclaim, digest, amensty_output_descriptor: tx_refund.amnesty_output_descriptor.clone(), watch_script: refund_address.script_pubkey(), diff --git a/swap-core/src/bitcoin/withhold.rs b/swap-core/src/bitcoin/withhold.rs index ddc39be5e3..638ff2ed5a 100644 --- a/swap-core/src/bitcoin/withhold.rs +++ b/swap-core/src/bitcoin/withhold.rs @@ -13,12 +13,12 @@ use bitcoin_wallet::primitives::Watchable; use ecdsa_fun::Signature; use std::collections::HashMap; -/// TxRefundBurn spends the amnesty output of TxPartialRefund and sends it to +/// TxWithhold spends the amnesty output of TxPartialRefund and sends it to /// a new 2-of-2 multisig. This allows Alice to "burn" the amnesty (prevent Bob -/// from claiming it via TxRefundAmnesty) while still allowing a later refund -/// via TxFinalAmnesty if Alice cooperates. +/// from claiming it via TxReclaim) while still allowing a later refund +/// via TxMercy if Alice cooperates. /// -/// Unlike TxRefundAmnesty, this transaction has no timelock - Alice can publish +/// Unlike TxReclaim, this transaction has no timelock - Alice can publish /// it immediately after TxPartialRefund is confirmed. #[derive(Debug, Clone)] pub struct TxWithhold { @@ -40,17 +40,17 @@ impl TxWithhold { // For now, assert to catch this during development assert!( tx_partial_refund.anti_spam_deposit() > spending_fee, - "TxRefundBurn fee ({}) must be less than amnesty amount ({})", + "TxWithhold fee ({}) must be less than amnesty amount ({})", spending_fee, tx_partial_refund.anti_spam_deposit() ); let burn_output_descriptor = build_shared_output_descriptor(A.0, B.0)?; - let tx_refund_burn = + let tx_withhold = tx_partial_refund.build_withhold_transaction(&burn_output_descriptor, spending_fee); - let digest = SighashCache::new(&tx_refund_burn) + let digest = SighashCache::new(&tx_withhold) .p2wsh_signature_hash( 0, // Only one input: amnesty output from tx_partial_refund &tx_partial_refund @@ -65,7 +65,7 @@ impl TxWithhold { let watch_script = burn_output_descriptor.script_pubkey(); Ok(Self { - inner: tx_refund_burn, + inner: tx_withhold, digest, amnesty_output_descriptor: tx_partial_refund.amnesty_output_descriptor.clone(), burn_output_descriptor, @@ -149,7 +149,7 @@ impl TxWithhold { } /// Build a transaction that spends the burn output to a destination address. - /// Used by TxFinalAmnesty to send the funds back to Bob's refund address. + /// Used by TxMercy to send the funds back to Bob's refund address. pub fn build_spend_transaction( &self, destination: &Address, @@ -164,7 +164,7 @@ impl TxWithhold { // For now, assert to catch this during development assert!( self.amount() > spending_fee, - "TxFinalAmnesty fee ({}) must be less than burn amount ({})", + "TxMercy fee ({}) must be less than burn amount ({})", spending_fee, self.amount() ); diff --git a/swap-env/src/config.rs b/swap-env/src/config.rs index 8f73ed73eb..a558aad09d 100644 --- a/swap-env/src/config.rs +++ b/swap-env/src/config.rs @@ -126,7 +126,7 @@ pub struct RefundPolicy { /// This protects the maker against griefing attacks. #[serde(default = "default_anti_spam_deposit_ratio")] pub anti_spam_deposit_ratio: Decimal, - /// If true, Alice will publish TxRefundBurn after refunding her XMR, + /// If true, Alice will publish TxWithhold after refunding her XMR, /// denying Bob access to the amnesty output. Alice can later grant /// final amnesty to return the funds to Bob. #[serde(default = "default_always_withhold_deposit")] diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index d9bf8c4f61..a63b591bcf 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -97,7 +97,7 @@ pub enum AliceState { state3: Box, }, /// Operator has decided to grant final amnesty to Bob. - /// This state will publish TxFinalAmnesty and transition to BtcRefundFinalAmnestyPublished. + /// This state will publish TxMercy and transition to BtcMercyPublished. BtcMercyGranted { state3: Box, }, @@ -131,9 +131,9 @@ pub enum AliceState { pub fn is_complete(state: &AliceState) -> bool { match state { - // XmrRefunded is only complete if we don't need to publish TxRefundBurn + // XmrRefunded is only complete if we don't need to publish TxWithhold AliceState::XmrRefunded { state3 } => match state3 { - Some(s3) if s3.should_publish_tx_refund_burn == Some(true) => false, + Some(s3) if s3.should_publish_tx_withhold == Some(true) => false, _ => true, }, AliceState::BtcRedeemed @@ -210,8 +210,8 @@ pub struct State0 { punish_address: bitcoin::Address, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, - tx_refund_burn_fee: Option, - should_publish_tx_refund_burn: Option, + tx_withhold_fee: Option, + should_publish_tx_withhold: Option, } impl State0 { @@ -225,8 +225,8 @@ impl State0 { punish_address: bitcoin::Address, tx_redeem_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, - tx_refund_burn_fee: bitcoin::Amount, - should_publish_tx_refund_burn: bool, + tx_withhold_fee: bitcoin::Amount, + should_publish_tx_withhold: bool, rng: &mut R, ) -> Self where @@ -256,8 +256,8 @@ impl State0 { remaining_refund_timelock: Some(env_config.bitcoin_remaining_refund_timelock.into()), tx_redeem_fee, tx_punish_fee, - tx_refund_burn_fee: Some(tx_refund_burn_fee), - should_publish_tx_refund_burn: Some(should_publish_tx_refund_burn), + tx_withhold_fee: Some(tx_withhold_fee), + should_publish_tx_withhold: Some(should_publish_tx_withhold), } } @@ -274,17 +274,17 @@ impl State0 { let amnesty_amount = self .btc_amnesty_amount .context("btc_amnesty_amount missing for new swap")?; - let tx_refund_burn_fee = self - .tx_refund_burn_fee - .context("tx_refund_burn_fee missing for new swap")?; + let tx_withhold_fee = self + .tx_withhold_fee + .context("tx_withhold_fee missing for new swap")?; crate::common::sanity_check_amnesty_amount( self.btc, amnesty_amount, msg.tx_partial_refund_fee, - msg.tx_refund_amnesty_fee, - tx_refund_burn_fee, - msg.tx_final_amnesty_fee, + msg.tx_reclaim_fee, + tx_withhold_fee, + msg.tx_mercy_fee, )?; let v = self.v_a + msg.v_b; @@ -315,11 +315,11 @@ impl State0 { tx_punish_fee: self.tx_punish_fee, tx_refund_fee: msg.tx_refund_fee, tx_partial_refund_fee: Some(msg.tx_partial_refund_fee), - tx_refund_amnesty_fee: Some(msg.tx_refund_amnesty_fee), - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: Some(msg.tx_final_amnesty_fee), + tx_reclaim_fee: Some(msg.tx_reclaim_fee), + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: Some(msg.tx_mercy_fee), tx_cancel_fee: msg.tx_cancel_fee, - should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, + should_publish_tx_withhold: self.should_publish_tx_withhold, }, )) } @@ -351,11 +351,11 @@ pub struct State1 { tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, tx_cancel_fee: bitcoin::Amount, - should_publish_tx_refund_burn: Option, + should_publish_tx_withhold: Option, } impl State1 { @@ -373,9 +373,9 @@ impl State1 { amnesty_amount: self .btc_amnesty_amount .context("Missing btc_amesty_amount for new swap that should have it")?, - tx_refund_burn_fee: self - .tx_refund_burn_fee - .context("Missing tx_refund_burn_fee for new swap that should have it")?, + tx_withhold_fee: self + .tx_withhold_fee + .context("Missing tx_withhold_fee for new swap that should have it")?, }) } @@ -409,11 +409,11 @@ impl State1 { tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, tx_cancel_fee: self.tx_cancel_fee, - should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, + should_publish_tx_withhold: self.should_publish_tx_withhold, }) } } @@ -441,11 +441,11 @@ pub struct State2 { tx_punish_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, tx_cancel_fee: bitcoin::Amount, - should_publish_tx_refund_burn: Option, + should_publish_tx_withhold: Option, } impl State2 { @@ -473,7 +473,7 @@ impl State2 { tx_cancel_sig, tx_partial_refund_encsig: None, tx_full_refund_encsig: Some(tx_refund_encsig), - tx_refund_amnesty_sig: None, + tx_reclaim_sig: None, }); } @@ -493,21 +493,21 @@ impl State2 { // A) is alice's keypair and (s_b, S_b) is bob's keypair. let tx_partial_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_partial_refund.digest()); - // Construct and sign TxRefundAmnesty - let tx_refund_amnesty = swap_core::bitcoin::TxReclaim::new( + // Construct and sign TxReclaim + let tx_reclaim = swap_core::bitcoin::TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee - .context("Missing tx_refund_amnesty_fee for new swap")?, + self.tx_reclaim_fee + .context("Missing tx_reclaim_fee for new swap")?, self.remaining_refund_timelock .context("Missing remaining_refund_timelock for new swap")?, )?; - let tx_refund_amnesty_sig = self.a.sign(tx_refund_amnesty.digest()); + let tx_reclaim_sig = self.a.sign(tx_reclaim.digest()); Ok(Message3 { tx_cancel_sig, tx_partial_refund_encsig: Some(tx_partial_refund_encsig), - tx_refund_amnesty_sig: Some(tx_refund_amnesty_sig), + tx_reclaim_sig: Some(tx_reclaim_sig), tx_full_refund_encsig: None, }) } @@ -578,22 +578,22 @@ impl State2 { tx_punish_sig_bob: msg.tx_punish_sig, tx_cancel_sig_bob: msg.tx_cancel_sig, tx_early_refund_sig_bob: msg.tx_early_refund_sig.into(), - tx_refund_amnesty_sig_bob: None, + tx_reclaim_sig_bob: None, tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, tx_cancel_fee: self.tx_cancel_fee, - tx_refund_burn_sig_bob: None, - tx_final_amnesty_sig_bob: None, - should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, + tx_withhold_sig_bob: None, + tx_mercy_sig_bob: None, + should_publish_tx_withhold: self.should_publish_tx_withhold, }); } - // Create TxRefundAmnesty ourself + // Create TxReclaim ourself let tx_partial_refund = TxPartialRefund::new( &tx_cancel, &self.refund_address, @@ -605,55 +605,55 @@ impl State2 { .context("missing tx_partial_refund_fee")?, ) .context("Couldn't construct TxPartialRefund")?; - let tx_refund_amnesty = TxReclaim::new( + let tx_reclaim = TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee - .context("missing tx_refund_amnesty_fee")?, + self.tx_reclaim_fee + .context("missing tx_reclaim_fee")?, self.remaining_refund_timelock .context("missing remaining_refund_timelock")?, )?; // Check if the provided signature by Bob is valid for the transaction - let tx_refund_amnesty_sig = msg - .tx_refund_amnesty_sig + let tx_reclaim_sig = msg + .tx_reclaim_sig .as_ref() - .context("Missing tx_refund_amnesty_sig from Bob")?; - swap_core::bitcoin::verify_sig(&self.B, &tx_refund_amnesty.digest(), tx_refund_amnesty_sig) - .context("Failed to verify refund amnesty transaction")?; + .context("Missing tx_reclaim_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_reclaim.digest(), tx_reclaim_sig) + .context("Failed to verify reclaim transaction")?; - // Create TxRefundBurn ourself - let tx_refund_burn = TxWithhold::new( + // Create TxWithhold ourself + let tx_withhold = TxWithhold::new( &tx_partial_refund, self.a.public(), self.B, - self.tx_refund_burn_fee - .context("missing tx_refund_burn_fee")?, + self.tx_withhold_fee + .context("missing tx_withhold_fee")?, )?; // Check if the provided signature by Bob is valid for the transaction - let tx_refund_burn_sig = msg - .tx_refund_burn_sig + let tx_withhold_sig = msg + .tx_withhold_sig .as_ref() - .context("Missing tx_refund_burn_sig from Bob")?; - swap_core::bitcoin::verify_sig(&self.B, &tx_refund_burn.digest(), tx_refund_burn_sig) - .context("Failed to verify refund burn transaction")?; + .context("Missing tx_withhold_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_withhold.digest(), tx_withhold_sig) + .context("Failed to verify withhold transaction")?; - // Create TxFinalAmnesty ourself - let tx_final_amnesty = TxMercy::new( - &tx_refund_burn, + // Create TxMercy ourself + let tx_mercy = TxMercy::new( + &tx_withhold, &self.refund_address, - self.tx_final_amnesty_fee - .context("missing tx_final_amnesty_fee")?, + self.tx_mercy_fee + .context("missing tx_mercy_fee")?, ); // Check if the provided signature by Bob is valid for the transaction - let tx_final_amnesty_sig = msg - .tx_final_amnesty_sig + let tx_mercy_sig = msg + .tx_mercy_sig .as_ref() - .context("Missing tx_final_amnesty_sig from Bob")?; - swap_core::bitcoin::verify_sig(&self.B, &tx_final_amnesty.digest(), tx_final_amnesty_sig) - .context("Failed to verify final amnesty transaction")?; + .context("Missing tx_mercy_sig from Bob")?; + swap_core::bitcoin::verify_sig(&self.B, &tx_mercy.digest(), tx_mercy_sig) + .context("Failed to verify mercy transaction")?; Ok(State3 { a: self.a, @@ -675,18 +675,18 @@ impl State2 { tx_punish_sig_bob: msg.tx_punish_sig, tx_cancel_sig_bob: msg.tx_cancel_sig, tx_early_refund_sig_bob: msg.tx_early_refund_sig.into(), - tx_refund_amnesty_sig_bob: msg.tx_refund_amnesty_sig.into(), + tx_reclaim_sig_bob: msg.tx_reclaim_sig.into(), tx_redeem_fee: self.tx_redeem_fee, tx_punish_fee: self.tx_punish_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, tx_cancel_fee: self.tx_cancel_fee, - tx_refund_burn_sig_bob: msg.tx_refund_burn_sig, - tx_final_amnesty_sig_bob: msg.tx_final_amnesty_sig, - should_publish_tx_refund_burn: self.should_publish_tx_refund_burn, + tx_withhold_sig_bob: msg.tx_withhold_sig, + tx_mercy_sig_bob: msg.tx_mercy_sig, + should_publish_tx_withhold: self.should_publish_tx_withhold, }) } } @@ -730,32 +730,32 @@ pub struct State3 { tx_early_refund_sig_bob: Option, /// This field was added in PR [#675](https://github.com/eigenwallet/core/pull/344). /// It is optional to maintain backwards compatibility with old swaps in the database. - /// Bob must send this to us during swap setup, in order for us to publish TxRefundAmnesty + /// Bob must send this to us during swap setup, in order for us to publish TxReclaim /// in case of a refund. Otherwise Bob will only be partially refunded. #[serde(default)] - tx_refund_amnesty_sig_bob: Option, + tx_reclaim_sig_bob: Option, tx_redeem_fee: bitcoin::Amount, pub tx_punish_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, #[serde(default)] pub tx_partial_refund_fee: Option, #[serde(default)] - pub tx_refund_amnesty_fee: Option, + pub tx_reclaim_fee: Option, #[serde(default)] - pub tx_refund_burn_fee: Option, + pub tx_withhold_fee: Option, #[serde(default)] - pub tx_final_amnesty_fee: Option, + pub tx_mercy_fee: Option, pub tx_cancel_fee: bitcoin::Amount, #[serde(default)] - tx_refund_burn_sig_bob: Option, + tx_withhold_sig_bob: Option, #[serde(default)] - tx_final_amnesty_sig_bob: Option, - /// Whether Alice should publish TxRefundBurn to deny Bob's amnesty. + tx_mercy_sig_bob: Option, + /// Whether Alice should publish TxWithhold to deny Bob's amnesty. /// None = no decision yet (legacy swaps or awaiting controller input) /// Some(false) = don't burn (default for new swaps) - /// Some(true) = burn the amnesty output + /// Some(true) = withhold the amnesty output #[serde(default)] - pub should_publish_tx_refund_burn: Option, + pub should_publish_tx_withhold: Option, } impl State3 { @@ -918,8 +918,8 @@ impl State3 { let tx_amnesty = TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee - .context("Missing tx_refund_amnesty_fee")?, + self.tx_reclaim_fee + .context("Missing tx_reclaim_fee")?, self.remaining_refund_timelock .context("Missing remaining_refund_timelock")?, )?; @@ -927,61 +927,61 @@ impl State3 { tx_amnesty.complete_as_alice( self.a.clone(), self.B, - self.tx_refund_amnesty_sig_bob + self.tx_reclaim_sig_bob .clone() - .context("missing Bob's signature for TxRefundAmnesty")?, + .context("missing Bob's signature for TxReclaim")?, ) } - /// Check if we have Bob's signature for TxRefundBurn. - pub fn has_tx_refund_burn_sig(&self) -> bool { - self.tx_refund_burn_sig_bob.is_some() + /// Check if we have Bob's signature for TxWithhold. + pub fn has_tx_withhold_sig(&self) -> bool { + self.tx_withhold_sig_bob.is_some() } - /// Construct TxRefundBurn from tx_partial_refund output. - pub fn tx_refund_burn(&self) -> Result { + /// Construct TxWithhold from tx_partial_refund output. + pub fn tx_withhold(&self) -> Result { TxWithhold::new( &self.tx_partial_refund()?, self.a.public(), self.B, - self.tx_refund_burn_fee - .context("Missing tx_refund_burn_fee")?, + self.tx_withhold_fee + .context("Missing tx_withhold_fee")?, ) } - /// Construct signed TxRefundBurn using Alice's key and Bob's presigned signature. - pub fn signed_refund_burn_transaction(&self) -> Result { - let tx_refund_burn = self.tx_refund_burn()?; + /// Construct signed TxWithhold using Alice's key and Bob's presigned signature. + pub fn signed_withhold_transaction(&self) -> Result { + let tx_withhold = self.tx_withhold()?; - tx_refund_burn.complete_as_alice( + tx_withhold.complete_as_alice( self.a.clone(), self.B, - self.tx_refund_burn_sig_bob + self.tx_withhold_sig_bob .clone() - .context("missing Bob's signature for TxRefundBurn")?, + .context("missing Bob's signature for TxWithhold")?, ) } - /// Construct TxFinalAmnesty from tx_refund_burn output. - pub fn tx_final_amnesty(&self) -> Result { + /// Construct TxMercy from tx_withhold output. + pub fn tx_mercy(&self) -> Result { Ok(TxMercy::new( - &self.tx_refund_burn()?, + &self.tx_withhold()?, &self.refund_address, - self.tx_final_amnesty_fee - .context("Missing tx_final_amnesty_fee")?, + self.tx_mercy_fee + .context("Missing tx_mercy_fee")?, )) } - /// Construct signed TxFinalAmnesty using Alice's key and Bob's presigned signature. - pub fn signed_final_amnesty_transaction(&self) -> Result { - let tx_final_amnesty = self.tx_final_amnesty()?; + /// Construct signed TxMercy using Alice's key and Bob's presigned signature. + pub fn signed_mercy_transaction(&self) -> Result { + let tx_mercy = self.tx_mercy()?; - tx_final_amnesty.complete_as_alice( + tx_mercy.complete_as_alice( self.a.clone(), self.B, - self.tx_final_amnesty_sig_bob + self.tx_mercy_sig_bob .clone() - .context("missing Bob's signature for TxFinalAmnesty")?, + .context("missing Bob's signature for TxMercy")?, ) } diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 6f36f1e1c1..3328a58a8c 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -79,19 +79,19 @@ pub enum BobState { BtcEarlyRefunded(State6), BtcPartiallyRefunded(State6), /// Waiting for RemainingRefundTimelock to expire after partial refund confirmed. - /// During this time, Alice may publish TxRefundBurn. + /// During this time, Alice may publish TxWithhold. WaitingForReclaimTimelockExpiration(State6), - /// RemainingRefundTimelock has expired, we can now publish TxRefundAmnesty. + /// RemainingRefundTimelock has expired, we can now publish TxReclaim. ReclaimTimelockExpired(State6), - /// Alice published TxRefundBurn before we could publish TxRefundAmnesty. + /// Alice published TxWithhold before we could publish TxReclaim. BtcWithholdPublished(State6), - /// TxRefundBurn has been confirmed. The amnesty output is now burnt. + /// TxWithhold has been confirmed. The amnesty output is now burnt. BtcWithheld(State6), BtcReclaimPublished(State6), BtcReclaimConfirmed(State6), - /// Alice published TxFinalAmnesty (using our presigned signature) to refund us. + /// Alice published TxMercy (using our presigned signature) to refund us. BtcMercyPublished(State6), - /// TxFinalAmnesty has been confirmed. We received the burnt funds back. + /// TxMercy has been confirmed. We received the burnt funds back. BtcMercyConfirmed(State6), XmrRedeemed { tx_lock_id: bitcoin::Txid, @@ -121,7 +121,7 @@ pub enum RefundSignatures { /// Includes the amnesty signature which is always provided in new swaps. Partial { tx_partial_refund_encsig: bitcoin::EncryptedSignature, - tx_refund_amnesty_sig: bitcoin::Signature, + tx_reclaim_sig: bitcoin::Signature, }, /// Alice has signed both the partial and full refund transactions. /// Includes the amnesty signature which is always provided in new swaps. @@ -130,7 +130,7 @@ pub enum RefundSignatures { // Serde rename keeps + untagged + flatten keeps this backwards compatible with old swaps in the database. #[serde(rename = "tx_refund_encsig")] tx_full_refund_encsig: bitcoin::EncryptedSignature, - tx_refund_amnesty_sig: bitcoin::Signature, + tx_reclaim_sig: bitcoin::Signature, }, /// Alice has only signed the full refund transaction. /// This is only used to maintain backwards compatibility for older swaps @@ -191,13 +191,13 @@ impl fmt::Display for BobState { BobState::ReclaimTimelockExpired { .. } => { write!(f, "remaining refund timelock expired") } - BobState::BtcWithholdPublished { .. } => write!(f, "btc refund burn is published"), - BobState::BtcWithheld { .. } => write!(f, "btc refund is burnt"), + BobState::BtcWithholdPublished { .. } => write!(f, "btc withhold is published"), + BobState::BtcWithheld { .. } => write!(f, "btc is withheld"), BobState::BtcMercyPublished { .. } => { - write!(f, "btc final amnesty is published") + write!(f, "btc mercy is published") } BobState::BtcMercyConfirmed { .. } => { - write!(f, "btc final amnesty is confirmed") + write!(f, "btc mercy is confirmed") } BobState::SafelyAborted => write!(f, "safely aborted"), } @@ -291,8 +291,8 @@ pub struct State0 { refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_mercy_fee: Option, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -311,8 +311,8 @@ impl State0 { refund_address: bitcoin::Address, min_monero_confirmations: u64, tx_partial_refund_fee: bitcoin::Amount, - tx_refund_amnesty_fee: bitcoin::Amount, - tx_final_amnesty_fee: bitcoin::Amount, + tx_reclaim_fee: bitcoin::Amount, + tx_mercy_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_cancel_fee: bitcoin::Amount, tx_lock_fee: bitcoin::Amount, @@ -341,8 +341,8 @@ impl State0 { refund_address, min_monero_confirmations, tx_partial_refund_fee: Some(tx_partial_refund_fee), - tx_refund_amnesty_fee: Some(tx_refund_amnesty_fee), - tx_final_amnesty_fee: Some(tx_final_amnesty_fee), + tx_reclaim_fee: Some(tx_reclaim_fee), + tx_mercy_fee: Some(tx_mercy_fee), tx_refund_fee, tx_cancel_fee, tx_lock_fee, @@ -362,12 +362,12 @@ impl State0 { tx_partial_refund_fee: self .tx_partial_refund_fee .context("tx_partial_refund_fee missing but required to setup swap")?, - tx_refund_amnesty_fee: self - .tx_refund_amnesty_fee - .context("tx_refund_amnesty_fee missing but required to setup swap")?, - tx_final_amnesty_fee: self - .tx_final_amnesty_fee - .context("tx_final_amnesty_fee missing but required to setup swap")?, + tx_reclaim_fee: self + .tx_reclaim_fee + .context("tx_reclaim_fee missing but required to setup swap")?, + tx_mercy_fee: self + .tx_mercy_fee + .context("tx_mercy_fee missing but required to setup swap")?, tx_cancel_fee: self.tx_cancel_fee, }) } @@ -390,20 +390,20 @@ impl State0 { let tx_partial_refund_fee = self .tx_partial_refund_fee .context("tx_partial_refund_fee missing for new swap")?; - let tx_refund_amnesty_fee = self - .tx_refund_amnesty_fee - .context("tx_refund_amnesty_fee missing for new swap")?; - let tx_final_amnesty_fee = self - .tx_final_amnesty_fee - .context("tx_final_amnesty_fee missing for new swap")?; + let tx_reclaim_fee = self + .tx_reclaim_fee + .context("tx_reclaim_fee missing for new swap")?; + let tx_mercy_fee = self + .tx_mercy_fee + .context("tx_mercy_fee missing for new swap")?; crate::common::sanity_check_amnesty_amount( self.btc, msg.amnesty_amount, tx_partial_refund_fee, - tx_refund_amnesty_fee, - msg.tx_refund_burn_fee, - tx_final_amnesty_fee, + tx_reclaim_fee, + msg.tx_withhold_fee, + tx_mercy_fee, )?; } @@ -438,9 +438,9 @@ impl State0 { tx_redeem_fee: msg.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: Some(msg.tx_refund_burn_fee), - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: Some(msg.tx_withhold_fee), + tx_mercy_fee: self.tx_mercy_fee, tx_punish_fee: msg.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -467,9 +467,9 @@ pub struct State1 { tx_lock: bitcoin::TxLock, min_monero_confirmations: u64, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_punish_fee: bitcoin::Amount, @@ -496,7 +496,7 @@ impl State1 { let refund_signatures = match ( msg.tx_full_refund_encsig, msg.tx_partial_refund_encsig, - msg.tx_refund_amnesty_sig, + msg.tx_reclaim_sig, ) { // We got the encrypted signature for the full refund - awesome (Some(tx_full_refund_encsig), _, _) => { @@ -515,7 +515,7 @@ impl State1 { } } // We got the encrypted signatures for the partial refund path. - (None, Some(tx_partial_refund_encsig), Some(tx_refund_amnesty_sig)) => { + (None, Some(tx_partial_refund_encsig), Some(tx_reclaim_sig)) => { let tx_partial_refund = TxPartialRefund::new( &tx_cancel, &self.refund_address, @@ -533,19 +533,19 @@ impl State1 { &tx_partial_refund_encsig, )?; - let tx_refund_amnesty = TxReclaim::new( + let tx_reclaim = TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee - .context("missing tx_refund_amnesty_fee")?, + self.tx_reclaim_fee + .context("missing tx_reclaim_fee")?, self.remaining_refund_timelock .context("missing remaining_refund_timelock")?, )?; - bitcoin::verify_sig(&self.A, &tx_refund_amnesty.digest(), &tx_refund_amnesty_sig)?; + bitcoin::verify_sig(&self.A, &tx_reclaim.digest(), &tx_reclaim_sig)?; RefundSignatures::Partial { tx_partial_refund_encsig, - tx_refund_amnesty_sig, + tx_reclaim_sig, } } (_, _, _) => anyhow::bail!( @@ -575,9 +575,9 @@ impl State1 { tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, tx_punish_fee: self.tx_punish_fee, tx_cancel_fee: self.tx_cancel_fee, }) @@ -617,9 +617,9 @@ pub struct State2 { pub tx_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, } impl State2 { @@ -648,10 +648,10 @@ impl State2 { let tx_early_refund_sig = self.b.sign(tx_early_refund.digest()); - // We can only construct a valid TxRefundAmnesty/TxRefundBurn/TxFinalAmnesty when the amnesty amount + // We can only construct a valid TxReclaim/TxWithhold/TxMercy when the amnesty amount // is greater than zero. Thus we only send our signatures for them if that is the case. // Alice accepts this because she sent us her signature for TxFullRefund already anyway. - let (tx_refund_amnesty_sig, tx_refund_burn_sig, tx_final_amnesty_sig) = + let (tx_reclaim_sig, tx_withhold_sig, tx_mercy_sig) = if self.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO) == bitcoin::Amount::ZERO { (None, None, None) } else { @@ -666,37 +666,37 @@ impl State2 { .context("missing tx_partial_refund_fee")?, ) .context("Couldn't construct TxPartialRefund")?; - let tx_refund_amnesty = TxReclaim::new( + let tx_reclaim = TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee - .context("Missing tx_refund_amnesty_fee")?, + self.tx_reclaim_fee + .context("Missing tx_reclaim_fee")?, self.remaining_refund_timelock .context("missing remaining_refund_timelock")?, )?; - let tx_refund_amnesty_sig = self.b.sign(tx_refund_amnesty.digest()); + let tx_reclaim_sig = self.b.sign(tx_reclaim.digest()); - let tx_refund_burn = TxWithhold::new( + let tx_withhold = TxWithhold::new( &tx_partial_refund, self.A, self.b.public(), - self.tx_refund_burn_fee - .context("Missing tx_refund_burn_fee")?, + self.tx_withhold_fee + .context("Missing tx_withhold_fee")?, )?; - let tx_refund_burn_sig = self.b.sign(tx_refund_burn.digest()); + let tx_withhold_sig = self.b.sign(tx_withhold.digest()); - let tx_final_amnesty = TxMercy::new( - &tx_refund_burn, + let tx_mercy = TxMercy::new( + &tx_withhold, &self.refund_address, - self.tx_final_amnesty_fee - .context("Missing tx_final_amnesty_fee")?, + self.tx_mercy_fee + .context("Missing tx_mercy_fee")?, ); - let tx_final_amnesty_sig = self.b.sign(tx_final_amnesty.digest()); + let tx_mercy_sig = self.b.sign(tx_mercy.digest()); ( - Some(tx_refund_amnesty_sig), - Some(tx_refund_burn_sig), - Some(tx_final_amnesty_sig), + Some(tx_reclaim_sig), + Some(tx_withhold_sig), + Some(tx_mercy_sig), ) }; @@ -704,9 +704,9 @@ impl State2 { tx_punish_sig, tx_cancel_sig, tx_early_refund_sig, - tx_refund_amnesty_sig, - tx_refund_burn_sig, - tx_final_amnesty_sig, + tx_reclaim_sig, + tx_withhold_sig, + tx_mercy_sig, }) } @@ -733,9 +733,9 @@ impl State2 { tx_redeem_fee: self.tx_redeem_fee, tx_refund_fee: self.tx_refund_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, tx_cancel_fee: self.tx_cancel_fee, }, self.tx_lock, @@ -774,9 +774,9 @@ pub struct State3 { tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -821,9 +821,9 @@ impl State3 { tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, } } @@ -844,9 +844,9 @@ impl State3 { tx_refund_fee: self.tx_refund_fee, tx_cancel_fee: self.tx_cancel_fee, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, xmr: self.xmr, btc_amnesty_amount: self.btc_amnesty_amount, } @@ -955,9 +955,9 @@ pub struct State4 { tx_redeem_fee: bitcoin::Amount, tx_refund_fee: bitcoin::Amount, tx_partial_refund_fee: Option, - tx_refund_amnesty_fee: Option, - tx_refund_burn_fee: Option, - tx_final_amnesty_fee: Option, + tx_reclaim_fee: Option, + tx_withhold_fee: Option, + tx_mercy_fee: Option, tx_cancel_fee: bitcoin::Amount, } @@ -1081,9 +1081,9 @@ impl State4 { xmr: self.xmr, btc_amnesty_amount: self.btc_amnesty_amount, tx_partial_refund_fee: self.tx_partial_refund_fee, - tx_refund_amnesty_fee: self.tx_refund_amnesty_fee, - tx_refund_burn_fee: self.tx_refund_burn_fee, - tx_final_amnesty_fee: self.tx_final_amnesty_fee, + tx_reclaim_fee: self.tx_reclaim_fee, + tx_withhold_fee: self.tx_withhold_fee, + tx_mercy_fee: self.tx_mercy_fee, } } @@ -1146,9 +1146,9 @@ pub struct State6 { pub tx_refund_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, pub tx_partial_refund_fee: Option, - pub tx_refund_amnesty_fee: Option, - pub tx_refund_burn_fee: Option, - pub tx_final_amnesty_fee: Option, + pub tx_reclaim_fee: Option, + pub tx_withhold_fee: Option, + pub tx_mercy_fee: Option, } impl State6 { @@ -1327,7 +1327,7 @@ impl State6 { pub fn signed_amnesty_transaction(&self) -> Result { let tx_amnesty = self.construct_tx_amnesty()?; - let sig_a = self.refund_signatures.tx_refund_amnesty_sig().context( + let sig_a = self.refund_signatures.tx_reclaim_sig().context( "Can't sign amnesty transaction because Alice's amnesty signature is missing", )?; let sig_b = self.b.sign(tx_amnesty.digest()); @@ -1344,33 +1344,33 @@ impl State6 { bitcoin::TxReclaim::new( &tx_partial_refund, &self.refund_address, - self.tx_refund_amnesty_fee.context( - "Can't construct TxRefundAmnesty because tx_refund_amnesty_fee is missing", + self.tx_reclaim_fee.context( + "Can't construct TxReclaim because tx_reclaim_fee is missing", )?, self.remaining_refund_timelock.context( - "Can't construct TxRefundAmnesty because remaining_refund_timelock is missing", + "Can't construct TxReclaim because remaining_refund_timelock is missing", )?, ) } - pub fn construct_tx_refund_burn(&self) -> Result { + pub fn construct_tx_withhold(&self) -> Result { let tx_partial_refund = self.construct_tx_partial_refund()?; bitcoin::TxWithhold::new( &tx_partial_refund, self.A, self.b.public(), - self.tx_refund_burn_fee - .context("Can't construct TxRefundBurn because tx_refund_burn_fee is missing")?, + self.tx_withhold_fee + .context("Can't construct TxWithhold because tx_withhold_fee is missing")?, ) } - pub fn construct_tx_final_amnesty(&self) -> Result { - let tx_refund_burn = self.construct_tx_refund_burn()?; + pub fn construct_tx_mercy(&self) -> Result { + let tx_withhold = self.construct_tx_withhold()?; Ok(bitcoin::TxMercy::new( - &tx_refund_burn, + &tx_withhold, &self.refund_address, - self.tx_final_amnesty_fee.context( - "Can't construct TxFinalAmnesty because tx_final_amnesty_fee is missing", + self.tx_mercy_fee.context( + "Can't construct TxMercy because tx_mercy_fee is missing", )?, )) } @@ -1422,18 +1422,18 @@ impl RefundSignatures { pub fn from_possibly_full_refund_sig( partial_refund_encsig: bitcoin::EncryptedSignature, full_refund_encsig: Option, - refund_amnesty_sig: bitcoin::Signature, + reclaim_sig: bitcoin::Signature, ) -> Self { if let Some(full_refund_encsig) = full_refund_encsig { Self::Full { tx_partial_refund_encsig: partial_refund_encsig, tx_full_refund_encsig: full_refund_encsig, - tx_refund_amnesty_sig: refund_amnesty_sig, + tx_reclaim_sig: reclaim_sig, } } else { Self::Partial { tx_partial_refund_encsig: partial_refund_encsig, - tx_refund_amnesty_sig: refund_amnesty_sig, + tx_reclaim_sig: reclaim_sig, } } } @@ -1467,16 +1467,16 @@ impl RefundSignatures { /// Returns Alice's signature for the amnesty transaction. /// Only available for new swaps (Partial/Full variants), not Legacy swaps. - pub fn tx_refund_amnesty_sig(&self) -> Option { + pub fn tx_reclaim_sig(&self) -> Option { match self { RefundSignatures::Partial { - tx_refund_amnesty_sig, + tx_reclaim_sig, .. - } => Some(tx_refund_amnesty_sig.clone()), + } => Some(tx_reclaim_sig.clone()), RefundSignatures::Full { - tx_refund_amnesty_sig, + tx_reclaim_sig, .. - } => Some(tx_refund_amnesty_sig.clone()), + } => Some(tx_reclaim_sig.clone()), RefundSignatures::Legacy { .. } => None, } } diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index bfcee84df8..f6f7c6a71f 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -38,9 +38,9 @@ pub struct Message0 { pub refund_address: bitcoin::Address, pub tx_refund_fee: bitcoin::Amount, pub tx_partial_refund_fee: bitcoin::Amount, - pub tx_refund_amnesty_fee: bitcoin::Amount, + pub tx_reclaim_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, - pub tx_final_amnesty_fee: bitcoin::Amount, + pub tx_mercy_fee: bitcoin::Amount, } #[allow(non_snake_case)] @@ -60,7 +60,7 @@ pub struct Message1 { /// The amount of Bitcoin that Bob not get refunded unless Alice decides so. /// Introduced in [#675](https://github.com/eigenwallet/core/pull/675) to combat spam. pub amnesty_amount: bitcoin::Amount, - pub tx_refund_burn_fee: bitcoin::Amount, + pub tx_withhold_fee: bitcoin::Amount, } #[allow(non_snake_case)] @@ -78,7 +78,7 @@ pub struct Message3 { // and tx refund amnesty. pub tx_full_refund_encsig: Option, pub tx_partial_refund_encsig: Option, - pub tx_refund_amnesty_sig: Option, + pub tx_reclaim_sig: Option, } #[allow(non_snake_case)] @@ -87,9 +87,9 @@ pub struct Message4 { pub tx_punish_sig: bitcoin::Signature, pub tx_cancel_sig: bitcoin::Signature, pub tx_early_refund_sig: bitcoin::Signature, - pub tx_refund_amnesty_sig: Option, - pub tx_refund_burn_sig: Option, - pub tx_final_amnesty_sig: Option, + pub tx_reclaim_sig: Option, + pub tx_withhold_sig: Option, + pub tx_mercy_sig: Option, } /// Validates that a proposed transaction fee is between diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 53427b7c7e..c0560e4078 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -55,7 +55,7 @@ pub struct WalletSnapshot { redeem_fee: bitcoin::Amount, punish_fee: bitcoin::Amount, - refund_burn_fee: bitcoin::Amount, + withhold_fee: bitcoin::Amount, } impl WalletSnapshot { @@ -65,7 +65,7 @@ impl WalletSnapshot { punish_address: bitcoin::Address, redeem_fee: bitcoin::Amount, punish_fee: bitcoin::Amount, - refund_burn_fee: bitcoin::Amount, + withhold_fee: bitcoin::Amount, ) -> Self { Self { unlocked_balance, @@ -74,7 +74,7 @@ impl WalletSnapshot { punish_address, redeem_fee, punish_fee, - refund_burn_fee, + withhold_fee, } } } @@ -544,7 +544,7 @@ async fn run_swap_setup( wallet_snapshot.punish_address, wallet_snapshot.redeem_fee, wallet_snapshot.punish_fee, - wallet_snapshot.refund_burn_fee, + wallet_snapshot.withhold_fee, should_burn_on_refund, &mut rand::thread_rng(), ); diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 245d11bb22..db0db74b82 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -330,8 +330,8 @@ pub struct NewSwap { pub tx_lock_fee: bitcoin::Amount, pub tx_refund_fee: bitcoin::Amount, pub tx_partial_refund_fee: bitcoin::Amount, - pub tx_refund_amnesty_fee: bitcoin::Amount, - pub tx_final_amnesty_fee: bitcoin::Amount, + pub tx_reclaim_fee: bitcoin::Amount, + pub tx_mercy_fee: bitcoin::Amount, pub tx_cancel_fee: bitcoin::Amount, pub bitcoin_refund_address: bitcoin::Address, } @@ -576,8 +576,8 @@ async fn run_swap_setup( new_swap_request.bitcoin_refund_address.clone(), env_config.monero_finality_confirmations, new_swap_request.tx_partial_refund_fee, - new_swap_request.tx_refund_amnesty_fee, - new_swap_request.tx_final_amnesty_fee, + new_swap_request.tx_reclaim_fee, + new_swap_request.tx_mercy_fee, new_swap_request.tx_refund_fee, new_swap_request.tx_cancel_fee, new_swap_request.tx_lock_fee, diff --git a/swap/src/asb.rs b/swap/src/asb.rs index 2457de7e69..12f958b1ff 100644 --- a/swap/src/asb.rs +++ b/swap/src/asb.rs @@ -11,7 +11,7 @@ pub use recovery::cancel::cancel; pub use recovery::punish::punish; pub use recovery::redeem::{redeem, Finality}; pub use recovery::refund::refund; -pub use recovery::grant_final_amnesty::grant_final_amnesty; +pub use recovery::grant_mercy::grant_mercy; pub use recovery::safely_abort::safely_abort; pub use recovery::{cancel, refund}; pub use swap_feed::{ExchangeRate, FixedRate, LatestRate, Rate}; diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 4e8957a032..a72add2440 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -259,7 +259,7 @@ where }; // TODO: propagate error to the swap_setup routine instead of swallowing it - let (btc_amnesty_amount, should_publish_tx_refund_burn )= match apply_anti_spam_policy(btc, &self.refund_policy) { + let (btc_amnesty_amount, should_publish_tx_withhold )= match apply_anti_spam_policy(btc, &self.refund_policy) { Ok(amount) => amount, Err(error) => { tracing::error!("Swap request will be ignored because we were unable to create wallet snapshot for swap: {:#}", error); @@ -276,7 +276,7 @@ where }; // Ignore result, we should never hit this because the receiver will alive as long as the connection is. - let _ = responder.respond((wallet_snapshot, btc_amnesty_amount, should_publish_tx_refund_burn)); + let _ = responder.respond((wallet_snapshot, btc_amnesty_amount, should_publish_tx_withhold)); } SwarmEvent::Behaviour(OutEvent::SwapSetupCompleted{peer_id, swap_id, state3}) => { if let Err(error) = self.handle_execution_setup_done(peer_id, swap_id, state3).await { @@ -569,8 +569,8 @@ where }; let _ = respond_to.send(result); } - EventLoopRequest::GrantFinalAmnesty { swap_id, respond_to } => { - let result = self.handle_grant_final_amnesty(swap_id).await; + EventLoopRequest::GrantMercy { swap_id, respond_to } => { + let result = self.handle_grant_mercy(swap_id).await; let _ = respond_to.send(result); } } @@ -730,25 +730,25 @@ where } } - /// Handle a request to grant final amnesty for a swap. + /// Handle a request to grant mercy for a swap. /// /// This checks that the swap is not currently running, transitions the - /// state to BtcFinalAmnestyGranted, and resumes the swap. - async fn handle_grant_final_amnesty(&mut self, swap_id: Uuid) -> Result<()> { - use crate::asb::grant_final_amnesty; + /// state to BtcMercyGranted, and resumes the swap. + async fn handle_grant_mercy(&mut self, swap_id: Uuid) -> Result<()> { + use crate::asb::grant_mercy; // Check if swap is currently running if self.recv_encrypted_signature.contains_key(&swap_id) || self.recv_burn_on_refund_instruction.contains_key(&swap_id) { return Err(anyhow!( - "Cannot grant final amnesty while swap {} is still running", + "Cannot grant mercy while swap {} is still running", swap_id )); } - // Use the grant_final_amnesty function to transition the state - let new_state = grant_final_amnesty(swap_id, self.db.clone()).await?; + // Use the grant_mercy function to transition the state + let new_state = grant_mercy(swap_id, self.db.clone()).await?; // Get peer ID for this swap let peer_id = self.db.get_peer_id(swap_id).await?; @@ -772,7 +772,7 @@ where .await .context("Failed to send swap to be resumed")?; - tracing::info!(%swap_id, "Granted final amnesty and resumed swap"); + tracing::info!(%swap_id, "Granted mercy and resumed swap"); Ok(()) } @@ -995,7 +995,7 @@ async fn capture_wallet_snapshot( let punish_fee = bitcoin_wallet .estimate_fee(bitcoin::TxPunish::weight(), Some(transfer_amount)) .await?; - let refund_burn_fee = bitcoin_wallet + let withhold_fee = bitcoin_wallet .estimate_fee(bitcoin::TxWithhold::weight(), Some(transfer_amount)) .await?; @@ -1005,7 +1005,7 @@ async fn capture_wallet_snapshot( punish_address, redeem_fee, punish_fee, - refund_burn_fee, + withhold_fee, )) } @@ -1031,7 +1031,7 @@ mod service { burn: bool, respond_to: oneshot::Sender>, }, - GrantFinalAmnesty { + GrantMercy { swap_id: Uuid, respond_to: oneshot::Sender>, }, @@ -1098,14 +1098,14 @@ mod service { .map_err(|_| anyhow::anyhow!("EventLoop service did not respond"))? } - /// Grant final amnesty for a swap in BtcRefundBurnConfirmed state + /// Grant mercy for a swap in BtcWithholdConfirmed state /// - /// This transitions the swap to BtcFinalAmnestyGranted and resumes - /// the swap state machine to publish the final amnesty transaction. + /// This transitions the swap to BtcMercyGranted and resumes + /// the swap state machine to publish the mercy transaction. pub async fn grant_mercy(&self, swap_id: Uuid) -> anyhow::Result<()> { let (tx, rx) = oneshot::channel(); self.sender - .send(EventLoopRequest::GrantFinalAmnesty { + .send(EventLoopRequest::GrantMercy { swap_id, respond_to: tx, }) diff --git a/swap/src/asb/recovery.rs b/swap/src/asb/recovery.rs index e730f77110..858c09704b 100644 --- a/swap/src/asb/recovery.rs +++ b/swap/src/asb/recovery.rs @@ -1,5 +1,5 @@ pub mod cancel; -pub mod grant_final_amnesty; +pub mod grant_mercy; pub mod punish; pub mod redeem; pub mod refund; diff --git a/swap/src/asb/recovery/grant_final_amnesty.rs b/swap/src/asb/recovery/grant_mercy.rs similarity index 81% rename from swap/src/asb/recovery/grant_final_amnesty.rs rename to swap/src/asb/recovery/grant_mercy.rs index 4f5b898607..c9d7585a74 100644 --- a/swap/src/asb/recovery/grant_final_amnesty.rs +++ b/swap/src/asb/recovery/grant_mercy.rs @@ -5,7 +5,7 @@ use std::convert::TryInto; use std::sync::Arc; use uuid::Uuid; -pub async fn grant_final_amnesty( +pub async fn grant_mercy( swap_id: Uuid, db: Arc, ) -> Result { @@ -21,7 +21,7 @@ pub async fn grant_final_amnesty( Ok(new_state) } _ => bail!( - "Cannot grant final amnesty for swap {} because it is in state {} which is not BtcRefundBurnConfirmed", + "Cannot grant mercy for swap {} because it is in state {} which is not BtcWithholdConfirmed", swap_id, state ), diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 64f312f7b2..630234cddc 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -1159,37 +1159,37 @@ pub enum TauriSwapProgressEvent { #[typeshare(serialized_as = "number")] btc_amnesty_amount: bitcoin::Amount, }, - // TxRefundBurn has been published (waiting for confirmation) - BtcRefundBurnPublished { + // TxWithhold has been published (waiting for confirmation) + BtcWithholdPublished { #[typeshare(serialized_as = "string")] - btc_refund_burn_txid: Txid, + btc_withhold_txid: Txid, #[typeshare(serialized_as = "number")] btc_lock_amount: bitcoin::Amount, #[typeshare(serialized_as = "number")] btc_amnesty_amount: bitcoin::Amount, }, - // TxRefundBurn has been confirmed - amnesty output is burnt - BtcRefundBurnt { + // TxWithhold has been confirmed - amnesty output is withheld + BtcWithheld { #[typeshare(serialized_as = "string")] - btc_refund_burn_txid: Txid, + btc_withhold_txid: Txid, #[typeshare(serialized_as = "number")] btc_lock_amount: bitcoin::Amount, #[typeshare(serialized_as = "number")] btc_amnesty_amount: bitcoin::Amount, }, - // Alice published TxFinalAmnesty - BtcFinalAmnestyPublished { + // Alice published TxMercy + BtcMercyPublished { #[typeshare(serialized_as = "string")] - btc_final_amnesty_txid: Txid, + btc_mercy_txid: Txid, #[typeshare(serialized_as = "number")] btc_lock_amount: bitcoin::Amount, #[typeshare(serialized_as = "number")] btc_amnesty_amount: bitcoin::Amount, }, - // TxFinalAmnesty has been confirmed - user received burnt funds back - BtcFinalAmnestyConfirmed { + // TxMercy has been confirmed - user received withheld funds back + BtcMercyConfirmed { #[typeshare(serialized_as = "string")] - btc_final_amnesty_txid: Txid, + btc_mercy_txid: Txid, #[typeshare(serialized_as = "number")] btc_lock_amount: bitcoin::Amount, #[typeshare(serialized_as = "number")] diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 252671e529..19aa8d3b67 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -160,7 +160,7 @@ pub async fn cancel( )); } Ok(ExpiredTimelocks::RemainingRefund) => { - bail!(err.context("Cannot cancel swap because we are in the partial refund phase. TxRefundAmnesty can be published.")); + bail!(err.context("Cannot cancel swap because we are in the partial refund phase. TxReclaim can be published.")); } Err(timelock_err) => { bail!(err @@ -307,9 +307,9 @@ pub async fn refund( ); } Ok(ExpiredTimelocks::RemainingRefund) => { - // TODO: Try to publish TxRefundAmnesty here instead of just reporting the state + // TODO: Try to publish TxReclaim here instead of just reporting the state bail!(bitcoin_publication_err.context( - "Amnesty timelock has expired. TxRefundAmnesty can be published." + "Amnesty timelock has expired. TxReclaim can be published." )); } Err(e) => { diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index b2f5a5cbfe..67c6faed44 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -428,7 +428,7 @@ where burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { let burn = burn_instruction.context("Failed to receive burn instruction")?; let mut updated_state3 = (*state3).clone(); - updated_state3.should_publish_tx_refund_burn = Some(burn); + updated_state3.should_publish_tx_withhold = Some(burn); AliceState::XmrLockTransferProofSent { monero_wallet_restore_blockheight, @@ -566,7 +566,7 @@ where burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { let burn = burn_instruction.context("Failed to receive burn instruction")?; let mut updated_state3 = (*state3).clone(); - updated_state3.should_publish_tx_refund_burn = Some(burn); + updated_state3.should_publish_tx_withhold = Some(burn); AliceState::WaitingForCancelTimelockExpiration { monero_wallet_restore_blockheight, @@ -673,7 +673,7 @@ where burn_instruction = event_loop_handle.wait_for_burn_on_refund_instruction() => { let burn = burn_instruction.context("Failed to receive burn instruction")?; let mut updated_state3 = (*state3).clone(); - updated_state3.should_publish_tx_refund_burn = Some(burn); + updated_state3.should_publish_tx_withhold = Some(burn); AliceState::BtcCancelled { monero_wallet_restore_blockheight, @@ -700,9 +700,9 @@ where state3, monero_wallet_restore_blockheight, } => { - // Bob has the pre-signed TxRefundAmnesty from swap setup and can + // Bob has the pre-signed TxReclaim from swap setup and can // publish it himself after the remaining refund timelock expires. - // TODO: implement system for publishing TxRefundBurn at this point + // TODO: implement system for publishing TxWithhold at this point AliceState::XmrRefundable { monero_wallet_restore_blockheight, transfer_proof, @@ -775,7 +775,7 @@ where .expect("We should never run out of retries while publishing the punish transaction") } AliceState::XmrRefunded { state3 } => { - // Only publish TxRefundBurn + // Only publish TxWithhold let Some(mut state3) = state3 else { tracing::info!( "Running a pre-partial refund swap, there is no amnesty output to burn" @@ -785,72 +785,72 @@ where // Fetch the burn decision, if it was made via the controller if let Some(burn_decision) = event_loop_handle.get_burn_on_refund_instruction().await { - state3.should_publish_tx_refund_burn = Some(burn_decision); + state3.should_publish_tx_withhold = Some(burn_decision); } - if !state3.should_publish_tx_refund_burn.unwrap_or(false) { + if !state3.should_publish_tx_withhold.unwrap_or(false) { tracing::info!("Not instructed to partially burn the takers refund. Finishing"); return Ok(AliceState::XmrRefunded { state3: Some(state3), }); } - let signed_tx = state3.signed_refund_burn_transaction().context("Can't burn the amnesty output after Bob refunded because we couldn't construct the ")?; + let signed_tx = state3.signed_withhold_transaction().context("Can't withhold the amnesty output after Bob refunded because we couldn't construct the transaction")?; bitcoin_wallet - .ensure_broadcasted(signed_tx, "refund_burn") + .ensure_broadcasted(signed_tx, "withhold") .await - .context("Couldn't publish TxRefundBurn")?; + .context("Couldn't publish TxWithhold")?; AliceState::BtcWithholdPublished { state3 } } AliceState::BtcWithholdPublished { state3 } => { - let tx_refund_burn = state3 - .tx_refund_burn() - .context("Can't construct TxRefundBurn even though we published it")?; + let tx_withhold = state3 + .tx_withhold() + .context("Can't construct TxWithhold even though we published it")?; - let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_withhold)).await; subscription .wait_until_final() .await - .context("Failed to wait for TxRefundBurn to be confirmed")?; + .context("Failed to wait for TxWithhold to be confirmed")?; AliceState::BtcWithholdConfirmed { state3 } } AliceState::BtcWithholdConfirmed { state3 } => { - // Nothing to do here. Final amnesty is triggered manually. + // Nothing to do here. Mercy is triggered manually. AliceState::BtcWithholdConfirmed { state3 } } AliceState::BtcMercyGranted { state3 } => { - // Operator has decided to grant final amnesty to Bob + // Operator has decided to grant mercy to Bob let signed_tx = state3 - .signed_final_amnesty_transaction() - .context("Failed to construct signed TxFinalAmnesty")?; + .signed_mercy_transaction() + .context("Failed to construct signed TxMercy")?; bitcoin_wallet - .ensure_broadcasted(signed_tx, "final_amnesty") + .ensure_broadcasted(signed_tx, "mercy") .await - .context("Failed to publish TxFinalAmnesty")?; + .context("Failed to publish TxMercy")?; - tracing::info!("TxFinalAmnesty published successfully"); + tracing::info!("TxMercy published successfully"); AliceState::BtcMercyPublished { state3 } } AliceState::BtcMercyPublished { state3 } => { - // Wait for TxFinalAmnesty to be confirmed - let tx_final_amnesty = state3 - .tx_final_amnesty() - .context("Couldn't construct TxFinalAmnesty even though we have published it")?; + // Wait for TxMercy to be confirmed + let tx_mercy = state3 + .tx_mercy() + .context("Couldn't construct TxMercy even though we have published it")?; let subscription = bitcoin_wallet - .subscribe_to(Box::new(tx_final_amnesty)) + .subscribe_to(Box::new(tx_mercy)) .await; subscription .wait_until_final() .await - .context("Failed to wait for TxFinalAmnesty to be confirmed")?; + .context("Failed to wait for TxMercy to be confirmed")?; AliceState::BtcMercyConfirmed { state3 } } @@ -1055,7 +1055,7 @@ mod tests { #[test] fn test_build_transfer_destinations_with_zero_tip() { - // Nonzero ratio but tiny lock amount → effective tip rounds to near-zero + // Nonzero ratio but tiny lock amount -> effective tip rounds to near-zero let lock_amount = monero_oxide_ext::Amount::from_pico(100); let tip = TipConfig { ratio: Decimal::new(1, 1), // 0.1 = 10% diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index b1173a9df3..c4ea7b38bc 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -49,7 +49,7 @@ pub fn has_already_processed_transfer_proof(state: &BobState) -> bool { // - If unsuccessful, we exit to avoid an infinite retry loop. // - The swap can still be manually resumed later and retried if desired. // -// The same is true for the BtcRefundBurnt. +// The same is true for the BtcWithheld. pub fn is_run_at_most_once(state: &BobState) -> bool { matches!(state, BobState::BtcPunished { .. } | BobState::BtcWithheld(..)) } @@ -129,10 +129,10 @@ async fn next_state( let tx_partial_refund_fee = bitcoin_wallet .estimate_fee(TxPartialRefund::weight(), Some(btc_amount)) .await?; - let tx_refund_amnesty_fee = bitcoin_wallet + let tx_reclaim_fee = bitcoin_wallet .estimate_fee(TxReclaim::weight(), Some(btc_amount)) .await?; - let tx_final_amnesty_fee = bitcoin_wallet + let tx_mercy_fee = bitcoin_wallet .estimate_fee(TxMercy::weight(), Some(btc_amount)) .await?; @@ -151,8 +151,8 @@ async fn next_state( tx_lock_fee, tx_refund_fee, tx_partial_refund_fee, - tx_refund_amnesty_fee, - tx_final_amnesty_fee, + tx_reclaim_fee, + tx_mercy_fee, tx_cancel_fee, bitcoin_refund_address: change_address, }) @@ -909,8 +909,8 @@ async fn next_state( ))) } ExpiredTimelocks::RemainingRefund => { - // TxPartialRefund was published and timelock expired - publish TxRefundAmnesty - // Transition to BtcPartiallyRefunded which handles amnesty publication + // TxPartialRefund was published and timelock expired - publish TxReclaim + // Transition to BtcPartiallyRefunded which handles reclaim publication tracing::info!("Remaining refund timelock expired, can publish amnesty transaction"); Ok(BobState::BtcPartiallyRefunded(state)) } @@ -1065,7 +1065,7 @@ async fn next_state( ); // Transition to waiting state where we race remaining_refund_timelock - // against Alice potentially publishing TxRefundBurn + // against Alice potentially publishing TxWithhold BobState::WaitingForReclaimTimelockExpiration(state) } BobState::BtcRefunded(state) => { @@ -1262,10 +1262,10 @@ async fn next_state( }, BobState::WaitingForReclaimTimelockExpiration(state) => { // Race between: - // - Remaining refund timelock expiring (so we can publish TxRefundAmnesty) - // - Alice publishing TxRefundBurn (burns the amnesty output) + // - Remaining refund timelock expiring (so we can publish TxReclaim) + // - Alice publishing TxWithhold (burns the amnesty output) let tx_partial_refund = state.construct_tx_partial_refund()?; - let tx_refund_burn = state.construct_tx_refund_burn()?; + let tx_withhold = state.construct_tx_withhold()?; let remaining_refund_timelock = state.remaining_refund_timelock.context( "Can't wait for remaining refund timelock because remaining_refund_timelock is missing", @@ -1282,9 +1282,9 @@ async fn next_state( }, ); - let (tx_partial_refund_status, tx_refund_burn_status) = tokio::join!( + let (tx_partial_refund_status, tx_withhold_status) = tokio::join!( bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund.clone())), - bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)), + bitcoin_wallet.subscribe_to(Box::new(tx_withhold)), ); // Emit a tauri event everytime the TxPartialRefund status changes so we can @@ -1308,28 +1308,28 @@ async fn next_state( // Wait for remaining_refund_timelock confirmations on tx_partial_refund result = timelock_expired_future => { result?; - tracing::info!("Remaining refund timelock expired, can now publish TxRefundAmnesty"); + tracing::info!("Remaining refund timelock expired, can now publish TxReclaim"); BobState::ReclaimTimelockExpired(state) } - // Watch for Alice publishing TxRefundBurn - _ = tx_refund_burn_status.wait_until_seen() => { - tracing::info!("Alice published TxRefundBurn, amnesty output is being burnt"); + // Watch for Alice publishing TxWithhold + _ = tx_withhold_status.wait_until_seen() => { + tracing::info!("Alice published TxWithhold, amnesty output is being burnt"); BobState::BtcWithholdPublished(state) } } } BobState::ReclaimTimelockExpired(state) => { // TODO: We should retry this and the check - // First check if TxRefundBurn was seen (we may have missed it while offline) - let tx_refund_burn = state.construct_tx_refund_burn()?; - let tx_refund_burn_status = bitcoin_wallet.status_of_script(&tx_refund_burn).await?; + // First check if TxWithhold was seen (we may have missed it while offline) + let tx_withhold = state.construct_tx_withhold()?; + let tx_withhold_status = bitcoin_wallet.status_of_script(&tx_withhold).await?; - if tx_refund_burn_status.has_been_seen() { - tracing::info!("TxRefundBurn was already published, transitioning to BtcRefundBurnPublished"); + if tx_withhold_status.has_been_seen() { + tracing::info!("TxWithhold was already published, transitioning to BtcWithholdPublished"); return Ok(BobState::BtcWithholdPublished(state)); } - // TxRefundBurn not published, we can publish TxRefundAmnesty + // TxWithhold not published, we can publish TxReclaim // Alice always sends the amnesty signature in swap setup let transaction = state.signed_amnesty_transaction() .context("Couldn't construct Bitcoin amnesty transaction")?; @@ -1339,72 +1339,72 @@ async fn next_state( BobState::BtcReclaimPublished(state) } BobState::BtcWithholdPublished(state) => { - // Wait for TxRefundBurn confirmation - let tx_refund_burn = state.construct_tx_refund_burn()?; + // Wait for TxWithhold confirmation + let tx_withhold = state.construct_tx_withhold()?; event_emitter.emit_swap_progress_event( swap_id, - TauriSwapProgressEvent::BtcRefundBurnPublished { - btc_refund_burn_txid: tx_refund_burn.txid(), + TauriSwapProgressEvent::BtcWithholdPublished { + btc_withhold_txid: tx_withhold.txid(), btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); - let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_refund_burn)).await; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_withhold)).await; subscription.wait_until_final().await?; - tracing::info!("TxRefundBurn confirmed, amnesty output is burnt"); + tracing::info!("TxWithhold confirmed, amnesty output is burnt"); BobState::BtcWithheld(state) } BobState::BtcWithheld(state) => { - // Watch for Alice publishing TxFinalAmnesty - // Alice may grant final amnesty after burning our refund + // Watch for Alice publishing TxMercy + // Alice may grant mercy after withholding our refund // However, we don't expect Alice to publish the tx at once, if at all. // Thus we only check once, and then stop the swap. // User's can still manually resume the swap to check again. - let tx_refund_burn = state.construct_tx_refund_burn()?; + let tx_withhold = state.construct_tx_withhold()?; event_emitter.emit_swap_progress_event( swap_id, - TauriSwapProgressEvent::BtcRefundBurnt { - btc_refund_burn_txid: tx_refund_burn.txid(), + TauriSwapProgressEvent::BtcWithheld { + btc_withhold_txid: tx_withhold.txid(), btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); - let tx_final_amnesty = state.construct_tx_final_amnesty()?; + let tx_mercy = state.construct_tx_mercy()?; - let final_amnesty_status = bitcoin_wallet.status_of_script(&tx_final_amnesty).await.context("Failed to check TxFinalAmnesty status")?; + let mercy_status = bitcoin_wallet.status_of_script(&tx_mercy).await.context("Failed to check TxMercy status")?; - if final_amnesty_status.has_been_seen() { + if mercy_status.has_been_seen() { BobState::BtcMercyPublished(state) } else { BobState::BtcWithheld(state) } } BobState::BtcMercyPublished(state) => { - // Wait for TxFinalAmnesty confirmation - let tx_final_amnesty = state.construct_tx_final_amnesty()?; + // Wait for TxMercy confirmation + let tx_mercy = state.construct_tx_mercy()?; event_emitter.emit_swap_progress_event( swap_id, - TauriSwapProgressEvent::BtcFinalAmnestyPublished { - btc_final_amnesty_txid: tx_final_amnesty.txid(), + TauriSwapProgressEvent::BtcMercyPublished { + btc_mercy_txid: tx_mercy.txid(), btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, ); - let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_final_amnesty)).await; + let subscription = bitcoin_wallet.subscribe_to(Box::new(tx_mercy)).await; subscription.wait_until_final().await?; - tracing::info!("TxFinalAmnesty confirmed, received burnt funds back"); + tracing::info!("TxMercy confirmed, received withheld funds back"); BobState::BtcMercyConfirmed(state) } BobState::BtcMercyConfirmed(state) => { - // Terminal state - we received the burnt funds back - let tx_final_amnesty = state.construct_tx_final_amnesty()?; + // Terminal state - we received the withheld funds back + let tx_mercy = state.construct_tx_mercy()?; event_emitter.emit_swap_progress_event( swap_id, - TauriSwapProgressEvent::BtcFinalAmnestyConfirmed { - btc_final_amnesty_txid: tx_final_amnesty.txid(), + TauriSwapProgressEvent::BtcMercyConfirmed { + btc_mercy_txid: tx_mercy.txid(), btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), }, diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 27bba95e37..26939cd611 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -854,7 +854,7 @@ impl TestContext { .unwrap(); } - pub async fn assert_alice_refund_burn_confirmed(&mut self, state: AliceState) { + pub async fn assert_alice_withhold_confirmed(&mut self, state: AliceState) { assert!(matches!(state, AliceState::BtcWithholdConfirmed { .. })); // Same as refunded - Alice still has her XMR back @@ -875,7 +875,7 @@ impl TestContext { .unwrap(); } - pub async fn assert_alice_final_amnesty_confirmed(&mut self, state: AliceState) { + pub async fn assert_alice_mercy_confirmed(&mut self, state: AliceState) { assert!(matches!( state, AliceState::BtcMercyConfirmed { .. } @@ -1038,7 +1038,7 @@ impl TestContext { state6.tx_lock_id(), state6.tx_cancel_fee, state6.tx_partial_refund_fee.expect("partial refund fee"), - state6.tx_refund_amnesty_fee.expect("amnesty fee"), + state6.tx_reclaim_fee.expect("amnesty fee"), ), _ => panic!("Bob is not in btc amnesty confirmed state: {:?}", state), }; @@ -1059,7 +1059,7 @@ impl TestContext { assert_eq!(btc_balance_after_swap, expected_balance); } - pub async fn assert_bob_refund_burnt(&self, state: BobState) { + pub async fn assert_bob_withheld(&self, state: BobState) { self.bob_bitcoin_wallet.sync().await.unwrap(); let (lock_tx_id, cancel_fee, partial_refund_fee, amnesty_amount) = match state { @@ -1069,7 +1069,7 @@ impl TestContext { state6.tx_partial_refund_fee.expect("partial refund fee"), state6.btc_amnesty_amount.expect("amnesty amount"), ), - _ => panic!("Bob is not in btc refund burnt state: {:?}", state), + _ => panic!("Bob is not in btc withheld state: {:?}", state), }; let lock_tx_bitcoin_fee = self .bob_bitcoin_wallet @@ -1078,7 +1078,7 @@ impl TestContext { .unwrap(); let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); - // Bob lost the amnesty amount (it was burnt) + // Bob lost the amnesty amount (it was withheld) let expected_balance = self.bob_starting_balances.btc - lock_tx_bitcoin_fee - cancel_fee @@ -1088,18 +1088,18 @@ impl TestContext { assert_eq!(btc_balance_after_swap, expected_balance); } - pub async fn assert_bob_final_amnesty_received(&self, state: BobState) { + pub async fn assert_bob_mercy_received(&self, state: BobState) { self.bob_bitcoin_wallet.sync().await.unwrap(); - let (lock_tx_id, cancel_fee, partial_refund_fee, final_amnesty_fee) = match state { + let (lock_tx_id, cancel_fee, partial_refund_fee, mercy_fee) = match state { BobState::BtcMercyConfirmed(state6) => ( state6.tx_lock_id(), state6.tx_cancel_fee, state6.tx_partial_refund_fee.expect("partial refund fee"), - state6.tx_final_amnesty_fee.expect("final amnesty fee"), + state6.tx_mercy_fee.expect("mercy fee"), ), _ => panic!( - "Bob is not in btc final amnesty confirmed state: {:?}", + "Bob is not in btc mercy confirmed state: {:?}", state ), }; @@ -1110,12 +1110,12 @@ impl TestContext { .unwrap(); let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); - // Bob gets full amount back via final amnesty + // Bob gets full amount back via mercy let expected_balance = self.bob_starting_balances.btc - lock_tx_bitcoin_fee - cancel_fee - partial_refund_fee - - final_amnesty_fee; + - mercy_fee; assert_eq!(btc_balance_after_swap, expected_balance); } @@ -1443,11 +1443,11 @@ pub mod alice_run_until { matches!(state, AliceState::XmrRefunded { .. }) } - pub fn is_btc_refund_burn_confirmed(state: &AliceState) -> bool { + pub fn is_btc_withhold_confirmed(state: &AliceState) -> bool { matches!(state, AliceState::BtcWithholdConfirmed { .. }) } - pub fn is_btc_final_amnesty_confirmed(state: &AliceState) -> bool { + pub fn is_btc_mercy_confirmed(state: &AliceState) -> bool { matches!(state, AliceState::BtcMercyConfirmed { .. }) } } @@ -1487,11 +1487,11 @@ pub mod bob_run_until { matches!(state, BobState::BtcReclaimConfirmed(..)) } - pub fn is_btc_refund_burnt(state: &BobState) -> bool { + pub fn is_btc_withheld(state: &BobState) -> bool { matches!(state, BobState::BtcWithheld(..)) } - pub fn is_btc_final_amnesty_confirmed(state: &BobState) -> bool { + pub fn is_btc_mercy_confirmed(state: &BobState) -> bool { matches!(state, BobState::BtcMercyConfirmed(..)) } } diff --git a/swap/tests/partial_refund_alice_burns.rs b/swap/tests/partial_refund_alice_burns.rs index 344089794b..f7bd355c98 100644 --- a/swap/tests/partial_refund_alice_burns.rs +++ b/swap/tests/partial_refund_alice_burns.rs @@ -13,13 +13,13 @@ use swap::protocol::{alice, bob}; use swap_env::config::RefundPolicy; /// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial -/// refund. Alice then burns the refund, denying Bob access to the amnesty. +/// refund. Alice then withholds the deposit, denying Bob access to the amnesty. #[tokio::test] async fn given_partial_refund_alice_burns_the_amnesty() { - // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty - // Alice burns the amnesty + // Use 5% anti-spam deposit ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice withholds the deposit let refund_policy = Some(RefundPolicy { - anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% always_withhold_deposit: true, }); @@ -53,14 +53,14 @@ async fn given_partial_refund_alice_burns_the_amnesty() { let bob_state = bob_swap.await??; assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); - // Restart Alice so she can refund her XMR and burn Bob's amnesty - // Alice needs to publish burn BEFORE Bob's remaining refund timelock expires + // Restart Alice so she can refund her XMR and withhold Bob's deposit + // Alice needs to publish withhold BEFORE Bob's remaining refund timelock expires ctx.restart_alice().await; let alice_swap = ctx.alice_next_swap().await; let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); - // Bob continues - he's watching for TxRefundBurn while waiting for timelock - // Alice's burn should get published before Bob's timelock expires + // Bob continues - he's watching for TxWithhold while waiting for timelock + // Alice's withhold should get published before Bob's timelock expires let (bob_swap, _) = ctx .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) .await; @@ -71,13 +71,13 @@ async fn given_partial_refund_alice_burns_the_amnesty() { tokio::time::sleep(Duration::from_secs(15)).await; ctx.monero.generate_blocks().await?; - // Bob should end up in BtcRefundBurnt because Alice's burn beat his amnesty + // Bob should end up in BtcWithheld because Alice's withhold beat his amnesty let bob_state = bob_swap.await??; - ctx.assert_bob_refund_burnt(bob_state).await; + ctx.assert_bob_withheld(bob_state).await; - // Alice should be in refund burn confirmed state + // Alice should be in withhold confirmed state let alice_state = alice_swap.await??; - ctx.assert_alice_refund_burn_confirmed(alice_state).await; + ctx.assert_alice_withhold_confirmed(alice_state).await; Ok(()) }, diff --git a/swap/tests/partial_refund_alice_burns_after_command.rs b/swap/tests/partial_refund_alice_burns_after_command.rs index 68c876a14e..69ae09b635 100644 --- a/swap/tests/partial_refund_alice_burns_after_command.rs +++ b/swap/tests/partial_refund_alice_burns_after_command.rs @@ -14,14 +14,14 @@ use swap_controller_api::AsbApiClient; use swap_env::config::RefundPolicy; /// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial -/// refund. Alice receives an RPC command to burn the amnesty and then burns it. +/// refund. Alice receives an RPC command to withhold the deposit and then withholds it. #[tokio::test] async fn given_partial_refund_alice_burns_after_command() { - // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty - // Alice does NOT burn by default - burn_on_refund is false + // Use 5% anti-spam deposit ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice does NOT withhold by default - always_withhold_deposit is false let refund_policy = Some(RefundPolicy { - anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% - always_withhold_deposit: false, // Do not burn by default + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% + always_withhold_deposit: false, // Do not withhold by default }); harness::setup_test( @@ -55,22 +55,22 @@ async fn given_partial_refund_alice_burns_after_command() { let bob_state = bob_swap.await??; assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); - // Restart Alice so she can refund her XMR and burn Bob's amnesty - // Alice needs to publish burn BEFORE Bob's remaining refund timelock expires + // Restart Alice so she can refund her XMR and withhold Bob's deposit + // Alice needs to publish withhold BEFORE Bob's remaining refund timelock expires ctx.restart_alice().await; let alice_swap = ctx.alice_next_swap().await; - // Send RPC command to Alice to burn this swap's amnesty + // Send RPC command to Alice to withhold this swap's deposit // Must be done AFTER restart (so EventLoopHandle exists) but BEFORE running the swap ctx.alice_rpc_client .set_withhold_deposit(alice_swap_id, true) .await - .expect("Failed to send burn command to Alice"); + .expect("Failed to send withhold command to Alice"); let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); - // Bob continues - he's watching for TxRefundBurn while waiting for timelock - // Alice's burn should get published before Bob's timelock expires + // Bob continues - he's watching for TxWithhold while waiting for timelock + // Alice's withhold should get published before Bob's timelock expires let (bob_swap, _) = ctx .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) .await; @@ -81,13 +81,13 @@ async fn given_partial_refund_alice_burns_after_command() { tokio::time::sleep(Duration::from_secs(15)).await; ctx.monero.generate_blocks().await?; - // Bob should end up in BtcRefundBurnt because Alice's burn beat his amnesty + // Bob should end up in BtcWithheld because Alice's withhold beat his amnesty let bob_state = bob_swap.await??; - ctx.assert_bob_refund_burnt(bob_state).await; + ctx.assert_bob_withheld(bob_state).await; - // Alice should be in refund burn confirmed state + // Alice should be in withhold confirmed state let alice_state = alice_swap.await??; - ctx.assert_alice_refund_burn_confirmed(alice_state).await; + ctx.assert_alice_withhold_confirmed(alice_state).await; Ok(()) }, diff --git a/swap/tests/partial_refund_alice_grants_final_amnesty.rs b/swap/tests/partial_refund_alice_grants_final_amnesty.rs index bc95767f8f..2879835688 100644 --- a/swap/tests/partial_refund_alice_grants_final_amnesty.rs +++ b/swap/tests/partial_refund_alice_grants_final_amnesty.rs @@ -15,15 +15,15 @@ use crate::harness::alice_run_until::is_xmr_refunded; use crate::harness::bob_run_until; /// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob does a partial -/// refund. Alice burns the refund, then later grants final amnesty to Bob. +/// refund. Alice withholds the deposit, then later grants mercy to Bob. /// NOTE: This test cannot pass yet because we haven't implemented the manual -/// trigger for final amnesty. BtcRefundBurnConfirmed is currently terminal. +/// trigger for mercy. BtcWithholdConfirmed is currently terminal. #[tokio::test] -async fn given_partial_refund_alice_grants_final_amnesty() { - // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty - // Alice burns the amnesty, then grants final amnesty +async fn given_partial_refund_alice_grants_mercy() { + // Use 5% anti-spam deposit ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice withholds the deposit, then grants mercy let refund_policy = Some(RefundPolicy { - anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% always_withhold_deposit: true, }); @@ -54,19 +54,19 @@ async fn given_partial_refund_alice_grants_final_amnesty() { ctx.monero.generate_blocks().await?; - // Restart alice and wait for bob to be burnt. + // Restart alice and wait for bob to be withheld. ctx.restart_alice().await; let alice_swap = ctx.alice_next_swap().await; let swap_id = alice_swap.swap_id; let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); - // Give alice time to publish TxRefundBurn before restarting bob + // Give alice time to publish TxWithhold before restarting bob tokio::time::sleep(Duration::from_secs(20)).await; let (bob_swap, bob_app_handle) = ctx .stop_and_resume_bob_from_db(bob_app_handle, swap_id) .await; - let bob_state = tokio::spawn(bob::run(bob_swap)); // Bob should stop automatically after BtcRefundBurnt + let bob_state = tokio::spawn(bob::run(bob_swap)); // Bob should stop automatically after BtcWithheld let alice_state = alice_swap.await??; assert!(matches!( @@ -77,7 +77,7 @@ async fn given_partial_refund_alice_grants_final_amnesty() { let bob_state = bob_state.await??; assert!(matches!(bob_state, BobState::BtcWithheld(..))); - // Simulate alice's controller sending the final amnesty command via `controller` cli + // Simulate alice's controller sending the mercy command via `controller` cli ctx.restart_alice().await; ctx.alice_rpc_client.grant_mercy(swap_id).await?; diff --git a/swap/tests/partial_refund_bob_claims_amnesty.rs b/swap/tests/partial_refund_bob_claims_amnesty.rs index 9ccd078e7a..e175069b08 100644 --- a/swap/tests/partial_refund_bob_claims_amnesty.rs +++ b/swap/tests/partial_refund_bob_claims_amnesty.rs @@ -12,10 +12,10 @@ use swap_env::config::RefundPolicy; /// refund, waits for the remaining refund timelock, and then claims the amnesty. #[tokio::test] async fn given_partial_refund_bob_claims_amnesty_after_timelock() { - // Use 95% refund ratio - Bob gets 95% immediately, 5% locked in amnesty - // Alice does NOT burn - Bob can claim amnesty after timelock + // Use 5% anti-spam deposit ratio - Bob gets 95% immediately, 5% locked in amnesty + // Alice does NOT withhold - Bob can claim amnesty after timelock let refund_policy = Some(RefundPolicy { - anti_spam_deposit_ratio: Decimal::new(95, 2), // 0.95 = 95% + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% always_withhold_deposit: false, }); From 5700caa497dfaef5027b18134d01806719b72219 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 10:55:06 -0600 Subject: [PATCH 116/146] silence wallet2 unused-parameter warnings --- monero-sys/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monero-sys/build.rs b/monero-sys/build.rs index 13e2a26121..2bfc5442d9 100644 --- a/monero-sys/build.rs +++ b/monero-sys/build.rs @@ -425,7 +425,9 @@ fn main() { .to_string(), ) .include(output_directory) - .flag("-fPIC"); // Position independent code + .flag("-fPIC") // Position independent code + .flag("-Wno-unused-parameter") // Suppress warnings from upstream Monero C++ headers + .flag("-Wno-reorder-ctor"); // Suppress harmless ctor init order warning from wallet2.h build.compile("monero-sys"); } From fb79129eb88b1de27ff496b647580aed40c96107 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 11:00:33 -0600 Subject: [PATCH 117/146] fix tauri dependency version mismatch --- src-gui/package.json | 2 +- src-gui/yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src-gui/package.json b/src-gui/package.json index 6efda81102..84a0ee1be7 100644 --- a/src-gui/package.json +++ b/src-gui/package.json @@ -28,7 +28,7 @@ "@tauri-apps/api": "^2.8.0", "@tauri-apps/plugin-cli": "^2.4.0", "@tauri-apps/plugin-clipboard-manager": "^2.3.0", - "@tauri-apps/plugin-dialog": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.6.0", "@tauri-apps/plugin-opener": "^2.5.0", "@tauri-apps/plugin-process": "^2.3.0", "@tauri-apps/plugin-store": "^2.4.0", diff --git a/src-gui/yarn.lock b/src-gui/yarn.lock index 8f4abf9b8e..ff653951db 100644 --- a/src-gui/yarn.lock +++ b/src-gui/yarn.lock @@ -1546,12 +1546,12 @@ __metadata: languageName: node linkType: hard -"@tauri-apps/plugin-dialog@npm:^2.0.0": - version: 2.4.2 - resolution: "@tauri-apps/plugin-dialog@npm:2.4.2" +"@tauri-apps/plugin-dialog@npm:^2.6.0": + version: 2.6.0 + resolution: "@tauri-apps/plugin-dialog@npm:2.6.0" dependencies: "@tauri-apps/api": "npm:^2.8.0" - checksum: 10c0/2950a5aa07727710b5395491e9b80886c13cbefd05445a84412819128e90bdaec751795c47ed39dd80fb5181c4e21ee7aaaae6152551dbf1ddc02aa3eac59b37 + checksum: 10c0/b5d4f91588d28e1790caffaba3fed0f656b3d569ea78a5cf4d6e873686fb7b423b84cfdc75777863da8d916cc0784f3c2e1806de16765d4a1f4e4e6623d2408a languageName: node linkType: hard @@ -6129,7 +6129,7 @@ __metadata: "@tauri-apps/cli": "npm:^2.0.0" "@tauri-apps/plugin-cli": "npm:^2.4.0" "@tauri-apps/plugin-clipboard-manager": "npm:^2.3.0" - "@tauri-apps/plugin-dialog": "npm:^2.0.0" + "@tauri-apps/plugin-dialog": "npm:^2.6.0" "@tauri-apps/plugin-opener": "npm:^2.5.0" "@tauri-apps/plugin-process": "npm:^2.3.0" "@tauri-apps/plugin-store": "npm:^2.4.0" From 3bbd2432322669fe684a4b601a18a306cfcd49d5 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 12:25:56 -0600 Subject: [PATCH 118/146] refactor: distinguish between txcancelled and txcancelpublished --- src-gui/src/dev/mockSwapEvents.ts | 4 ++ src-gui/src/models/tauriModelExt.ts | 7 +++ .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 1 + .../modal/swap/SwapStateStepper.tsx | 1 + .../pages/swap/swap/SwapStatePage.tsx | 2 + swap-db/src/bob.rs | 4 ++ swap-machine/src/bob/mod.rs | 3 + swap/src/cli/api/tauri_bindings.rs | 8 +++ swap/src/cli/cancel_and_refund.rs | 6 +- swap/src/protocol/bob/swap.rs | 62 ++++++++++++++++++- ..._refund_using_cancel_and_refund_command.rs | 4 +- ...punishes_after_bob_dead_and_bob_cancels.rs | 6 +- 12 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src-gui/src/dev/mockSwapEvents.ts b/src-gui/src/dev/mockSwapEvents.ts index a915d79a47..2281d933ad 100644 --- a/src-gui/src/dev/mockSwapEvents.ts +++ b/src-gui/src/dev/mockSwapEvents.ts @@ -139,6 +139,7 @@ const cooperativeRedeemRejected: TauriSwapProgressEvent[] = [ { type: "CooperativeRedeemRejected", content: { reason: "Peer offline" } }, { type: "WaitingForCancelTimelockExpiration" }, { type: "CancelTimelockExpired" }, + { type: "BtcCancelPublished", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID, btc_cancel_confirmations: 0, btc_cancel_target_confirmations: 1 } }, { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcRefundPublished", content: { btc_refund_txid: MOCK_BTC_REFUND_TXID } }, { type: "BtcRefunded", content: { btc_refund_txid: MOCK_BTC_REFUND_TXID } }, @@ -156,6 +157,7 @@ const partialRefundWithAmnesty: TauriSwapProgressEvent[] = [ ...baseScenario, { type: "WaitingForCancelTimelockExpiration" }, { type: "CancelTimelockExpired" }, + { type: "BtcCancelPublished", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID, btc_cancel_confirmations: 0, btc_cancel_target_confirmations: 1 } }, { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", @@ -207,6 +209,7 @@ const partialRefundWithBurn: TauriSwapProgressEvent[] = [ ...baseScenario, { type: "WaitingForCancelTimelockExpiration" }, { type: "CancelTimelockExpired" }, + { type: "BtcCancelPublished", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID, btc_cancel_confirmations: 0, btc_cancel_target_confirmations: 1 } }, { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", @@ -258,6 +261,7 @@ const partialRefundWithWithholdAndMercy: TauriSwapProgressEvent[] = [ ...baseScenario, { type: "WaitingForCancelTimelockExpiration" }, { type: "CancelTimelockExpired" }, + { type: "BtcCancelPublished", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID, btc_cancel_confirmations: 0, btc_cancel_target_confirmations: 1 } }, { type: "BtcCancelled", content: { btc_cancel_txid: MOCK_BTC_CANCEL_TXID } }, { type: "BtcPartialRefundPublished", diff --git a/src-gui/src/models/tauriModelExt.ts b/src-gui/src/models/tauriModelExt.ts index f22faa4ff1..23fd98e48f 100644 --- a/src-gui/src/models/tauriModelExt.ts +++ b/src-gui/src/models/tauriModelExt.ts @@ -49,6 +49,7 @@ export enum BobStateName { EncSigSent = "encrypted signature is sent", BtcRedeemed = "btc is redeemed", CancelTimelockExpired = "cancel timelock is expired", + BtcCancelPublished = "btc cancel is published", BtcCancelled = "btc is cancelled", BtcRefundPublished = "btc refund is published", BtcPartialRefundPublished = "btc partial refund is published", @@ -89,6 +90,8 @@ export function bobStateNameToHumanReadable(stateName: BobStateName): string { return "Bitcoin redeemed"; case BobStateName.CancelTimelockExpired: return "Cancel timelock expired"; + case BobStateName.BtcCancelPublished: + return "Bitcoin cancel published"; case BobStateName.BtcCancelled: return "Bitcoin cancelled"; case BobStateName.BtcRefundPublished: @@ -213,6 +216,7 @@ export type BobStateNamePossiblyCancellableSwap = | BobStateName.XmrLocked | BobStateName.EncSigSent | BobStateName.CancelTimelockExpired + | BobStateName.BtcCancelPublished | BobStateName.BtcRefundPublished | BobStateName.BtcEarlyRefundPublished; @@ -239,6 +243,7 @@ export function isBobStateNamePossiblyCancellableSwap( BobStateName.XmrLocked, BobStateName.EncSigSent, BobStateName.CancelTimelockExpired, + BobStateName.BtcCancelPublished, BobStateName.BtcRefundPublished, BobStateName.BtcEarlyRefundPublished, ].includes(state); @@ -251,6 +256,7 @@ export type BobStateNamePossiblyRefundableSwap = | BobStateName.XmrLocked | BobStateName.EncSigSent | BobStateName.CancelTimelockExpired + | BobStateName.BtcCancelPublished | BobStateName.BtcCancelled | BobStateName.BtcRefundPublished | BobStateName.BtcEarlyRefundPublished; @@ -276,6 +282,7 @@ export function isBobStateNamePossiblyRefundableSwap( BobStateName.XmrLocked, BobStateName.EncSigSent, BobStateName.CancelTimelockExpired, + BobStateName.BtcCancelPublished, BobStateName.BtcCancelled, BobStateName.BtcRefundPublished, BobStateName.BtcEarlyRefundPublished, diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 622d32a6bc..40133fbb49 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -267,6 +267,7 @@ export function StateAlert({ // Even if the refund transactions have been published, it cannot be // guaranteed that they will be confirmed in time // falls through + case BobStateName.BtcCancelPublished: case BobStateName.BtcCancelled: case BobStateName.BtcRefundPublished: case BobStateName.BtcPartialRefundPublished: diff --git a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx index da3794b16b..3ff2bf3738 100644 --- a/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ b/src-gui/src/renderer/components/modal/swap/SwapStateStepper.tsx @@ -108,6 +108,7 @@ function getActiveStep(state: SwapState | null): PathStep | null { case "CancelTimelockExpired": return [PathType.RECOVERY_PATH, 0, isReleased, RecoveryScenario.GENERIC]; + case "BtcCancelPublished": case "BtcCancelled": return [PathType.RECOVERY_PATH, 1, isReleased, RecoveryScenario.GENERIC]; diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx index 818a7aadd3..89ed8f4a0c 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/SwapStatePage.tsx @@ -114,6 +114,8 @@ export default function SwapStatePage({ state }: { state: SwapState | null }) { break; case "CancelTimelockExpired": return ; + case "BtcCancelPublished": + return ; case "BtcCancelled": return ; diff --git a/swap-db/src/bob.rs b/swap-db/src/bob.rs index 91e77a52a1..0966891af7 100644 --- a/swap-db/src/bob.rs +++ b/swap-db/src/bob.rs @@ -50,6 +50,7 @@ pub enum Bob { monero_wallet_restore_blockheight: BlockHeight, }, CancelTimelockExpired(bob::State6), + BtcCancelPublished(bob::State6), BtcCancelled(bob::State6), BtcRefundPublished(bob::State6), BtcEarlyRefundPublished(bob::State6), @@ -132,6 +133,7 @@ impl From for Bob { monero_wallet_restore_blockheight, }, BobState::CancelTimelockExpired(state6) => Bob::CancelTimelockExpired(state6), + BobState::BtcCancelPublished(state6) => Bob::BtcCancelPublished(state6), BobState::BtcCancelled(state6) => Bob::BtcCancelled(state6), BobState::BtcRefundPublished(state6) => Bob::BtcRefundPublished(state6), BobState::BtcEarlyRefundPublished(state6) => Bob::BtcEarlyRefundPublished(state6), @@ -222,6 +224,7 @@ impl From for BobState { monero_wallet_restore_blockheight, }, Bob::CancelTimelockExpired(state6) => BobState::CancelTimelockExpired(state6), + Bob::BtcCancelPublished(state6) => BobState::BtcCancelPublished(state6), Bob::BtcCancelled(state6) => BobState::BtcCancelled(state6), Bob::BtcRefundPublished(state6) => BobState::BtcRefundPublished(state6), Bob::BtcPartialRefundPublished(state6) => BobState::BtcPartialRefundPublished(state6), @@ -264,6 +267,7 @@ impl fmt::Display for Bob { f.write_str("Waiting for cancel timelock expiration") } Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"), + Bob::BtcCancelPublished(_) => f.write_str("Bitcoin cancel published"), Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"), Bob::BtcRefundPublished { .. } => f.write_str("Bitcoin refund published"), Bob::BtcEarlyRefundPublished { .. } => f.write_str("Bitcoin early refund published"), diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index 3328a58a8c..fe608115cf 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -71,6 +71,7 @@ pub enum BobState { monero_wallet_restore_blockheight: BlockHeight, }, CancelTimelockExpired(State6), + BtcCancelPublished(State6), BtcCancelled(State6), BtcRefundPublished(State6), BtcEarlyRefundPublished(State6), @@ -172,6 +173,7 @@ impl fmt::Display for BobState { write!(f, "waiting for cancel timelock expiration") } BobState::CancelTimelockExpired(..) => write!(f, "cancel timelock is expired"), + BobState::BtcCancelPublished(..) => write!(f, "btc cancel is published"), BobState::BtcCancelled(..) => write!(f, "btc is cancelled"), BobState::BtcRefundPublished { .. } => write!(f, "btc refund is published"), BobState::BtcEarlyRefundPublished { .. } => write!(f, "btc early refund is published"), @@ -237,6 +239,7 @@ impl BobState { Some(state.expired_timelock(bitcoin_wallet.as_ref()).await?) } BobState::CancelTimelockExpired(state) + | BobState::BtcCancelPublished(state) | BobState::BtcCancelled(state) | BobState::BtcRefundPublished(state) | BobState::BtcEarlyRefundPublished(state) diff --git a/swap/src/cli/api/tauri_bindings.rs b/swap/src/cli/api/tauri_bindings.rs index 630234cddc..85125f886d 100644 --- a/swap/src/cli/api/tauri_bindings.rs +++ b/swap/src/cli/api/tauri_bindings.rs @@ -1082,6 +1082,14 @@ pub enum TauriSwapProgressEvent { }, WaitingForCancelTimelockExpiration, // TODO: Add current confirmations and target confirmations here? CancelTimelockExpired, + BtcCancelPublished { + #[typeshare(serialized_as = "string")] + btc_cancel_txid: Txid, + #[typeshare(serialized_as = "number")] + btc_cancel_confirmations: u32, + #[typeshare(serialized_as = "number")] + btc_cancel_target_confirmations: u32, + }, BtcCancelled { #[typeshare(serialized_as = "string")] btc_cancel_txid: Txid, diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index 19aa8d3b67..c9f549ff1c 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -69,6 +69,7 @@ pub async fn cancel( } => state.cancel(monero_wallet_restore_blockheight), BobState::CancelTimelockExpired(state6) => state6, BobState::BtcRefunded(state6) => state6, + BobState::BtcCancelPublished(state6) => state6, BobState::BtcCancelled(state6) => state6, BobState::BtcRefundPublished(state6) => state6, BobState::BtcEarlyRefundPublished(state6) => state6, @@ -105,7 +106,7 @@ pub async fn cancel( // Attempt to just publish the cancel transaction match state6.submit_tx_cancel(bitcoin_wallet.as_ref()).await { Ok((txid, _)) => { - let state = BobState::BtcCancelled(state6); + let state = BobState::BtcCancelPublished(state6); db.insert_latest_state(swap_id, state.clone().into()) .await?; Ok((txid, state)) @@ -117,7 +118,7 @@ pub async fn cancel( Err(err) => { // Check if Alice has already published the cancel transaction while we were absent if let Some(tx) = state6.check_for_tx_cancel(bitcoin_wallet.as_ref()).await? { - let state = BobState::BtcCancelled(state6); + let state = BobState::BtcCancelPublished(state6); db.insert_latest_state(swap_id, state.clone().into()) .await?; tracing::info!("Alice has already cancelled the swap"); @@ -206,6 +207,7 @@ pub async fn refund( monero_wallet_restore_blockheight, } => state.cancel(monero_wallet_restore_blockheight), BobState::CancelTimelockExpired(state6) => state6, + BobState::BtcCancelPublished(state6) => state6, BobState::BtcCancelled(state6) => state6, BobState::BtcRefunded(state6) => state6, BobState::BtcRefundPublished(state6) => state6, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index c4ea7b38bc..499da927db 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -823,13 +823,13 @@ async fn next_state( // Then we check if tx_cancel is present on the chain if state6.check_for_tx_cancel(&*bitcoin_wallet).await.context("Failed to check for existence of tx_cancel before cancelling").map_err(backoff::Error::transient)?.is_some() { - return Ok(BobState::BtcCancelled(state6.clone())); + return Ok(BobState::BtcCancelPublished(state6.clone())); } // If none of the above are present, we publish tx_cancel state6.submit_tx_cancel(&*bitcoin_wallet).await.context("Failed to submit tx_cancel after ensuring both tx_early_refund and tx_cancel are not present").map_err(backoff::Error::transient)?; - Ok(BobState::BtcCancelled(state6)) + Ok(BobState::BtcCancelPublished(state6)) } }, None, @@ -838,8 +838,64 @@ async fn next_state( .await .expect("we never stop retrying to check for tx_redeem, tx_early_refund and tx_cancel then publishing tx_cancel if necessary") } + BobState::BtcCancelPublished(state) => { + let btc_cancel_txid = state.construct_tx_cancel()?.txid(); + let tx_early_refund = state.construct_tx_early_refund(); + let tx_early_refund_txid = tx_early_refund.txid(); + let btc_finality_confirmations = env_config.bitcoin_finality_confirmations; + + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcCancelPublished { + btc_cancel_txid, + btc_cancel_confirmations: 0, + btc_cancel_target_confirmations: btc_finality_confirmations, + }, + ); + + let tx_cancel_for_sub = state.construct_tx_cancel()?; + let (tx_cancel_sub, tx_early_refund_sub): ( + bitcoin_wallet::Subscription, + bitcoin_wallet::Subscription, + ) = tokio::join!( + bitcoin_wallet.subscribe_to(Box::new(tx_cancel_for_sub)), + bitcoin_wallet.subscribe_to(Box::new(tx_early_refund)), + ); + + let tx_cancel_confirmed = tx_cancel_sub.wait_until(|status| { + let bitcoin_wallet::primitives::ScriptStatus::Confirmed(confirmed) = status else { + return false; + }; + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcCancelPublished { + btc_cancel_txid, + btc_cancel_confirmations: confirmed.confirmations(), + btc_cancel_target_confirmations: btc_finality_confirmations, + }, + ); + confirmed.meets_target(btc_finality_confirmations) + }); + + // TxCancel and TxEarlyRefund spend the same UTXO (TxLock output). + // We wait for whichever confirms first. + select! { + _ = tx_cancel_confirmed => { + event_emitter.emit_swap_progress_event( + swap_id, + TauriSwapProgressEvent::BtcCancelled { btc_cancel_txid }, + ); + + BobState::BtcCancelled(state) + }, + _ = tx_early_refund_sub.wait_until_final() => { + tracing::info!(%tx_early_refund_txid, "Alice refunded us our Bitcoin early while waiting for TxCancel confirmation"); + + BobState::BtcEarlyRefunded(state) + }, + } + } BobState::BtcCancelled(state) => { - // TODO: We should differentiate between BtcCancelPublished and BtcCancelled (confirmed) let btc_cancel_txid = state.construct_tx_cancel()?.txid(); event_emitter.emit_swap_progress_event( diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs index edb0b2880d..b75d4f9028 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command.rs @@ -51,12 +51,12 @@ async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() { // Bob manually cancels bob_join_handle.abort(); let (_, state) = cli::cancel(bob_swap.id, bob_swap.bitcoin_wallet, bob_swap.db).await?; - assert!(matches!(state, BobState::BtcCancelled { .. })); + assert!(matches!(state, BobState::BtcCancelPublished { .. })); let (bob_swap, bob_join_handle) = ctx .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) .await; - assert!(matches!(bob_swap.state, BobState::BtcCancelled { .. })); + assert!(matches!(bob_swap.state, BobState::BtcCancelPublished { .. })); // Bob manually refunds bob_join_handle.abort(); diff --git a/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs b/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs index 03bfaa1188..543bf24a3e 100644 --- a/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs +++ b/swap/tests/alice_manually_punishes_after_bob_dead_and_bob_cancels.rs @@ -77,13 +77,13 @@ async fn alice_manually_punishes_after_bob_dead_and_bob_cancels() { bob_join_handle.abort(); let (_, state) = cli::cancel(bob_swap_id, bob_swap.bitcoin_wallet, bob_swap.db).await?; - // Bob should be in BtcCancelled state now. - assert!(matches!(state, BobState::BtcCancelled { .. })); + // Bob should be in BtcCancelPublished state now. + assert!(matches!(state, BobState::BtcCancelPublished { .. })); let (bob_swap, _) = ctx .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) .await; - assert!(matches!(bob_swap.state, BobState::BtcCancelled { .. })); + assert!(matches!(bob_swap.state, BobState::BtcCancelPublished { .. })); // Alice punished Bob, so he should be in the BtcPunished state. let error = cli::refund(bob_swap_id, bob_swap.bitcoin_wallet, bob_swap.db) .await From 29bad8ea81bd12c1fa04a17c945a5ab40ad76a9e Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 12:26:13 -0600 Subject: [PATCH 119/146] fix gui chip for anti spam deposit --- .../swap/init/deposit_and_choose_offer/MakerOfferItem.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index 0a6eff34a4..8aaaa4caff 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -198,8 +198,10 @@ function EarnestDepositChip(quote: BidQuote) { (quote.refund_policy.type === "FullRefund" ? 0 : quote.refund_policy.content?.anti_spam_deposit_ratio) * 1000 ) / 1000; - const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `If the swap is refunded, the maker may choose to freeze ${earnest_deposit_ratio * 100}% of your refund. This is allows them to protect themselves against griefing.`; - const text = full_refund ? "No earnest deposit" : `${earnest_deposit_ratio * 100}% earnest deposit`; + const guaranteed_refund_percentage = (1 - earnest_deposit_ratio) * 100; + + const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `${guaranteed_refund_percentage}% refund cryptographically guaranteed. The maker may withhold the remaining ${earnest_deposit_ratio * 100}% to protect themselves against griefing.`; + const text = full_refund ? "Zero anti-spam deposit" : `${earnest_deposit_ratio * 100}% deposit`; return + color={full_refund ? "success" : "warning"} /> ; } From 9b8c3ef488e6a58eac414c690a4b6a604e6a1588 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 14:26:11 -0600 Subject: [PATCH 120/146] make sanity check for deposit amount for precise, send errors to peer instead of just disconnecting --- swap-machine/src/common/mod.rs | 79 +++++++++++++++------- swap-p2p/src/protocols/swap_setup.rs | 40 +++++++++-- swap-p2p/src/protocols/swap_setup/alice.rs | 12 ++-- swap-p2p/src/protocols/swap_setup/bob.rs | 13 ++-- swap/src/asb/event_loop.rs | 23 +++++-- 5 files changed, 119 insertions(+), 48 deletions(-) diff --git a/swap-machine/src/common/mod.rs b/swap-machine/src/common/mod.rs index f6f7c6a71f..f55b0c66a0 100644 --- a/swap-machine/src/common/mod.rs +++ b/swap-machine/src/common/mod.rs @@ -107,19 +107,34 @@ pub fn sanity_check_transaction_fee( let ceiling = conservative_estimated_fee.to_sat().saturating_mul(3); if fee.to_sat() > ceiling { - bail!( - "Fee ({fee}) exceeds 3x the conservative estimate ({conservative_estimated_fee})", - ); + bail!("Fee ({fee}) exceeds 3x the conservative estimate ({conservative_estimated_fee})",); } Ok(()) } +/// Number of transactions in the withhold path (TxPartialRefund + TxWithhold + TxMercy). +pub const NUM_WITHHOLD_PATH_TXS: u64 = 3; + +#[derive(Clone, Debug, thiserror::Error)] +pub enum SanityCheckError { + #[error("Anti-spam deposit ({amount}) doesn't cover fees (minimum: {minimum_to_cover_fees})")] + AntiSpamDepositTooSmall { + amount: bitcoin::Amount, + minimum_to_cover_fees: bitcoin::Amount, + }, + #[error("Anti-spam deposit ratio ({ratio}) exceeds maximum accepted ({max_accepted_ratio})")] + AntiSpamDepositRatioTooHigh { + ratio: rust_decimal::Decimal, + max_accepted_ratio: rust_decimal::Decimal, + }, +} + /// Validates that the amnesty amount is within sane bounds. /// /// - If amnesty is zero, this is a full-refund swap and no checks are needed. /// - Otherwise, the amnesty must cover all transaction fees that could be spent -/// from it (TxPartialRefund, TxReclaim, TxWithhold, TxMercy). +/// from it (TxPartialRefund + TxReclaim, or TxPartialRefund + TxWithhold + TxMercy). /// - The amnesty ratio (amnesty / lock amount) must not exceed /// [`swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO`]. pub fn sanity_check_amnesty_amount( @@ -129,19 +144,25 @@ pub fn sanity_check_amnesty_amount( tx_reclaim_fee: bitcoin::Amount, tx_withhold_fee: bitcoin::Amount, tx_mercy_fee: bitcoin::Amount, -) -> Result<()> { +) -> std::result::Result<(), SanityCheckError> { if amnesty_amount == bitcoin::Amount::ZERO { return Ok(()); } - let min_amnesty = tx_partial_refund_fee + tx_reclaim_fee + tx_withhold_fee + tx_mercy_fee; - if amnesty_amount < min_amnesty { - bail!( - "Amnesty amount ({amnesty_amount}) is less than the combined fees \ - for TxPartialRefund ({tx_partial_refund_fee}), TxReclaim ({tx_reclaim_fee}), \ - TxWithhold ({tx_withhold_fee}), and TxMercy ({tx_mercy_fee}). \ - The deposit would be consumed by fees.", - ); + let reclaim_path = tx_partial_refund_fee + tx_reclaim_fee; + if amnesty_amount <= reclaim_path { + return Err(SanityCheckError::AntiSpamDepositTooSmall { + amount: amnesty_amount, + minimum_to_cover_fees: reclaim_path, + }); + } + + let withhold_path = tx_partial_refund_fee + tx_withhold_fee + tx_mercy_fee; + if amnesty_amount <= withhold_path { + return Err(SanityCheckError::AntiSpamDepositTooSmall { + amount: amnesty_amount, + minimum_to_cover_fees: withhold_path, + }); } let amnesty_sats = rust_decimal::Decimal::from_u64(amnesty_amount.to_sat()) @@ -151,11 +172,10 @@ pub fn sanity_check_amnesty_amount( let ratio = amnesty_sats / lock_sats; if ratio > swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO { - bail!( - "Amnesty ratio ({ratio}) exceeds maximum allowed ratio of {}. \ - The requested deposit is unreasonably high.", - swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO, - ); + return Err(SanityCheckError::AntiSpamDepositRatioTooHigh { + ratio, + max_accepted_ratio: swap_env::config::MAX_ANTI_SPAM_DEPOSIT_RATIO, + }); } Ok(()) @@ -278,8 +298,8 @@ mod tests { /// 1 BTC lock amount. const LOCK: bitcoin::Amount = bitcoin::Amount::from_sat(100_000_000); const FEE: bitcoin::Amount = MIN_ABSOLUTE_TX_FEE; - /// Sum of all 4 fees (the lower bound). - const FEE_FLOOR: u64 = MIN_ABSOLUTE_TX_FEE_SATS * 4; + /// Withhold path: TxPartialRefund + TxWithhold + TxMercy (the binding constraint when all fees are equal). + const WITHHOLD_PATH: u64 = MIN_ABSOLUTE_TX_FEE_SATS * NUM_WITHHOLD_PATH_TXS; /// 20% of LOCK (the upper bound). const RATIO_CEILING: u64 = 20_000_000; @@ -290,17 +310,24 @@ mod tests { } #[test] - fn reject_amnesty_below_fee_floor() { - let amnesty = bitcoin::Amount::from_sat(FEE_FLOOR - 1); + fn reject_amnesty_below_withhold_path() { + let amnesty = bitcoin::Amount::from_sat(WITHHOLD_PATH - 1); + sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) + .expect_err("amnesty below withhold path fees should be rejected"); + } + + #[test] + fn reject_amnesty_equal_to_withhold_path() { + let amnesty = bitcoin::Amount::from_sat(WITHHOLD_PATH); sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) - .expect_err("amnesty below fee floor should be rejected"); + .expect_err("amnesty equal to withhold path fees should be rejected"); } #[test] - fn pass_amnesty_at_fee_floor() { - let amnesty = bitcoin::Amount::from_sat(FEE_FLOOR); + fn pass_amnesty_above_withhold_path() { + let amnesty = bitcoin::Amount::from_sat(WITHHOLD_PATH + 1); sanity_check_amnesty_amount(LOCK, amnesty, FEE, FEE, FEE, FEE) - .expect("amnesty exactly at fee floor should pass"); + .expect("amnesty above withhold path fees should pass"); } #[test] diff --git a/swap-p2p/src/protocols/swap_setup.rs b/swap-p2p/src/protocols/swap_setup.rs index 776c0009ab..540d4a3c70 100644 --- a/swap-p2p/src/protocols/swap_setup.rs +++ b/swap-p2p/src/protocols/swap_setup.rs @@ -53,6 +53,20 @@ pub enum SpotPriceResponse { Error(SpotPriceError), } +#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)] +pub enum SwapSetupError { + #[error("Anti-spam deposit ({amount}) doesn't cover fees (minimum: {minimum_to_cover_fees})")] + AntiSpamDepositTooSmall { + amount: bitcoin::Amount, + minimum_to_cover_fees: bitcoin::Amount, + }, + #[error("Anti-spam deposit ratio ({ratio}) exceeds maximum accepted ({max_accepted_ratio})")] + AntiSpamDepositRatioTooHigh { + ratio: rust_decimal::Decimal, + max_accepted_ratio: rust_decimal::Decimal, + }, +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub enum SpotPriceError { NoSwapsAccepted, @@ -82,7 +96,7 @@ fn codec() -> unsigned_varint::codec::UviBytes { codec } -pub async fn read_cbor_message(stream: &mut Stream) -> Result +pub async fn read_cbor_message(stream: &mut Stream) -> Result> where T: DeserializeOwned, { @@ -94,8 +108,8 @@ where .context("Failed to read length-prefixed message from stream")??; let mut de = serde_cbor::Deserializer::from_slice(&bytes); - let message = - T::deserialize(&mut de).context("Failed to deserialize bytes into message using CBOR")?; + let message = Result::::deserialize(&mut de) + .context("Failed to deserialize bytes into message using CBOR")?; Ok(message) } @@ -104,8 +118,24 @@ pub async fn write_cbor_message(stream: &mut Stream, message: T) -> Result<() where T: Serialize, { - let bytes = - serde_cbor::to_vec(&message).context("Failed to serialize message as bytes using CBOR")?; + let wrapped = Ok::<_, SwapSetupError>(message); + let bytes = serde_cbor::to_vec(&wrapped) + .context("Failed to serialize message as bytes using CBOR")?; + + let mut frame = Framed::new(stream, codec()); + + frame + .send(Bytes::from(bytes)) + .await + .context("Failed to write bytes as length-prefixed message")?; + + Ok(()) +} + +pub async fn write_cbor_error(stream: &mut Stream, error: SwapSetupError) -> Result<()> { + let wrapped = Err::<(), _>(error); + let bytes = serde_cbor::to_vec(&wrapped) + .context("Failed to serialize error as bytes using CBOR")?; let mut frame = Framed::new(stream, codec()); diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index c0560e4078..34b7985595 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -455,7 +455,8 @@ async fn run_swap_setup( ) -> Result<(Uuid, State3)> { let request = swap_setup::read_cbor_message::(&mut substream) .await - .context("Failed to read spot price request")?; + .context("Failed to read spot price request")? + .context("Peer sent an error instead of spot price request")?; let (wallet_snapshot, btc_amnesty_amount, should_burn_on_refund) = sender .send_receive(request.btc) @@ -551,7 +552,8 @@ async fn run_swap_setup( let message0 = swap_setup::read_cbor_message::(&mut substream) .await - .context("Failed to read message0")?; + .context("Failed to read message0")? + .context("Peer sent an error instead of message0")?; let (swap_id, state1) = state0 .receive(message0) .context("Failed to transition state0 -> state1 using message0")?; @@ -567,7 +569,8 @@ async fn run_swap_setup( let message2 = swap_setup::read_cbor_message::(&mut substream) .await - .context("Failed to read message2")?; + .context("Failed to read message2")? + .context("Peer sent an error instead of message2")?; let state2 = state1 .receive(message2) .context("Failed to transition state1 -> state2 using message2")?; @@ -581,7 +584,8 @@ async fn run_swap_setup( let message4 = swap_setup::read_cbor_message::(&mut substream) .await - .context("Failed to read message4")?; + .context("Failed to read message4")? + .context("Peer sent an error instead of message4")?; let state3 = state2 .receive(message4) .context("Failed to transition state2 -> state3 using message4")?; diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index db0db74b82..37387b8de8 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -548,14 +548,11 @@ async fn run_swap_setup( .await .context("Failed to send spot price request to Alice")?; - // Here we read the spot price response from Alice - // The outer ? checks if Alice responded with an error (SpotPriceError) let xmr = Result::from( - // The inner ? is for the read_cbor_message function - // It will return an error if the deserialization fails read_cbor_message::(&mut substream) .await - .context("Failed to read spot price response from Alice")?, + .context("Failed to read spot price response from Alice")? + .context("Peer sent an error instead of spot price response")?, )?; tracing::trace!( @@ -598,7 +595,8 @@ async fn run_swap_setup( .context("Failed to send state0 message to Alice")?; let message1 = read_cbor_message::(&mut substream) .await - .context("Failed to read message1 from Alice")?; + .context("Failed to read message1 from Alice")? + .context("Peer sent an error instead of message1")?; let state1 = state0 .receive(bitcoin_wallet.as_ref(), message1) .await @@ -614,7 +612,8 @@ async fn run_swap_setup( .context("Failed to send state1 message")?; let message3 = read_cbor_message::(&mut substream) .await - .context("Failed to read message3 from Alice")?; + .context("Failed to read message3 from Alice")? + .context("Peer sent an error instead of message3")?; let state2 = state1 .receive(message3) .context("Failed to receive state2")?; diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index a72add2440..2f556dd95f 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -12,7 +12,7 @@ use crate::network::transfer_proof; use crate::protocol::alice::swap::has_already_processed_enc_sig; use crate::protocol::alice::{AliceState, State3, Swap, TipConfig}; use crate::protocol::{Database, State}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use bitcoin_wallet::BitcoinWallet; use futures::future; use futures::future::{BoxFuture, FutureExt}; @@ -961,14 +961,25 @@ fn apply_anti_spam_policy( .checked_mul(btc_anti_spam_deposit_ratio) .context("Decimal overflow when computing amnesty amount in sats")? .floor(); - let btc_amnesty_sats = btc_amnesty_decimal + let btc_amnesty_sats: u64 = btc_amnesty_decimal .try_into() .context("Couldn't convert Decimal to u64")?; - Ok(( - bitcoin::Amount::from_sat(btc_amnesty_sats), - should_always_withhold, - )) + let btc_amnesty_amount = bitcoin::Amount::from_sat(btc_amnesty_sats); + + let minimum_to_cover_fees = bitcoin::Amount::from_sat( + bitcoin_wallet::MIN_ABSOLUTE_TX_FEE_SATS + * swap_machine::common::NUM_WITHHOLD_PATH_TXS + + 1, + ); + if btc_amnesty_amount < minimum_to_cover_fees { + bail!( + "Anti-spam deposit ({btc_amnesty_amount}) doesn't cover fees \ + (minimum: {minimum_to_cover_fees}). Increase the swap amount or the deposit ratio.", + ); + } + + Ok((btc_amnesty_amount, should_always_withhold)) } async fn capture_wallet_snapshot( From b55b18675436648af6e27568653701ace763eaf2 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 16 Feb 2026 14:42:47 -0600 Subject: [PATCH 121/146] swap_setup(bob+alice): share sanity check error with peer before ending stream --- swap-machine/src/alice/mod.rs | 16 ---------------- swap-machine/src/bob/mod.rs | 21 --------------------- swap-p2p/src/protocols/swap_setup.rs | 21 +++++++++++++++++++++ swap-p2p/src/protocols/swap_setup/alice.rs | 13 +++++++++++++ swap-p2p/src/protocols/swap_setup/bob.rs | 15 ++++++++++++++- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index a63b591bcf..ed733b203c 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -271,22 +271,6 @@ impl State0 { bail!("Bob's dleq proof doesn't verify") } - let amnesty_amount = self - .btc_amnesty_amount - .context("btc_amnesty_amount missing for new swap")?; - let tx_withhold_fee = self - .tx_withhold_fee - .context("tx_withhold_fee missing for new swap")?; - - crate::common::sanity_check_amnesty_amount( - self.btc, - amnesty_amount, - msg.tx_partial_refund_fee, - msg.tx_reclaim_fee, - tx_withhold_fee, - msg.tx_mercy_fee, - )?; - let v = self.v_a + msg.v_b; Ok(( diff --git a/swap-machine/src/bob/mod.rs b/swap-machine/src/bob/mod.rs index fe608115cf..b8a41221ab 100644 --- a/swap-machine/src/bob/mod.rs +++ b/swap-machine/src/bob/mod.rs @@ -389,27 +389,6 @@ impl State0 { bail!("Alice's dleq proof doesn't verify") } - { - let tx_partial_refund_fee = self - .tx_partial_refund_fee - .context("tx_partial_refund_fee missing for new swap")?; - let tx_reclaim_fee = self - .tx_reclaim_fee - .context("tx_reclaim_fee missing for new swap")?; - let tx_mercy_fee = self - .tx_mercy_fee - .context("tx_mercy_fee missing for new swap")?; - - crate::common::sanity_check_amnesty_amount( - self.btc, - msg.amnesty_amount, - tx_partial_refund_fee, - tx_reclaim_fee, - msg.tx_withhold_fee, - tx_mercy_fee, - )?; - } - let tx_lock = swap_core::bitcoin::TxLock::new( wallet, self.btc, diff --git a/swap-p2p/src/protocols/swap_setup.rs b/swap-p2p/src/protocols/swap_setup.rs index 540d4a3c70..2feb567eb5 100644 --- a/swap-p2p/src/protocols/swap_setup.rs +++ b/swap-p2p/src/protocols/swap_setup.rs @@ -67,6 +67,27 @@ pub enum SwapSetupError { }, } +impl From for SwapSetupError { + fn from(err: swap_machine::common::SanityCheckError) -> Self { + match err { + swap_machine::common::SanityCheckError::AntiSpamDepositTooSmall { + amount, + minimum_to_cover_fees, + } => SwapSetupError::AntiSpamDepositTooSmall { + amount, + minimum_to_cover_fees, + }, + swap_machine::common::SanityCheckError::AntiSpamDepositRatioTooHigh { + ratio, + max_accepted_ratio, + } => SwapSetupError::AntiSpamDepositRatioTooHigh { + ratio, + max_accepted_ratio, + }, + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub enum SpotPriceError { NoSwapsAccepted, diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 34b7985595..8dd4dfd5d1 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -554,6 +554,19 @@ async fn run_swap_setup( .await .context("Failed to read message0")? .context("Peer sent an error instead of message0")?; + + if let Err(sanity_err) = swap_machine::common::sanity_check_amnesty_amount( + request.btc, + btc_amnesty_amount, + message0.tx_partial_refund_fee, + message0.tx_reclaim_fee, + wallet_snapshot.withhold_fee, + message0.tx_mercy_fee, + ) { + let _ = swap_setup::write_cbor_error(&mut substream, sanity_err.clone().into()).await; + return Err(sanity_err).context("Amnesty sanity check failed"); + } + let (swap_id, state1) = state0 .receive(message0) .context("Failed to transition state0 -> state1 using message0")?; diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 37387b8de8..574e15458d 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -25,7 +25,7 @@ use swap_machine::bob::{State0, State2}; use swap_machine::common::{Message1, Message3}; use uuid::Uuid; -use super::{SpotPriceRequest, read_cbor_message, write_cbor_message}; +use super::{SpotPriceRequest, read_cbor_message, write_cbor_error, write_cbor_message}; // TODO: This should use redial::Behaviour to keep connections alive for peers with queued requests // TODO: Do not use swap_id as key inside the ConnectionHandler, use another key @@ -597,6 +597,19 @@ async fn run_swap_setup( .await .context("Failed to read message1 from Alice")? .context("Peer sent an error instead of message1")?; + + if let Err(sanity_err) = swap_machine::common::sanity_check_amnesty_amount( + new_swap_request.btc, + message1.amnesty_amount, + new_swap_request.tx_partial_refund_fee, + new_swap_request.tx_reclaim_fee, + message1.tx_withhold_fee, + new_swap_request.tx_mercy_fee, + ) { + let _ = write_cbor_error(&mut substream, sanity_err.clone().into()).await; + return Err(sanity_err).context("Amnesty sanity check failed"); + } + let state1 = state0 .receive(bitcoin_wallet.as_ref(), message1) .await From 805f9945aea9edae73ddf05ccb8965df835876f6 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 23 Feb 2026 17:35:25 +0100 Subject: [PATCH 122/146] fix gui states, timelock display --- src-gui/src/models/tauriModelExt.ts | 6 ++++++ .../alert/SwapStatusAlert/SwapStatusAlert.tsx | 4 ++++ swap-machine/src/alice/mod.rs | 3 ++- swap-p2p/src/protocols/swap_setup/alice.rs | 6 +++++- swap/src/asb/event_loop.rs | 15 +++++---------- swap/src/protocol/bob/swap.rs | 2 +- 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src-gui/src/models/tauriModelExt.ts b/src-gui/src/models/tauriModelExt.ts index 23fd98e48f..89a6372844 100644 --- a/src-gui/src/models/tauriModelExt.ts +++ b/src-gui/src/models/tauriModelExt.ts @@ -63,6 +63,8 @@ export enum BobStateName { BtcWithheld = "btc is withheld", BtcMercyPublished = "btc mercy is published", BtcMercyConfirmed = "btc mercy is confirmed", + WaitingForReclaimTimelockExpiration = "waiting for remaining refund timelock to expire", + ReclaimTimelockExpired = "remaining refund timelock expired", XmrRedeemed = "xmr is redeemed", BtcPunished = "btc is punished", SafelyAborted = "safely aborted", @@ -118,6 +120,10 @@ export function bobStateNameToHumanReadable(stateName: BobStateName): string { return "Bitcoin mercy published"; case BobStateName.BtcMercyConfirmed: return "Bitcoin mercy received"; + case BobStateName.WaitingForReclaimTimelockExpiration: + return "Waiting for amnesty timelock"; + case BobStateName.ReclaimTimelockExpired: + return "Amnesty timelock expired"; case BobStateName.XmrRedeemed: return "Monero redeemed"; case BobStateName.BtcPunished: diff --git a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx index 40133fbb49..1d559f36ea 100644 --- a/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx +++ b/src-gui/src/renderer/components/alert/SwapStatusAlert/SwapStatusAlert.tsx @@ -328,6 +328,10 @@ export function StateAlert({ // Amnesty tx published, waiting for confirmation - no specific alert needed return null; + case BobStateName.WaitingForReclaimTimelockExpiration: + case BobStateName.ReclaimTimelockExpired: + return null; + // If the Bitcoin lock transaction has not been published yet // there is no need to display an alert case BobStateName.BtcLockReadyToPublish: diff --git a/swap-machine/src/alice/mod.rs b/swap-machine/src/alice/mod.rs index ed733b203c..2cb7d0133f 100644 --- a/swap-machine/src/alice/mod.rs +++ b/swap-machine/src/alice/mod.rs @@ -468,7 +468,8 @@ impl State2 { self.B, self.btc_amnesty_amount .context("Missing btc_amnesty_amount for new swap that should have it")?, - self.tx_refund_fee, + self.tx_partial_refund_fee + .context("Missing tx_partial_refund_fee for new swap")?, )?; // Alice encsigns the partial refund transaction(bitcoin) digest with Bob's monero // pubkey(S_b). The partial refund transaction spends the output of diff --git a/swap-p2p/src/protocols/swap_setup/alice.rs b/swap-p2p/src/protocols/swap_setup/alice.rs index 8dd4dfd5d1..9bfb7f22c1 100644 --- a/swap-p2p/src/protocols/swap_setup/alice.rs +++ b/swap-p2p/src/protocols/swap_setup/alice.rs @@ -563,7 +563,11 @@ async fn run_swap_setup( wallet_snapshot.withhold_fee, message0.tx_mercy_fee, ) { - let _ = swap_setup::write_cbor_error(&mut substream, sanity_err.clone().into()).await; + if let Err(err) = + swap_setup::write_cbor_error(&mut substream, sanity_err.clone().into()).await + { + tracing::error!(error=%err, "Couldn't send error message to Bob after encountering it, closing connection"); + }; return Err(sanity_err).context("Amnesty sanity check failed"); } diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 2f556dd95f..5c65319df6 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -968,18 +968,13 @@ fn apply_anti_spam_policy( let btc_amnesty_amount = bitcoin::Amount::from_sat(btc_amnesty_sats); let minimum_to_cover_fees = bitcoin::Amount::from_sat( - bitcoin_wallet::MIN_ABSOLUTE_TX_FEE_SATS - * swap_machine::common::NUM_WITHHOLD_PATH_TXS - + 1, + bitcoin_wallet::MIN_ABSOLUTE_TX_FEE_SATS * swap_machine::common::NUM_WITHHOLD_PATH_TXS + 1, ); - if btc_amnesty_amount < minimum_to_cover_fees { - bail!( - "Anti-spam deposit ({btc_amnesty_amount}) doesn't cover fees \ - (minimum: {minimum_to_cover_fees}). Increase the swap amount or the deposit ratio.", - ); - } - Ok((btc_amnesty_amount, should_always_withhold)) + Ok(( + btc_amnesty_amount.max(minimum_to_cover_fees), + should_always_withhold, + )) } async fn capture_wallet_snapshot( diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 499da927db..3d1141af55 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1353,7 +1353,7 @@ async fn next_state( btc_lock_amount: state.tx_lock.lock_amount(), btc_amnesty_amount: state.btc_amnesty_amount.unwrap_or(bitcoin::Amount::ZERO), target_blocks: remaining_refund_timelock.into(), - blocks_until_expiry: status.confirmations(), + blocks_until_expiry: status.blocks_left_until(remaining_refund_timelock), }, ); From 6a2e327f7c869e5b8502ba307f5a9129f68ceb81 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 23 Feb 2026 20:09:34 +0100 Subject: [PATCH 123/146] bob: propagate permantent swap_setup_error and don't retry them e.g. swap was rejected due to the anti spam deposit not covering tx fees, etc. --- swap-p2p/src/protocols/swap_setup/bob.rs | 52 ++++++++++++++++++++---- swap/src/cli/event_loop.rs | 9 +++- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/swap-p2p/src/protocols/swap_setup/bob.rs b/swap-p2p/src/protocols/swap_setup/bob.rs index 574e15458d..78220cf1c5 100644 --- a/swap-p2p/src/protocols/swap_setup/bob.rs +++ b/swap-p2p/src/protocols/swap_setup/bob.rs @@ -387,9 +387,12 @@ impl ConnectionHandler for Handler { let result = run_swap_setup(&mut substream, info, env_config, bitcoin_wallet).await; - result.map_err(|err: anyhow::Error| { - tracing::error!(?err, "Error occurred during swap setup protocol"); - Error::Protocol(format!("{:?}", err)) + result.map_err(|err| match err { + SetupError::Rejected(reason) => Error::SwapRejected(reason), + SetupError::Transient(e) => { + tracing::error!(?e, "Error occurred during swap setup protocol"); + Error::Protocol(format!("{:?}", e)) + } }) }); @@ -527,13 +530,33 @@ impl ConnectionHandler for Handler { } } +/// Distinguishes permanent rejections from transient errors during swap setup. +enum SetupError { + /// The peer (or our own sanity check) explicitly rejected the swap. + Rejected(String), + /// A transient error (network, serialization, etc.) that may succeed on retry. + Transient(anyhow::Error), +} + +impl From for SetupError { + fn from(err: anyhow::Error) -> Self { + SetupError::Transient(err) + } +} + +impl From for SetupError { + fn from(err: Error) -> Self { + SetupError::Transient(err.into()) + } +} + // TODO: This is protocol and should be moved to another crate (probably swap-machine, swap-core or swap) async fn run_swap_setup( mut substream: &mut libp2p::swarm::Stream, new_swap_request: NewSwap, env_config: env::Config, bitcoin_wallet: Arc, -) -> Result { +) -> Result { // Here we request the spot price from Alice write_cbor_message( &mut substream, @@ -593,10 +616,13 @@ async fn run_swap_setup( ) .await .context("Failed to send state0 message to Alice")?; - let message1 = read_cbor_message::(&mut substream) + let message1 = match read_cbor_message::(&mut substream) .await .context("Failed to read message1 from Alice")? - .context("Peer sent an error instead of message1")?; + { + Ok(msg) => msg, + Err(setup_err) => return Err(SetupError::Rejected(setup_err.to_string())), + }; if let Err(sanity_err) = swap_machine::common::sanity_check_amnesty_amount( new_swap_request.btc, @@ -607,7 +633,7 @@ async fn run_swap_setup( new_swap_request.tx_mercy_fee, ) { let _ = write_cbor_error(&mut substream, sanity_err.clone().into()).await; - return Err(sanity_err).context("Amnesty sanity check failed"); + return Err(SetupError::Rejected(sanity_err.to_string())); } let state1 = state0 @@ -623,10 +649,13 @@ async fn run_swap_setup( write_cbor_message(&mut substream, state1.next_message()) .await .context("Failed to send state1 message")?; - let message3 = read_cbor_message::(&mut substream) + let message3 = match read_cbor_message::(&mut substream) .await .context("Failed to read message3 from Alice")? - .context("Peer sent an error instead of message3")?; + { + Ok(msg) => msg, + Err(setup_err) => return Err(SetupError::Rejected(setup_err.to_string())), + }; let state2 = state1 .receive(message3) .context("Failed to receive state2")?; @@ -706,6 +735,11 @@ pub enum Error { #[error("Something went wrong during the swap setup protocol: {0}")] Protocol(String), + /// The peer explicitly rejected the swap setup (e.g. anti-spam deposit too small). + /// This is a permanent error that should not be retried. + #[error("Swap rejected: {0}")] + SwapRejected(String), + /// To be used for errors that cannot be explained on the CLI side (e.g. /// rate update problems on the seller side) #[error("Seller encountered a problem, please try again later.")] diff --git a/swap/src/cli/event_loop.rs b/swap/src/cli/event_loop.rs index 221ce467e9..433ac41cc8 100644 --- a/swap/src/cli/event_loop.rs +++ b/swap/src/cli/event_loop.rs @@ -710,7 +710,14 @@ impl EventLoopHandle { } // These are errors thrown by the swap_setup/bob behaviour Ok(Err(err)) => { - Err(backoff::Error::transient(err.context("A network error occurred while setting up the swap"))) + use swap_p2p::protocols::swap_setup::bob::Error as SetupError; + if err.downcast_ref::() + .is_some_and(|e| matches!(e, SetupError::SwapRejected(_))) + { + Err(backoff::Error::permanent(err)) + } else { + Err(backoff::Error::transient(err.context("A network error occurred while setting up the swap"))) + } } // This will happen if we don't establish a connection to Alice within the timeout of the MPSC channel // The protocol does not dial Alice it self From d655f9195ef2e260fa2b168a61c1decb3257554c Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 23 Feb 2026 20:10:19 +0100 Subject: [PATCH 124/146] test: add integration tests - too small anti spam deposit -> swap rejected -> error gets propagated and bob doesn't retry - bob goes offline during WaitingForReclaimTimelock -> alice publishes TxWithhold -> bob comes back online and goes to BtcWithheld --- .github/workflows/ci.yml | 4 + ...ial_refund_bob_restart_detects_withhold.rs | 88 +++++++++++++++++++ swap/tests/swap_rejected_deposit_too_small.rs | 46 ++++++++++ 3 files changed, 138 insertions(+) create mode 100644 swap/tests/partial_refund_bob_restart_detects_withhold.rs create mode 100644 swap/tests/swap_rejected_deposit_too_small.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08d072f790..e118ca01b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,6 +188,10 @@ jobs: test_name: partial_refund_alice_burns - package: swap test_name: partial_refund_alice_grants_final_amnesty + - package: swap + test_name: swap_rejected_deposit_too_small + - package: swap + test_name: partial_refund_bob_restart_detects_withhold - package: monero-tests test_name: reserve_proof - package: monero-tests diff --git a/swap/tests/partial_refund_bob_restart_detects_withhold.rs b/swap/tests/partial_refund_bob_restart_detects_withhold.rs new file mode 100644 index 0000000000..c9a4ff543c --- /dev/null +++ b/swap/tests/partial_refund_bob_restart_detects_withhold.rs @@ -0,0 +1,88 @@ +pub mod harness; + +use std::time::Duration; + +use harness::bob_run_until::is_remaining_refund_timelock_expired; +use harness::FastAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use swap_env::config::RefundPolicy; + +/// Bob does a partial refund, reaches ReclaimTimelockExpired, then crashes. +/// While Bob is offline, Alice publishes TxWithhold. +/// When Bob restarts, he detects the TxWithhold and transitions to BtcWithheld +/// instead of trying to publish TxReclaim against a spent UTXO. +/// +/// This tests the defensive check in ReclaimTimelockExpired (bob/swap.rs) +/// that verifies TxWithhold hasn't been published before attempting TxReclaim. +#[tokio::test] +async fn bob_restart_at_reclaim_timelock_expired_detects_withhold() { + let refund_policy = Some(RefundPolicy { + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% + always_withhold_deposit: true, + }); + + harness::setup_test( + FastAmnestyConfig, + None, + refund_policy, + |mut ctx| async move { + // Start Bob and save his swap ID for later restart + let (bob_swap, bob_app_handle) = ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + + // Bob runs until ReclaimTimelockExpired. + // With FastAmnestyConfig (3-block remaining refund timelock), this + // happens quickly — well before Alice finishes XMR recovery. + let bob_task = tokio::spawn(bob::run_until( + bob_swap, + is_remaining_refund_timelock_expired, + )); + + // Alice runs all the way to BtcWithholdConfirmed. + // She will: lock XMR → see cancel → see partial refund → recover + // XMR → publish TxWithhold → wait for confirmation. + let alice_swap = ctx.alice_next_swap().await; + let alice_task = + tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Bob finishes first (3-block timelock is much faster than XMR recovery) + let bob_state = bob_task.await??; + assert!( + matches!(bob_state, BobState::ReclaimTimelockExpired(..)), + "Expected ReclaimTimelockExpired, got: {bob_state}" + ); + + // Stop Bob's event loop and prepare for restart + let (bob_swap, _) = ctx + .stop_and_resume_bob_from_db(bob_app_handle, bob_swap_id) + .await; + // Verify Bob loaded the correct state from DB + assert!( + matches!(bob_swap.state, BobState::ReclaimTimelockExpired(..)), + "Expected ReclaimTimelockExpired after DB load, got: {}", + bob_swap.state + ); + + // Help Alice's Monero recovery along by generating blocks + tokio::time::sleep(Duration::from_secs(15)).await; + ctx.monero.generate_blocks().await?; + + // Wait for Alice to finish: XMR recovered, TxWithhold confirmed + let alice_state = alice_task.await??; + ctx.assert_alice_withhold_confirmed(alice_state).await; + + // Now restart Bob. He's in ReclaimTimelockExpired but TxWithhold + // has been published while he was offline. The defensive check + // should detect it and route to BtcWithholdPublished → BtcWithheld. + let bob_task = tokio::spawn(bob::run(bob_swap)); + let bob_state = bob_task.await??; + ctx.assert_bob_withheld(bob_state).await; + + Ok(()) + }, + ) + .await; +} diff --git a/swap/tests/swap_rejected_deposit_too_small.rs b/swap/tests/swap_rejected_deposit_too_small.rs new file mode 100644 index 0000000000..f9abb2cadb --- /dev/null +++ b/swap/tests/swap_rejected_deposit_too_small.rs @@ -0,0 +1,46 @@ +pub mod harness; + +use harness::FastAmnestyConfig; +use rust_decimal::Decimal; +use swap::protocol::bob; +use swap_env::config::RefundPolicy; + +/// Bob tries to swap a very small BTC amount (10,000 sats). +/// Alice has a 5% anti-spam deposit ratio. +/// +/// Alice computes: amnesty = max(10000 * 0.05, 3001) = 3001 sats. +/// But 3001 / 10000 = 30.01% which exceeds the 20% ceiling. +/// +/// Alice rejects the swap during setup and sends an error to Bob. +/// Bob must receive a clear rejection error (not a timeout or generic +/// "connection closed" error). +#[tokio::test] +async fn swap_rejected_due_to_small_deposit_reported_to_bob() { + let refund_policy = Some(RefundPolicy { + anti_spam_deposit_ratio: Decimal::new(5, 2), // 0.05 = 5% + always_withhold_deposit: false, + }); + + harness::setup_test(FastAmnestyConfig, None, refund_policy, |ctx| async move { + // 10,000 sats is small enough that the minimum fee floor (3001 sats) + // pushes the amnesty ratio above the 20% ceiling. + let small_btc = bitcoin::Amount::from_sat(10_000); + let (bob_swap, event_loop) = ctx.bob_params.new_swap(small_btc).await?; + let bob_event_loop = tokio::spawn(event_loop.run()); + + let result = bob::run(bob_swap).await; + + let err = result.expect_err("Expected swap to be rejected due to small deposit"); + let err_msg = format!("{:#}", err); + + assert!( + err_msg.contains("Anti-spam deposit ratio"), + "Expected rejection error about anti-spam deposit ratio, got: {err_msg}" + ); + + bob_event_loop.abort(); + + Ok(()) + }) + .await; +} From 0cdaa65310ecae2d47110b77e537edb82c3d0bf8 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 2 Mar 2026 15:23:12 +0100 Subject: [PATCH 125/146] build: enforce higher stack size --- .cargo/config.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 9b0737155b..8cc5779db4 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,9 +10,6 @@ linker = "arm-linux-gnueabihf-gcc" [target.'cfg(all(windows, target_env = "msvc"))'] rustflags = ["-C", "link-arg=/STACK:8388608"] -[target.'cfg(macos)'] -rustflags = ["-C", "link-arg=-Wl,stack_size,41943040"] - # For the GNU/MinGW tool-chain [target.'cfg(all(windows, target_env = "gnu"))'] linker = "x86_64-w64-mingw32-g++" # Use g++ driver so -lstdc++ gets pulled in automatically @@ -45,3 +42,8 @@ rustflags = [ # "-Lnative=/home/me/Android/Sdk/ndk/27.3.13750724/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android", # "-lstatic=c++abi", ] + +# Increase the default thread stack size to 40 MiB. +# Our callstack can get pretty big (especially in debug mode). +[env] +RUST_MIN_STACK = "41943040" From d5afaf8eaa632c5722309cd31357174856d35c84 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 2 Mar 2026 15:24:28 +0100 Subject: [PATCH 126/146] state-machine(bob): simplify BtcCancelled logic it's not actually simple, but a bit better --- swap/src/protocol/bob/swap.rs | 103 ++++++++++++++++------------------ 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 3d1141af55..6f05780e9c 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -912,66 +912,59 @@ async fn next_state( let bitcoin_wallet = bitcoin_wallet_for_retry.clone(); let state = state_for_retry.clone(); async move { - match state.expired_timelock(&*bitcoin_wallet).await.map_err(backoff::Error::transient)? { - ExpiredTimelocks::None { .. } => { - Err(backoff::Error::Permanent(anyhow::anyhow!( - "Internal error: canceled state reached before cancel timelock was expired" - ))) - } - ExpiredTimelocks::Cancel { .. } => { - // Publish the best Bitcoin refund transaction we can sign: - // - either full refund, if alice sent use that signature (prioritized) - // - or just partial refund. - tracing::debug!("Attempting to refund Bitcoin"); + match state.expired_timelock(&*bitcoin_wallet).await.map_err(backoff::Error::transient)? { + ExpiredTimelocks::None { .. } => { + Err(backoff::Error::Permanent(anyhow::anyhow!( + "Internal error: canceled state reached before cancel timelock was expired" + ))) + } + ExpiredTimelocks::Cancel { .. } => { + // Publish the best Bitcoin refund transaction we can sign: + // - either full refund, if alice sent use that signature (prioritized) + // - or just partial refund. + tracing::debug!("Attempting to refund Bitcoin"); - if state.refund_signatures.has_full_refund_encsig() { - let full_refund_tx = state.signed_full_refund_transaction().context("Couldn't construct full refund Bitcoin transaction")?; - tracing::debug!("Have full refund signature, attempting full refund"); - bitcoin_wallet.ensure_broadcasted(full_refund_tx, "full refund") - .await - .context("Couldn't ensure broadcast of Bitcoin full refund transaction") - .map_err(backoff::Error::transient)?; - - Ok(BobState::BtcRefundPublished(state.clone())) - } else if state.refund_signatures.has_partial_refund_encsig() { - let partial_refund_tx = state.signed_partial_refund_transaction().context("Couldn't construct partial refund Bitcoin transaction")?; - tracing::debug!("Don't have full refund signature, attempting partial refund"); - bitcoin_wallet.ensure_broadcasted(partial_refund_tx, "partial refund") - .await - .context("Couldn't ensure broadcast of Bitcoin partial refund transaction") - .map_err(backoff::Error::transient)?; + if state.refund_signatures.has_full_refund_encsig() { + let full_refund_tx = state.signed_full_refund_transaction().context("Couldn't construct full refund Bitcoin transaction")?; + tracing::debug!("Have full refund signature, attempting full refund"); + bitcoin_wallet.ensure_broadcasted(full_refund_tx, "full refund") + .await + .context("Couldn't ensure broadcast of Bitcoin full refund transaction") + .map_err(backoff::Error::transient)?; + + Ok(BobState::BtcRefundPublished(state.clone())) + } else if state.refund_signatures.has_partial_refund_encsig() { + let partial_refund_tx = state.signed_partial_refund_transaction().context("Couldn't construct partial refund Bitcoin transaction")?; + tracing::debug!("Don't have full refund signature, attempting partial refund"); + bitcoin_wallet.ensure_broadcasted(partial_refund_tx, "partial refund") + .await + .context("Couldn't ensure broadcast of Bitcoin partial refund transaction") + .map_err(backoff::Error::transient)?; - Ok(BobState::BtcPartialRefundPublished(state.clone())) - } else { - Err(backoff::Error::permanent(anyhow!("Unreachable - We have neither partial nor full refund signatures"))) + Ok(BobState::BtcPartialRefundPublished(state.clone())) + } else { + unreachable!("We must have either partial of full refund signatures") + } } - } - ExpiredTimelocks::Punish => { - let tx_lock_id = state.tx_lock_id(); + ExpiredTimelocks::Punish => { + let tx_lock_id = state.tx_lock_id(); - Ok(BobState::BtcPunished { - tx_lock_id, - state, - }) - } - ExpiredTimelocks::WaitingForRemainingRefund { blocks_left } => { - // TxPartialRefund has been published, waiting for remaining_refund_timelock - // This is unusual from BtcCancelled state - means we published partial refund but crashed - // Retry until timelock expires - tracing::debug!("Partial refund published, waiting {} blocks for amnesty timelock", blocks_left); - Err(backoff::Error::transient(anyhow::anyhow!( - "Waiting for remaining refund timelock to expire. Blocks left: {}", - blocks_left - ))) - } - ExpiredTimelocks::RemainingRefund => { - // TxPartialRefund was published and timelock expired - publish TxReclaim - // Transition to BtcPartiallyRefunded which handles reclaim publication - tracing::info!("Remaining refund timelock expired, can publish amnesty transaction"); - Ok(BobState::BtcPartiallyRefunded(state)) + Ok(BobState::BtcPunished { + tx_lock_id, + state, + }) + } + ExpiredTimelocks::WaitingForRemainingRefund { blocks_left } => { + Ok(BobState::WaitingForReclaimTimelockExpiration(state)) + } + ExpiredTimelocks::RemainingRefund => { + // TxPartialRefund was published and timelock expired + // We transition to BtcPartiallyRefunded and handle the reclaim from there + tracing::info!("Bitcoin was partially refunded and the remainig refund timelock expired"); + Ok(BobState::BtcPartiallyRefunded(state)) + } } } - } }, None, None, @@ -1319,7 +1312,7 @@ async fn next_state( BobState::WaitingForReclaimTimelockExpiration(state) => { // Race between: // - Remaining refund timelock expiring (so we can publish TxReclaim) - // - Alice publishing TxWithhold (burns the amnesty output) + // - Alice publishing TxWithhold let tx_partial_refund = state.construct_tx_partial_refund()?; let tx_withhold = state.construct_tx_withhold()?; From b3f0018ac127fa3fdf441177777421ad694f5208 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 15:28:42 +0100 Subject: [PATCH 127/146] gui: bump minimum compatible version to 4.0.0 --- src-gui/src/utils/multiAddrUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-gui/src/utils/multiAddrUtils.ts b/src-gui/src/utils/multiAddrUtils.ts index e753392de3..d03312915d 100644 --- a/src-gui/src/utils/multiAddrUtils.ts +++ b/src-gui/src/utils/multiAddrUtils.ts @@ -1,12 +1,12 @@ import { ExtendedMakerStatus, Maker } from "models/apiModel"; -import { Multiaddr } from "multiaddr"; import semver from "semver"; import { isTestnet } from "store/config"; // const MIN_ASB_VERSION = "1.0.0-alpha.1" // First version to support new libp2p protocol // const MIN_ASB_VERSION = "1.1.0-rc.3" // First version with support for bdk > 1.0 // const MIN_ASB_VERSION = "2.0.0-beta.1"; // First version with support for tx_early_refund -const MIN_ASB_VERSION = "3.2.0-rc.1"; +// const MIN_ASB_VERSION = "3.2.0-rc.1"; +const MIN_ASB_VERSION = "4.0.0"; // First version with partial refund path export function isMakerOnCorrectNetwork( provider: ExtendedMakerStatus, From f3126b805a0dcacebafddb6ebd5b9d67cfe54245 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 15:29:15 +0100 Subject: [PATCH 128/146] gui: add local reputation chip to maker offers also rephrase anti-spam deposit chip --- .../MakerOfferItem.tsx | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index 8aaaa4caff..3105ed4b2e 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -11,6 +11,8 @@ import { resolveApproval } from "renderer/rpc"; import { isMakerVersionOutdated } from "utils/multiAddrUtils"; import WarningIcon from "@mui/icons-material/Warning"; import { RefundPolicy } from "store/features/settingsSlice"; +import { useAppSelector } from "store/hooks"; +import { BobStateName } from "models/tauriModelExt"; function getRefundPercentage(policy: RefundPolicyWire): number { if (policy.type === "FullRefund") { @@ -29,6 +31,7 @@ export default function MakerOfferItem({ const { multiaddr, peer_id, quote, version } = quoteWithAddress; const isOutOfLiquidity = quote.max_quantity == 0; + return (
{EarnestDepositChip(quote)} + {ReputationChip(peer_id)} {isMakerVersionOutdated(version) ? ( ; } +function ReputationChip(peer_id: string) { + const allSwaps = useAppSelector(state => state.rpc.state.swapInfos) + if (!allSwaps) { return <> } + const swapsWithThisPeer = Object.values(allSwaps).filter(swap => swap.seller.peer_id == peer_id) + + const successfullSwaps = swapsWithThisPeer.filter(swap => swap.state_name === BobStateName.XmrRedeemed).length + // TODO: don't hardcode this check (was swap refunded/punished?) here, put into tauriModelExt or other place + const refundedSwaps = swapsWithThisPeer.filter(swap => [BobStateName.BtcRefunded, BobStateName.BtcEarlyRefunded, BobStateName.BtcMercyConfirmed].includes(swap.state_name)).length + const failedSwaps = swapsWithThisPeer.filter(swap => [BobStateName.BtcPunished, BobStateName.BtcWithheld].includes(swap.state_name)).length + + return + + {successfullSwaps} success + + {refundedSwaps} refund + + {failedSwaps} fail + + } + /> + +} From f0b7d82b4310745a4b2312a5bb76f1dff46d6fb9 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 15:33:02 +0100 Subject: [PATCH 129/146] fix typo: successfull -> successful --- .../swap/init/deposit_and_choose_offer/MakerOfferItem.tsx | 6 +++--- swap/src/protocol/bob/swap.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx index 3105ed4b2e..545d8bedd7 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/init/deposit_and_choose_offer/MakerOfferItem.tsx @@ -204,7 +204,7 @@ function EarnestDepositChip(quote: BidQuote) { ) / 1000; const guaranteed_refund_percentage = (1 - earnest_deposit_ratio) * 100; - const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `${guaranteed_refund_percentage}% refund cryptographically guaranteed. The maker may withhold the remaining ${earnest_deposit_ratio * 100}% to protect themselves against griefing.`; + const tooltip_text = full_refund ? "100% refund cryptographically guaranteed." : `${guaranteed_refund_percentage}% refund cryptographically guaranteed. During refunds maker may withhold the remaining ${earnest_deposit_ratio * 100}% to protect themselves against griefing. Does not apply to successful swaps`; const text = `${guaranteed_refund_percentage}% refund guaranteed`; // TODO: use colors better to distinguish between low deposits (1%) and high ones (20%) @@ -225,7 +225,7 @@ function ReputationChip(peer_id: string) { if (!allSwaps) { return <> } const swapsWithThisPeer = Object.values(allSwaps).filter(swap => swap.seller.peer_id == peer_id) - const successfullSwaps = swapsWithThisPeer.filter(swap => swap.state_name === BobStateName.XmrRedeemed).length + const successfulSwaps = swapsWithThisPeer.filter(swap => swap.state_name === BobStateName.XmrRedeemed).length // TODO: don't hardcode this check (was swap refunded/punished?) here, put into tauriModelExt or other place const refundedSwaps = swapsWithThisPeer.filter(swap => [BobStateName.BtcRefunded, BobStateName.BtcEarlyRefunded, BobStateName.BtcMercyConfirmed].includes(swap.state_name)).length const failedSwaps = swapsWithThisPeer.filter(swap => [BobStateName.BtcPunished, BobStateName.BtcWithheld].includes(swap.state_name)).length @@ -238,7 +238,7 @@ function ReputationChip(peer_id: string) { size="small" label={ - {successfullSwaps} success + {successfulSwaps} success {refundedSwaps} refund diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 6f05780e9c..517869063a 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -31,7 +31,7 @@ const PRE_BTC_LOCK_APPROVAL_TIMEOUT_SECS: u64 = 60 * 3; /// This is necessary because sometimes our acknowledgement might not reach Alice. pub fn has_already_processed_transfer_proof(state: &BobState) -> bool { // This match statement MUST match all states which Bob can enter after receiving the transfer proof. - // We do not match any of the cancel / refund states because in those, the swap cannot be successfull anymore. + // We do not match any of the cancel / refund states because in those, the swap cannot be successful anymore. matches!( state, |BobState::XmrLockTransactionSeen { .. }| BobState::XmrLocked(..) From 5d966a7c657b087c5d3733a4e044885ae1c4c335 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 17:47:24 +0100 Subject: [PATCH 130/146] docs: update logo --- docs/components/Logo.tsx | 25 +++++---- docs/public/favicon.svg | 115 +-------------------------------------- 2 files changed, 14 insertions(+), 126 deletions(-) diff --git a/docs/components/Logo.tsx b/docs/components/Logo.tsx index 48387720d2..81a762a8dc 100644 --- a/docs/components/Logo.tsx +++ b/docs/components/Logo.tsx @@ -1,16 +1,17 @@ -import Image from "next/image"; - export default function Logo() { return ( -
- eigenwallet - eigenwallet -
+
); } diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg index 9308c0c65e..ff1f037def 100644 --- a/docs/public/favicon.svg +++ b/docs/public/favicon.svg @@ -1,114 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + From 887c48b14e40c763231101b42cc6be71ba8bb3ac Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 17:47:45 +0100 Subject: [PATCH 131/146] docs: use yarn v4 via corepack --- docs/.yarn/install-state.gz | Bin 0 -> 349039 bytes docs/.yarnrc.yml | 1 + docs/package.json | 3 +- docs/yarn.lock | 7076 ++++++++++++++++++++--------------- 4 files changed, 4063 insertions(+), 3017 deletions(-) create mode 100644 docs/.yarn/install-state.gz create mode 100644 docs/.yarnrc.yml diff --git a/docs/.yarn/install-state.gz b/docs/.yarn/install-state.gz new file mode 100644 index 0000000000000000000000000000000000000000..02b8c1549fc96ebd7a6af563344325dbf2631085 GIT binary patch literal 349039 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%0A|8Qs2AKhEIjcY3?OJQ%z2 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�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 aE}7+60=VGiFaM3d`u_tiK7IA10}udWhqt!? literal 0 HcmV?d00001 diff --git a/docs/.yarnrc.yml b/docs/.yarnrc.yml new file mode 100644 index 0000000000..3186f3f079 --- /dev/null +++ b/docs/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/docs/package.json b/docs/package.json index 3efe72022f..033cca2aff 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,5 +19,6 @@ "devDependencies": { "@types/node": "20.14.5", "typescript": "5.4.5" - } + }, + "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8" } diff --git a/docs/yarn.lock b/docs/yarn.lock index ec6dd8434a..20265d415d 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -1,3016 +1,4060 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/runtime@^7.23.8": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" - integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== - dependencies: - regenerator-runtime "^0.14.0" - -"@braintree/sanitize-url@^6.0.1": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783" - integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A== - -"@emnapi/runtime@^1.2.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60" - integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== - dependencies: - tslib "^2.4.0" - -"@headlessui/react@^1.7.17": - version "1.7.19" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.19.tgz#91c78cf5fcb254f4a0ebe96936d48421caf75f40" - integrity sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw== - dependencies: - "@tanstack/react-virtual" "^3.0.0-beta.60" - client-only "^0.0.1" - -"@img/sharp-darwin-arm64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08" - integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ== - optionalDependencies: - "@img/sharp-libvips-darwin-arm64" "1.0.4" - -"@img/sharp-darwin-x64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" - integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q== - optionalDependencies: - "@img/sharp-libvips-darwin-x64" "1.0.4" - -"@img/sharp-libvips-darwin-arm64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" - integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== - -"@img/sharp-libvips-darwin-x64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" - integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== - -"@img/sharp-libvips-linux-arm64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" - integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== - -"@img/sharp-libvips-linux-arm@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" - integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== - -"@img/sharp-libvips-linux-s390x@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" - integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== - -"@img/sharp-libvips-linux-x64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" - integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== - -"@img/sharp-libvips-linuxmusl-arm64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" - integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== - -"@img/sharp-libvips-linuxmusl-x64@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" - integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== - -"@img/sharp-linux-arm64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" - integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA== - optionalDependencies: - "@img/sharp-libvips-linux-arm64" "1.0.4" - -"@img/sharp-linux-arm@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" - integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ== - optionalDependencies: - "@img/sharp-libvips-linux-arm" "1.0.5" - -"@img/sharp-linux-s390x@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" - integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q== - optionalDependencies: - "@img/sharp-libvips-linux-s390x" "1.0.4" - -"@img/sharp-linux-x64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" - integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA== - optionalDependencies: - "@img/sharp-libvips-linux-x64" "1.0.4" - -"@img/sharp-linuxmusl-arm64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" - integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" - -"@img/sharp-linuxmusl-x64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" - integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-x64" "1.0.4" - -"@img/sharp-wasm32@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" - integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg== - dependencies: - "@emnapi/runtime" "^1.2.0" - -"@img/sharp-win32-ia32@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" - integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== - -"@img/sharp-win32-x64@0.33.5": - version "0.33.5" - resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" - integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== - -"@mdx-js/mdx@^2.2.1", "@mdx-js/mdx@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.3.0.tgz#d65d8c3c28f3f46bb0e7cb3bf7613b39980671a9" - integrity sha512-jLuwRlz8DQfQNiUCJR50Y09CGPq3fLtmtUQfVrj79E0JWu3dvsVcxVIcfhR5h0iXu+/z++zDrYeiJqifRynJkA== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/mdx" "^2.0.0" - estree-util-build-jsx "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - estree-util-to-js "^1.1.0" - estree-walker "^3.0.0" - hast-util-to-estree "^2.0.0" - markdown-extensions "^1.0.0" - periscopic "^3.0.0" - remark-mdx "^2.0.0" - remark-parse "^10.0.0" - remark-rehype "^10.0.0" - unified "^10.0.0" - unist-util-position-from-estree "^1.0.0" - unist-util-stringify-position "^3.0.0" - unist-util-visit "^4.0.0" - vfile "^5.0.0" - -"@mdx-js/react@^2.2.1", "@mdx-js/react@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-2.3.0.tgz#4208bd6d70f0d0831def28ef28c26149b03180b3" - integrity sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g== - dependencies: - "@types/mdx" "^2.0.0" - "@types/react" ">=16" - -"@napi-rs/simple-git-android-arm-eabi@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-android-arm-eabi/-/simple-git-android-arm-eabi-0.1.16.tgz#36b752f84a7e75a9dada3d8b307817f0b015a57d" - integrity sha512-dbrCL0Pl5KZG7x7tXdtVsA5CO6At5ohDX3myf5xIYn9kN4jDFxsocl8bNt6Vb/hZQoJd8fI+k5VlJt+rFhbdVw== - -"@napi-rs/simple-git-android-arm64@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-android-arm64/-/simple-git-android-arm64-0.1.16.tgz#f84d9e2fdae91bb810b55ffc30a42ce5fe020c76" - integrity sha512-xYz+TW5J09iK8SuTAKK2D5MMIsBUXVSs8nYp7HcMi8q6FCRO7yJj96YfP9PvKsc/k64hOyqGmL5DhCzY9Cu1FQ== - -"@napi-rs/simple-git-darwin-arm64@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-darwin-arm64/-/simple-git-darwin-arm64-0.1.16.tgz#8d995a920146c320bf13b32d1b1654f44beaa16b" - integrity sha512-XfgsYqxhUE022MJobeiX563TJqyQyX4FmYCnqrtJwAfivESVeAJiH6bQIum8dDEYMHXCsG7nL8Ok0Dp8k2m42g== - -"@napi-rs/simple-git-darwin-x64@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-darwin-x64/-/simple-git-darwin-x64-0.1.16.tgz#7cc7155392c62f885d248af5f720e108d0aad2b5" - integrity sha512-tkEVBhD6vgRCbeWsaAQqM3bTfpIVGeitamPPRVSbsq8qgzJ5Dx6ZedH27R7KSsA/uao7mZ3dsrNLXbu1Wy5MzA== - -"@napi-rs/simple-git-linux-arm-gnueabihf@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-linux-arm-gnueabihf/-/simple-git-linux-arm-gnueabihf-0.1.16.tgz#d5135543d372e0571d7c19928e75751eb407d7dd" - integrity sha512-R6VAyNnp/yRaT7DV1Ao3r67SqTWDa+fNq2LrNy0Z8gXk2wB9ZKlrxFtLPE1WSpWknWtyRDLpRlsorh7Evk7+7w== - -"@napi-rs/simple-git-linux-arm64-gnu@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-linux-arm64-gnu/-/simple-git-linux-arm64-gnu-0.1.16.tgz#4e293005b2fd62d1eb399b50e53d983378c19fb7" - integrity sha512-LAGI0opFKw/HBMCV2qIBK3uWSEW9h4xd2ireZKLJy8DBPymX6NrWIamuxYNyCuACnFdPRxR4LaRFy4J5ZwuMdw== - -"@napi-rs/simple-git-linux-arm64-musl@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-linux-arm64-musl/-/simple-git-linux-arm64-musl-0.1.16.tgz#679edd2c6d88de6aa35993401722ade04595869b" - integrity sha512-I57Ph0F0Yn2KW93ep+V1EzKhACqX0x49vvSiapqIsdDA2PifdEWLc1LJarBolmK7NKoPqKmf6lAKKO9lhiZzkg== - -"@napi-rs/simple-git-linux-x64-gnu@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-linux-x64-gnu/-/simple-git-linux-x64-gnu-0.1.16.tgz#b33054b14a88335f19261b812f65f8d567e7d199" - integrity sha512-AZYYFY2V7hlcQASPEOWyOa3e1skzTct9QPzz0LiDM3f/hCFY/wBaU2M6NC5iG3d2Kr38heuyFS/+JqxLm5WaKA== - -"@napi-rs/simple-git-linux-x64-musl@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-linux-x64-musl/-/simple-git-linux-x64-musl-0.1.16.tgz#8cfc8f5f35951dacae86e72b5535ea401f868b7a" - integrity sha512-9TyMcYSBJwjT8jwjY9m24BZbu7ozyWTjsmYBYNtK3B0Um1Ov6jthSNneLVvouQ6x+k3Ow+00TiFh6bvmT00r8g== - -"@napi-rs/simple-git-win32-arm64-msvc@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-win32-arm64-msvc/-/simple-git-win32-arm64-msvc-0.1.16.tgz#e6b220574421695f4c05be4e065b1fd46ffb7007" - integrity sha512-uslJ1WuAHCYJWui6xjsyT47SjX6KOHDtClmNO8hqKz1pmDSNY7AjyUY8HxvD1lK9bDnWwc4JYhikS9cxCqHybw== - -"@napi-rs/simple-git-win32-x64-msvc@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-win32-x64-msvc/-/simple-git-win32-x64-msvc-0.1.16.tgz#4ec44d57fc2c069544ffb923a2871d81d5db7cfc" - integrity sha512-SoEaVeCZCDF1MP+M9bMSXsZWgEjk4On9GWADO5JOulvzR1bKjk0s9PMHwe/YztR9F0sJzrCxwtvBZowhSJsQPg== - -"@napi-rs/simple-git@^0.1.9": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@napi-rs/simple-git/-/simple-git-0.1.16.tgz#c48d03b27956ddcd2c886a5e3d5c8bdc0d7ad5fe" - integrity sha512-C5wRPw9waqL2jk3jEDeJv+f7ScuO3N0a39HVdyFLkwKxHH4Sya4ZbzZsu2JLi6eEqe7RuHipHL6mC7B2OfYZZw== - optionalDependencies: - "@napi-rs/simple-git-android-arm-eabi" "0.1.16" - "@napi-rs/simple-git-android-arm64" "0.1.16" - "@napi-rs/simple-git-darwin-arm64" "0.1.16" - "@napi-rs/simple-git-darwin-x64" "0.1.16" - "@napi-rs/simple-git-linux-arm-gnueabihf" "0.1.16" - "@napi-rs/simple-git-linux-arm64-gnu" "0.1.16" - "@napi-rs/simple-git-linux-arm64-musl" "0.1.16" - "@napi-rs/simple-git-linux-x64-gnu" "0.1.16" - "@napi-rs/simple-git-linux-x64-musl" "0.1.16" - "@napi-rs/simple-git-win32-arm64-msvc" "0.1.16" - "@napi-rs/simple-git-win32-x64-msvc" "0.1.16" - -"@next/env@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.3.tgz#a2e9bf274743c52b74d30f415f3eba750d51313a" - integrity sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA== - -"@next/swc-darwin-arm64@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz#4c40c506cf3d4d87da0204f4cccf39e6bdc46a71" - integrity sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw== - -"@next/swc-darwin-x64@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz#8e06cacae3dae279744f9fbe88dea679ec2c1ca3" - integrity sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw== - -"@next/swc-linux-arm64-gnu@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz#c144ad1f21091b9c6e1e330ecc2d56188763191d" - integrity sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw== - -"@next/swc-linux-arm64-musl@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz#3ccb71c6703bf421332f177d1bb0e10528bc73a2" - integrity sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA== - -"@next/swc-linux-x64-gnu@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz#b90aa9b07001b4000427c35ab347a9273cbeebb3" - integrity sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w== - -"@next/swc-linux-x64-musl@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz#0ac9724fb44718fc97bfea971ac3fe17e486590e" - integrity sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA== - -"@next/swc-win32-arm64-msvc@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz#932437d4cf27814e963ba8ae5f033b4421fab9ca" - integrity sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ== - -"@next/swc-win32-x64-msvc@15.0.3": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz#940a6f7b370cdde0cc67eabe945d9e6d97e0be9f" - integrity sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA== - -"@popperjs/core@^2.11.8": - version "2.11.8" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" - integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== - -"@swc/counter@0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" - integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== - -"@swc/helpers@0.5.13": - version "0.5.13" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c" - integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w== - dependencies: - tslib "^2.4.0" - -"@tanstack/react-virtual@^3.0.0-beta.60": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.5.1.tgz#1ce466f530a10f781871360ed2bf7ff83e664f85" - integrity sha512-jIsuhfgy8GqA67PdWqg73ZB2LFE+HD9hjWL1L6ifEIZVyZVAKpYmgUG4WsKQ005aEyImJmbuimPiEvc57IY0Aw== - dependencies: - "@tanstack/virtual-core" "3.5.1" - -"@tanstack/virtual-core@3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.5.1.tgz#f519149bce9156d0e7954b9531df15f446f2fc12" - integrity sha512-046+AUSiDru/V9pajE1du8WayvBKeCvJ2NmKPy/mR8/SbKKrqmSbj7LJBfXE+nSq4f5TBXvnCzu0kcYebI9WdQ== - -"@theguild/remark-mermaid@^0.0.5": - version "0.0.5" - resolved "https://registry.yarnpkg.com/@theguild/remark-mermaid/-/remark-mermaid-0.0.5.tgz#0f95671d247381f416e528e937be08bb7a695224" - integrity sha512-e+ZIyJkEv9jabI4m7q29wZtZv+2iwPGsXJ2d46Zi7e+QcFudiyuqhLhHG/3gX3ZEB+hxTch+fpItyMS8jwbIcw== - dependencies: - mermaid "^10.2.2" - unist-util-visit "^5.0.0" - -"@theguild/remark-npm2yarn@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@theguild/remark-npm2yarn/-/remark-npm2yarn-0.2.1.tgz#63bf5a8c85d7fe505d4808812dbc56d9c2ce00f8" - integrity sha512-jUTFWwDxtLEFtGZh/TW/w30ySaDJ8atKWH8dq2/IiQF61dPrGfETpl0WxD0VdBfuLOeU14/kop466oBSRO/5CA== - dependencies: - npm-to-yarn "^2.1.0" - unist-util-visit "^5.0.0" - -"@types/acorn@^4.0.0": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" - integrity sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ== - dependencies: - "@types/estree" "*" - -"@types/d3-scale-chromatic@^3.0.0": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz#fc0db9c10e789c351f4c42d96f31f2e4df8f5644" - integrity sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw== - -"@types/d3-scale@^4.0.3": - version "4.0.8" - resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.8.tgz#d409b5f9dcf63074464bf8ddfb8ee5a1f95945bb" - integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ== - dependencies: - "@types/d3-time" "*" - -"@types/d3-time@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.3.tgz#3c186bbd9d12b9d84253b6be6487ca56b54f88be" - integrity sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw== - -"@types/debug@^4.0.0": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - -"@types/estree-jsx@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" - integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== - dependencies: - "@types/estree" "*" - -"@types/estree@*", "@types/estree@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - -"@types/hast@^2.0.0": - version "2.3.10" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" - integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== - dependencies: - "@types/unist" "^2" - -"@types/hast@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" - integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== - dependencies: - "@types/unist" "*" - -"@types/js-yaml@^4.0.0": - version "4.0.9" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" - integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== - -"@types/katex@^0.16.0": - version "0.16.7" - resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.16.7.tgz#03ab680ab4fa4fbc6cb46ecf987ecad5d8019868" - integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ== - -"@types/mdast@^3.0.0": - version "3.0.15" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5" - integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ== - dependencies: - "@types/unist" "^2" - -"@types/mdast@^4.0.0": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" - integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== - dependencies: - "@types/unist" "*" - -"@types/mdx@^2.0.0": - version "2.0.13" - resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" - integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== - -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - -"@types/node@20.14.5": - version "20.14.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.5.tgz#fe35e3022ebe58b8f201580eb24e1fcfc0f2487d" - integrity sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA== - dependencies: - undici-types "~5.26.4" - -"@types/prop-types@*": - version "15.7.12" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== - -"@types/react@>=16": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/unist@*", "@types/unist@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" - integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== - -"@types/unist@^2", "@types/unist@^2.0.0": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" - integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== - -"@ungap/structured-clone@^1.0.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -acorn-jsx@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.0.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" - integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== - -ansi-sequence-parser@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" - integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== - -ansi-styles@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -arch@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - -arg@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050" - integrity sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -astring@^1.8.0: - version "1.8.6" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.6.tgz#2c9c157cf1739d67561c56ba896e6948f6b93731" - integrity sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg== - -bail@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" - integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== - -busboy@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - -caniuse-lite@^1.0.30001579: - version "1.0.30001636" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz#b15f52d2bdb95fad32c2f53c0b68032b85188a78" - integrity sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg== - -ccount@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" - integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== - -chalk@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" - integrity sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q== - dependencies: - ansi-styles "^3.1.0" - escape-string-regexp "^1.0.5" - supports-color "^4.0.0" - -character-entities-html4@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" - integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== - -character-entities-legacy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" - integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - -character-entities@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" - integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== - -character-reference-invalid@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" - integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== - -client-only@0.0.1, client-only@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" - integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== - -clipboardy@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.2.tgz#2ce320b9ed9be1514f79878b53ff9765420903e2" - integrity sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw== - dependencies: - arch "^2.1.0" - execa "^0.8.0" - -clsx@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" - integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" - integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" - integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - -comma-separated-tokens@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" - integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== - -commander@7: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - -compute-scroll-into-view@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87" - integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg== - -cose-base@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" - integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg== - dependencies: - layout-base "^1.0.0" - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A== - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -cytoscape-cose-bilkent@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" - integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ== - dependencies: - cose-base "^1.0.0" - -cytoscape@^3.28.1: - version "3.29.2" - resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.29.2.tgz#c99f42513c80a75e2e94858add32896c860202ac" - integrity sha512-2G1ycU28Nh7OHT9rkXRLpCDP30MKH1dXJORZuBhtEhEW7pKwgPi77ImqlCWinouyE1PNepIOGZBOrE84DG7LyQ== - -"d3-array@1 - 2": - version "2.12.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== - dependencies: - internmap "^1.0.0" - -"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" - integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== - dependencies: - internmap "1 - 2" - -d3-axis@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" - integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== - -d3-brush@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" - integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "3" - d3-transition "3" - -d3-chord@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" - integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== - dependencies: - d3-path "1 - 3" - -"d3-color@1 - 3", d3-color@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" - integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== - -d3-contour@4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc" - integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA== - dependencies: - d3-array "^3.2.0" - -d3-delaunay@6: - version "6.0.4" - resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b" - integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A== - dependencies: - delaunator "5" - -"d3-dispatch@1 - 3", d3-dispatch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" - integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== - -"d3-drag@2 - 3", d3-drag@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" - integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== - dependencies: - d3-dispatch "1 - 3" - d3-selection "3" - -"d3-dsv@1 - 3", d3-dsv@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" - integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== - dependencies: - commander "7" - iconv-lite "0.6" - rw "1" - -"d3-ease@1 - 3", d3-ease@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" - integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== - -d3-fetch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" - integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== - dependencies: - d3-dsv "1 - 3" - -d3-force@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" - integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== - dependencies: - d3-dispatch "1 - 3" - d3-quadtree "1 - 3" - d3-timer "1 - 3" - -"d3-format@1 - 3", d3-format@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" - integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== - -d3-geo@3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.1.tgz#6027cf51246f9b2ebd64f99e01dc7c3364033a4d" - integrity sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q== - dependencies: - d3-array "2.5.0 - 3" - -d3-hierarchy@3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" - integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== - -"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" - integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== - dependencies: - d3-color "1 - 3" - -d3-path@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" - integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== - -"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" - integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== - -d3-polygon@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" - integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== - -"d3-quadtree@1 - 3", d3-quadtree@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" - integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== - -d3-random@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" - integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== - -d3-sankey@^0.12.3: - version "0.12.3" - resolved "https://registry.yarnpkg.com/d3-sankey/-/d3-sankey-0.12.3.tgz#b3c268627bd72e5d80336e8de6acbfec9d15d01d" - integrity sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ== - dependencies: - d3-array "1 - 2" - d3-shape "^1.2.0" - -d3-scale-chromatic@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" - integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== - dependencies: - d3-color "1 - 3" - d3-interpolate "1 - 3" - -d3-scale@4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" - integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== - dependencies: - d3-array "2.10.0 - 3" - d3-format "1 - 3" - d3-interpolate "1.2.0 - 3" - d3-time "2.1.1 - 3" - d3-time-format "2 - 4" - -"d3-selection@2 - 3", d3-selection@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" - integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== - -d3-shape@3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" - integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== - dependencies: - d3-path "^3.1.0" - -d3-shape@^1.2.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" - integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== - dependencies: - d3-path "1" - -"d3-time-format@2 - 4", d3-time-format@4: - version "4.1.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" - integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== - dependencies: - d3-time "1 - 3" - -"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" - integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== - dependencies: - d3-array "2 - 3" - -"d3-timer@1 - 3", d3-timer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" - integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== - -"d3-transition@2 - 3", d3-transition@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" - integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== - dependencies: - d3-color "1 - 3" - d3-dispatch "1 - 3" - d3-ease "1 - 3" - d3-interpolate "1 - 3" - d3-timer "1 - 3" - -d3-zoom@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" - integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "2 - 3" - d3-transition "2 - 3" - -d3@^7.4.0, d3@^7.8.2: - version "7.9.0" - resolved "https://registry.yarnpkg.com/d3/-/d3-7.9.0.tgz#579e7acb3d749caf8860bd1741ae8d371070cd5d" - integrity sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA== - dependencies: - d3-array "3" - d3-axis "3" - d3-brush "3" - d3-chord "3" - d3-color "3" - d3-contour "4" - d3-delaunay "6" - d3-dispatch "3" - d3-drag "3" - d3-dsv "3" - d3-ease "3" - d3-fetch "3" - d3-force "3" - d3-format "3" - d3-geo "3" - d3-hierarchy "3" - d3-interpolate "3" - d3-path "3" - d3-polygon "3" - d3-quadtree "3" - d3-random "3" - d3-scale "4" - d3-scale-chromatic "3" - d3-selection "3" - d3-shape "3" - d3-time "3" - d3-time-format "4" - d3-timer "3" - d3-transition "3" - d3-zoom "3" - -dagre-d3-es@7.0.10: - version "7.0.10" - resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz#19800d4be674379a3cd8c86a8216a2ac6827cadc" - integrity sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A== - dependencies: - d3 "^7.8.2" - lodash-es "^4.17.21" - -dayjs@^1.11.7: - version "1.11.11" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" - integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== - -debug@^4.0.0: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -decode-named-character-reference@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" - integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== - dependencies: - character-entities "^2.0.0" - -delaunator@5: - version "5.0.1" - resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" - integrity sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw== - dependencies: - robust-predicates "^3.0.2" - -dequal@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" - integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== - -detect-libc@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" - integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== - -devlop@^1.0.0, devlop@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" - integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== - dependencies: - dequal "^2.0.0" - -diff@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" - integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== - -dompurify@^3.0.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.1.5.tgz#2c6a113fc728682a0f55684b1388c58ddb79dc38" - integrity sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA== - -elkjs@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.9.3.tgz#16711f8ceb09f1b12b99e971b138a8384a529161" - integrity sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ== - -entities@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" - integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -estree-util-attach-comments@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-2.1.1.tgz#ee44f4ff6890ee7dfb3237ac7810154c94c63f84" - integrity sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w== - dependencies: - "@types/estree" "^1.0.0" - -estree-util-build-jsx@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-2.2.2.tgz#32f8a239fb40dc3f3dca75bb5dcf77a831e4e47b" - integrity sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg== - dependencies: - "@types/estree-jsx" "^1.0.0" - estree-util-is-identifier-name "^2.0.0" - estree-walker "^3.0.0" - -estree-util-is-identifier-name@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.1.0.tgz#fb70a432dcb19045e77b05c8e732f1364b4b49b2" - integrity sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ== - -estree-util-to-js@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/estree-util-to-js/-/estree-util-to-js-1.2.0.tgz#0f80d42443e3b13bd32f7012fffa6f93603f4a36" - integrity sha512-IzU74r1PK5IMMGZXUVZbmiu4A1uhiPgW5hm1GjcOfr4ZzHaMPpLNJjR7HjXiIOzi25nZDrgFTobHTkV5Q6ITjA== - dependencies: - "@types/estree-jsx" "^1.0.0" - astring "^1.8.0" - source-map "^0.7.0" - -estree-util-value-to-estree@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/estree-util-value-to-estree/-/estree-util-value-to-estree-1.3.0.tgz#1d3125594b4d6680f666644491e7ac1745a3df49" - integrity sha512-Y+ughcF9jSUJvncXwqRageavjrNPAI+1M/L3BI3PyLp1nmgYTGUXU6t5z1Y7OWuThoDdhPME07bQU+d5LxdJqw== - dependencies: - is-plain-obj "^3.0.0" - -estree-util-visit@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.2.1.tgz#8bc2bc09f25b00827294703835aabee1cc9ec69d" - integrity sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/unist" "^2.0.0" - -estree-walker@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" - integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== - dependencies: - "@types/estree" "^1.0.0" - -execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - integrity sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA== - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -flexsearch@^0.7.31: - version "0.7.43" - resolved "https://registry.yarnpkg.com/flexsearch/-/flexsearch-0.7.43.tgz#34f89b36278a466ce379c5bf6fb341965ed3f16c" - integrity sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg== - -focus-visible@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.2.0.tgz#3a9e41fccf587bd25dcc2ef045508284f0a4d6b3" - integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== - -git-up@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467" - integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ== - dependencies: - is-ssh "^1.4.0" - parse-url "^8.1.0" - -git-url-parse@^13.1.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-13.1.1.tgz#664bddf0857c6a75b3c1f0ae6239abb08a1486d4" - integrity sha512-PCFJyeSSdtnbfhSNRw9Wk96dDCNx+sogTe4YNXeXSJxt7xz5hvXekuRn9JX7m+Mf4OscCu8h+mtAl3+h5Fo8lQ== - dependencies: - git-up "^7.0.0" - -github-slugger@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" - integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== - -graceful-fs@^4.2.11: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -gray-matter@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" - integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== - dependencies: - js-yaml "^3.13.1" - kind-of "^6.0.2" - section-matter "^1.0.0" - strip-bom-string "^1.0.0" - -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng== - -hash-obj@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hash-obj/-/hash-obj-4.0.0.tgz#3fafeb0b5f17994441dbe04efbdee82e26b74c8c" - integrity sha512-FwO1BUVWkyHasWDW4S8o0ssQXjvyghLV2rfVhnN36b2bbcj45eGiuzdn9XOvOpjV3TKQD7Gm2BWNXdE9V4KKYg== - dependencies: - is-obj "^3.0.0" - sort-keys "^5.0.0" - type-fest "^1.0.2" - -hast-util-from-dom@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/hast-util-from-dom/-/hast-util-from-dom-5.0.0.tgz#d32edd25bf28f4b178b5ae318f8d05762e67bd16" - integrity sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg== - dependencies: - "@types/hast" "^3.0.0" - hastscript "^8.0.0" - web-namespaces "^2.0.0" - -hast-util-from-html-isomorphic@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz#b31baee386a899a2472326a3c5692f29f86d1d3c" - integrity sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw== - dependencies: - "@types/hast" "^3.0.0" - hast-util-from-dom "^5.0.0" - hast-util-from-html "^2.0.0" - unist-util-remove-position "^5.0.0" - -hast-util-from-html@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz#9cd38ee81bf40b2607368b92a04b0905fa987488" - integrity sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g== - dependencies: - "@types/hast" "^3.0.0" - devlop "^1.1.0" - hast-util-from-parse5 "^8.0.0" - parse5 "^7.0.0" - vfile "^6.0.0" - vfile-message "^4.0.0" - -hast-util-from-parse5@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz#654a5676a41211e14ee80d1b1758c399a0327651" - integrity sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - devlop "^1.0.0" - hastscript "^8.0.0" - property-information "^6.0.0" - vfile "^6.0.0" - vfile-location "^5.0.0" - web-namespaces "^2.0.0" - -hast-util-is-element@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz#6e31a6532c217e5b533848c7e52c9d9369ca0932" - integrity sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g== - dependencies: - "@types/hast" "^3.0.0" - -hast-util-parse-selector@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" - integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== - dependencies: - "@types/hast" "^3.0.0" - -hast-util-raw@^9.0.0: - version "9.0.4" - resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-9.0.4.tgz#2da03e37c46eb1a6f1391f02f9b84ae65818f7ed" - integrity sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - "@ungap/structured-clone" "^1.0.0" - hast-util-from-parse5 "^8.0.0" - hast-util-to-parse5 "^8.0.0" - html-void-elements "^3.0.0" - mdast-util-to-hast "^13.0.0" - parse5 "^7.0.0" - unist-util-position "^5.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - web-namespaces "^2.0.0" - zwitch "^2.0.0" - -hast-util-to-estree@^2.0.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz#da60142ffe19a6296923ec222aba73339c8bf470" - integrity sha512-ihhPIUPxN0v0w6M5+IiAZZrn0LH2uZomeWwhn7uP7avZC6TE7lIiEh2yBMPr5+zi1aUCXq6VoYRgs2Bw9xmycQ== - dependencies: - "@types/estree" "^1.0.0" - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/unist" "^2.0.0" - comma-separated-tokens "^2.0.0" - estree-util-attach-comments "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - hast-util-whitespace "^2.0.0" - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdxjs-esm "^1.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - style-to-object "^0.4.1" - unist-util-position "^4.0.0" - zwitch "^2.0.0" - -hast-util-to-parse5@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz#477cd42d278d4f036bc2ea58586130f6f39ee6ed" - integrity sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw== - dependencies: - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - devlop "^1.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - web-namespaces "^2.0.0" - zwitch "^2.0.0" - -hast-util-to-text@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz#57b676931e71bf9cb852453678495b3080bfae3e" - integrity sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - hast-util-is-element "^3.0.0" - unist-util-find-after "^5.0.0" - -hast-util-whitespace@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" - integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== - -hastscript@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-8.0.0.tgz#4ef795ec8dee867101b9f23cc830d4baf4fd781a" - integrity sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw== - dependencies: - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - hast-util-parse-selector "^4.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - -html-void-elements@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" - integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== - -iconv-lite@0.6: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== - -"internmap@1 - 2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" - integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== - -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== - -intersection-observer@^0.12.2: - version "0.12.2" - resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375" - integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg== - -is-alphabetical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" - integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== - -is-alphanumerical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" - integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== - dependencies: - is-alphabetical "^2.0.0" - is-decimal "^2.0.0" - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-decimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" - integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== - -is-extendable@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-hexadecimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" - integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== - -is-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-3.0.0.tgz#b0889f1f9f8cb87e87df53a8d1230a2250f8b9be" - integrity sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ== - -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - -is-plain-obj@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" - integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== - -is-reference@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c" - integrity sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg== - dependencies: - "@types/estree" "*" - -is-ssh@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" - integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== - dependencies: - protocols "^2.0.1" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - -katex@^0.16.0, katex@^0.16.9: - version "0.16.10" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.10.tgz#6f81b71ac37ff4ec7556861160f53bc5f058b185" - integrity sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA== - dependencies: - commander "^8.3.0" - -khroma@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.1.0.tgz#45f2ce94ce231a437cf5b63c2e886e6eb42bbbb1" - integrity sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^4.0.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" - integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== - -layout-base@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2" - integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg== - -lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== - -longest-streak@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" - integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== - -loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -markdown-extensions@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-1.1.1.tgz#fea03b539faeaee9b4ef02a3769b455b189f7fc3" - integrity sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q== - -markdown-table@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" - integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== - -match-sorter@^6.3.1: - version "6.3.4" - resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7" - integrity sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg== - dependencies: - "@babel/runtime" "^7.23.8" - remove-accents "0.5.0" - -mdast-util-definitions@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" - integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" - -mdast-util-find-and-replace@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz#cc2b774f7f3630da4bd592f61966fecade8b99b1" - integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw== - dependencies: - "@types/mdast" "^3.0.0" - escape-string-regexp "^5.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^5.0.0" - -mdast-util-from-markdown@^1.0.0, mdast-util-from-markdown@^1.1.0, mdast-util-from-markdown@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0" - integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - decode-named-character-reference "^1.0.0" - mdast-util-to-string "^3.1.0" - micromark "^3.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-decode-string "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-stringify-position "^3.0.0" - uvu "^0.5.0" - -mdast-util-gfm-autolink-literal@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06" - integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA== - dependencies: - "@types/mdast" "^3.0.0" - ccount "^2.0.0" - mdast-util-find-and-replace "^2.0.0" - micromark-util-character "^1.0.0" - -mdast-util-gfm-footnote@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e" - integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" - micromark-util-normalize-identifier "^1.0.0" - -mdast-util-gfm-strikethrough@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7" - integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" - -mdast-util-gfm-table@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46" - integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg== - dependencies: - "@types/mdast" "^3.0.0" - markdown-table "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.3.0" - -mdast-util-gfm-task-list-item@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b" - integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.3.0" - -mdast-util-gfm@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6" - integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg== - dependencies: - mdast-util-from-markdown "^1.0.0" - mdast-util-gfm-autolink-literal "^1.0.0" - mdast-util-gfm-footnote "^1.0.0" - mdast-util-gfm-strikethrough "^1.0.0" - mdast-util-gfm-table "^1.0.0" - mdast-util-gfm-task-list-item "^1.0.0" - mdast-util-to-markdown "^1.0.0" - -mdast-util-math@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-math/-/mdast-util-math-2.0.2.tgz#19a06a81f31643f48cc805e7c31edb7ce739242c" - integrity sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ== - dependencies: - "@types/mdast" "^3.0.0" - longest-streak "^3.0.0" - mdast-util-to-markdown "^1.3.0" - -mdast-util-mdx-expression@^1.0.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.2.tgz#d027789e67524d541d6de543f36d51ae2586f220" - integrity sha512-xIPmR5ReJDu/DHH1OoIT1HkuybIfRGYRywC+gJtI7qHjCJp/M9jrmBEJW22O8lskDWm562BX2W8TiAwRTb0rKA== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" - -mdast-util-mdx-jsx@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.4.tgz#7c1f07f10751a78963cfabee38017cbc8b7786d1" - integrity sha512-DtMn9CmVhVzZx3f+optVDF8yFgQVt7FghCRNdlIaS3X5Bnym3hZwPbg/XW86vdpKjlc1PVj26SpnLGeJBXD3JA== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - ccount "^2.0.0" - mdast-util-from-markdown "^1.1.0" - mdast-util-to-markdown "^1.3.0" - parse-entities "^4.0.0" - stringify-entities "^4.0.0" - unist-util-remove-position "^4.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" - -mdast-util-mdx@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz#49b6e70819b99bb615d7223c088d295e53bb810f" - integrity sha512-38w5y+r8nyKlGvNjSEqWrhG0w5PmnRA+wnBvm+ulYCct7nsGYhFVb0lljS9bQav4psDAS1eGkP2LMVcZBi/aqw== - dependencies: - mdast-util-from-markdown "^1.0.0" - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdx-jsx "^2.0.0" - mdast-util-mdxjs-esm "^1.0.0" - mdast-util-to-markdown "^1.0.0" - -mdast-util-mdxjs-esm@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.1.tgz#645d02cd607a227b49721d146fd81796b2e2d15b" - integrity sha512-SXqglS0HrEvSdUEfoXFtcg7DRl7S2cwOXc7jkuusG472Mmjag34DUDeOJUZtl+BVnyeO1frIgVpHlNRWc2gk/w== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" - -mdast-util-phrasing@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz#c7c21d0d435d7fb90956038f02e8702781f95463" - integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg== - dependencies: - "@types/mdast" "^3.0.0" - unist-util-is "^5.0.0" - -mdast-util-to-hast@^12.1.0: - version "12.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" - integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== - dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-definitions "^5.0.0" - micromark-util-sanitize-uri "^1.1.0" - trim-lines "^3.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - -mdast-util-to-hast@^13.0.0: - version "13.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4" - integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - "@ungap/structured-clone" "^1.0.0" - devlop "^1.0.0" - micromark-util-sanitize-uri "^2.0.0" - trim-lines "^3.0.0" - unist-util-position "^5.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6" - integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - longest-streak "^3.0.0" - mdast-util-phrasing "^3.0.0" - mdast-util-to-string "^3.0.0" - micromark-util-decode-string "^1.0.0" - unist-util-visit "^4.0.0" - zwitch "^2.0.0" - -mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789" - integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg== - dependencies: - "@types/mdast" "^3.0.0" - -mermaid@^10.2.2: - version "10.9.1" - resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.9.1.tgz#5f582c23f3186c46c6aa673e59eeb46d741b2ea6" - integrity sha512-Mx45Obds5W1UkW1nv/7dHRsbfMM1aOKA2+Pxs/IGHNonygDHwmng8xTHyS9z4KWVi0rbko8gjiBmuwwXQ7tiNA== - dependencies: - "@braintree/sanitize-url" "^6.0.1" - "@types/d3-scale" "^4.0.3" - "@types/d3-scale-chromatic" "^3.0.0" - cytoscape "^3.28.1" - cytoscape-cose-bilkent "^4.1.0" - d3 "^7.4.0" - d3-sankey "^0.12.3" - dagre-d3-es "7.0.10" - dayjs "^1.11.7" - dompurify "^3.0.5" - elkjs "^0.9.0" - katex "^0.16.9" - khroma "^2.0.0" - lodash-es "^4.17.21" - mdast-util-from-markdown "^1.3.0" - non-layered-tidy-tree-layout "^2.0.2" - stylis "^4.1.3" - ts-dedent "^2.2.0" - uuid "^9.0.0" - web-worker "^1.2.0" - -micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8" - integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-factory-destination "^1.0.0" - micromark-factory-label "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-factory-title "^1.0.0" - micromark-factory-whitespace "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-classify-character "^1.0.0" - micromark-util-html-tag-name "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - -micromark-extension-gfm-autolink-literal@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz#5853f0e579bbd8ef9e39a7c0f0f27c5a063a66e7" - integrity sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-extension-gfm-footnote@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz#05e13034d68f95ca53c99679040bc88a6f92fe2e" - integrity sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q== - dependencies: - micromark-core-commonmark "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-gfm-strikethrough@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz#c8212c9a616fa3bf47cb5c711da77f4fdc2f80af" - integrity sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-classify-character "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-gfm-table@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz#dcb46074b0c6254c3fc9cc1f6f5002c162968008" - integrity sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-gfm-tagfilter@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz#aa7c4dd92dabbcb80f313ebaaa8eb3dac05f13a7" - integrity sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g== - dependencies: - micromark-util-types "^1.0.0" - -micromark-extension-gfm-task-list-item@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz#b52ce498dc4c69b6a9975abafc18f275b9dde9f4" - integrity sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-gfm@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz#e517e8579949a5024a493e49204e884aa74f5acf" - integrity sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ== - dependencies: - micromark-extension-gfm-autolink-literal "^1.0.0" - micromark-extension-gfm-footnote "^1.0.0" - micromark-extension-gfm-strikethrough "^1.0.0" - micromark-extension-gfm-table "^1.0.0" - micromark-extension-gfm-tagfilter "^1.0.0" - micromark-extension-gfm-task-list-item "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-extension-math@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-2.1.2.tgz#52c70cc8266cd20ada1ef5a479bfed9a19b789bf" - integrity sha512-es0CcOV89VNS9wFmyn+wyFTKweXGW4CEvdaAca6SWRWPyYCbBisnjaHLjWO4Nszuiud84jCpkHsqAJoa768Pvg== - dependencies: - "@types/katex" "^0.16.0" - katex "^0.16.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-mdx-expression@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.8.tgz#5bc1f5fd90388e8293b3ef4f7c6f06c24aff6314" - integrity sha512-zZpeQtc5wfWKdzDsHRBY003H2Smg+PUi2REhqgIhdzAa5xonhP03FcXxqFSerFiNUr5AWmHpaNPQTBVOS4lrXw== - dependencies: - "@types/estree" "^1.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-mdx-jsx@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.5.tgz#e72d24b7754a30d20fb797ece11e2c4e2cae9e82" - integrity sha512-gPH+9ZdmDflbu19Xkb8+gheqEDqkSpdCEubQyxuz/Hn8DOXiXvrXeikOoBA71+e8Pfi0/UYmU3wW3H58kr7akA== - dependencies: - "@types/acorn" "^4.0.0" - "@types/estree" "^1.0.0" - estree-util-is-identifier-name "^2.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-extension-mdx-md@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.1.tgz#595d4b2f692b134080dca92c12272ab5b74c6d1a" - integrity sha512-7MSuj2S7xjOQXAjjkbjBsHkMtb+mDGVW6uI2dBL9snOBCbZmoNgDAeZ0nSn9j3T42UE/g2xVNMn18PJxZvkBEA== - dependencies: - micromark-util-types "^1.0.0" - -micromark-extension-mdxjs-esm@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.5.tgz#e4f8be9c14c324a80833d8d3a227419e2b25dec1" - integrity sha512-xNRBw4aoURcyz/S69B19WnZAkWJMxHMT5hE36GtDAyhoyn/8TuAeqjFJQlwk+MKQsUD7b3l7kFX+vlfVWgcX1w== - dependencies: - "@types/estree" "^1.0.0" - micromark-core-commonmark "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.1.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-extension-mdxjs@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.1.tgz#f78d4671678d16395efeda85170c520ee795ded8" - integrity sha512-7YA7hF6i5eKOfFUzZ+0z6avRG52GpWR8DL+kN47y3f2KhxbBZMhmxe7auOeaTBrW2DenbbZTf1ea9tA2hDpC2Q== - dependencies: - acorn "^8.0.0" - acorn-jsx "^5.0.0" - micromark-extension-mdx-expression "^1.0.0" - micromark-extension-mdx-jsx "^1.0.0" - micromark-extension-mdx-md "^1.0.0" - micromark-extension-mdxjs-esm "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-destination@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f" - integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-label@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68" - integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-factory-mdx-expression@^1.0.0: - version "1.0.9" - resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.9.tgz#57ba4571b69a867a1530f34741011c71c73a4976" - integrity sha512-jGIWzSmNfdnkJq05c7b0+Wv0Kfz3NJ3N4cBjnbO4zjXIlxJr+f8lk+5ZmwFvqdAbUy2q6B5rCY//g0QAAaXDWA== - dependencies: - "@types/estree" "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-factory-space@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz#c8f40b0640a0150751d3345ed885a080b0d15faf" - integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-title@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1" - integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-whitespace@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705" - integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-util-character@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc" - integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-util-character@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" - integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== - dependencies: - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-chunked@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b" - integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ== - dependencies: - micromark-util-symbol "^1.0.0" - -micromark-util-classify-character@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d" - integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-util-combine-extensions@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84" - integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-util-decode-numeric-character-reference@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz#b1e6e17009b1f20bc652a521309c5f22c85eb1c6" - integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw== - dependencies: - micromark-util-symbol "^1.0.0" - -micromark-util-decode-string@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c" - integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-symbol "^1.0.0" - -micromark-util-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5" - integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw== - -micromark-util-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" - integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== - -micromark-util-events-to-acorn@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.3.tgz#a4ab157f57a380e646670e49ddee97a72b58b557" - integrity sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w== - dependencies: - "@types/acorn" "^4.0.0" - "@types/estree" "^1.0.0" - "@types/unist" "^2.0.0" - estree-util-visit "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - -micromark-util-html-tag-name@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588" - integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q== - -micromark-util-normalize-identifier@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7" - integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q== - dependencies: - micromark-util-symbol "^1.0.0" - -micromark-util-resolve-all@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188" - integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA== - dependencies: - micromark-util-types "^1.0.0" - -micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d" - integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-symbol "^1.0.0" - -micromark-util-sanitize-uri@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" - integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-encode "^2.0.0" - micromark-util-symbol "^2.0.0" - -micromark-util-subtokenize@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz#941c74f93a93eaf687b9054aeb94642b0e92edb1" - integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-util-symbol@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142" - integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== - -micromark-util-symbol@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" - integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== - -micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283" - integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== - -micromark-util-types@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" - integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== - -micromark@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9" - integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA== - dependencies: - "@types/debug" "^4.0.0" - debug "^4.0.0" - decode-named-character-reference "^1.0.0" - micromark-core-commonmark "^1.0.1" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - -mri@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -nanoid@^3.3.6: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - -next-mdx-remote@^4.2.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/next-mdx-remote/-/next-mdx-remote-4.4.1.tgz#96b16e2adc54dbcd0a7f204a9a3c3fd269d41abf" - integrity sha512-1BvyXaIou6xy3XoNF4yaMZUCb6vD2GTAa5ciOa6WoO+gAUTYsb1K4rI/HSC2ogAWLrb/7VSV52skz07vOzmqIQ== - dependencies: - "@mdx-js/mdx" "^2.2.1" - "@mdx-js/react" "^2.2.1" - vfile "^5.3.0" - vfile-matter "^3.0.1" - -next-seo@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-6.5.0.tgz#5ccfbcfaced9d296499aa88f074b9e82e252a9c8" - integrity sha512-MfzUeWTN/x/rsKp/1n0213eojO97lIl0unxqbeCY+6pAucViHDA8GSLRRcXpgjsSmBxfCFdfpu7LXbt4ANQoNQ== - -next-themes@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45" - integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A== - -next@^15.0.3: - version "15.0.3" - resolved "https://registry.yarnpkg.com/next/-/next-15.0.3.tgz#804f5b772e7570ef1f088542a59860914d3288e9" - integrity sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw== - dependencies: - "@next/env" "15.0.3" - "@swc/counter" "0.1.3" - "@swc/helpers" "0.5.13" - busboy "1.6.0" - caniuse-lite "^1.0.30001579" - postcss "8.4.31" - styled-jsx "5.1.6" - optionalDependencies: - "@next/swc-darwin-arm64" "15.0.3" - "@next/swc-darwin-x64" "15.0.3" - "@next/swc-linux-arm64-gnu" "15.0.3" - "@next/swc-linux-arm64-musl" "15.0.3" - "@next/swc-linux-x64-gnu" "15.0.3" - "@next/swc-linux-x64-musl" "15.0.3" - "@next/swc-win32-arm64-msvc" "15.0.3" - "@next/swc-win32-x64-msvc" "15.0.3" - sharp "^0.33.5" - -nextra-theme-docs@^2.13.4: - version "2.13.4" - resolved "https://registry.yarnpkg.com/nextra-theme-docs/-/nextra-theme-docs-2.13.4.tgz#821795e149537413f459ae4b520eba1a195e5e07" - integrity sha512-2XOoMfwBCTYBt8ds4ZHftt9Wyf2XsykiNo02eir/XEYB+sGeUoE77kzqfidjEOKCSzOHYbK9BDMcg2+B/2vYRw== - dependencies: - "@headlessui/react" "^1.7.17" - "@popperjs/core" "^2.11.8" - clsx "^2.0.0" - escape-string-regexp "^5.0.0" - flexsearch "^0.7.31" - focus-visible "^5.2.0" - git-url-parse "^13.1.0" - intersection-observer "^0.12.2" - match-sorter "^6.3.1" - next-seo "^6.0.0" - next-themes "^0.2.1" - scroll-into-view-if-needed "^3.1.0" - zod "^3.22.3" - -nextra@^2.13.4: - version "2.13.4" - resolved "https://registry.yarnpkg.com/nextra/-/nextra-2.13.4.tgz#49e9f558735d86292cd8578b5a69f6d926bc2a14" - integrity sha512-7of2rSBxuUa3+lbMmZwG9cqgftcoNOVQLTT6Rxf3EhBR9t1EI7b43dted8YoqSNaigdE3j1CoyNkX8N/ZzlEpw== - dependencies: - "@headlessui/react" "^1.7.17" - "@mdx-js/mdx" "^2.3.0" - "@mdx-js/react" "^2.3.0" - "@napi-rs/simple-git" "^0.1.9" - "@theguild/remark-mermaid" "^0.0.5" - "@theguild/remark-npm2yarn" "^0.2.0" - clsx "^2.0.0" - github-slugger "^2.0.0" - graceful-fs "^4.2.11" - gray-matter "^4.0.3" - katex "^0.16.9" - lodash.get "^4.4.2" - next-mdx-remote "^4.2.1" - p-limit "^3.1.0" - rehype-katex "^7.0.0" - rehype-pretty-code "0.9.11" - rehype-raw "^7.0.0" - remark-gfm "^3.0.1" - remark-math "^5.1.1" - remark-reading-time "^2.0.1" - shiki "^0.14.3" - slash "^3.0.0" - title "^3.5.3" - unist-util-remove "^4.0.0" - unist-util-visit "^5.0.0" - zod "^3.22.3" - -non-layered-tidy-tree-layout@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804" - integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - -npm-to-yarn@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/npm-to-yarn/-/npm-to-yarn-2.2.1.tgz#048843a6630621daffc6a239dfc89698b8abf7e8" - integrity sha512-O/j/ROyX0KGLG7O6Ieut/seQ0oiTpHF2tXAcFbpdTLQFiaNtkyTXXocM1fwpaa60dg1qpWj0nHlbNhx6qwuENQ== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -parse-entities@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" - integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== - dependencies: - "@types/unist" "^2.0.0" - character-entities "^2.0.0" - character-entities-legacy "^3.0.0" - character-reference-invalid "^2.0.0" - decode-named-character-reference "^1.0.0" - is-alphanumerical "^2.0.0" - is-decimal "^2.0.0" - is-hexadecimal "^2.0.0" - -parse-numeric-range@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3" - integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== - -parse-path@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b" - integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog== - dependencies: - protocols "^2.0.0" - -parse-url@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d" - integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w== - dependencies: - parse-path "^7.0.0" - -parse5@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== - dependencies: - entities "^4.4.0" - -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - -periscopic@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a" - integrity sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^3.0.0" - is-reference "^3.0.0" - -picocolors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -postcss@8.4.31: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -property-information@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" - integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== - -protocols@^2.0.0, protocols@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" - integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - -react-dom@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - -react@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -reading-time@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.5.0.tgz#d2a7f1b6057cb2e169beaf87113cc3411b5bc5bb" - integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -rehype-katex@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-7.0.0.tgz#f5e9e2825981175a7b0a4d58ed9816c33576dfed" - integrity sha512-h8FPkGE00r2XKU+/acgqwWUlyzve1IiOKwsEkg4pDL3k48PiE0Pt+/uLtVHDVkN1yA4iurZN6UES8ivHVEQV6Q== - dependencies: - "@types/hast" "^3.0.0" - "@types/katex" "^0.16.0" - hast-util-from-html-isomorphic "^2.0.0" - hast-util-to-text "^4.0.0" - katex "^0.16.0" - unist-util-visit-parents "^6.0.0" - vfile "^6.0.0" - -rehype-pretty-code@0.9.11: - version "0.9.11" - resolved "https://registry.yarnpkg.com/rehype-pretty-code/-/rehype-pretty-code-0.9.11.tgz#742017cbcfd5bd85466dfedd65b33a954aff7f2a" - integrity sha512-Eq90eCYXQJISktfRZ8PPtwc5SUyH6fJcxS8XOMnHPUQZBtC6RYo67gGlley9X2nR8vlniPj0/7oCDEYHKQa/oA== - dependencies: - "@types/hast" "^2.0.0" - hash-obj "^4.0.0" - parse-numeric-range "^1.3.0" - -rehype-raw@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4" - integrity sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww== - dependencies: - "@types/hast" "^3.0.0" - hast-util-raw "^9.0.0" - vfile "^6.0.0" - -remark-gfm@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" - integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-gfm "^2.0.0" - micromark-extension-gfm "^2.0.0" - unified "^10.0.0" - -remark-math@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-5.1.1.tgz#459e798d978d4ca032e745af0bac81ddcdf94964" - integrity sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-math "^2.0.0" - micromark-extension-math "^2.0.0" - unified "^10.0.0" - -remark-mdx@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.3.0.tgz#efe678025a8c2726681bde8bf111af4a93943db4" - integrity sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g== - dependencies: - mdast-util-mdx "^2.0.0" - micromark-extension-mdxjs "^1.0.0" - -remark-parse@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.2.tgz#ca241fde8751c2158933f031a4e3efbaeb8bc262" - integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - unified "^10.0.0" - -remark-reading-time@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/remark-reading-time/-/remark-reading-time-2.0.1.tgz#fe8bb8e420db7678dc749385167adb4fc99318f7" - integrity sha512-fy4BKy9SRhtYbEHvp6AItbRTnrhiDGbqLQTSYVbQPGuRCncU1ubSsh9p/W5QZSxtYcUXv8KGL0xBgPLyNJA1xw== - dependencies: - estree-util-is-identifier-name "^2.0.0" - estree-util-value-to-estree "^1.3.0" - reading-time "^1.3.0" - unist-util-visit "^3.1.0" - -remark-rehype@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" - integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== - dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-to-hast "^12.1.0" - unified "^10.0.0" - -remove-accents@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" - integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== - -robust-predicates@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" - integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== - -rw@1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== - -sade@^1.7.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" - integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== - dependencies: - mri "^1.1.0" - -"safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - -scroll-into-view-if-needed@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f" - integrity sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ== - dependencies: - compute-scroll-into-view "^3.0.2" - -section-matter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" - integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== - dependencies: - extend-shallow "^2.0.1" - kind-of "^6.0.0" - -semver@^7.6.3: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -sharp@^0.33.5: - version "0.33.5" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.33.5.tgz#13e0e4130cc309d6a9497596715240b2ec0c594e" - integrity sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw== - dependencies: - color "^4.2.3" - detect-libc "^2.0.3" - semver "^7.6.3" - optionalDependencies: - "@img/sharp-darwin-arm64" "0.33.5" - "@img/sharp-darwin-x64" "0.33.5" - "@img/sharp-libvips-darwin-arm64" "1.0.4" - "@img/sharp-libvips-darwin-x64" "1.0.4" - "@img/sharp-libvips-linux-arm" "1.0.5" - "@img/sharp-libvips-linux-arm64" "1.0.4" - "@img/sharp-libvips-linux-s390x" "1.0.4" - "@img/sharp-libvips-linux-x64" "1.0.4" - "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" - "@img/sharp-libvips-linuxmusl-x64" "1.0.4" - "@img/sharp-linux-arm" "0.33.5" - "@img/sharp-linux-arm64" "0.33.5" - "@img/sharp-linux-s390x" "0.33.5" - "@img/sharp-linux-x64" "0.33.5" - "@img/sharp-linuxmusl-arm64" "0.33.5" - "@img/sharp-linuxmusl-x64" "0.33.5" - "@img/sharp-wasm32" "0.33.5" - "@img/sharp-win32-ia32" "0.33.5" - "@img/sharp-win32-x64" "0.33.5" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - -shiki@^0.14.3: - version "0.14.7" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" - integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== - dependencies: - ansi-sequence-parser "^1.1.0" - jsonc-parser "^3.2.0" - vscode-oniguruma "^1.7.0" - vscode-textmate "^8.0.0" - -signal-exit@^3.0.0: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== - dependencies: - is-arrayish "^0.3.1" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -sort-keys@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-5.0.0.tgz#5d775f8ae93ecc29bc7312bbf3acac4e36e3c446" - integrity sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw== - dependencies: - is-plain-obj "^4.0.0" - -source-map-js@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -source-map@^0.7.0: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - -space-separated-tokens@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" - integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - -stringify-entities@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.4.tgz#b3b79ef5f277cc4ac73caeb0236c5ba939b3a4f3" - integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== - dependencies: - character-entities-html4 "^2.0.0" - character-entities-legacy "^3.0.0" - -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - integrity sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - -style-to-object@^0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec" - integrity sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg== - dependencies: - inline-style-parser "0.1.1" - -styled-jsx@5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" - integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== - dependencies: - client-only "0.0.1" - -stylis@^4.1.3: - version "4.3.2" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.2.tgz#8f76b70777dd53eb669c6f58c997bf0a9972e444" - integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg== - -supports-color@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - integrity sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw== - dependencies: - has-flag "^2.0.0" - -title@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/title/-/title-3.5.3.tgz#b338d701a3d949db6b49b2c86f409f9c2f36cd91" - integrity sha512-20JyowYglSEeCvZv3EZ0nZ046vLarO37prvV0mbtQV7C8DJPGgN967r8SJkqd3XK3K3lD3/Iyfp3avjfil8Q2Q== - dependencies: - arg "1.0.0" - chalk "2.3.0" - clipboardy "1.2.2" - titleize "1.0.0" - -titleize@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.0.tgz#7d350722061830ba6617631e0cfd3ea08398d95a" - integrity sha512-TARUb7z1pGvlLxgPk++7wJ6aycXF3GJ0sNSBTAsTuJrQG5QuZlkUQP+zl+nbjAh4gMX9yDw9ZYklMd7vAfJKEw== - -trim-lines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" - integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== - -trough@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" - integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== - -ts-dedent@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" - integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== - -tslib@^2.4.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== - -type-fest@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - -typescript@5.4.5: - version "5.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" - integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -unified@^10.0.0: - version "10.1.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" - integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== - dependencies: - "@types/unist" "^2.0.0" - bail "^2.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^4.0.0" - trough "^2.0.0" - vfile "^5.0.0" - -unist-util-find-after@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz#3fccc1b086b56f34c8b798e1ff90b5c54468e896" - integrity sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - -unist-util-generated@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" - integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== - -unist-util-is@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.2.1.tgz#b74960e145c18dcb6226bc57933597f5486deae9" - integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw== - dependencies: - "@types/unist" "^2.0.0" - -unist-util-is@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" - integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.2.tgz#8ac2480027229de76512079e377afbcabcfcce22" - integrity sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww== - dependencies: - "@types/unist" "^2.0.0" - -unist-util-position@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037" - integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg== - dependencies: - "@types/unist" "^2.0.0" - -unist-util-position@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" - integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-remove-position@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-4.0.2.tgz#a89be6ea72e23b1a402350832b02a91f6a9afe51" - integrity sha512-TkBb0HABNmxzAcfLf4qsIbFbaPDvMO6wa3b3j4VcEzFVaw1LBKwnW4/sRJ/atSLSzoIg41JWEdnE7N6DIhGDGQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" - -unist-util-remove-position@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" - integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== - dependencies: - "@types/unist" "^3.0.0" - unist-util-visit "^5.0.0" - -unist-util-remove@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-4.0.0.tgz#94b7d6bbd24e42d2f841e947ed087be5c82b222e" - integrity sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - unist-util-visit-parents "^6.0.0" - -unist-util-stringify-position@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d" - integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg== - dependencies: - "@types/unist" "^2.0.0" - -unist-util-stringify-position@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" - integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-visit-parents@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" - integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - -unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1: - version "5.1.3" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb" - integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - -unist-util-visit-parents@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" - integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - -unist-util-visit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" - integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^4.0.0" - -unist-util-visit@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2" - integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^5.1.1" - -unist-util-visit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" - integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - unist-util-visit-parents "^6.0.0" - -uuid@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - -uvu@^0.5.0: - version "0.5.6" - resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" - integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA== - dependencies: - dequal "^2.0.0" - diff "^5.0.0" - kleur "^4.0.3" - sade "^1.7.3" - -vfile-location@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.2.tgz#220d9ca1ab6f8b2504a4db398f7ebc149f9cb464" - integrity sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg== - dependencies: - "@types/unist" "^3.0.0" - vfile "^6.0.0" - -vfile-matter@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/vfile-matter/-/vfile-matter-3.0.1.tgz#85e26088e43aa85c04d42ffa3693635fa2bc5624" - integrity sha512-CAAIDwnh6ZdtrqAuxdElUqQRQDQgbbIrYtDYI8gCjXS1qQ+1XdLoK8FIZWxJwn0/I+BkSSZpar3SOgjemQz4fg== - dependencies: - "@types/js-yaml" "^4.0.0" - is-buffer "^2.0.0" - js-yaml "^4.0.0" - -vfile-message@^3.0.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea" - integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^3.0.0" - -vfile-message@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" - integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - -vfile@^5.0.0, vfile@^5.3.0: - version "5.3.7" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.7.tgz#de0677e6683e3380fafc46544cfe603118826ab7" - integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" - -vfile@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" - integrity sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - vfile-message "^4.0.0" - -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== - -vscode-textmate@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" - integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== - -web-namespaces@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" - integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== - -web-worker@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.3.0.tgz#e5f2df5c7fe356755a5fb8f8410d4312627e6776" - integrity sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA== - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zod@^3.22.3: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== - -zwitch@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@babel/runtime@npm:^7.23.8": + version: 7.24.7 + resolution: "@babel/runtime@npm:7.24.7" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + languageName: node + linkType: hard + +"@braintree/sanitize-url@npm:^6.0.1": + version: 6.0.4 + resolution: "@braintree/sanitize-url@npm:6.0.4" + checksum: 10c0/5d7bac57f3e49931db83f65aaa4fd22f96caa323bf0c7fcf6851fdbed179a8cf29eaa5dd372d340fc51ca5f44345ea5bc0196b36c8b16179888a7c9044313420 + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.2.0": + version: 1.3.1 + resolution: "@emnapi/runtime@npm:1.3.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/060ffede50f1b619c15083312b80a9e62a5b0c87aa8c1b54854c49766c9d69f8d1d3d87bd963a647071263a320db41b25eaa50b74d6a80dcc763c23dbeaafd6c + languageName: node + linkType: hard + +"@headlessui/react@npm:^1.7.17": + version: 1.7.19 + resolution: "@headlessui/react@npm:1.7.19" + dependencies: + "@tanstack/react-virtual": "npm:^3.0.0-beta.60" + client-only: "npm:^0.0.1" + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + checksum: 10c0/c0ece0db6ca15092439177a5322de50b60fa5fd90354ae0f999b3e56abab0065ed54fa7b4b69994ec1bdc23adc6ae9919d7dd57f97922d0b9bb6515d27e3a7e5 + languageName: node + linkType: hard + +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": "npm:^1.2.0" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@mdx-js/mdx@npm:^2.2.1, @mdx-js/mdx@npm:^2.3.0": + version: 2.3.0 + resolution: "@mdx-js/mdx@npm:2.3.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/mdx": "npm:^2.0.0" + estree-util-build-jsx: "npm:^2.0.0" + estree-util-is-identifier-name: "npm:^2.0.0" + estree-util-to-js: "npm:^1.1.0" + estree-walker: "npm:^3.0.0" + hast-util-to-estree: "npm:^2.0.0" + markdown-extensions: "npm:^1.0.0" + periscopic: "npm:^3.0.0" + remark-mdx: "npm:^2.0.0" + remark-parse: "npm:^10.0.0" + remark-rehype: "npm:^10.0.0" + unified: "npm:^10.0.0" + unist-util-position-from-estree: "npm:^1.0.0" + unist-util-stringify-position: "npm:^3.0.0" + unist-util-visit: "npm:^4.0.0" + vfile: "npm:^5.0.0" + checksum: 10c0/719384d8e72abd3e83aa2fd3010394636e32cc0e5e286b6414427ef03121397586ce97ec816afcc4d2b22ba65939c3801a8198e04cf921dd597c0aa9fd75dbb4 + languageName: node + linkType: hard + +"@mdx-js/react@npm:^2.2.1, @mdx-js/react@npm:^2.3.0": + version: 2.3.0 + resolution: "@mdx-js/react@npm:2.3.0" + dependencies: + "@types/mdx": "npm:^2.0.0" + "@types/react": "npm:>=16" + peerDependencies: + react: ">=16" + checksum: 10c0/6d647115703dbe258f7fe372499fa8c6fe17a053ff0f2a208111c9973a71ae738a0ed376770445d39194d217e00e1a015644b24f32c2f7cb4f57988de0649b15 + languageName: node + linkType: hard + +"@napi-rs/simple-git-android-arm-eabi@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-android-arm-eabi@npm:0.1.16" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/simple-git-android-arm64@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-android-arm64@npm:0.1.16" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-darwin-arm64@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-darwin-arm64@npm:0.1.16" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-darwin-x64@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-darwin-x64@npm:0.1.16" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm-gnueabihf@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-linux-arm-gnueabihf@npm:0.1.16" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm64-gnu@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-linux-arm64-gnu@npm:0.1.16" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-arm64-musl@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-linux-arm64-musl@npm:0.1.16" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-x64-gnu@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-linux-x64-gnu@npm:0.1.16" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/simple-git-linux-x64-musl@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-linux-x64-musl@npm:0.1.16" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/simple-git-win32-arm64-msvc@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-win32-arm64-msvc@npm:0.1.16" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/simple-git-win32-x64-msvc@npm:0.1.16": + version: 0.1.16 + resolution: "@napi-rs/simple-git-win32-x64-msvc@npm:0.1.16" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/simple-git@npm:^0.1.9": + version: 0.1.16 + resolution: "@napi-rs/simple-git@npm:0.1.16" + dependencies: + "@napi-rs/simple-git-android-arm-eabi": "npm:0.1.16" + "@napi-rs/simple-git-android-arm64": "npm:0.1.16" + "@napi-rs/simple-git-darwin-arm64": "npm:0.1.16" + "@napi-rs/simple-git-darwin-x64": "npm:0.1.16" + "@napi-rs/simple-git-linux-arm-gnueabihf": "npm:0.1.16" + "@napi-rs/simple-git-linux-arm64-gnu": "npm:0.1.16" + "@napi-rs/simple-git-linux-arm64-musl": "npm:0.1.16" + "@napi-rs/simple-git-linux-x64-gnu": "npm:0.1.16" + "@napi-rs/simple-git-linux-x64-musl": "npm:0.1.16" + "@napi-rs/simple-git-win32-arm64-msvc": "npm:0.1.16" + "@napi-rs/simple-git-win32-x64-msvc": "npm:0.1.16" + dependenciesMeta: + "@napi-rs/simple-git-android-arm-eabi": + optional: true + "@napi-rs/simple-git-android-arm64": + optional: true + "@napi-rs/simple-git-darwin-arm64": + optional: true + "@napi-rs/simple-git-darwin-x64": + optional: true + "@napi-rs/simple-git-linux-arm-gnueabihf": + optional: true + "@napi-rs/simple-git-linux-arm64-gnu": + optional: true + "@napi-rs/simple-git-linux-arm64-musl": + optional: true + "@napi-rs/simple-git-linux-x64-gnu": + optional: true + "@napi-rs/simple-git-linux-x64-musl": + optional: true + "@napi-rs/simple-git-win32-arm64-msvc": + optional: true + "@napi-rs/simple-git-win32-x64-msvc": + optional: true + checksum: 10c0/6d17ecfe15346f744495b71fe18bfd36c2c85132060833e25690d2f23e875c7715a597a6c91348b60f495c5080a4da85b6eed55a8c695533795b2c93ce91499b + languageName: node + linkType: hard + +"@next/env@npm:15.0.3": + version: 15.0.3 + resolution: "@next/env@npm:15.0.3" + checksum: 10c0/63582fed80d6a28fff102c935095da71fd57ddf6b5f5d564e85ebdefdeb93298f7f7cf7d813c75b460c6627106717ea959b4c232939e7abb97d73d8b8467d4cd + languageName: node + linkType: hard + +"@next/swc-darwin-arm64@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-darwin-arm64@npm:15.0.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@next/swc-darwin-x64@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-darwin-x64@npm:15.0.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@next/swc-linux-arm64-gnu@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-linux-arm64-gnu@npm:15.0.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@next/swc-linux-arm64-musl@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-linux-arm64-musl@npm:15.0.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@next/swc-linux-x64-gnu@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-linux-x64-gnu@npm:15.0.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@next/swc-linux-x64-musl@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-linux-x64-musl@npm:15.0.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@next/swc-win32-arm64-msvc@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-win32-arm64-msvc@npm:15.0.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@next/swc-win32-x64-msvc@npm:15.0.3": + version: 15.0.3 + resolution: "@next/swc-win32-x64-msvc@npm:15.0.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@popperjs/core@npm:^2.11.8": + version: 2.11.8 + resolution: "@popperjs/core@npm:2.11.8" + checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 + languageName: node + linkType: hard + +"@swc/counter@npm:0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 + languageName: node + linkType: hard + +"@swc/helpers@npm:0.5.13": + version: 0.5.13 + resolution: "@swc/helpers@npm:0.5.13" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/b9df578401fc62405da9a6c31e79e447a2fd90f68b25b1daee12f2caf2821991bb89106f0397bc1acb4c4d84a8ce079d04b60b65f534496952e3bf8c9a52f40f + languageName: node + linkType: hard + +"@tanstack/react-virtual@npm:^3.0.0-beta.60": + version: 3.5.1 + resolution: "@tanstack/react-virtual@npm:3.5.1" + dependencies: + "@tanstack/virtual-core": "npm:3.5.1" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 10c0/165992ca01d124be2289f61cc51d1c26d12cd4af11f658167f512d86a89795903478ce3ded1799072cc20feffd1d17bbcb8843269736145769cfc00b113349bd + languageName: node + linkType: hard + +"@tanstack/virtual-core@npm:3.5.1": + version: 3.5.1 + resolution: "@tanstack/virtual-core@npm:3.5.1" + checksum: 10c0/3ed6c82d168c8a7f240f7882c4386f1136ccc727a4db7ca8051505dab6175c43aa4c8d5a0eaca861d1503f4f98ad2f8e46b876e02002d8218a9f344fc944708b + languageName: node + linkType: hard + +"@theguild/remark-mermaid@npm:^0.0.5": + version: 0.0.5 + resolution: "@theguild/remark-mermaid@npm:0.0.5" + dependencies: + mermaid: "npm:^10.2.2" + unist-util-visit: "npm:^5.0.0" + peerDependencies: + react: ^18.2.0 + checksum: 10c0/3471a32a87d50f7eb699f15ff181f9a3698209951ef0fab1e928ea391275105286b0391e46cca4dd22d30dcab934e5c7eb6573c341f5d8543ca5bcb2f60cc916 + languageName: node + linkType: hard + +"@theguild/remark-npm2yarn@npm:^0.2.0": + version: 0.2.1 + resolution: "@theguild/remark-npm2yarn@npm:0.2.1" + dependencies: + npm-to-yarn: "npm:^2.1.0" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/69380ac3814bcf2f9c00c8e375d97e55220adea04d9c887df1b6ac888b726a8a7aaf391ed80ceca1756cfa39d572221d12f681bc1a5f3fdf49a0ed59f7c3addc + languageName: node + linkType: hard + +"@types/acorn@npm:^4.0.0": + version: 4.0.6 + resolution: "@types/acorn@npm:4.0.6" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/5a65a1d7e91fc95703f0a717897be60fa7ccd34b17f5462056274a246e6690259fe0a1baabc86fd3260354f87245cb3dc483346d7faad2b78fc199763978ede9 + languageName: node + linkType: hard + +"@types/d3-scale-chromatic@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/d3-scale-chromatic@npm:3.0.3" + checksum: 10c0/2f48c6f370edba485b57b73573884ded71914222a4580140ff87ee96e1d55ccd05b1d457f726e234a31269b803270ac95d5554229ab6c43c7e4a9894e20dd490 + languageName: node + linkType: hard + +"@types/d3-scale@npm:^4.0.3": + version: 4.0.8 + resolution: "@types/d3-scale@npm:4.0.8" + dependencies: + "@types/d3-time": "npm:*" + checksum: 10c0/57de90e4016f640b83cb960b7e3a0ab3ed02e720898840ddc5105264ffcfea73336161442fdc91895377c2d2f91904d637282f16852b8535b77e15a761c8e99e + languageName: node + linkType: hard + +"@types/d3-time@npm:*": + version: 3.0.3 + resolution: "@types/d3-time@npm:3.0.3" + checksum: 10c0/245a8aadca504df27edf730de502e47a68f16ae795c86b5ca35e7afa91c133aa9ef4d08778f8cf1ed2be732f89a4105ba4b437ce2afbdfd17d3d937b6ba5f568 + languageName: node + linkType: hard + +"@types/debug@npm:^4.0.0": + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" + dependencies: + "@types/ms": "npm:*" + checksum: 10c0/5dcd465edbb5a7f226e9a5efd1f399c6172407ef5840686b73e3608ce135eeca54ae8037dcd9f16bdb2768ac74925b820a8b9ecc588a58ca09eca6acabe33e2f + languageName: node + linkType: hard + +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree-jsx@npm:1.0.5" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d + languageName: node + linkType: hard + +"@types/hast@npm:^2.0.0": + version: 2.3.10 + resolution: "@types/hast@npm:2.3.10" + dependencies: + "@types/unist": "npm:^2" + checksum: 10c0/16daac35d032e656defe1f103f9c09c341a6dc553c7ec17b388274076fa26e904a71ea5ea41fd368a6d5f1e9e53be275c80af7942b9c466d8511d261c9529c7e + languageName: node + linkType: hard + +"@types/hast@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + +"@types/js-yaml@npm:^4.0.0": + version: 4.0.9 + resolution: "@types/js-yaml@npm:4.0.9" + checksum: 10c0/24de857aa8d61526bbfbbaa383aa538283ad17363fcd5bb5148e2c7f604547db36646440e739d78241ed008702a8920665d1add5618687b6743858fae00da211 + languageName: node + linkType: hard + +"@types/katex@npm:^0.16.0": + version: 0.16.7 + resolution: "@types/katex@npm:0.16.7" + checksum: 10c0/68dcb9f68a90513ec78ca0196a142e15c2a2c270b1520d752bafd47a99207115085a64087b50140359017d7e9c870b3c68e7e4d36668c9e348a9ef0c48919b5a + languageName: node + linkType: hard + +"@types/mdast@npm:^3.0.0": + version: 3.0.15 + resolution: "@types/mdast@npm:3.0.15" + dependencies: + "@types/unist": "npm:^2" + checksum: 10c0/fcbf716c03d1ed5465deca60862e9691414f9c43597c288c7d2aefbe274552e1bbd7aeee91b88a02597e88a28c139c57863d0126fcf8416a95fdc681d054ee3d + languageName: node + linkType: hard + +"@types/mdast@npm:^4.0.0": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + languageName: node + linkType: hard + +"@types/mdx@npm:^2.0.0": + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 10c0/5edf1099505ac568da55f9ae8a93e7e314e8cbc13d3445d0be61b75941226b005e1390d9b95caecf5dcb00c9d1bab2f1f60f6ff9876dc091a48b547495007720 + languageName: node + linkType: hard + +"@types/ms@npm:*": + version: 0.7.34 + resolution: "@types/ms@npm:0.7.34" + checksum: 10c0/ac80bd90012116ceb2d188fde62d96830ca847823e8ca71255616bc73991aa7d9f057b8bfab79e8ee44ffefb031ddd1bcce63ea82f9e66f7c31ec02d2d823ccc + languageName: node + linkType: hard + +"@types/node@npm:20.14.5": + version: 20.14.5 + resolution: "@types/node@npm:20.14.5" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/06a8c304b5f7f190d4497807dc67ad09ee7b14ea2996bfdc823553c624698d8cab1ef9d16f8b764f20cb9eb11caa0e832787741e9ef70e1c89d620797ab28436 + languageName: node + linkType: hard + +"@types/prop-types@npm:*": + version: 15.7.12 + resolution: "@types/prop-types@npm:15.7.12" + checksum: 10c0/1babcc7db6a1177779f8fde0ccc78d64d459906e6ef69a4ed4dd6339c920c2e05b074ee5a92120fe4e9d9f1a01c952f843ebd550bee2332fc2ef81d1706878f8 + languageName: node + linkType: hard + +"@types/react@npm:>=16": + version: 18.3.3 + resolution: "@types/react@npm:18.3.3" + dependencies: + "@types/prop-types": "npm:*" + csstype: "npm:^3.0.2" + checksum: 10c0/fe455f805c5da13b89964c3d68060cebd43e73ec15001a68b34634604a78140e6fc202f3f61679b9d809dde6d7a7c2cb3ed51e0fd1462557911db09879b55114 + languageName: node + linkType: hard + +"@types/unist@npm:*, @types/unist@npm:^3.0.0": + version: 3.0.2 + resolution: "@types/unist@npm:3.0.2" + checksum: 10c0/39f220ce184a773c55c18a127062bfc4d0d30c987250cd59bab544d97be6cfec93717a49ef96e81f024b575718f798d4d329eb81c452fc57d6d051af8b043ebf + languageName: node + linkType: hard + +"@types/unist@npm:^2, @types/unist@npm:^2.0.0": + version: 2.0.10 + resolution: "@types/unist@npm:2.0.10" + checksum: 10c0/5f247dc2229944355209ad5c8e83cfe29419fa7f0a6d557421b1985a1500444719cc9efcc42c652b55aab63c931813c88033e0202c1ac684bcd4829d66e44731 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.0.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 10c0/8209c937cb39119f44eb63cf90c0b73e7c754209a6411c707be08e50e29ee81356dca1a848a405c8bdeebfe2f5e4f831ad310ae1689eeef65e7445c090c6657d + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.0.0": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.0.0": + version: 8.12.0 + resolution: "acorn@npm:8.12.0" + bin: + acorn: bin/acorn + checksum: 10c0/a19f9dead009d3b430fa3c253710b47778cdaace15b316de6de93a68c355507bc1072a9956372b6c990cbeeb167d4a929249d0faeb8ae4bb6911d68d53299549 + languageName: node + linkType: hard + +"ansi-sequence-parser@npm:^1.1.0": + version: 1.1.1 + resolution: "ansi-sequence-parser@npm:1.1.1" + checksum: 10c0/ab2259ccf69f145ecf1418d4e71524158828f44afdf37c7536677871f4cebaa8b176fcb95de8f94a68129357dddc59586597da25f9d4ebf9968f6ef022bf0b31 + languageName: node + linkType: hard + +"ansi-styles@npm:^3.1.0": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: "npm:^1.9.0" + checksum: 10c0/ece5a8ef069fcc5298f67e3f4771a663129abd174ea2dfa87923a2be2abf6cd367ef72ac87942da00ce85bd1d651d4cd8595aebdb1b385889b89b205860e977b + languageName: node + linkType: hard + +"arch@npm:^2.1.0": + version: 2.2.0 + resolution: "arch@npm:2.2.0" + checksum: 10c0/4ceaf8d8207817c216ebc4469742052cb0a097bc45d9b7fcd60b7507220da545a28562ab5bdd4dfe87921bb56371a0805da4e10d704e01f93a15f83240f1284c + languageName: node + linkType: hard + +"arg@npm:1.0.0": + version: 1.0.0 + resolution: "arg@npm:1.0.0" + checksum: 10c0/10bbbda299b1a5d5f1cc6492bdea9413f148c36b58e7abc49e8b8337047eec5db154c1d2f99e942c4b777ae28215fc28506d303d7e30bcd80ca1ad7baeb6ce28 + languageName: node + linkType: hard + +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: "npm:~1.0.2" + checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + languageName: node + linkType: hard + +"astring@npm:^1.8.0": + version: 1.8.6 + resolution: "astring@npm:1.8.6" + bin: + astring: bin/astring + checksum: 10c0/31f09144597048c11072417959a412f208f8f95ba8dce408dfbc3367acb929f31fbcc00ed5eb61ccbf7c2f1173b9ac8bfcaaa37134a9455050c669b2b036ed88 + languageName: node + linkType: hard + +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b + languageName: node + linkType: hard + +"busboy@npm:1.6.0": + version: 1.6.0 + resolution: "busboy@npm:1.6.0" + dependencies: + streamsearch: "npm:^1.1.0" + checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001636 + resolution: "caniuse-lite@npm:1.0.30001636" + checksum: 10c0/e5f965b4da7bae1531fd9f93477d015729ff9e3fa12670ead39a9e6cdc4c43e62c272d47857c5cc332e7b02d697cb3f2f965a1030870ac7476da60c2fc81ee94 + languageName: node + linkType: hard + +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 + languageName: node + linkType: hard + +"chalk@npm:2.3.0": + version: 2.3.0 + resolution: "chalk@npm:2.3.0" + dependencies: + ansi-styles: "npm:^3.1.0" + escape-string-regexp: "npm:^1.0.5" + supports-color: "npm:^4.0.0" + checksum: 10c0/ff3d14e7b31b1acdcd06b0c3b8d00e08748d76a0f2a6cc86baa1fe2456ebd4dd45037315a58df7f3c1886153c5d0a35da8183d2757f7fad28eaef6dedd33b437 + languageName: node + linkType: hard + +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 + languageName: node + linkType: hard + +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 + languageName: node + linkType: hard + +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 + languageName: node + linkType: hard + +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 + languageName: node + linkType: hard + +"client-only@npm:0.0.1, client-only@npm:^0.0.1": + version: 0.0.1 + resolution: "client-only@npm:0.0.1" + checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 + languageName: node + linkType: hard + +"clipboardy@npm:1.2.2": + version: 1.2.2 + resolution: "clipboardy@npm:1.2.2" + dependencies: + arch: "npm:^2.1.0" + execa: "npm:^0.8.0" + checksum: 10c0/c343ee1ff74fd7202b8e549575e0e09d36d122cd06b078b171cf9ee37f03479d53547a5792ee879145841122c11ee4419078ffec07daf3eda4fa800758c8f1d9 + languageName: node + linkType: hard + +"clsx@npm:^2.0.0": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + +"color-convert@npm:^1.9.0": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: "npm:1.1.3" + checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 + languageName: node + linkType: hard + +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: "npm:^1.0.0" + simple-swizzle: "npm:^0.2.2" + checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404 + languageName: node + linkType: hard + +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: "npm:^2.0.1" + color-string: "npm:^1.9.0" + checksum: 10c0/7fbe7cfb811054c808349de19fb380252e5e34e61d7d168ec3353e9e9aacb1802674bddc657682e4e9730c2786592a4de6f8283e7e0d3870b829bb0b7b2f6118 + languageName: node + linkType: hard + +"comma-separated-tokens@npm:^2.0.0": + version: 2.0.3 + resolution: "comma-separated-tokens@npm:2.0.3" + checksum: 10c0/91f90f1aae320f1755d6957ef0b864fe4f54737f3313bd95e0802686ee2ca38bff1dd381964d00ae5db42912dd1f4ae5c2709644e82706ffc6f6842a813cdd67 + languageName: node + linkType: hard + +"commander@npm:7": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 10c0/8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a + languageName: node + linkType: hard + +"commander@npm:^8.3.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 10c0/8b043bb8322ea1c39664a1598a95e0495bfe4ca2fad0d84a92d7d1d8d213e2a155b441d2470c8e08de7c4a28cf2bc6e169211c49e1b21d9f7edc6ae4d9356060 + languageName: node + linkType: hard + +"compute-scroll-into-view@npm:^3.0.2": + version: 3.1.0 + resolution: "compute-scroll-into-view@npm:3.1.0" + checksum: 10c0/bf305c4ece8e5c59ed3f7ed82b6dab5b7487ce26f56a693d903869964712870fccb08fe31d40edcbd600b03c99198f54d443acb315d674bd64fd344410c8672e + languageName: node + linkType: hard + +"cose-base@npm:^1.0.0": + version: 1.0.3 + resolution: "cose-base@npm:1.0.3" + dependencies: + layout-base: "npm:^1.0.0" + checksum: 10c0/a6e400b1d101393d6af0967c1353355777c1106c40417c5acaef6ca8bdda41e2fc9398f466d6c85be30290943ad631f2590569f67b3fd5368a0d8318946bd24f + languageName: node + linkType: hard + +"cross-spawn@npm:^5.0.1": + version: 5.1.0 + resolution: "cross-spawn@npm:5.1.0" + dependencies: + lru-cache: "npm:^4.0.1" + shebang-command: "npm:^1.2.0" + which: "npm:^1.2.9" + checksum: 10c0/1918621fddb9f8c61e02118b2dbf81f611ccd1544ceaca0d026525341832b8511ce2504c60f935dbc06b35e5ef156fe8c1e72708c27dd486f034e9c0e1e07201 + languageName: node + linkType: hard + +"csstype@npm:^3.0.2": + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 + languageName: node + linkType: hard + +"cytoscape-cose-bilkent@npm:^4.1.0": + version: 4.1.0 + resolution: "cytoscape-cose-bilkent@npm:4.1.0" + dependencies: + cose-base: "npm:^1.0.0" + peerDependencies: + cytoscape: ^3.2.0 + checksum: 10c0/5e2480ddba9da1a68e700ed2c674cbfd51e9efdbd55788f1971a68de4eb30708e3b3a5e808bf5628f7a258680406bbe6586d87a9133e02a9bdc1ab1a92f512f2 + languageName: node + linkType: hard + +"cytoscape@npm:^3.28.1": + version: 3.29.2 + resolution: "cytoscape@npm:3.29.2" + checksum: 10c0/fbd2b32496cc866429f2851200653dc1788c809bcb4da85e17054a0d4cd5a531cdebcf20d404c289b6ef7d0f914c107645372d958deb693458de15665b8fdf8b + languageName: node + linkType: hard + +"d3-array@npm:1 - 2": + version: 2.12.1 + resolution: "d3-array@npm:2.12.1" + dependencies: + internmap: "npm:^1.0.0" + checksum: 10c0/7eca10427a9f113a4ca6a0f7301127cab26043fd5e362631ef5a0edd1c4b2dd70c56ed317566700c31e4a6d88b55f3951aaba192291817f243b730cb2352882e + languageName: node + linkType: hard + +"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.2.0": + version: 3.2.4 + resolution: "d3-array@npm:3.2.4" + dependencies: + internmap: "npm:1 - 2" + checksum: 10c0/08b95e91130f98c1375db0e0af718f4371ccacef7d5d257727fe74f79a24383e79aba280b9ffae655483ffbbad4fd1dec4ade0119d88c4749f388641c8bf8c50 + languageName: node + linkType: hard + +"d3-axis@npm:3": + version: 3.0.0 + resolution: "d3-axis@npm:3.0.0" + checksum: 10c0/a271e70ba1966daa5aaf6a7f959ceca3e12997b43297e757c7b945db2e1ead3c6ee226f2abcfa22abbd4e2e28bd2b71a0911794c4e5b911bbba271328a582c78 + languageName: node + linkType: hard + +"d3-brush@npm:3": + version: 3.0.0 + resolution: "d3-brush@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:3" + d3-transition: "npm:3" + checksum: 10c0/07baf00334c576da2f68a91fc0da5732c3a5fa19bd3d7aed7fd24d1d674a773f71a93e9687c154176f7246946194d77c48c2d8fed757f5dcb1a4740067ec50a8 + languageName: node + linkType: hard + +"d3-chord@npm:3": + version: 3.0.1 + resolution: "d3-chord@npm:3.0.1" + dependencies: + d3-path: "npm:1 - 3" + checksum: 10c0/baa6013914af3f4fe1521f0d16de31a38eb8a71d08ff1dec4741f6f45a828661e5cd3935e39bd14e3032bdc78206c283ca37411da21d46ec3cfc520be6e7a7ce + languageName: node + linkType: hard + +"d3-color@npm:1 - 3, d3-color@npm:3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 10c0/a4e20e1115fa696fce041fbe13fbc80dc4c19150fa72027a7c128ade980bc0eeeba4bcf28c9e21f0bce0e0dbfe7ca5869ef67746541dcfda053e4802ad19783c + languageName: node + linkType: hard + +"d3-contour@npm:4": + version: 4.0.2 + resolution: "d3-contour@npm:4.0.2" + dependencies: + d3-array: "npm:^3.2.0" + checksum: 10c0/98bc5fbed6009e08707434a952076f39f1cd6ed8b9288253cc3e6a3286e4e80c63c62d84954b20e64bf6e4ededcc69add54d3db25e990784a59c04edd3449032 + languageName: node + linkType: hard + +"d3-delaunay@npm:6": + version: 6.0.4 + resolution: "d3-delaunay@npm:6.0.4" + dependencies: + delaunator: "npm:5" + checksum: 10c0/57c3aecd2525664b07c4c292aa11cf49b2752c0cf3f5257f752999399fe3c592de2d418644d79df1f255471eec8057a9cc0c3062ed7128cb3348c45f69597754 + languageName: node + linkType: hard + +"d3-dispatch@npm:1 - 3, d3-dispatch@npm:3": + version: 3.0.1 + resolution: "d3-dispatch@npm:3.0.1" + checksum: 10c0/6eca77008ce2dc33380e45d4410c67d150941df7ab45b91d116dbe6d0a3092c0f6ac184dd4602c796dc9e790222bad3ff7142025f5fd22694efe088d1d941753 + languageName: node + linkType: hard + +"d3-drag@npm:2 - 3, d3-drag@npm:3": + version: 3.0.0 + resolution: "d3-drag@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-selection: "npm:3" + checksum: 10c0/d2556e8dc720741a443b595a30af403dd60642dfd938d44d6e9bfc4c71a962142f9a028c56b61f8b4790b65a34acad177d1263d66f103c3c527767b0926ef5aa + languageName: node + linkType: hard + +"d3-dsv@npm:1 - 3, d3-dsv@npm:3": + version: 3.0.1 + resolution: "d3-dsv@npm:3.0.1" + dependencies: + commander: "npm:7" + iconv-lite: "npm:0.6" + rw: "npm:1" + bin: + csv2json: bin/dsv2json.js + csv2tsv: bin/dsv2dsv.js + dsv2dsv: bin/dsv2dsv.js + dsv2json: bin/dsv2json.js + json2csv: bin/json2dsv.js + json2dsv: bin/json2dsv.js + json2tsv: bin/json2dsv.js + tsv2csv: bin/dsv2dsv.js + tsv2json: bin/dsv2json.js + checksum: 10c0/10e6af9e331950ed258f34ab49ac1b7060128ef81dcf32afc790bd1f7e8c3cc2aac7f5f875250a83f21f39bb5925fbd0872bb209f8aca32b3b77d32bab8a65ab + languageName: node + linkType: hard + +"d3-ease@npm:1 - 3, d3-ease@npm:3": + version: 3.0.1 + resolution: "d3-ease@npm:3.0.1" + checksum: 10c0/fec8ef826c0cc35cda3092c6841e07672868b1839fcaf556e19266a3a37e6bc7977d8298c0fcb9885e7799bfdcef7db1baaba9cd4dcf4bc5e952cf78574a88b0 + languageName: node + linkType: hard + +"d3-fetch@npm:3": + version: 3.0.1 + resolution: "d3-fetch@npm:3.0.1" + dependencies: + d3-dsv: "npm:1 - 3" + checksum: 10c0/4f467a79bf290395ac0cbb5f7562483f6a18668adc4c8eb84c9d3eff048b6f6d3b6f55079ba1ebf1908dabe000c941d46be447f8d78453b2dad5fb59fb6aa93b + languageName: node + linkType: hard + +"d3-force@npm:3": + version: 3.0.0 + resolution: "d3-force@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-quadtree: "npm:1 - 3" + d3-timer: "npm:1 - 3" + checksum: 10c0/220a16a1a1ac62ba56df61028896e4b52be89c81040d20229c876efc8852191482c233f8a52bb5a4e0875c321b8e5cb6413ef3dfa4d8fe79eeb7d52c587f52cf + languageName: node + linkType: hard + +"d3-format@npm:1 - 3, d3-format@npm:3": + version: 3.1.0 + resolution: "d3-format@npm:3.1.0" + checksum: 10c0/049f5c0871ebce9859fc5e2f07f336b3c5bfff52a2540e0bac7e703fce567cd9346f4ad1079dd18d6f1e0eaa0599941c1810898926f10ac21a31fd0a34b4aa75 + languageName: node + linkType: hard + +"d3-geo@npm:3": + version: 3.1.1 + resolution: "d3-geo@npm:3.1.1" + dependencies: + d3-array: "npm:2.5.0 - 3" + checksum: 10c0/d32270dd2dc8ac3ea63e8805d63239c4c8ec6c0d339d73b5e5a30a87f8f54db22a78fb434369799465eae169503b25f9a107c642c8a16c32a3285bc0e6d8e8c1 + languageName: node + linkType: hard + +"d3-hierarchy@npm:3": + version: 3.1.2 + resolution: "d3-hierarchy@npm:3.1.2" + checksum: 10c0/6dcdb480539644aa7fc0d72dfc7b03f99dfbcdf02714044e8c708577e0d5981deb9d3e99bbbb2d26422b55bcc342ac89a0fa2ea6c9d7302e2fc0951dd96f89cf + languageName: node + linkType: hard + +"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + checksum: 10c0/19f4b4daa8d733906671afff7767c19488f51a43d251f8b7f484d5d3cfc36c663f0a66c38fe91eee30f40327443d799be17169f55a293a3ba949e84e57a33e6a + languageName: node + linkType: hard + +"d3-path@npm:1": + version: 1.0.9 + resolution: "d3-path@npm:1.0.9" + checksum: 10c0/e35e84df5abc18091f585725b8235e1fa97efc287571585427d3a3597301e6c506dea56b11dfb3c06ca5858b3eb7f02c1bf4f6a716aa9eade01c41b92d497eb5 + languageName: node + linkType: hard + +"d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 10c0/dc1d58ec87fa8319bd240cf7689995111a124b141428354e9637aa83059eb12e681f77187e0ada5dedfce346f7e3d1f903467ceb41b379bfd01cd8e31721f5da + languageName: node + linkType: hard + +"d3-polygon@npm:3": + version: 3.0.1 + resolution: "d3-polygon@npm:3.0.1" + checksum: 10c0/e236aa7f33efa9a4072907af7dc119f85b150a0716759d4fe5f12f62573018264a6cbde8617fbfa6944a7ae48c1c0c8d3f39ae72e11f66dd471e9b5e668385df + languageName: node + linkType: hard + +"d3-quadtree@npm:1 - 3, d3-quadtree@npm:3": + version: 3.0.1 + resolution: "d3-quadtree@npm:3.0.1" + checksum: 10c0/18302d2548bfecaef788152397edec95a76400fd97d9d7f42a089ceb68d910f685c96579d74e3712d57477ed042b056881b47cd836a521de683c66f47ce89090 + languageName: node + linkType: hard + +"d3-random@npm:3": + version: 3.0.1 + resolution: "d3-random@npm:3.0.1" + checksum: 10c0/987a1a1bcbf26e6cf01fd89d5a265b463b2cea93560fc17d9b1c45e8ed6ff2db5924601bcceb808de24c94133f000039eb7fa1c469a7a844ccbf1170cbb25b41 + languageName: node + linkType: hard + +"d3-sankey@npm:^0.12.3": + version: 0.12.3 + resolution: "d3-sankey@npm:0.12.3" + dependencies: + d3-array: "npm:1 - 2" + d3-shape: "npm:^1.2.0" + checksum: 10c0/261debb01a13269f6fc53b9ebaef174a015d5ad646242c23995bf514498829ab8b8f920a7873724a7494288b46bea3ce7ebc5a920b745bc8ae4caa5885cf5204 + languageName: node + linkType: hard + +"d3-scale-chromatic@npm:3": + version: 3.1.0 + resolution: "d3-scale-chromatic@npm:3.1.0" + dependencies: + d3-color: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + checksum: 10c0/9a3f4671ab0b971f4a411b42180d7cf92bfe8e8584e637ce7e698d705e18d6d38efbd20ec64f60cc0dfe966c20d40fc172565bc28aaa2990c0a006360eed91af + languageName: node + linkType: hard + +"d3-scale@npm:4": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: "npm:2.10.0 - 3" + d3-format: "npm:1 - 3" + d3-interpolate: "npm:1.2.0 - 3" + d3-time: "npm:2.1.1 - 3" + d3-time-format: "npm:2 - 4" + checksum: 10c0/65d9ad8c2641aec30ed5673a7410feb187a224d6ca8d1a520d68a7d6eac9d04caedbff4713d1e8545be33eb7fec5739983a7ab1d22d4e5ad35368c6729d362f1 + languageName: node + linkType: hard + +"d3-selection@npm:2 - 3, d3-selection@npm:3": + version: 3.0.0 + resolution: "d3-selection@npm:3.0.0" + checksum: 10c0/e59096bbe8f0cb0daa1001d9bdd6dbc93a688019abc97d1d8b37f85cd3c286a6875b22adea0931b0c88410d025563e1643019161a883c516acf50c190a11b56b + languageName: node + linkType: hard + +"d3-shape@npm:3": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: "npm:^3.1.0" + checksum: 10c0/f1c9d1f09926daaf6f6193ae3b4c4b5521e81da7d8902d24b38694517c7f527ce3c9a77a9d3a5722ad1e3ff355860b014557b450023d66a944eabf8cfde37132 + languageName: node + linkType: hard + +"d3-shape@npm:^1.2.0": + version: 1.3.7 + resolution: "d3-shape@npm:1.3.7" + dependencies: + d3-path: "npm:1" + checksum: 10c0/548057ce59959815decb449f15632b08e2a1bdce208f9a37b5f98ec7629dda986c2356bc7582308405ce68aedae7d47b324df41507404df42afaf352907577ae + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4, d3-time-format@npm:4": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: "npm:1 - 3" + checksum: 10c0/735e00fb25a7fd5d418fac350018713ae394eefddb0d745fab12bbff0517f9cdb5f807c7bbe87bb6eeb06249662f8ea84fec075f7d0cd68609735b2ceb29d206 + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: "npm:2 - 3" + checksum: 10c0/a984f77e1aaeaa182679b46fbf57eceb6ebdb5f67d7578d6f68ef933f8eeb63737c0949991618a8d29472dbf43736c7d7f17c452b2770f8c1271191cba724ca1 + languageName: node + linkType: hard + +"d3-timer@npm:1 - 3, d3-timer@npm:3": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 10c0/d4c63cb4bb5461d7038aac561b097cd1c5673969b27cbdd0e87fa48d9300a538b9e6f39b4a7f0e3592ef4f963d858c8a9f0e92754db73116770856f2fc04561a + languageName: node + linkType: hard + +"d3-transition@npm:2 - 3, d3-transition@npm:3": + version: 3.0.1 + resolution: "d3-transition@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + d3-dispatch: "npm:1 - 3" + d3-ease: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + d3-timer: "npm:1 - 3" + peerDependencies: + d3-selection: 2 - 3 + checksum: 10c0/4e74535dda7024aa43e141635b7522bb70cf9d3dfefed975eb643b36b864762eca67f88fafc2ca798174f83ca7c8a65e892624f824b3f65b8145c6a1a88dbbad + languageName: node + linkType: hard + +"d3-zoom@npm:3": + version: 3.0.0 + resolution: "d3-zoom@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:2 - 3" + d3-transition: "npm:2 - 3" + checksum: 10c0/ee2036479049e70d8c783d594c444fe00e398246048e3f11a59755cd0e21de62ece3126181b0d7a31bf37bcf32fd726f83ae7dea4495ff86ec7736ce5ad36fd3 + languageName: node + linkType: hard + +"d3@npm:^7.4.0, d3@npm:^7.8.2": + version: 7.9.0 + resolution: "d3@npm:7.9.0" + dependencies: + d3-array: "npm:3" + d3-axis: "npm:3" + d3-brush: "npm:3" + d3-chord: "npm:3" + d3-color: "npm:3" + d3-contour: "npm:4" + d3-delaunay: "npm:6" + d3-dispatch: "npm:3" + d3-drag: "npm:3" + d3-dsv: "npm:3" + d3-ease: "npm:3" + d3-fetch: "npm:3" + d3-force: "npm:3" + d3-format: "npm:3" + d3-geo: "npm:3" + d3-hierarchy: "npm:3" + d3-interpolate: "npm:3" + d3-path: "npm:3" + d3-polygon: "npm:3" + d3-quadtree: "npm:3" + d3-random: "npm:3" + d3-scale: "npm:4" + d3-scale-chromatic: "npm:3" + d3-selection: "npm:3" + d3-shape: "npm:3" + d3-time: "npm:3" + d3-time-format: "npm:4" + d3-timer: "npm:3" + d3-transition: "npm:3" + d3-zoom: "npm:3" + checksum: 10c0/3dd9c08c73cfaa69c70c49e603c85e049c3904664d9c79a1a52a0f52795828a1ff23592dc9a7b2257e711d68a615472a13103c212032f38e016d609796e087e8 + languageName: node + linkType: hard + +"dagre-d3-es@npm:7.0.10": + version: 7.0.10 + resolution: "dagre-d3-es@npm:7.0.10" + dependencies: + d3: "npm:^7.8.2" + lodash-es: "npm:^4.17.21" + checksum: 10c0/3e1bb6efe9a78cea3fe6ff265eb330692f057bf84c99d6a1d67db379231c37a1a1ca2e1ccc25a732ddf924cd5566062c033d88defd230debec324dc9256c6775 + languageName: node + linkType: hard + +"dayjs@npm:^1.11.7": + version: 1.11.11 + resolution: "dayjs@npm:1.11.11" + checksum: 10c0/0131d10516b9945f05a57e13f4af49a6814de5573a494824e103131a3bbe4cc470b1aefe8e17e51f9a478a22cd116084be1ee5725cedb66ec4c3f9091202dc4b + languageName: node + linkType: hard + +"debug@npm:^4.0.0": + version: 4.3.5 + resolution: "debug@npm:4.3.5" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/082c375a2bdc4f4469c99f325ff458adad62a3fc2c482d59923c260cb08152f34e2659f72b3767db8bb2f21ca81a60a42d1019605a412132d7b9f59363a005cc + languageName: node + linkType: hard + +"decode-named-character-reference@npm:^1.0.0": + version: 1.0.2 + resolution: "decode-named-character-reference@npm:1.0.2" + dependencies: + character-entities: "npm:^2.0.0" + checksum: 10c0/66a9fc5d9b5385a2b3675c69ba0d8e893393d64057f7dbbb585265bb4fc05ec513d76943b8e5aac7d8016d20eea4499322cbf4cd6d54b466976b78f3a7587a4c + languageName: node + linkType: hard + +"delaunator@npm:5": + version: 5.0.1 + resolution: "delaunator@npm:5.0.1" + dependencies: + robust-predicates: "npm:^3.0.2" + checksum: 10c0/3d7ea4d964731c5849af33fec0a271bc6753487b331fd7d43ccb17d77834706e1c383e6ab8fda0032da955e7576d1083b9603cdaf9cbdfd6b3ebd1fb8bb675a5 + languageName: node + linkType: hard + +"dequal@npm:^2.0.0": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.3": + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 10c0/88095bda8f90220c95f162bf92cad70bd0e424913e655c20578600e35b91edc261af27531cf160a331e185c0ced93944bc7e09939143225f56312d7fd800fdb7 + languageName: node + linkType: hard + +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: "npm:^2.0.0" + checksum: 10c0/e0928ab8f94c59417a2b8389c45c55ce0a02d9ac7fd74ef62d01ba48060129e1d594501b77de01f3eeafc7cb00773819b0df74d96251cf20b31c5b3071f45c0e + languageName: node + linkType: hard + +"diff@npm:^5.0.0": + version: 5.2.0 + resolution: "diff@npm:5.2.0" + checksum: 10c0/aed0941f206fe261ecb258dc8d0ceea8abbde3ace5827518ff8d302f0fc9cc81ce116c4d8f379151171336caf0516b79e01abdc1ed1201b6440d895a66689eb4 + languageName: node + linkType: hard + +"dompurify@npm:^3.0.5": + version: 3.1.5 + resolution: "dompurify@npm:3.1.5" + checksum: 10c0/8227fb1328c02d94f823de8cd499fca5ee07051e03e6b52bce06b592348aeb6e56ea8e2a4b0a9cfaeac7d623e4b5a52e4326aedf72596a6c2510b88dfcf2a2b6 + languageName: node + linkType: hard + +"elkjs@npm:^0.9.0": + version: 0.9.3 + resolution: "elkjs@npm:0.9.3" + checksum: 10c0/caf544ff4fce8442d1d3dd6dface176c9b2fe26fc1e34f56122828e6eef7d2d7fe70d3202f9f3ecf0feb6287d4c8430949f483e63e450a7454bb39ccffab3808 + languageName: node + linkType: hard + +"entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95 + languageName: node + linkType: hard + +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 + languageName: node + linkType: hard + +"estree-util-attach-comments@npm:^2.0.0": + version: 2.1.1 + resolution: "estree-util-attach-comments@npm:2.1.1" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/cdb5fdb5809b376ca4a96afbcd916c3570b4bbf5d0115b8a9e1e8a10885d8d9fb549df0a16c077abb42ee35fa33192b69714bac25d4f3c43a36092288c9a64fd + languageName: node + linkType: hard + +"estree-util-build-jsx@npm:^2.0.0": + version: 2.2.2 + resolution: "estree-util-build-jsx@npm:2.2.2" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^2.0.0" + estree-walker: "npm:^3.0.0" + checksum: 10c0/2cef6ad6747f51934eba0601c3477ba08c98331cfe616635e08dfc89d06b9bbd370c4d80e87fe7d42d82776fa7840868201f48491b0ef9c808039f15fe4667e1 + languageName: node + linkType: hard + +"estree-util-is-identifier-name@npm:^2.0.0": + version: 2.1.0 + resolution: "estree-util-is-identifier-name@npm:2.1.0" + checksum: 10c0/cc241a6998d30f4e8775ec34b042ef93e0085cd1bdf692a01f22e9b748f0866c76679475ff87935be1d8d5b1a7648be8cba366dc60866b372269f35feec756fe + languageName: node + linkType: hard + +"estree-util-to-js@npm:^1.1.0": + version: 1.2.0 + resolution: "estree-util-to-js@npm:1.2.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + astring: "npm:^1.8.0" + source-map: "npm:^0.7.0" + checksum: 10c0/ad9c99dc34b0510ab813b485251acbf0abd06361c07b13c08da5d1611c279bee02ec09f2c269ae30b8d2da587115fc1fad4fa9f2f5ba69e094e758a3a4de7069 + languageName: node + linkType: hard + +"estree-util-value-to-estree@npm:^1.3.0": + version: 1.3.0 + resolution: "estree-util-value-to-estree@npm:1.3.0" + dependencies: + is-plain-obj: "npm:^3.0.0" + checksum: 10c0/8bf46c4629f55a6ad3a6c523277cd34591cf57dfcab01cf4f218a8780cd23d21901c393693484c449a46bad7b9cb6fbf24c3dd1c1b057e10fd6a076f24fd5f3f + languageName: node + linkType: hard + +"estree-util-visit@npm:^1.0.0": + version: 1.2.1 + resolution: "estree-util-visit@npm:1.2.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/unist": "npm:^2.0.0" + checksum: 10c0/3c47086ab25947a889fca9f58a842e0d27edadcad24dc393fdd7c9ad3419fe05b3c63b6fc9d6c9d8f50d32bca615cd0a3fe8d0e6b300fb94f74c91210b55ea5d + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.0": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + +"execa@npm:^0.8.0": + version: 0.8.0 + resolution: "execa@npm:0.8.0" + dependencies: + cross-spawn: "npm:^5.0.1" + get-stream: "npm:^3.0.0" + is-stream: "npm:^1.1.0" + npm-run-path: "npm:^2.0.0" + p-finally: "npm:^1.0.0" + signal-exit: "npm:^3.0.0" + strip-eof: "npm:^1.0.0" + checksum: 10c0/e6c085687024cd5d348cad98a12213f6ebad2e962c7f3298ea8608fd5ed2daad8d1e27e79bfe7104bf60d8d80b56dd60267a0667006c29019e4297c96ecfe99d + languageName: node + linkType: hard + +"extend-shallow@npm:^2.0.1": + version: 2.0.1 + resolution: "extend-shallow@npm:2.0.1" + dependencies: + is-extendable: "npm:^0.1.0" + checksum: 10c0/ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 + languageName: node + linkType: hard + +"extend@npm:^3.0.0": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 + languageName: node + linkType: hard + +"flexsearch@npm:^0.7.31": + version: 0.7.43 + resolution: "flexsearch@npm:0.7.43" + checksum: 10c0/797dc474ed97750b8e85c118b1af63eb2709da5fc05defcb13e96515774f28743ccb2448b63f3b703cf1ca571928c006069503dacf7d177bc07b9ee15e1f85d0 + languageName: node + linkType: hard + +"focus-visible@npm:^5.2.0": + version: 5.2.0 + resolution: "focus-visible@npm:5.2.0" + checksum: 10c0/bc746775e4c17d05faf7219a91fd5ae6fec320b87f20cde5402eff17fab148b6253f25748f0235b3110528a1335ee0c6d4dc3692cc6b6174d0ebd253dd28a50d + languageName: node + linkType: hard + +"get-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "get-stream@npm:3.0.0" + checksum: 10c0/003f5f3b8870da59c6aafdf6ed7e7b07b48c2f8629cd461bd3900726548b6b8cfa2e14d6b7814fbb08f07a42f4f738407fa70b989928b2783a76b278505bba22 + languageName: node + linkType: hard + +"git-up@npm:^7.0.0": + version: 7.0.0 + resolution: "git-up@npm:7.0.0" + dependencies: + is-ssh: "npm:^1.4.0" + parse-url: "npm:^8.1.0" + checksum: 10c0/a3fa02e1a63c7c824b5ebbf23f4a9a6b34dd80031114c5dd8adb7ef53493642e39d3d80dfef4025a452128400c35c2c138d20a0f6ae5d7d7ef70d9ba13083d34 + languageName: node + linkType: hard + +"git-url-parse@npm:^13.1.0": + version: 13.1.1 + resolution: "git-url-parse@npm:13.1.1" + dependencies: + git-up: "npm:^7.0.0" + checksum: 10c0/9304e6fbc1a6acf5e351e84ad87574fa6b840ccbe531afbbce9ba38e01fcacf6adf386ef7593daa037da59d9fd43b5d7c5232d5648638f8301cc2f18d00ad386 + languageName: node + linkType: hard + +"github-slugger@npm:^2.0.0": + version: 2.0.0 + resolution: "github-slugger@npm:2.0.0" + checksum: 10c0/21b912b6b1e48f1e5a50b2292b48df0ff6abeeb0691b161b3d93d84f4ae6b1acd6ae23702e914af7ea5d441c096453cf0f621b72d57893946618d21dd1a1c486 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.11": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"gray-matter@npm:^4.0.3": + version: 4.0.3 + resolution: "gray-matter@npm:4.0.3" + dependencies: + js-yaml: "npm:^3.13.1" + kind-of: "npm:^6.0.2" + section-matter: "npm:^1.0.0" + strip-bom-string: "npm:^1.0.0" + checksum: 10c0/e38489906dad4f162ca01e0dcbdbed96d1a53740cef446b9bf76d80bec66fa799af07776a18077aee642346c5e1365ed95e4c91854a12bf40ba0d4fb43a625a6 + languageName: node + linkType: hard + +"has-flag@npm:^2.0.0": + version: 2.0.0 + resolution: "has-flag@npm:2.0.0" + checksum: 10c0/5e1f136c7f801c2719048bedfabcf834a1ed46276cd4c98c6fcddb89a482f5d6a16df0771a38805cfc2d9010b4de157909e1a71b708e1d339b6e311041bde9b4 + languageName: node + linkType: hard + +"hash-obj@npm:^4.0.0": + version: 4.0.0 + resolution: "hash-obj@npm:4.0.0" + dependencies: + is-obj: "npm:^3.0.0" + sort-keys: "npm:^5.0.0" + type-fest: "npm:^1.0.2" + checksum: 10c0/af0a8bd3905afa2b9bd05ec75e37d904c66f6621ae185d53699fc7e5baf8157aeff6f4b9ae3c579da08aae6a5b2536c445c4dd1eecb94070c8717b63eeca97de + languageName: node + linkType: hard + +"hast-util-from-dom@npm:^5.0.0": + version: 5.0.0 + resolution: "hast-util-from-dom@npm:5.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hastscript: "npm:^8.0.0" + web-namespaces: "npm:^2.0.0" + checksum: 10c0/1b0a9d65eb8f8cd3616559190bb6db271b7b4f72a13c5dc16abac264b6f7145beb408fbaa497d1b5c725d55392b951972d8313802bfe90ccac33f888ec34c63c + languageName: node + linkType: hard + +"hast-util-from-html-isomorphic@npm:^2.0.0": + version: 2.0.0 + resolution: "hast-util-from-html-isomorphic@npm:2.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-from-dom: "npm:^5.0.0" + hast-util-from-html: "npm:^2.0.0" + unist-util-remove-position: "npm:^5.0.0" + checksum: 10c0/fc68d9245e794483a802d5c85a9f6c25959e00db78cc796411efc965134f3206f9cc9fa38134572ea781ad74663e801f1f83202007b208e27a770855566a62b6 + languageName: node + linkType: hard + +"hast-util-from-html@npm:^2.0.0": + version: 2.0.1 + resolution: "hast-util-from-html@npm:2.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + devlop: "npm:^1.1.0" + hast-util-from-parse5: "npm:^8.0.0" + parse5: "npm:^7.0.0" + vfile: "npm:^6.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/856ceec209940ac4f9db52bf6338b97fb11f27e6d5b930f89676bc16ee282c06f9ff2a17254280803aefdf740507cf3004f181d0286b04dda11907852decbe77 + languageName: node + linkType: hard + +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-from-parse5@npm:8.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + hastscript: "npm:^8.0.0" + property-information: "npm:^6.0.0" + vfile: "npm:^6.0.0" + vfile-location: "npm:^5.0.0" + web-namespaces: "npm:^2.0.0" + checksum: 10c0/4a30bb885cff1f0e023c429ae3ece73fe4b03386f07234bf23f5555ca087c2573ff4e551035b417ed7615bde559f394cdaf1db2b91c3b7f0575f3563cd238969 + languageName: node + linkType: hard + +"hast-util-is-element@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-is-element@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/f5361e4c9859c587ca8eb0d8343492f3077ccaa0f58a44cd09f35d5038f94d65152288dcd0c19336ef2c9491ec4d4e45fde2176b05293437021570aa0bc3613b + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/5e98168cb44470dc274aabf1a28317e4feb09b1eaf7a48bbaa8c1de1b43a89cd195cb1284e535698e658e3ec26ad91bc5e52c9563c36feb75abbc68aaf68fb9f + languageName: node + linkType: hard + +"hast-util-raw@npm:^9.0.0": + version: 9.0.4 + resolution: "hast-util-raw@npm:9.0.4" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + hast-util-from-parse5: "npm:^8.0.0" + hast-util-to-parse5: "npm:^8.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + parse5: "npm:^7.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/03d0fe7ba8bd75c9ce81f829650b19b78917bbe31db70d36bf6f136842496c3474e3bb1841f2d30dafe1f6b561a89a524185492b9a93d40b131000743c0d7998 + languageName: node + linkType: hard + +"hast-util-to-estree@npm:^2.0.0": + version: 2.3.3 + resolution: "hast-util-to-estree@npm:2.3.3" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^2.0.0" + "@types/unist": "npm:^2.0.0" + comma-separated-tokens: "npm:^2.0.0" + estree-util-attach-comments: "npm:^2.0.0" + estree-util-is-identifier-name: "npm:^2.0.0" + hast-util-whitespace: "npm:^2.0.0" + mdast-util-mdx-expression: "npm:^1.0.0" + mdast-util-mdxjs-esm: "npm:^1.0.0" + property-information: "npm:^6.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-object: "npm:^0.4.1" + unist-util-position: "npm:^4.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/5947b5030a6d20c193f5ea576cc751507e0b30d00f91e40a5208ca3a7add03a3862795a83600c0fdadf19c8b051917c7904715fa7dd358f04603d67a36341c38 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.0 + resolution: "hast-util-to-parse5@npm:8.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + property-information: "npm:^6.0.0" + space-separated-tokens: "npm:^2.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/3c0c7fba026e0c4be4675daf7277f9ff22ae6da801435f1b7104f7740de5422576f1c025023c7b3df1d0a161e13a04c6ab8f98ada96eb50adb287b537849a2bd + languageName: node + linkType: hard + +"hast-util-to-text@npm:^4.0.0": + version: 4.0.2 + resolution: "hast-util-to-text@npm:4.0.2" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + hast-util-is-element: "npm:^3.0.0" + unist-util-find-after: "npm:^5.0.0" + checksum: 10c0/93ecc10e68fe5391c6e634140eb330942e71dea2724c8e0c647c73ed74a8ec930a4b77043b5081284808c96f73f2bee64ee416038ece75a63a467e8d14f09946 + languageName: node + linkType: hard + +"hast-util-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "hast-util-whitespace@npm:2.0.1" + checksum: 10c0/dcf6ebab091c802ffa7bb3112305c7631c15adb6c07a258f5528aefbddf82b4e162c8310ef426c48dc1dc623982cc33920e6dde5a50015d307f2778dcf6c2487 + languageName: node + linkType: hard + +"hastscript@npm:^8.0.0": + version: 8.0.0 + resolution: "hastscript@npm:8.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-parse-selector: "npm:^4.0.0" + property-information: "npm:^6.0.0" + space-separated-tokens: "npm:^2.0.0" + checksum: 10c0/f0b54bbdd710854b71c0f044612db0fe1b5e4d74fa2001633dc8c535c26033269f04f536f9fd5b03f234de1111808f9e230e9d19493bf919432bb24d541719e0 + languageName: node + linkType: hard + +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 10c0/a8b9ec5db23b7c8053876dad73a0336183e6162bf6d2677376d8b38d654fdc59ba74fdd12f8812688f7db6fad451210c91b300e472afc0909224e0a44c8610d2 + languageName: node + linkType: hard + +"iconv-lite@npm:0.6": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"inline-style-parser@npm:0.1.1": + version: 0.1.1 + resolution: "inline-style-parser@npm:0.1.1" + checksum: 10c0/08832a533f51a1e17619f2eabf2f5ec5e956d6dcba1896351285c65df022c9420de61d73256e1dca8015a52abf96cc84ddc3b73b898b22de6589d3962b5e501b + languageName: node + linkType: hard + +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 10c0/8cedd57f07bbc22501516fbfc70447f0c6812871d471096fad9ea603516eacc2137b633633daf432c029712df0baefd793686388ddf5737e3ea15074b877f7ed + languageName: node + linkType: hard + +"internmap@npm:^1.0.0": + version: 1.0.1 + resolution: "internmap@npm:1.0.1" + checksum: 10c0/60942be815ca19da643b6d4f23bd0bf4e8c97abbd080fb963fe67583b60bdfb3530448ad4486bae40810e92317bded9995cc31411218acc750d72cd4e8646eee + languageName: node + linkType: hard + +"intersection-observer@npm:^0.12.2": + version: 0.12.2 + resolution: "intersection-observer@npm:0.12.2" + checksum: 10c0/9591f46b2b742f5801ed69dbc8860f487771b4af8361e7a5dcb28a377beff2ba56336a2b090af261825430d225dae9417121496d2e6925e000e4a469958843ff + languageName: node + linkType: hard + +"is-alphabetical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphabetical@npm:2.0.1" + checksum: 10c0/932367456f17237533fd1fc9fe179df77957271020b83ea31da50e5cc472d35ef6b5fb8147453274ffd251134472ce24eb6f8d8398d96dee98237cdb81a6c9a7 + languageName: node + linkType: hard + +"is-alphanumerical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphanumerical@npm:2.0.1" + dependencies: + is-alphabetical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + checksum: 10c0/4b35c42b18e40d41378293f82a3ecd9de77049b476f748db5697c297f686e1e05b072a6aaae2d16f54d2a57f85b00cbbe755c75f6d583d1c77d6657bd0feb5a2 + languageName: node + linkType: hard + +"is-arrayish@npm:^0.3.1": + version: 0.3.2 + resolution: "is-arrayish@npm:0.3.2" + checksum: 10c0/f59b43dc1d129edb6f0e282595e56477f98c40278a2acdc8b0a5c57097c9eff8fe55470493df5775478cf32a4dc8eaf6d3a749f07ceee5bc263a78b2434f6a54 + languageName: node + linkType: hard + +"is-buffer@npm:^2.0.0": + version: 2.0.5 + resolution: "is-buffer@npm:2.0.5" + checksum: 10c0/e603f6fced83cf94c53399cff3bda1a9f08e391b872b64a73793b0928be3e5f047f2bcece230edb7632eaea2acdbfcb56c23b33d8a20c820023b230f1485679a + languageName: node + linkType: hard + +"is-decimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-decimal@npm:2.0.1" + checksum: 10c0/8085dd66f7d82f9de818fba48b9e9c0429cb4291824e6c5f2622e96b9680b54a07a624cfc663b24148b8e853c62a1c987cfe8b0b5a13f5156991afaf6736e334 + languageName: node + linkType: hard + +"is-extendable@npm:^0.1.0": + version: 0.1.1 + resolution: "is-extendable@npm:0.1.1" + checksum: 10c0/dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 + languageName: node + linkType: hard + +"is-hexadecimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-hexadecimal@npm:2.0.1" + checksum: 10c0/3eb60fe2f1e2bbc760b927dcad4d51eaa0c60138cf7fc671803f66353ad90c301605b502c7ea4c6bb0548e1c7e79dfd37b73b632652e3b76030bba603a7e9626 + languageName: node + linkType: hard + +"is-obj@npm:^3.0.0": + version: 3.0.0 + resolution: "is-obj@npm:3.0.0" + checksum: 10c0/48d678fa15c56fd38353634ae2106a538827af9050211b18df13540dba0b38aa25c5cb498648a01311bf493a99ac3ce416576649b8cace10bcce7344611fa56a + languageName: node + linkType: hard + +"is-plain-obj@npm:^3.0.0": + version: 3.0.0 + resolution: "is-plain-obj@npm:3.0.0" + checksum: 10c0/8e6483bfb051d42ec9c704c0ede051a821c6b6f9a6c7a3e3b55aa855e00981b0580c8f3b1f5e2e62649b39179b1abfee35d6f8086d999bfaa32c1908d29b07bc + languageName: node + linkType: hard + +"is-plain-obj@npm:^4.0.0": + version: 4.1.0 + resolution: "is-plain-obj@npm:4.1.0" + checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e + languageName: node + linkType: hard + +"is-reference@npm:^3.0.0": + version: 3.0.2 + resolution: "is-reference@npm:3.0.2" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/652d31b405e8e8269071cee78fe874b072745012eba202c6dc86880fd603a65ae043e3160990ab4a0a4b33567cbf662eecf3bc6b3c2c1550e6c2b6cf885ce5aa + languageName: node + linkType: hard + +"is-ssh@npm:^1.4.0": + version: 1.4.0 + resolution: "is-ssh@npm:1.4.0" + dependencies: + protocols: "npm:^2.0.1" + checksum: 10c0/3eb30d1bcb4507cd25562e7ac61a1c0aa31772134c67cec9c3afe6f4d57ec17e8c2892600a608e8e583f32f53f36465b8968c0305f2855cfbff95acfd049e113 + languageName: node + linkType: hard + +"is-stream@npm:^1.1.0": + version: 1.1.0 + resolution: "is-stream@npm:1.1.0" + checksum: 10c0/b8ae7971e78d2e8488d15f804229c6eed7ed36a28f8807a1815938771f4adff0e705218b7dab968270433f67103e4fef98062a0beea55d64835f705ee72c7002 + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"js-yaml@npm:^3.13.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: "npm:^1.0.7" + esprima: "npm:^4.0.0" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b + languageName: node + linkType: hard + +"js-yaml@npm:^4.0.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f + languageName: node + linkType: hard + +"jsonc-parser@npm:^3.2.0": + version: 3.2.1 + resolution: "jsonc-parser@npm:3.2.1" + checksum: 10c0/ada66dec143d7f9cb0e2d0d29c69e9ce40d20f3a4cb96b0c6efb745025ac7f9ba647d7ac0990d0adfc37a2d2ae084a12009a9c833dbdbeadf648879a99b9df89 + languageName: node + linkType: hard + +"katex@npm:^0.16.0, katex@npm:^0.16.9": + version: 0.16.10 + resolution: "katex@npm:0.16.10" + dependencies: + commander: "npm:^8.3.0" + bin: + katex: cli.js + checksum: 10c0/b465213157e5245bbb31ff6563c33ae81807c06d6f2246325b3a2397497e8929a34eebbb262f5e0991ec00fbc0cc85f388246e6dfc38ec86c28d3e481cb70afa + languageName: node + linkType: hard + +"khroma@npm:^2.0.0": + version: 2.1.0 + resolution: "khroma@npm:2.1.0" + checksum: 10c0/634d98753ff5d2540491cafeb708fc98de0d43f4e6795256d5c8f6e3ad77de93049ea41433928fda3697adf7bbe6fe27351858f6d23b78f8b5775ef314c59891 + languageName: node + linkType: hard + +"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 + languageName: node + linkType: hard + +"kleur@npm:^4.0.3": + version: 4.1.5 + resolution: "kleur@npm:4.1.5" + checksum: 10c0/e9de6cb49657b6fa70ba2d1448fd3d691a5c4370d8f7bbf1c2f64c24d461270f2117e1b0afe8cb3114f13bbd8e51de158c2a224953960331904e636a5e4c0f2a + languageName: node + linkType: hard + +"layout-base@npm:^1.0.0": + version: 1.0.2 + resolution: "layout-base@npm:1.0.2" + checksum: 10c0/2a55d0460fd9f6ed53d7e301b9eb3dea19bda03815d616a40665ce6dc75c1f4d62e1ca19a897da1cfaf6de1b91de59cd6f2f79ba1258f3d7fccc7d46ca7f3337 + languageName: node + linkType: hard + +"lodash-es@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash-es@npm:4.17.21" + checksum: 10c0/fb407355f7e6cd523a9383e76e6b455321f0f153a6c9625e21a8827d10c54c2a2341bd2ae8d034358b60e07325e1330c14c224ff582d04612a46a4f0479ff2f2 + languageName: node + linkType: hard + +"lodash.get@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.get@npm:4.4.2" + checksum: 10c0/48f40d471a1654397ed41685495acb31498d5ed696185ac8973daef424a749ca0c7871bf7b665d5c14f5cc479394479e0307e781f61d5573831769593411be6e + languageName: node + linkType: hard + +"longest-streak@npm:^3.0.0": + version: 3.1.0 + resolution: "longest-streak@npm:3.1.0" + checksum: 10c0/7c2f02d0454b52834d1bcedef79c557bd295ee71fdabb02d041ff3aa9da48a90b5df7c0409156dedbc4df9b65da18742652aaea4759d6ece01f08971af6a7eaa + languageName: node + linkType: hard + +"loose-envify@npm:^1.1.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + +"lru-cache@npm:^4.0.1": + version: 4.1.5 + resolution: "lru-cache@npm:4.1.5" + dependencies: + pseudomap: "npm:^1.0.2" + yallist: "npm:^2.1.2" + checksum: 10c0/1ca5306814e5add9ec63556d6fd9b24a4ecdeaef8e9cea52cbf30301e6b88c8d8ddc7cab45b59b56eb763e6c45af911585dc89925a074ab65e1502e3fe8103cf + languageName: node + linkType: hard + +"markdown-extensions@npm:^1.0.0": + version: 1.1.1 + resolution: "markdown-extensions@npm:1.1.1" + checksum: 10c0/eb9154016502ad1fb4477683ddb5cae8ba3ca06451b381b04dc4c34e91d8d168129d50d404b717d6bf7d458e13088c109303fc72d57cee7151a6082b0e7bba71 + languageName: node + linkType: hard + +"markdown-table@npm:^3.0.0": + version: 3.0.3 + resolution: "markdown-table@npm:3.0.3" + checksum: 10c0/47433a3f31e4637a184e38e873ab1d2fadfb0106a683d466fec329e99a2d8dfa09f091fa42202c6f13ec94aef0199f449a684b28042c636f2edbc1b7e1811dcd + languageName: node + linkType: hard + +"match-sorter@npm:^6.3.1": + version: 6.3.4 + resolution: "match-sorter@npm:6.3.4" + dependencies: + "@babel/runtime": "npm:^7.23.8" + remove-accents: "npm:0.5.0" + checksum: 10c0/35d2a6b6df003c677d9ec87ecd4683657638f5bce856f43f9cf90b03e357ed2f09813ebbac759defa7e7438706936dd34dc2bfe1a18771f7d2541f14d639b4ad + languageName: node + linkType: hard + +"mdast-util-definitions@npm:^5.0.0": + version: 5.1.2 + resolution: "mdast-util-definitions@npm:5.1.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + "@types/unist": "npm:^2.0.0" + unist-util-visit: "npm:^4.0.0" + checksum: 10c0/da9049c15562e44ee4ea4a36113d98c6c9eaa3d8a17d6da2aef6a0626376dcd01d9ec007d77a8dfcad6d0cbd5c32a4abbad72a3f48c3172a55934c7d9a916480 + languageName: node + linkType: hard + +"mdast-util-find-and-replace@npm:^2.0.0": + version: 2.2.2 + resolution: "mdast-util-find-and-replace@npm:2.2.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + escape-string-regexp: "npm:^5.0.0" + unist-util-is: "npm:^5.0.0" + unist-util-visit-parents: "npm:^5.0.0" + checksum: 10c0/ce935f4bd4aeab47f91531a7f09dfab89aaeea62ad31029b43185c5b626921357703d8e5093c13073c097fdabfc57cb2f884d7dfad83dbe7239e351375d6797c + languageName: node + linkType: hard + +"mdast-util-from-markdown@npm:^1.0.0, mdast-util-from-markdown@npm:^1.1.0, mdast-util-from-markdown@npm:^1.3.0": + version: 1.3.1 + resolution: "mdast-util-from-markdown@npm:1.3.1" + dependencies: + "@types/mdast": "npm:^3.0.0" + "@types/unist": "npm:^2.0.0" + decode-named-character-reference: "npm:^1.0.0" + mdast-util-to-string: "npm:^3.1.0" + micromark: "npm:^3.0.0" + micromark-util-decode-numeric-character-reference: "npm:^1.0.0" + micromark-util-decode-string: "npm:^1.0.0" + micromark-util-normalize-identifier: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + unist-util-stringify-position: "npm:^3.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/f4e901bf2a2e93fe35a339e0cff581efacce2f7117cd5652e9a270847bd7e2508b3e717b7b4156af54d4f896d63033e06ff9fafbf59a1d46fe17dd5e2a3f7846 + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^1.0.0": + version: 1.0.3 + resolution: "mdast-util-gfm-autolink-literal@npm:1.0.3" + dependencies: + "@types/mdast": "npm:^3.0.0" + ccount: "npm:^2.0.0" + mdast-util-find-and-replace: "npm:^2.0.0" + micromark-util-character: "npm:^1.0.0" + checksum: 10c0/750e312eae73c3f2e8aa0e8c5232cb1b905357ff37ac236927f1af50cdbee7c2cfe2379b148ac32fa4137eeb3b24601e1bb6135084af926c7cd808867804193f + languageName: node + linkType: hard + +"mdast-util-gfm-footnote@npm:^1.0.0": + version: 1.0.2 + resolution: "mdast-util-gfm-footnote@npm:1.0.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-to-markdown: "npm:^1.3.0" + micromark-util-normalize-identifier: "npm:^1.0.0" + checksum: 10c0/767973e46b9e2ae44e80e51a5e38ad0b032fc7f06a1a3095aa96c2886ba333941c764474a56b82e7db05efc56242a4789bc7fbbcc753d61512750e86a4192fe8 + languageName: node + linkType: hard + +"mdast-util-gfm-strikethrough@npm:^1.0.0": + version: 1.0.3 + resolution: "mdast-util-gfm-strikethrough@npm:1.0.3" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-to-markdown: "npm:^1.3.0" + checksum: 10c0/29616b3dfdd33d3cd13f9b3181a8562fa2fbacfcb04a37dba3c690ba6829f0231b145444de984726d9277b2bc90dd7d96fb9df9f6292d5e77d65a8659ee2f52b + languageName: node + linkType: hard + +"mdast-util-gfm-table@npm:^1.0.0": + version: 1.0.7 + resolution: "mdast-util-gfm-table@npm:1.0.7" + dependencies: + "@types/mdast": "npm:^3.0.0" + markdown-table: "npm:^3.0.0" + mdast-util-from-markdown: "npm:^1.0.0" + mdast-util-to-markdown: "npm:^1.3.0" + checksum: 10c0/a37a05a936292c4f48394123332d3c034a6e1b15bb3e7f3b94e6bce3260c9184fd388abbc4100827edd5485a6563098306994d15a729bde3c96de7a62ed5720b + languageName: node + linkType: hard + +"mdast-util-gfm-task-list-item@npm:^1.0.0": + version: 1.0.2 + resolution: "mdast-util-gfm-task-list-item@npm:1.0.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-to-markdown: "npm:^1.3.0" + checksum: 10c0/91fa91f7d1a8797bf129008dab12d23917015ad12df00044e275b4459e8b383fbec6234338953a0089ef9c3a114d0a360c3e652eb0ebf6ece7e7a8fd3b5977c6 + languageName: node + linkType: hard + +"mdast-util-gfm@npm:^2.0.0": + version: 2.0.2 + resolution: "mdast-util-gfm@npm:2.0.2" + dependencies: + mdast-util-from-markdown: "npm:^1.0.0" + mdast-util-gfm-autolink-literal: "npm:^1.0.0" + mdast-util-gfm-footnote: "npm:^1.0.0" + mdast-util-gfm-strikethrough: "npm:^1.0.0" + mdast-util-gfm-table: "npm:^1.0.0" + mdast-util-gfm-task-list-item: "npm:^1.0.0" + mdast-util-to-markdown: "npm:^1.0.0" + checksum: 10c0/5b7f7f98a90a2962d7e0787e080c4e55b70119100c7685bbdb772d8d7865524aeffd1757edba5afba434250e0246b987c0617c2c635baaf51c26dbbb3b72dbec + languageName: node + linkType: hard + +"mdast-util-math@npm:^2.0.0": + version: 2.0.2 + resolution: "mdast-util-math@npm:2.0.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + longest-streak: "npm:^3.0.0" + mdast-util-to-markdown: "npm:^1.3.0" + checksum: 10c0/2270b6f8d7f0eb7dd5c27bee8ad43f29a8e76a7092742945fd115480ddd8bf72ae53ba1f8f63697cec82016e0c169f0a201503862dfe6bc7ac2286662de3fe8e + languageName: node + linkType: hard + +"mdast-util-mdx-expression@npm:^1.0.0": + version: 1.3.2 + resolution: "mdast-util-mdx-expression@npm:1.3.2" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^2.0.0" + "@types/mdast": "npm:^3.0.0" + mdast-util-from-markdown: "npm:^1.0.0" + mdast-util-to-markdown: "npm:^1.0.0" + checksum: 10c0/01f306ee809d28825cbec23b3c80376a0fbe69601b6b2843d23beb5662a31ec7560995f52b96b13093cc03de1130404a47f139d16f58c3f54e91e88f4bdd82d2 + languageName: node + linkType: hard + +"mdast-util-mdx-jsx@npm:^2.0.0": + version: 2.1.4 + resolution: "mdast-util-mdx-jsx@npm:2.1.4" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^2.0.0" + "@types/mdast": "npm:^3.0.0" + "@types/unist": "npm:^2.0.0" + ccount: "npm:^2.0.0" + mdast-util-from-markdown: "npm:^1.1.0" + mdast-util-to-markdown: "npm:^1.3.0" + parse-entities: "npm:^4.0.0" + stringify-entities: "npm:^4.0.0" + unist-util-remove-position: "npm:^4.0.0" + unist-util-stringify-position: "npm:^3.0.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/b0c16e56a99c5167e60c98dbdbe82645549630fb529688642c4664ca5557ff0b3029c75146f5657cadb7908d5fa99810eacc5dcc51676d0877c8b4dcebb11cbe + languageName: node + linkType: hard + +"mdast-util-mdx@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdx@npm:2.0.1" + dependencies: + mdast-util-from-markdown: "npm:^1.0.0" + mdast-util-mdx-expression: "npm:^1.0.0" + mdast-util-mdx-jsx: "npm:^2.0.0" + mdast-util-mdxjs-esm: "npm:^1.0.0" + mdast-util-to-markdown: "npm:^1.0.0" + checksum: 10c0/3b5e55781a7b7b4b7e71728a84afbec63516f251b3556efec52dbb4824c0733f5ebaa907d21211d008e5cb1a8265e6704bc062ee605f4c09e90fbfa2c6fbba3b + languageName: node + linkType: hard + +"mdast-util-mdxjs-esm@npm:^1.0.0": + version: 1.3.1 + resolution: "mdast-util-mdxjs-esm@npm:1.3.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^2.0.0" + "@types/mdast": "npm:^3.0.0" + mdast-util-from-markdown: "npm:^1.0.0" + mdast-util-to-markdown: "npm:^1.0.0" + checksum: 10c0/2ff0af34ea62004d39f15bd45b79e3008e68cae7e2510c9281e24a17e2c3f55d004524796166ef5aa3378798ca7f6c5f88883238f413577619bbaf41026b7e62 + languageName: node + linkType: hard + +"mdast-util-phrasing@npm:^3.0.0": + version: 3.0.1 + resolution: "mdast-util-phrasing@npm:3.0.1" + dependencies: + "@types/mdast": "npm:^3.0.0" + unist-util-is: "npm:^5.0.0" + checksum: 10c0/5e00e303652a7581593549dbce20dfb69d687d79a972f7928f6ca1920ef5385bceb737a3d5292ab6d937ed8c67bb59771e80e88f530b78734fe7d155f833e32b + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:^12.1.0": + version: 12.3.0 + resolution: "mdast-util-to-hast@npm:12.3.0" + dependencies: + "@types/hast": "npm:^2.0.0" + "@types/mdast": "npm:^3.0.0" + mdast-util-definitions: "npm:^5.0.0" + micromark-util-sanitize-uri: "npm:^1.1.0" + trim-lines: "npm:^3.0.0" + unist-util-generated: "npm:^2.0.0" + unist-util-position: "npm:^4.0.0" + unist-util-visit: "npm:^4.0.0" + checksum: 10c0/0753e45bfcce423f7a13979ac720a23ed8d6bafed174c387f43bbe8baf3838f3a043cd8006975b71e5c4068b7948f83f1348acea79801101af31eaec4e7a499a + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:^13.0.0": + version: 13.2.0 + resolution: "mdast-util-to-hast@npm:13.2.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + trim-lines: "npm:^3.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/9ee58def9287df8350cbb6f83ced90f9c088d72d4153780ad37854f87144cadc6f27b20347073b285173b1649b0723ddf0b9c78158608a804dcacb6bda6e1816 + languageName: node + linkType: hard + +"mdast-util-to-markdown@npm:^1.0.0, mdast-util-to-markdown@npm:^1.3.0": + version: 1.5.0 + resolution: "mdast-util-to-markdown@npm:1.5.0" + dependencies: + "@types/mdast": "npm:^3.0.0" + "@types/unist": "npm:^2.0.0" + longest-streak: "npm:^3.0.0" + mdast-util-phrasing: "npm:^3.0.0" + mdast-util-to-string: "npm:^3.0.0" + micromark-util-decode-string: "npm:^1.0.0" + unist-util-visit: "npm:^4.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/9831d14aa6c097750a90c7b87b4e814b040731c30606a794c9b136dc746633dd9ec07154ca97d4fec4eaf732cf89d14643424e2581732d6ee18c9b0e51ff7664 + languageName: node + linkType: hard + +"mdast-util-to-string@npm:^3.0.0, mdast-util-to-string@npm:^3.1.0": + version: 3.2.0 + resolution: "mdast-util-to-string@npm:3.2.0" + dependencies: + "@types/mdast": "npm:^3.0.0" + checksum: 10c0/112f4bf0f6758dcb95deffdcf37afba7eaecdfe2ee13252de031723094d4d55220e147326690a8b91244758e2d678e7aeb1fdd0fa6ef3317c979bc42effd9a21 + languageName: node + linkType: hard + +"mermaid@npm:^10.2.2": + version: 10.9.1 + resolution: "mermaid@npm:10.9.1" + dependencies: + "@braintree/sanitize-url": "npm:^6.0.1" + "@types/d3-scale": "npm:^4.0.3" + "@types/d3-scale-chromatic": "npm:^3.0.0" + cytoscape: "npm:^3.28.1" + cytoscape-cose-bilkent: "npm:^4.1.0" + d3: "npm:^7.4.0" + d3-sankey: "npm:^0.12.3" + dagre-d3-es: "npm:7.0.10" + dayjs: "npm:^1.11.7" + dompurify: "npm:^3.0.5" + elkjs: "npm:^0.9.0" + katex: "npm:^0.16.9" + khroma: "npm:^2.0.0" + lodash-es: "npm:^4.17.21" + mdast-util-from-markdown: "npm:^1.3.0" + non-layered-tidy-tree-layout: "npm:^2.0.2" + stylis: "npm:^4.1.3" + ts-dedent: "npm:^2.2.0" + uuid: "npm:^9.0.0" + web-worker: "npm:^1.2.0" + checksum: 10c0/034f326682e3e478e4bd85e418cfef00773db4432301b858247c8d4bf813e67fa1901e8548fc490eafe4c9c215c9fb96dead73007ff317ee99973cf4f63c8791 + languageName: node + linkType: hard + +"micromark-core-commonmark@npm:^1.0.0, micromark-core-commonmark@npm:^1.0.1": + version: 1.1.0 + resolution: "micromark-core-commonmark@npm:1.1.0" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + micromark-factory-destination: "npm:^1.0.0" + micromark-factory-label: "npm:^1.0.0" + micromark-factory-space: "npm:^1.0.0" + micromark-factory-title: "npm:^1.0.0" + micromark-factory-whitespace: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-chunked: "npm:^1.0.0" + micromark-util-classify-character: "npm:^1.0.0" + micromark-util-html-tag-name: "npm:^1.0.0" + micromark-util-normalize-identifier: "npm:^1.0.0" + micromark-util-resolve-all: "npm:^1.0.0" + micromark-util-subtokenize: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.1" + uvu: "npm:^0.5.0" + checksum: 10c0/b3bf7b7004ce7dbb3ae151dcca4db1d12546f1b943affb2418da4b90b9ce59357373c433ee2eea4c868aee0791dafa355aeed19f5ef2b0acaf271f32f1ecbe6a + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^1.0.0": + version: 1.0.5 + resolution: "micromark-extension-gfm-autolink-literal@npm:1.0.5" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/4964a52605ac36d24501d427e2d173fa39b5e0402275cb45068eba4898f4cb9cc57f7007b21b7514f0ab5f7b371b1701a5156a10b6ac8e77a7f36e830cf481d4 + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^1.0.0": + version: 1.1.2 + resolution: "micromark-extension-gfm-footnote@npm:1.1.2" + dependencies: + micromark-core-commonmark: "npm:^1.0.0" + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-normalize-identifier: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/b8090876cc3da5436c6253b0b40e39ceaa470c2429f699c19ee4163cef3102c4cd16c4ac2ec8caf916037fad310cfb52a9ef182c75d50fca7419ba08faad9b39 + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^1.0.0": + version: 1.0.7 + resolution: "micromark-extension-gfm-strikethrough@npm:1.0.7" + dependencies: + micromark-util-chunked: "npm:^1.0.0" + micromark-util-classify-character: "npm:^1.0.0" + micromark-util-resolve-all: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/b45fe93a7a412fc44bae7a183b92a988e17b49ed9d683bd80ee4dde96d462e1ca6b316dd64bda7759e4086d6d8686790a711e53c244f1f4d2b37e1cfe852884d + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^1.0.0": + version: 1.0.7 + resolution: "micromark-extension-gfm-table@npm:1.0.7" + dependencies: + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/38b5af80ecab8206845a057338235bee6f47fb6cb904208be4b76e87906765821683e25bef85dfa485809f931eaf8cd55f16cd2f4d6e33b84f56edfaf1dfb129 + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^1.0.0": + version: 1.0.2 + resolution: "micromark-extension-gfm-tagfilter@npm:1.0.2" + dependencies: + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/7e1bf278255cf2a8d2dda9de84bc238b39c53100e25ba8d7168220d5b00dc74869a6cb038fbf2e76b8ae89efc66906762311797a906d7d9cdd71e07bfe1ed505 + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^1.0.0": + version: 1.0.5 + resolution: "micromark-extension-gfm-task-list-item@npm:1.0.5" + dependencies: + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/2179742fa2cbb243cc06bd9e43fbb94cd98e4814c9d368ddf8b4b5afa0348023f335626ae955e89d679e2c2662a7f82c315117a3b060c87bdb4420fee5a219d1 + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-extension-gfm@npm:2.0.3" + dependencies: + micromark-extension-gfm-autolink-literal: "npm:^1.0.0" + micromark-extension-gfm-footnote: "npm:^1.0.0" + micromark-extension-gfm-strikethrough: "npm:^1.0.0" + micromark-extension-gfm-table: "npm:^1.0.0" + micromark-extension-gfm-tagfilter: "npm:^1.0.0" + micromark-extension-gfm-task-list-item: "npm:^1.0.0" + micromark-util-combine-extensions: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/53056376d14caf3fab2cc44881c1ad49d975776cc2267bca74abda2cb31f2a77ec0fb2bdb2dd97565f0d9943ad915ff192b89c1cee5d9d727569a5e38505799b + languageName: node + linkType: hard + +"micromark-extension-math@npm:^2.0.0": + version: 2.1.2 + resolution: "micromark-extension-math@npm:2.1.2" + dependencies: + "@types/katex": "npm:^0.16.0" + katex: "npm:^0.16.0" + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/5d40ffc93862498cbcbc9c96a40a05150b878c3d86ab25bc771dec005d286f4381578ccee3f421ecfd9db259298a89a37a5b6b48529842240d34f8acd8edffb5 + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^1.0.0": + version: 1.0.8 + resolution: "micromark-extension-mdx-expression@npm:1.0.8" + dependencies: + "@types/estree": "npm:^1.0.0" + micromark-factory-mdx-expression: "npm:^1.0.0" + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-events-to-acorn: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/99e2997a54caafc4258979c0591b3fe8e31018079df833d559768092fec41e57a71225d423f4179cea4e8bc1af2f52f5c9ae640673619d8fe142ded875240da3 + languageName: node + linkType: hard + +"micromark-extension-mdx-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "micromark-extension-mdx-jsx@npm:1.0.5" + dependencies: + "@types/acorn": "npm:^4.0.0" + "@types/estree": "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^2.0.0" + micromark-factory-mdx-expression: "npm:^1.0.0" + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/1b4bfbe60b9cabfabfb870f70ded8da0caacbaa3be6bdf07f6db25cc5a14c6bc970c34c60e5c80da1e97766064a117feb8160b6d661d69e530a4cc7ec97305de + languageName: node + linkType: hard + +"micromark-extension-mdx-md@npm:^1.0.0": + version: 1.0.1 + resolution: "micromark-extension-mdx-md@npm:1.0.1" + dependencies: + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/9ad70b3a5e842fd7ebd93c8c48a32fd3d05fe77be06a08ef32462ea53e97d8f297e2c1c4b30a6929dbd05125279fe98bb04e9cc0bb686c691bdcf7d36c6e51b0 + languageName: node + linkType: hard + +"micromark-extension-mdxjs-esm@npm:^1.0.0": + version: 1.0.5 + resolution: "micromark-extension-mdxjs-esm@npm:1.0.5" + dependencies: + "@types/estree": "npm:^1.0.0" + micromark-core-commonmark: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-events-to-acorn: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + unist-util-position-from-estree: "npm:^1.1.0" + uvu: "npm:^0.5.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/612028bced78e882641a43c78fc4813a573b383dc0a7b90db75ed88b37bf5b5997dc7ead4a1011315b34f17bc76b7f4419de6ad9532a088102ab1eea0245d380 + languageName: node + linkType: hard + +"micromark-extension-mdxjs@npm:^1.0.0": + version: 1.0.1 + resolution: "micromark-extension-mdxjs@npm:1.0.1" + dependencies: + acorn: "npm:^8.0.0" + acorn-jsx: "npm:^5.0.0" + micromark-extension-mdx-expression: "npm:^1.0.0" + micromark-extension-mdx-jsx: "npm:^1.0.0" + micromark-extension-mdx-md: "npm:^1.0.0" + micromark-extension-mdxjs-esm: "npm:^1.0.0" + micromark-util-combine-extensions: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3f123e4afea9674c96934c9ea6a057ec9e5584992c50c36c173a2e331d272b1f4e2a8552364a0e2cb50703d0218831fdae1a17b563f0009aac6a35350e6a7b77 + languageName: node + linkType: hard + +"micromark-factory-destination@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-destination@npm:1.1.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/71ebd9089bf0c9689b98ef42215c04032ae2701ae08c3546b663628553255dca18e5310dbdacddad3acd8de4f12a789835fff30dadc4da3c4e30387a75e6b488 + languageName: node + linkType: hard + +"micromark-factory-label@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-label@npm:1.1.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/5e2cd2d8214bb92a34dfcedf9c7aecf565e3648650a3a6a0495ededf15f2318dd214dc069e3026402792cd5839d395313f8ef9c2e86ca34a8facaa0f75a77753 + languageName: node + linkType: hard + +"micromark-factory-mdx-expression@npm:^1.0.0": + version: 1.0.9 + resolution: "micromark-factory-mdx-expression@npm:1.0.9" + dependencies: + "@types/estree": "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-events-to-acorn: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + unist-util-position-from-estree: "npm:^1.0.0" + uvu: "npm:^0.5.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/b28bd8e072f37ca91446fe8d113e4ae64baaef013b0cde4aa224add0ee40963ce3584b9709f7662d30491f875ae7104b897d37efa26cdaecf25082ed5bac7b8c + languageName: node + linkType: hard + +"micromark-factory-space@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-space@npm:1.1.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3da81187ce003dd4178c7adc4674052fb8befc8f1a700ae4c8227755f38581a4ae963866dc4857488d62d1dc9837606c9f2f435fa1332f62a0f1c49b83c6a822 + languageName: node + linkType: hard + +"micromark-factory-title@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-title@npm:1.1.0" + dependencies: + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/cf8c687d1d5c3928846a4791d4a7e2f1d7bdd2397051e20d60f06b7565a48bf85198ab6f85735e997ab3f0cbb80b8b6391f4f7ebc0aae2f2f8c3a08541257bf6 + languageName: node + linkType: hard + +"micromark-factory-whitespace@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-whitespace@npm:1.1.0" + dependencies: + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/7248cc4534f9befb38c6f398b6e38efd3199f1428fc214c9cb7ed5b6e9fa7a82c0d8cdfa9bcacde62887c9a7c8c46baf5c318b2ae8f701afbccc8ad702e92dce + languageName: node + linkType: hard + +"micromark-util-character@npm:^1.0.0": + version: 1.2.0 + resolution: "micromark-util-character@npm:1.2.0" + dependencies: + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3390a675a50731b58a8e5493cd802e190427f10fa782079b455b00f6b54e406e36882df7d4a3bd32b709f7a2c3735b4912597ebc1c0a99566a8d8d0b816e2cd4 + languageName: node + linkType: hard + +"micromark-util-character@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-character@npm:2.1.0" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/fc37a76aaa5a5138191ba2bef1ac50c36b3bcb476522e98b1a42304ab4ec76f5b036a746ddf795d3de3e7004b2c09f21dd1bad42d161f39b8cfc0acd067e6373 + languageName: node + linkType: hard + +"micromark-util-chunked@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-chunked@npm:1.1.0" + dependencies: + micromark-util-symbol: "npm:^1.0.0" + checksum: 10c0/59534cf4aaf481ed58d65478d00eae0080df9b5816673f79b5ddb0cea263e5a9ee9cbb6cc565daf1eb3c8c4ff86fc4e25d38a0577539655cda823a4249efd358 + languageName: node + linkType: hard + +"micromark-util-classify-character@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-classify-character@npm:1.1.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3266453dc0fdaf584e24c9b3c91d1ed180f76b5856699c51fd2549305814fcab7ec52afb4d3e83d002a9115cd2d2b2ffdc9c0b38ed85120822bf515cc00636ec + languageName: node + linkType: hard + +"micromark-util-combine-extensions@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-combine-extensions@npm:1.1.0" + dependencies: + micromark-util-chunked: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/0bc572fab3fe77f533c29aa1b75cb847b9fc9455f67a98623ef9740b925c0b0426ad9f09bbb56f1e844ea9ebada7873d1f06d27f7c979a917692b273c4b69e31 + languageName: node + linkType: hard + +"micromark-util-decode-numeric-character-reference@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-decode-numeric-character-reference@npm:1.1.0" + dependencies: + micromark-util-symbol: "npm:^1.0.0" + checksum: 10c0/64ef2575e3fc2426976c19e16973348f20b59ddd5543f1467ac2e251f29e0a91f12089703d29ae985b0b9a408ee0d72f06d04ed3920811aa2402aabca3bdf9e4 + languageName: node + linkType: hard + +"micromark-util-decode-string@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-decode-string@npm:1.1.0" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-decode-numeric-character-reference: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + checksum: 10c0/757a0aaa5ad6c50c7480bd75371d407ac75f5022cd4404aba07adadf1448189502aea9bb7b2d09d25e18745e0abf72b95506b6beb184bcccabe919e48e3a5df7 + languageName: node + linkType: hard + +"micromark-util-encode@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-encode@npm:1.1.0" + checksum: 10c0/9878c9bc96999d45626a7597fffac85348ea842dce75d2417345cbf070a9941c62477bd0963bef37d4f0fd29f2982be6ddf416d62806f00ccb334af9d6ee87e7 + languageName: node + linkType: hard + +"micromark-util-encode@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-encode@npm:2.0.0" + checksum: 10c0/ebdaafff23100bbf4c74e63b4b1612a9ddf94cd7211d6a076bc6fb0bc32c1b48d6fb615aa0953e607c62c97d849f97f1042260d3eb135259d63d372f401bbbb2 + languageName: node + linkType: hard + +"micromark-util-events-to-acorn@npm:^1.0.0": + version: 1.2.3 + resolution: "micromark-util-events-to-acorn@npm:1.2.3" + dependencies: + "@types/acorn": "npm:^4.0.0" + "@types/estree": "npm:^1.0.0" + "@types/unist": "npm:^2.0.0" + estree-util-visit: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/cd3af7365806a0b22efb83cb7726cb835725c0bc22e04f7ea83f2f38a09e7132413eff6ab6d53652b969a7ec30e442731c3abbbe8a74dc2081c51fd10223c269 + languageName: node + linkType: hard + +"micromark-util-html-tag-name@npm:^1.0.0": + version: 1.2.0 + resolution: "micromark-util-html-tag-name@npm:1.2.0" + checksum: 10c0/15421869678d36b4fe51df453921e8186bff514a14e9f79f32b7e1cdd67874e22a66ad34a7f048dd132cbbbfc7c382ae2f777a2bfd1f245a47705dc1c6d4f199 + languageName: node + linkType: hard + +"micromark-util-normalize-identifier@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-normalize-identifier@npm:1.1.0" + dependencies: + micromark-util-symbol: "npm:^1.0.0" + checksum: 10c0/a9657321a2392584e4d978061882117a84db7d2c2c1c052c0f5d25da089d463edb9f956d5beaf7f5768984b6f72d046d59b5972951ec7bf25397687a62b8278a + languageName: node + linkType: hard + +"micromark-util-resolve-all@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-resolve-all@npm:1.1.0" + dependencies: + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/b5c95484c06e87bbbb60d8430eb030a458733a5270409f4c67892d1274737087ca6a7ca888987430e57cf1dcd44bb16390d3b3936a2bf07f7534ec8f52ce43c9 + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^1.0.0, micromark-util-sanitize-uri@npm:^1.1.0": + version: 1.2.0 + resolution: "micromark-util-sanitize-uri@npm:1.2.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-encode: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + checksum: 10c0/dbdb98248e9f0408c7a00f1c1cd805775b41d213defd659533835f34b38da38e8f990bf7b3f782e96bffbc549aec9c3ecdab197d4ad5adbfe08f814a70327b6e + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-sanitize-uri@npm:2.0.0" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/74763ca1c927dd520d3ab8fd9856a19740acf76fc091f0a1f5d4e99c8cd5f1b81c5a0be3efb564941a071fb6d85fd951103f2760eb6cff77b5ab3abe08341309 + languageName: node + linkType: hard + +"micromark-util-subtokenize@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-subtokenize@npm:1.1.0" + dependencies: + micromark-util-chunked: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + uvu: "npm:^0.5.0" + checksum: 10c0/f292b1b162845db50d36255c9d4c4c6d47931fbca3ac98a80c7e536d2163233fd662f8ca0479ee2b80f145c66a1394c7ed17dfce801439741211015e77e3901e + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-symbol@npm:1.1.0" + checksum: 10c0/10ceaed33a90e6bfd3a5d57053dbb53f437d4809cc11430b5a09479c0ba601577059be9286df4a7eae6e350a60a2575dc9fa9d9872b5b8d058c875e075c33803 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-symbol@npm:2.0.0" + checksum: 10c0/4e76186c185ce4cefb9cea8584213d9ffacd77099d1da30c0beb09fa21f46f66f6de4c84c781d7e34ff763fe3a06b530e132fa9004882afab9e825238d0aa8b3 + languageName: node + linkType: hard + +"micromark-util-types@npm:^1.0.0, micromark-util-types@npm:^1.0.1": + version: 1.1.0 + resolution: "micromark-util-types@npm:1.1.0" + checksum: 10c0/a9749cb0a12a252ff536baabcb7012421b6fad4d91a5fdd80d7b33dc7b4c22e2d0c4637dfe5b902d00247fe6c9b01f4a24fce6b572b16ccaa4da90e6ce2a11e4 + languageName: node + linkType: hard + +"micromark-util-types@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-types@npm:2.0.0" + checksum: 10c0/d74e913b9b61268e0d6939f4209e3abe9dada640d1ee782419b04fd153711112cfaaa3c4d5f37225c9aee1e23c3bb91a1f5223e1e33ba92d33e83956a53e61de + languageName: node + linkType: hard + +"micromark@npm:^3.0.0": + version: 3.2.0 + resolution: "micromark@npm:3.2.0" + dependencies: + "@types/debug": "npm:^4.0.0" + debug: "npm:^4.0.0" + decode-named-character-reference: "npm:^1.0.0" + micromark-core-commonmark: "npm:^1.0.1" + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.0.0" + micromark-util-chunked: "npm:^1.0.0" + micromark-util-combine-extensions: "npm:^1.0.0" + micromark-util-decode-numeric-character-reference: "npm:^1.0.0" + micromark-util-encode: "npm:^1.0.0" + micromark-util-normalize-identifier: "npm:^1.0.0" + micromark-util-resolve-all: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^1.0.0" + micromark-util-subtokenize: "npm:^1.0.0" + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.1" + uvu: "npm:^0.5.0" + checksum: 10c0/f243e805d1b3cc699fddae2de0b1492bc82462f1a709d7ae5c82039f88b1e009c959100184717e748be057b5f88603289d5681679a4e6fbabcd037beb34bc744 + languageName: node + linkType: hard + +"mri@npm:^1.1.0": + version: 1.2.0 + resolution: "mri@npm:1.2.0" + checksum: 10c0/a3d32379c2554cf7351db6237ddc18dc9e54e4214953f3da105b97dc3babe0deb3ffe99cf409b38ea47cc29f9430561ba6b53b24ab8f9ce97a4b50409e4a50e7 + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc + languageName: node + linkType: hard + +"nanoid@npm:^3.3.6": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3 + languageName: node + linkType: hard + +"next-mdx-remote@npm:^4.2.1": + version: 4.4.1 + resolution: "next-mdx-remote@npm:4.4.1" + dependencies: + "@mdx-js/mdx": "npm:^2.2.1" + "@mdx-js/react": "npm:^2.2.1" + vfile: "npm:^5.3.0" + vfile-matter: "npm:^3.0.1" + peerDependencies: + react: ">=16.x <=18.x" + react-dom: ">=16.x <=18.x" + checksum: 10c0/d48ad271f58312d11f392b0fbd7b2dbc5990cc82fcb6d28f687875a52b28b695c0700b93f197c72910a4c73da0a1fe4867db95315bc2ee7f0fc1743279f41b80 + languageName: node + linkType: hard + +"next-seo@npm:^6.0.0": + version: 6.5.0 + resolution: "next-seo@npm:6.5.0" + peerDependencies: + next: ^8.1.1-canary.54 || >=9.0.0 + react: ">=16.0.0" + react-dom: ">=16.0.0" + checksum: 10c0/f2403356aa7fa91314fb91f9b1f7a3436ff76307e2345faec67132e8c0546312f4c6262bc10db28339612c1777dc07ba566bd407262d662f2e417932563837a6 + languageName: node + linkType: hard + +"next-themes@npm:^0.2.1": + version: 0.2.1 + resolution: "next-themes@npm:0.2.1" + peerDependencies: + next: "*" + react: "*" + react-dom: "*" + checksum: 10c0/979dec0a2de049ce7d1b5da835e7f7dc3b7ec83ba9e464348f497a52a6a6e5b5c395c97f071f66a63f50f22cce89fb6d19061ec7e75643b0eab215b21794bde7 + languageName: node + linkType: hard + +"next@npm:^15.0.3": + version: 15.0.3 + resolution: "next@npm:15.0.3" + dependencies: + "@next/env": "npm:15.0.3" + "@next/swc-darwin-arm64": "npm:15.0.3" + "@next/swc-darwin-x64": "npm:15.0.3" + "@next/swc-linux-arm64-gnu": "npm:15.0.3" + "@next/swc-linux-arm64-musl": "npm:15.0.3" + "@next/swc-linux-x64-gnu": "npm:15.0.3" + "@next/swc-linux-x64-musl": "npm:15.0.3" + "@next/swc-win32-arm64-msvc": "npm:15.0.3" + "@next/swc-win32-x64-msvc": "npm:15.0.3" + "@swc/counter": "npm:0.1.3" + "@swc/helpers": "npm:0.5.13" + busboy: "npm:1.6.0" + caniuse-lite: "npm:^1.0.30001579" + postcss: "npm:8.4.31" + sharp: "npm:^0.33.5" + styled-jsx: "npm:5.1.6" + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + sass: ^1.3.0 + dependenciesMeta: + "@next/swc-darwin-arm64": + optional: true + "@next/swc-darwin-x64": + optional: true + "@next/swc-linux-arm64-gnu": + optional: true + "@next/swc-linux-arm64-musl": + optional: true + "@next/swc-linux-x64-gnu": + optional: true + "@next/swc-linux-x64-musl": + optional: true + "@next/swc-win32-arm64-msvc": + optional: true + "@next/swc-win32-x64-msvc": + optional: true + sharp: + optional: true + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + bin: + next: dist/bin/next + checksum: 10c0/c5f6a57acb5f29063abc82d4d4417a048d0c2d5216d6ded6aa3fe32d60bb4835ed57dd34e2ef8fdda15579e97205820dc25bf34556b1d942a01a33d9ae7f88db + languageName: node + linkType: hard + +"nextra-theme-docs@npm:^2.13.4": + version: 2.13.4 + resolution: "nextra-theme-docs@npm:2.13.4" + dependencies: + "@headlessui/react": "npm:^1.7.17" + "@popperjs/core": "npm:^2.11.8" + clsx: "npm:^2.0.0" + escape-string-regexp: "npm:^5.0.0" + flexsearch: "npm:^0.7.31" + focus-visible: "npm:^5.2.0" + git-url-parse: "npm:^13.1.0" + intersection-observer: "npm:^0.12.2" + match-sorter: "npm:^6.3.1" + next-seo: "npm:^6.0.0" + next-themes: "npm:^0.2.1" + scroll-into-view-if-needed: "npm:^3.1.0" + zod: "npm:^3.22.3" + peerDependencies: + next: ">=9.5.3" + nextra: 2.13.4 + react: ">=16.13.1" + react-dom: ">=16.13.1" + checksum: 10c0/3c8711391a771878370db9e71296d700f30fdcc31a1c739eac1f586b12b0d7960326f5e4a75e1b7c3ffc16734bc2c98347b001734e6e607f0f89efa2ac0e84d2 + languageName: node + linkType: hard + +"nextra@npm:^2.13.4": + version: 2.13.4 + resolution: "nextra@npm:2.13.4" + dependencies: + "@headlessui/react": "npm:^1.7.17" + "@mdx-js/mdx": "npm:^2.3.0" + "@mdx-js/react": "npm:^2.3.0" + "@napi-rs/simple-git": "npm:^0.1.9" + "@theguild/remark-mermaid": "npm:^0.0.5" + "@theguild/remark-npm2yarn": "npm:^0.2.0" + clsx: "npm:^2.0.0" + github-slugger: "npm:^2.0.0" + graceful-fs: "npm:^4.2.11" + gray-matter: "npm:^4.0.3" + katex: "npm:^0.16.9" + lodash.get: "npm:^4.4.2" + next-mdx-remote: "npm:^4.2.1" + p-limit: "npm:^3.1.0" + rehype-katex: "npm:^7.0.0" + rehype-pretty-code: "npm:0.9.11" + rehype-raw: "npm:^7.0.0" + remark-gfm: "npm:^3.0.1" + remark-math: "npm:^5.1.1" + remark-reading-time: "npm:^2.0.1" + shiki: "npm:^0.14.3" + slash: "npm:^3.0.0" + title: "npm:^3.5.3" + unist-util-remove: "npm:^4.0.0" + unist-util-visit: "npm:^5.0.0" + zod: "npm:^3.22.3" + peerDependencies: + next: ">=9.5.3" + react: ">=16.13.1" + react-dom: ">=16.13.1" + checksum: 10c0/68941552f83639ae818e27b1cfbfef4031362c95bb5c80188cabe29ccd700e0889e20d90cde621d79e151fdf02713b096cfaa42b9304946133b82c223d2e01e3 + languageName: node + linkType: hard + +"non-layered-tidy-tree-layout@npm:^2.0.2": + version: 2.0.2 + resolution: "non-layered-tidy-tree-layout@npm:2.0.2" + checksum: 10c0/73856e9959667193e733a7ef2b06a69421f4d9d7428a3982ce39763cd979a04eed0007f2afb3414afa3f6dc4dc6b5c850c2af9aa71a974475236a465093ec9c7 + languageName: node + linkType: hard + +"npm-run-path@npm:^2.0.0": + version: 2.0.2 + resolution: "npm-run-path@npm:2.0.2" + dependencies: + path-key: "npm:^2.0.0" + checksum: 10c0/95549a477886f48346568c97b08c4fda9cdbf7ce8a4fbc2213f36896d0d19249e32d68d7451bdcbca8041b5fba04a6b2c4a618beaf19849505c05b700740f1de + languageName: node + linkType: hard + +"npm-to-yarn@npm:^2.1.0": + version: 2.2.1 + resolution: "npm-to-yarn@npm:2.2.1" + checksum: 10c0/65c696a3e595facad802b6b13c04e504806ea88fd4f87ab758f8042c19f65b4c4822815a47095df944b0809a95e574c27323c33cca5533f8454515eaa6e14fac + languageName: node + linkType: hard + +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 + languageName: node + linkType: hard + +"p-limit@npm:^3.1.0": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + languageName: node + linkType: hard + +"parse-entities@npm:^4.0.0": + version: 4.0.1 + resolution: "parse-entities@npm:4.0.1" + dependencies: + "@types/unist": "npm:^2.0.0" + character-entities: "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + character-reference-invalid: "npm:^2.0.0" + decode-named-character-reference: "npm:^1.0.0" + is-alphanumerical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + is-hexadecimal: "npm:^2.0.0" + checksum: 10c0/9dfa3b0dc43a913c2558c4bd625b1abcc2d6c6b38aa5724b141ed988471977248f7ad234eed57e1bc70b694dd15b0d710a04f66c2f7c096e35abd91962b7d926 + languageName: node + linkType: hard + +"parse-numeric-range@npm:^1.3.0": + version: 1.3.0 + resolution: "parse-numeric-range@npm:1.3.0" + checksum: 10c0/53465afaa92111e86697281b684aa4574427360889cc23a1c215488c06b72441febdbf09f47ab0bef9a0c701e059629f3eebd2fe6fb241a254ad7a7a642aebe8 + languageName: node + linkType: hard + +"parse-path@npm:^7.0.0": + version: 7.0.0 + resolution: "parse-path@npm:7.0.0" + dependencies: + protocols: "npm:^2.0.0" + checksum: 10c0/e7646f6b998b083bbd40102643d803557ce4ae18ae1704e6cc7ae2525ea7c5400f4a3635aca3244cfe65ce4dd0ff77db1142dde4d080e8a80c364c4b3e8fe8d2 + languageName: node + linkType: hard + +"parse-url@npm:^8.1.0": + version: 8.1.0 + resolution: "parse-url@npm:8.1.0" + dependencies: + parse-path: "npm:^7.0.0" + checksum: 10c0/68b95afdf4bbf72e57c7ab66f8757c935fff888f7e2b0f1e06098b4faa19e06b6b743bddaed5bc8df4f0c2de6fc475355d787373b2fdd40092be9e4e4b996648 + languageName: node + linkType: hard + +"parse5@npm:^7.0.0": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: "npm:^4.4.0" + checksum: 10c0/297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 + languageName: node + linkType: hard + +"path-key@npm:^2.0.0": + version: 2.0.1 + resolution: "path-key@npm:2.0.1" + checksum: 10c0/dd2044f029a8e58ac31d2bf34c34b93c3095c1481942960e84dd2faa95bbb71b9b762a106aead0646695330936414b31ca0bd862bf488a937ad17c8c5d73b32b + languageName: node + linkType: hard + +"periscopic@npm:^3.0.0": + version: 3.1.0 + resolution: "periscopic@npm:3.1.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^3.0.0" + is-reference: "npm:^3.0.0" + checksum: 10c0/fb5ce7cd810c49254cdf1cd3892811e6dd1a1dfbdf5f10a0a33fb7141baac36443c4cad4f0e2b30abd4eac613f6ab845c2bc1b7ce66ae9694c7321e6ada5bd96 + languageName: node + linkType: hard + +"picocolors@npm:^1.0.0": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 + languageName: node + linkType: hard + +"postcss@npm:8.4.31": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" + dependencies: + nanoid: "npm:^3.3.6" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.0.2" + checksum: 10c0/748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf + languageName: node + linkType: hard + +"property-information@npm:^6.0.0": + version: 6.5.0 + resolution: "property-information@npm:6.5.0" + checksum: 10c0/981e0f9cc2e5acdb414a6fd48a99dd0fd3a4079e7a91ab41cf97a8534cf43e0e0bc1ffada6602a1b3d047a33db8b5fc2ef46d863507eda712d5ceedac443f0ef + languageName: node + linkType: hard + +"protocols@npm:^2.0.0, protocols@npm:^2.0.1": + version: 2.0.1 + resolution: "protocols@npm:2.0.1" + checksum: 10c0/016cc58a596e401004a028a2f7005e3444bf89ee8f606409c411719374d1e8bba0464fc142a065cce0d19f41669b2f7ffe25a8bde4f16ce3b6eb01fabc51f2e7 + languageName: node + linkType: hard + +"pseudomap@npm:^1.0.2": + version: 1.0.2 + resolution: "pseudomap@npm:1.0.2" + checksum: 10c0/5a91ce114c64ed3a6a553aa7d2943868811377388bb31447f9d8028271bae9b05b340fe0b6961a64e45b9c72946aeb0a4ab635e8f7cb3715ffd0ff2beeb6a679 + languageName: node + linkType: hard + +"react-dom@npm:^18.3.1": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.2" + peerDependencies: + react: ^18.3.1 + checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 + languageName: node + linkType: hard + +"react@npm:^18.3.1": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 + languageName: node + linkType: hard + +"reading-time@npm:^1.3.0": + version: 1.5.0 + resolution: "reading-time@npm:1.5.0" + checksum: 10c0/0f730852fd4fb99e5f78c5b0cf36ab8c3fa15db96f87d9563843f6fd07a47864273ade539ebb184b785b728cde81a70283aa2d9b80cba5ca03b81868be03cabc + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 + languageName: node + linkType: hard + +"rehype-katex@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-katex@npm:7.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/katex": "npm:^0.16.0" + hast-util-from-html-isomorphic: "npm:^2.0.0" + hast-util-to-text: "npm:^4.0.0" + katex: "npm:^0.16.0" + unist-util-visit-parents: "npm:^6.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/4986d5db673576df0274464eafecef7c999fb72bf16e8df92454c68bf063b005010ab5465c64dacfbc1767ed6446dd03768917df7b9983f5e60711bce78b9880 + languageName: node + linkType: hard + +"rehype-pretty-code@npm:0.9.11": + version: 0.9.11 + resolution: "rehype-pretty-code@npm:0.9.11" + dependencies: + "@types/hast": "npm:^2.0.0" + hash-obj: "npm:^4.0.0" + parse-numeric-range: "npm:^1.3.0" + peerDependencies: + shiki: "*" + checksum: 10c0/10d9b87df6b9a963f6e650b90908347e6cce8f521bbc220ee3a101e82025d7721e2c108d90922f1a16f9d08a1b18f898ec241a12a12f5e931548e3fb528039d9 + languageName: node + linkType: hard + +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-raw: "npm:^9.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1435b4b6640a5bc3abe3b2133885c4dbff5ef2190ef9cfe09d6a63f74dd7d7ffd0cede70603278560ccf1acbfb9da9faae4b68065a28bc5aa88ad18e40f32d52 + languageName: node + linkType: hard + +"remark-gfm@npm:^3.0.1": + version: 3.0.1 + resolution: "remark-gfm@npm:3.0.1" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-gfm: "npm:^2.0.0" + micromark-extension-gfm: "npm:^2.0.0" + unified: "npm:^10.0.0" + checksum: 10c0/53c4e82204f82f81949a170efdeb49d3c45137b7bca06a7ff857a483aac1a44b55ef0de8fb1bbe4f1292f2a378058e2e42e644f2c61f3e0cdc3e56afa4ec2a2c + languageName: node + linkType: hard + +"remark-math@npm:^5.1.1": + version: 5.1.1 + resolution: "remark-math@npm:5.1.1" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-math: "npm:^2.0.0" + micromark-extension-math: "npm:^2.0.0" + unified: "npm:^10.0.0" + checksum: 10c0/e61e314398e65d1ef9343cce37bdb8e94697772d53f1b9e48f815cece35033b4d41db81766696135558c6de40f2ad86877b49891daec6c7b1453dba0e034a9dc + languageName: node + linkType: hard + +"remark-mdx@npm:^2.0.0": + version: 2.3.0 + resolution: "remark-mdx@npm:2.3.0" + dependencies: + mdast-util-mdx: "npm:^2.0.0" + micromark-extension-mdxjs: "npm:^1.0.0" + checksum: 10c0/2688bbf03094a9cd17cc86afb6cf0270e86ffc696a2fe25ccb1befb84eb0864d281388dc560b585e05e20f94a994c9fa88492430d2ba703a2fef6918bca4c36b + languageName: node + linkType: hard + +"remark-parse@npm:^10.0.0": + version: 10.0.2 + resolution: "remark-parse@npm:10.0.2" + dependencies: + "@types/mdast": "npm:^3.0.0" + mdast-util-from-markdown: "npm:^1.0.0" + unified: "npm:^10.0.0" + checksum: 10c0/30cb8f2790380b1c7370a1c66cda41f33a7dc196b9e440a00e2675037bca55aea868165a8204e0cdbacc27ef4a3bdb7d45879826bd6efa07d9fdf328cb67a332 + languageName: node + linkType: hard + +"remark-reading-time@npm:^2.0.1": + version: 2.0.1 + resolution: "remark-reading-time@npm:2.0.1" + dependencies: + estree-util-is-identifier-name: "npm:^2.0.0" + estree-util-value-to-estree: "npm:^1.3.0" + reading-time: "npm:^1.3.0" + unist-util-visit: "npm:^3.1.0" + checksum: 10c0/9efab1883a326964822442af234c3e7776596267431edae42ac3717887af60a1cd145d07cb8a0329fb5e4cab92ae4b3ca9dc058ee453139aa2978dc4c56c4527 + languageName: node + linkType: hard + +"remark-rehype@npm:^10.0.0": + version: 10.1.0 + resolution: "remark-rehype@npm:10.1.0" + dependencies: + "@types/hast": "npm:^2.0.0" + "@types/mdast": "npm:^3.0.0" + mdast-util-to-hast: "npm:^12.1.0" + unified: "npm:^10.0.0" + checksum: 10c0/803e658c9b51a9b53ee2ada42ff82e8e570444bb97c873e0d602c2d8dcb69a774fd22bd6f26643dfd5ab4c181059ea6c9fb9a99a2d7f9665f3f11bef1a1489bd + languageName: node + linkType: hard + +"remove-accents@npm:0.5.0": + version: 0.5.0 + resolution: "remove-accents@npm:0.5.0" + checksum: 10c0/a75321aa1b53d9abe82637115a492770bfe42bb38ed258be748bf6795871202bc8b4badff22013494a7029f5a241057ad8d3f72adf67884dbe15a9e37e87adc4 + languageName: node + linkType: hard + +"robust-predicates@npm:^3.0.2": + version: 3.0.2 + resolution: "robust-predicates@npm:3.0.2" + checksum: 10c0/4ecd53649f1c2d49529c85518f2fa69ffb2f7a4453f7fd19c042421c7b4d76c3efb48bc1c740c8f7049346d7cb58cf08ee0c9adaae595cc23564d360adb1fde4 + languageName: node + linkType: hard + +"rw@npm:1": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: 10c0/b1e1ef37d1e79d9dc7050787866e30b6ddcb2625149276045c262c6b4d53075ddc35f387a856a8e76f0d0df59f4cd58fe24707e40797ebee66e542b840ed6a53 + languageName: node + linkType: hard + +"sade@npm:^1.7.3": + version: 1.8.1 + resolution: "sade@npm:1.8.1" + dependencies: + mri: "npm:^1.1.0" + checksum: 10c0/da8a3a5d667ad5ce3bf6d4f054bbb9f711103e5df21003c5a5c1a8a77ce12b640ed4017dd423b13c2307ea7e645adee7c2ae3afe8051b9db16a6f6d3da3f90b1 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 + languageName: node + linkType: hard + +"scroll-into-view-if-needed@npm:^3.1.0": + version: 3.1.0 + resolution: "scroll-into-view-if-needed@npm:3.1.0" + dependencies: + compute-scroll-into-view: "npm:^3.0.2" + checksum: 10c0/1f46b090e1e04fcfdef1e384f6d7e615f9f84d4176faf4dbba7347cc0a6e491e5d578eaf4dbe9618dd3d8d38efafde58535b3e00f2a21ce4178c14be364850ff + languageName: node + linkType: hard + +"section-matter@npm:^1.0.0": + version: 1.0.0 + resolution: "section-matter@npm:1.0.0" + dependencies: + extend-shallow: "npm:^2.0.1" + kind-of: "npm:^6.0.0" + checksum: 10c0/8007f91780adc5aaa781a848eaae50b0f680bbf4043b90cf8a96778195b8fab690c87fe7a989e02394ce69890e330811ec8dab22397d384673ce59f7d750641d + languageName: node + linkType: hard + +"semver@npm:^7.6.3": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + languageName: node + linkType: hard + +"sharp@npm:^0.33.5": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.33.5" + "@img/sharp-darwin-x64": "npm:0.33.5" + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + "@img/sharp-linux-arm": "npm:0.33.5" + "@img/sharp-linux-arm64": "npm:0.33.5" + "@img/sharp-linux-s390x": "npm:0.33.5" + "@img/sharp-linux-x64": "npm:0.33.5" + "@img/sharp-linuxmusl-arm64": "npm:0.33.5" + "@img/sharp-linuxmusl-x64": "npm:0.33.5" + "@img/sharp-wasm32": "npm:0.33.5" + "@img/sharp-win32-ia32": "npm:0.33.5" + "@img/sharp-win32-x64": "npm:0.33.5" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.3" + semver: "npm:^7.6.3" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 + languageName: node + linkType: hard + +"shebang-command@npm:^1.2.0": + version: 1.2.0 + resolution: "shebang-command@npm:1.2.0" + dependencies: + shebang-regex: "npm:^1.0.0" + checksum: 10c0/7b20dbf04112c456b7fc258622dafd566553184ac9b6938dd30b943b065b21dabd3776460df534cc02480db5e1b6aec44700d985153a3da46e7db7f9bd21326d + languageName: node + linkType: hard + +"shebang-regex@npm:^1.0.0": + version: 1.0.0 + resolution: "shebang-regex@npm:1.0.0" + checksum: 10c0/9abc45dee35f554ae9453098a13fdc2f1730e525a5eb33c51f096cc31f6f10a4b38074c1ebf354ae7bffa7229506083844008dfc3bb7818228568c0b2dc1fff2 + languageName: node + linkType: hard + +"shiki@npm:^0.14.3": + version: 0.14.7 + resolution: "shiki@npm:0.14.7" + dependencies: + ansi-sequence-parser: "npm:^1.1.0" + jsonc-parser: "npm:^3.2.0" + vscode-oniguruma: "npm:^1.7.0" + vscode-textmate: "npm:^8.0.0" + checksum: 10c0/5c7fcbb870d0facccc7ae2f3410a28121f8e0b3f298e4e956de817ad6ab60a4c7e20a9184edfe50a93447addbb88b95b69e6ef88ac16ac6ca3e94c50771a6459 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.0": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + languageName: node + linkType: hard + +"simple-swizzle@npm:^0.2.2": + version: 0.2.2 + resolution: "simple-swizzle@npm:0.2.2" + dependencies: + is-arrayish: "npm:^0.3.1" + checksum: 10c0/df5e4662a8c750bdba69af4e8263c5d96fe4cd0f9fe4bdfa3cbdeb45d2e869dff640beaaeb1ef0e99db4d8d2ec92f85508c269f50c972174851bc1ae5bd64308 + languageName: node + linkType: hard + +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b + languageName: node + linkType: hard + +"sort-keys@npm:^5.0.0": + version: 5.0.0 + resolution: "sort-keys@npm:5.0.0" + dependencies: + is-plain-obj: "npm:^4.0.0" + checksum: 10c0/9f7abc51e184ef27327cb2e6da729c84d1c0223bdfc714b5065df3ff167f8e1bbdfaec6bbd41d87a308d9e79eba93c90534d034f5790b305dfbecf0701f3ee55 + languageName: node + linkType: hard + +"source-map-js@npm:^1.0.2": + version: 1.2.0 + resolution: "source-map-js@npm:1.2.0" + checksum: 10c0/7e5f896ac10a3a50fe2898e5009c58ff0dc102dcb056ed27a354623a0ece8954d4b2649e1a1b2b52ef2e161d26f8859c7710350930751640e71e374fe2d321a4 + languageName: node + linkType: hard + +"source-map@npm:^0.7.0": + version: 0.7.4 + resolution: "source-map@npm:0.7.4" + checksum: 10c0/dc0cf3768fe23c345ea8760487f8c97ef6fca8a73c83cd7c9bf2fde8bc2c34adb9c0824d6feb14bc4f9e37fb522e18af621543f1289038a66ac7586da29aa7dc + languageName: node + linkType: hard + +"space-separated-tokens@npm:^2.0.0": + version: 2.0.2 + resolution: "space-separated-tokens@npm:2.0.2" + checksum: 10c0/6173e1d903dca41dcab6a2deed8b4caf61bd13b6d7af8374713500570aa929ff9414ae09a0519f4f8772df993300305a395d4871f35bc4ca72b6db57e1f30af8 + languageName: node + linkType: hard + +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb + languageName: node + linkType: hard + +"streamsearch@npm:^1.1.0": + version: 1.1.0 + resolution: "streamsearch@npm:1.1.0" + checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab + languageName: node + linkType: hard + +"stringify-entities@npm:^4.0.0": + version: 4.0.4 + resolution: "stringify-entities@npm:4.0.4" + dependencies: + character-entities-html4: "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + checksum: 10c0/537c7e656354192406bdd08157d759cd615724e9d0873602d2c9b2f6a5c0a8d0b1d73a0a08677848105c5eebac6db037b57c0b3a4ec86331117fa7319ed50448 + languageName: node + linkType: hard + +"strip-bom-string@npm:^1.0.0": + version: 1.0.0 + resolution: "strip-bom-string@npm:1.0.0" + checksum: 10c0/5c5717e2643225aa6a6d659d34176ab2657037f1fe2423ac6fcdb488f135e14fef1022030e426d8b4d0989e09adbd5c3288d5d3b9c632abeefd2358dfc512bca + languageName: node + linkType: hard + +"strip-eof@npm:^1.0.0": + version: 1.0.0 + resolution: "strip-eof@npm:1.0.0" + checksum: 10c0/f336beed8622f7c1dd02f2cbd8422da9208fae81daf184f73656332899978919d5c0ca84dc6cfc49ad1fc4dd7badcde5412a063cf4e0d7f8ed95a13a63f68f45 + languageName: node + linkType: hard + +"style-to-object@npm:^0.4.1": + version: 0.4.4 + resolution: "style-to-object@npm:0.4.4" + dependencies: + inline-style-parser: "npm:0.1.1" + checksum: 10c0/3a733080da66952881175b17d65f92985cf94c1ca358a92cf21b114b1260d49b94a404ed79476047fb95698d64c7e366ca7443f0225939e2fb34c38bbc9c7639 + languageName: node + linkType: hard + +"styled-jsx@npm:5.1.6": + version: 5.1.6 + resolution: "styled-jsx@npm:5.1.6" + dependencies: + client-only: "npm:0.0.1" + peerDependencies: + react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + peerDependenciesMeta: + "@babel/core": + optional: true + babel-plugin-macros: + optional: true + checksum: 10c0/ace50e7ea5ae5ae6a3b65a50994c51fca6ae7df9c7ecfd0104c36be0b4b3a9c5c1a2374d16e2a11e256d0b20be6d47256d768ecb4f91ab390f60752a075780f5 + languageName: node + linkType: hard + +"stylis@npm:^4.1.3": + version: 4.3.2 + resolution: "stylis@npm:4.3.2" + checksum: 10c0/0410e1404cbeee3388a9e17587875211ce2f014c8379af0d1e24ca55878867c9f1ccc7b0ce9a156ca53f5d6e301391a82b0645522a604674a378b3189a4a1994 + languageName: node + linkType: hard + +"supports-color@npm:^4.0.0": + version: 4.5.0 + resolution: "supports-color@npm:4.5.0" + dependencies: + has-flag: "npm:^2.0.0" + checksum: 10c0/2dc369eeac73954e87037dea1ebae0238b2abc0a39d7e35aa60eb8a84cc8d1dcade8b62e010597f5859f94c937e992abe6a6195460855fcc5e51f8cfc7fcc72a + languageName: node + linkType: hard + +"title@npm:^3.5.3": + version: 3.5.3 + resolution: "title@npm:3.5.3" + dependencies: + arg: "npm:1.0.0" + chalk: "npm:2.3.0" + clipboardy: "npm:1.2.2" + titleize: "npm:1.0.0" + bin: + title: bin/title.js + checksum: 10c0/9334ff46f49c215a108adbb3ab39bd946dfd1a669b999ad173ff61aa7598a17718f954462d8ebf8fb3ea643b5c37f2f7a163310d186acb18a101c028248d3b15 + languageName: node + linkType: hard + +"titleize@npm:1.0.0": + version: 1.0.0 + resolution: "titleize@npm:1.0.0" + checksum: 10c0/7c542bdc5754406839fc61e1a43803cb460cb0b5472f7cecf267bd9498e72d549d7f5cdfadd72ec20c3bb0783d52f4c72fe68e104cecd84195b29a5ffe836510 + languageName: node + linkType: hard + +"trim-lines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-lines@npm:3.0.1" + checksum: 10c0/3a1611fa9e52aa56a94c69951a9ea15b8aaad760eaa26c56a65330dc8adf99cb282fc07cc9d94968b7d4d88003beba220a7278bbe2063328eb23fb56f9509e94 + languageName: node + linkType: hard + +"trough@npm:^2.0.0": + version: 2.2.0 + resolution: "trough@npm:2.2.0" + checksum: 10c0/58b671fc970e7867a48514168894396dd94e6d9d6456aca427cc299c004fe67f35ed7172a36449086b2edde10e78a71a284ec0076809add6834fb8f857ccb9b0 + languageName: node + linkType: hard + +"ts-dedent@npm:^2.2.0": + version: 2.2.0 + resolution: "ts-dedent@npm:2.2.0" + checksum: 10c0/175adea838468cc2ff7d5e97f970dcb798bbcb623f29c6088cb21aa2880d207c5784be81ab1741f56b9ac37840cbaba0c0d79f7f8b67ffe61c02634cafa5c303 + languageName: node + linkType: hard + +"tslib@npm:^2.4.0": + version: 2.6.3 + resolution: "tslib@npm:2.6.3" + checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a + languageName: node + linkType: hard + +"type-fest@npm:^1.0.2": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: 10c0/a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 + languageName: node + linkType: hard + +"typescript@npm:5.4.5": + version: 5.4.5 + resolution: "typescript@npm:5.4.5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2954022ada340fd3d6a9e2b8e534f65d57c92d5f3989a263754a78aba549f7e6529acc1921913560a4b816c46dce7df4a4d29f9f11a3dc0d4213bb76d043251e + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A5.4.5#optional!builtin": + version: 5.4.5 + resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/db2ad2a16ca829f50427eeb1da155e7a45e598eec7b086d8b4e8ba44e5a235f758e606d681c66992230d3fc3b8995865e5fd0b22a2c95486d0b3200f83072ec9 + languageName: node + linkType: hard + +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 + languageName: node + linkType: hard + +"unified@npm:^10.0.0": + version: 10.1.2 + resolution: "unified@npm:10.1.2" + dependencies: + "@types/unist": "npm:^2.0.0" + bail: "npm:^2.0.0" + extend: "npm:^3.0.0" + is-buffer: "npm:^2.0.0" + is-plain-obj: "npm:^4.0.0" + trough: "npm:^2.0.0" + vfile: "npm:^5.0.0" + checksum: 10c0/da9195e3375a74ab861a65e1d7b0454225d17a61646697911eb6b3e97de41091930ed3d167eb11881d4097c51deac407091d39ddd1ee8bf1fde3f946844a17a7 + languageName: node + linkType: hard + +"unist-util-find-after@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-find-after@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/a7cea473c4384df8de867c456b797ff1221b20f822e1af673ff5812ed505358b36f47f3b084ac14c3622cb879ed833b71b288e8aa71025352a2aab4c2925a6eb + languageName: node + linkType: hard + +"unist-util-generated@npm:^2.0.0": + version: 2.0.1 + resolution: "unist-util-generated@npm:2.0.1" + checksum: 10c0/6f052dd47a7280785f3787f52cdfe8819e1de50317a1bcf7c9346c63268cf2cebc61a5980e7ca734a54735e27dbb73091aa0361a98504ab7f9409fb75f1b16bb + languageName: node + linkType: hard + +"unist-util-is@npm:^5.0.0": + version: 5.2.1 + resolution: "unist-util-is@npm:5.2.1" + dependencies: + "@types/unist": "npm:^2.0.0" + checksum: 10c0/a2376910b832bb10653d2167c3cd85b3610a5fd53f5169834c08b3c3a720fae9043d75ad32d727eedfc611491966c26a9501d428ec62467edc17f270feb5410b + languageName: node + linkType: hard + +"unist-util-is@npm:^6.0.0": + version: 6.0.0 + resolution: "unist-util-is@npm:6.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/9419352181eaa1da35eca9490634a6df70d2217815bb5938a04af3a662c12c5607a2f1014197ec9c426fbef18834f6371bfdb6f033040fa8aa3e965300d70e7e + languageName: node + linkType: hard + +"unist-util-position-from-estree@npm:^1.0.0, unist-util-position-from-estree@npm:^1.1.0": + version: 1.1.2 + resolution: "unist-util-position-from-estree@npm:1.1.2" + dependencies: + "@types/unist": "npm:^2.0.0" + checksum: 10c0/1d95d0b2b05efcec07a4e6745a6950cd498f6100fb900615b252937baed5140df1c6319b9a67364c8a6bd891c58b3c9a52a22e8e1d3422c50bb785d7e3ad7484 + languageName: node + linkType: hard + +"unist-util-position@npm:^4.0.0": + version: 4.0.4 + resolution: "unist-util-position@npm:4.0.4" + dependencies: + "@types/unist": "npm:^2.0.0" + checksum: 10c0/e506d702e25a0fb47a64502054f709a6ff5db98993bf139eec868cd11eb7de34392b781c6c2002e2c24d97aa398c14b32a47076129f36e4b894a2c1351200888 + languageName: node + linkType: hard + +"unist-util-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-position@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dde3b31e314c98f12b4dc6402f9722b2bf35e96a4f2d463233dd90d7cde2d4928074a7a11eff0a5eb1f4e200f27fc1557e0a64a7e8e4da6558542f251b1b7400 + languageName: node + linkType: hard + +"unist-util-remove-position@npm:^4.0.0": + version: 4.0.2 + resolution: "unist-util-remove-position@npm:4.0.2" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-visit: "npm:^4.0.0" + checksum: 10c0/17371b1e53c52d1b00656c9c6fe1bb044846e7067022195823ed3d1a8d8b965d4f9a79b286b8a841e68731b4ec93afd563b81ae92151f80c28534ba51e9dc18f + languageName: node + linkType: hard + +"unist-util-remove-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-remove-position@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/e8c76da4399446b3da2d1c84a97c607b37d03d1d92561e14838cbe4fdcb485bfc06c06cfadbb808ccb72105a80643976d0660d1fe222ca372203075be9d71105 + languageName: node + linkType: hard + +"unist-util-remove@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-remove@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/30f3ed31095dd7f3109266d39c514fab5f2da3fb656d5f78a0e3e7700f219760f2f4d8286c810ae43c241fee3f0a8dd40f8d1e5ebeee3cb810581d5e7e8d4f7d + languageName: node + linkType: hard + +"unist-util-stringify-position@npm:^3.0.0": + version: 3.0.3 + resolution: "unist-util-stringify-position@npm:3.0.3" + dependencies: + "@types/unist": "npm:^2.0.0" + checksum: 10c0/14550027825230528f6437dad7f2579a841780318569851291be6c8a970bae6f65a7feb24dabbcfce0e5e68cacae85bf12cbda3f360f7c873b4db602bdf7bb21 + languageName: node + linkType: hard + +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dfe1dbe79ba31f589108cb35e523f14029b6675d741a79dea7e5f3d098785045d556d5650ec6a8338af11e9e78d2a30df12b1ee86529cded1098da3f17ee999e + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^4.0.0": + version: 4.1.1 + resolution: "unist-util-visit-parents@npm:4.1.1" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + checksum: 10c0/f84b544a111af5a17f2b80c462da9f7fdcb46a69f85ab317d2d9ddca766c00e2ceea6c76c0960e58ef4607aad89661c99eccf290973b453e15dd1621c57079d4 + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^5.0.0, unist-util-visit-parents@npm:^5.1.1": + version: 5.1.3 + resolution: "unist-util-visit-parents@npm:5.1.3" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + checksum: 10c0/f6829bfd8f2eddf63a32e2c302cd50978ef0c194b792c6fe60c2b71dfd7232415a3c5941903972543e9d34e6a8ea69dee9ccd95811f4a795495ed2ae855d28d0 + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-visit-parents@npm:6.0.1" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/51b1a5b0aa23c97d3e03e7288f0cdf136974df2217d0999d3de573c05001ef04cccd246f51d2ebdfb9e8b0ed2704451ad90ba85ae3f3177cf9772cef67f56206 + languageName: node + linkType: hard + +"unist-util-visit@npm:^3.1.0": + version: 3.1.0 + resolution: "unist-util-visit@npm:3.1.0" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + unist-util-visit-parents: "npm:^4.0.0" + checksum: 10c0/9b92ea4e6debadbb77f2c7a0ab8c8b7c63781b2f2050563c971687df368f6f6fe932d864442347a685f0dc56b570a55e5d7ffeb87a452489100640cf280dc8da + languageName: node + linkType: hard + +"unist-util-visit@npm:^4.0.0": + version: 4.1.2 + resolution: "unist-util-visit@npm:4.1.2" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-is: "npm:^5.0.0" + unist-util-visit-parents: "npm:^5.1.1" + checksum: 10c0/56a1f49a4d8e321e75b3c7821d540a45165a031dd06324bb0e8c75e7737bc8d73bdddbf0b0ca82000f9708a4c36861c6ebe88d01f7cf00e925f5d75f13a3a017 + languageName: node + linkType: hard + +"unist-util-visit@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-visit@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/51434a1d80252c1540cce6271a90fd1a106dbe624997c09ed8879279667fb0b2d3a685e02e92bf66598dcbe6cdffa7a5f5fb363af8fdf90dda6c855449ae39a5 + languageName: node + linkType: hard + +"unstoppableswap-docs@workspace:.": + version: 0.0.0-use.local + resolution: "unstoppableswap-docs@workspace:." + dependencies: + "@types/node": "npm:20.14.5" + next: "npm:^15.0.3" + nextra: "npm:^2.13.4" + nextra-theme-docs: "npm:^2.13.4" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + typescript: "npm:5.4.5" + languageName: unknown + linkType: soft + +"uuid@npm:^9.0.0": + version: 9.0.1 + resolution: "uuid@npm:9.0.1" + bin: + uuid: dist/bin/uuid + checksum: 10c0/1607dd32ac7fc22f2d8f77051e6a64845c9bce5cd3dd8aa0070c074ec73e666a1f63c7b4e0f4bf2bc8b9d59dc85a15e17807446d9d2b17c8485fbc2147b27f9b + languageName: node + linkType: hard + +"uvu@npm:^0.5.0": + version: 0.5.6 + resolution: "uvu@npm:0.5.6" + dependencies: + dequal: "npm:^2.0.0" + diff: "npm:^5.0.0" + kleur: "npm:^4.0.3" + sade: "npm:^1.7.3" + bin: + uvu: bin.js + checksum: 10c0/ad32eb5f7d94bdeb71f80d073003f0138e24f61ed68cecc8e15d2f30838f44c9670577bb1775c8fac894bf93d1bc1583d470a9195e49bfa6efa14cc6f4942bff + languageName: node + linkType: hard + +"vfile-location@npm:^5.0.0": + version: 5.0.2 + resolution: "vfile-location@npm:5.0.2" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/cfc7e49de93ac5be6f3c9a9fe77676756e00d33a6c69d9c1ce279b06eedafa67fe5d0da2334b40e97963c43b014501bca2f829dfd6622a3290fb6f7dd2b9339e + languageName: node + linkType: hard + +"vfile-matter@npm:^3.0.1": + version: 3.0.1 + resolution: "vfile-matter@npm:3.0.1" + dependencies: + "@types/js-yaml": "npm:^4.0.0" + is-buffer: "npm:^2.0.0" + js-yaml: "npm:^4.0.0" + checksum: 10c0/45ff9b49e7a5817b646d76f14d2486e12a93a16951bd8cfa6c64f0c78c4e56e48d30a0542a980bc9c7aae1bb430d457f9dfc2677e514d66cc2976ab31f10403a + languageName: node + linkType: hard + +"vfile-message@npm:^3.0.0": + version: 3.1.4 + resolution: "vfile-message@npm:3.1.4" + dependencies: + "@types/unist": "npm:^2.0.0" + unist-util-stringify-position: "npm:^3.0.0" + checksum: 10c0/c4ccf9c0ced92d657846fd067fefcf91c5832cdbe2ecc431bb67886e8c959bf7fc05a9dbbca5551bc34c9c87a0a73854b4249f65c64ddfebc4d59ea24a18b996 + languageName: node + linkType: hard + +"vfile-message@npm:^4.0.0": + version: 4.0.2 + resolution: "vfile-message@npm:4.0.2" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/07671d239a075f888b78f318bc1d54de02799db4e9dce322474e67c35d75ac4a5ac0aaf37b18801d91c9f8152974ea39678aa72d7198758b07f3ba04fb7d7514 + languageName: node + linkType: hard + +"vfile@npm:^5.0.0, vfile@npm:^5.3.0": + version: 5.3.7 + resolution: "vfile@npm:5.3.7" + dependencies: + "@types/unist": "npm:^2.0.0" + is-buffer: "npm:^2.0.0" + unist-util-stringify-position: "npm:^3.0.0" + vfile-message: "npm:^3.0.0" + checksum: 10c0/c36bd4c3f16ec0c6cbad0711ca99200316bbf849d6b07aa4cb5d9062cc18ae89249fe62af9521926e9659c0e6bc5c2c1da0fe26b41fb71e757438297e1a41da4 + languageName: node + linkType: hard + +"vfile@npm:^6.0.0": + version: 6.0.1 + resolution: "vfile@npm:6.0.1" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-stringify-position: "npm:^4.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/443bda43e5ad3b73c5976e987dba2b2d761439867ba7d5d7c5f4b01d3c1cb1b976f5f0e6b2399a00dc9b4eaec611bd9984ce9ce8a75a72e60aed518b10a902d2 + languageName: node + linkType: hard + +"vscode-oniguruma@npm:^1.7.0": + version: 1.7.0 + resolution: "vscode-oniguruma@npm:1.7.0" + checksum: 10c0/bef0073c665ddf8c86e51da94529c905856559e9aba97a9882f951acd572da560384775941ab6e7e8db94d9c578b25fefb951e4b73c37e8712e16b0231de2689 + languageName: node + linkType: hard + +"vscode-textmate@npm:^8.0.0": + version: 8.0.0 + resolution: "vscode-textmate@npm:8.0.0" + checksum: 10c0/836f7fe73fc94998a38ca193df48173a2b6eab08b4943d83c8cac9a2a0c3546cfdab4cf1b10b890ec4a4374c5bee03a885ef0e83e7fd2bd618cf00781c017c04 + languageName: node + linkType: hard + +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: 10c0/df245f466ad83bd5cd80bfffc1674c7f64b7b84d1de0e4d2c0934fb0782e0a599164e7197a4bce310ee3342fd61817b8047ff04f076a1ce12dd470584142a4bd + languageName: node + linkType: hard + +"web-worker@npm:^1.2.0": + version: 1.3.0 + resolution: "web-worker@npm:1.3.0" + checksum: 10c0/bca341b421f07c2d33aa205d463e6a2d3d376fb0628a01052dc343fd88a1d688df58d1c7fe36f631d0d860bbd3060f5014cca67d6f8781634b6c2fae25d1fc70 + languageName: node + linkType: hard + +"which@npm:^1.2.9": + version: 1.3.1 + resolution: "which@npm:1.3.1" + dependencies: + isexe: "npm:^2.0.0" + bin: + which: ./bin/which + checksum: 10c0/e945a8b6bbf6821aaaef7f6e0c309d4b615ef35699576d5489b4261da9539f70393c6b2ce700ee4321c18f914ebe5644bc4631b15466ffbaad37d83151f6af59 + languageName: node + linkType: hard + +"yallist@npm:^2.1.2": + version: 2.1.2 + resolution: "yallist@npm:2.1.2" + checksum: 10c0/0b9e25aa00adf19e01d2bcd4b208aee2b0db643d9927131797b7af5ff69480fc80f1c3db738cbf3946f0bddf39d8f2d0a5709c644fd42d4aa3a4e6e786c087b5 + languageName: node + linkType: hard + +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f + languageName: node + linkType: hard + +"zod@npm:^3.22.3": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 + languageName: node + linkType: hard + +"zwitch@npm:^2.0.0": + version: 2.0.4 + resolution: "zwitch@npm:2.0.4" + checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e + languageName: node + linkType: hard From c1c1619922501a406d4a8f100003d1d3a37a0fcf Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 17:48:54 +0100 Subject: [PATCH 132/146] docs: update primary color to match new website --- docs/theme.config.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx index a7dffb2a14..4bd7ffe6a0 100644 --- a/docs/theme.config.jsx +++ b/docs/theme.config.jsx @@ -16,6 +16,6 @@ export default { ), - primaryHue: 14.3, - primarySaturation: 90.68, + primaryHue: 38, + primarySaturation: 100, }; From a10f254d574534b1d9bf6ab31199044b394835a1 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 18:31:19 +0100 Subject: [PATCH 133/146] docs: remove sidebar pointing to nextra repo --- docs/theme.config.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx index 4bd7ffe6a0..0e0c0821f4 100644 --- a/docs/theme.config.jsx +++ b/docs/theme.config.jsx @@ -18,4 +18,10 @@ export default { ), primaryHue: 38, primarySaturation: 100, + feedback: { + content: null, + }, + editLink: { + component: null, + }, }; From d067187c5a3e2e5918d375cb12e1978be7902b70 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 18:31:36 +0100 Subject: [PATCH 134/146] docs: rephrase feedback section to explicitly mention support --- docs/pages/_meta.json | 2 +- docs/pages/send_feedback.mdx | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/pages/_meta.json b/docs/pages/_meta.json index 6995521d0f..521a18e107 100644 --- a/docs/pages/_meta.json +++ b/docs/pages/_meta.json @@ -4,6 +4,6 @@ "usage": "Usage", "advanced": "Advanced", "becoming_a_maker": "Becoming a Maker", - "send_feedback": "Send Feedback", + "send_feedback": "Support / Feedback", "donate": "Donate" } diff --git a/docs/pages/send_feedback.mdx b/docs/pages/send_feedback.mdx index 4a20808410..87439b77e6 100644 --- a/docs/pages/send_feedback.mdx +++ b/docs/pages/send_feedback.mdx @@ -1,8 +1,11 @@ import Image from 'next/image' -# Send Feedback +# Feedback and Support -We value your feedback and are committed to providing the best support possible. There are two ways to send feedback: + +We are an open source project, so you can help by contributing feedback and suggestions! + +You can also reach us on a variety of channels to get support directly from the developers. ## In-App Feedback @@ -15,7 +18,6 @@ The easiest way to send feedback is through the app: - Select the relevant swap from the dropdown menu - Check "Attach logs from the current session" - Review the logs before sending (you can click the eye icon to view them) - - Use the redaction option if you want to remove sensitive information Your feedback will be answered directly in the app under the Feedback tab. @@ -26,7 +28,11 @@ If you prefer to send an email, please include: 1. A clear description of your issue or feedback 2. Swap logs you want to share or encountered problems with (You can use the "Export Logs" functionality in the history tab) -Send your email to: [help@unstoppableswap.net](mailto:help@unstoppableswap.net) +Send your email to: [help@unstoppableswap.net](mailto:help@unstoppableswap.net) (this is our email address from before the rename). + +## Discord and Matrix + +You can also ask for help on our [Discord](https://eigenwallet.org/discord) and [Matrix](https://eigenwallet.org/matrix) servers. They are bridged. ## Tips for Effective Feedback @@ -39,7 +45,7 @@ To help us assist you better: ## What to Expect -- We try to answer within 24 hours, but please be patient if you don't receive a message directly. -- You can continue the conversation through the app or email +- We try to answer as quickly as possible, but please be patient if this takes up to a few days. + We are an open source project and do the support in our free time. - We may ask for additional information to help resolve your issue From edd1792df9b85f31bf2611319f8503c1aa4b5662 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 18:32:09 +0100 Subject: [PATCH 135/146] docs: update install instructions, make release independant --- .../getting_started/install_instructions.mdx | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/docs/pages/getting_started/install_instructions.mdx b/docs/pages/getting_started/install_instructions.mdx index 32eacebf6d..553c90e8cc 100644 --- a/docs/pages/getting_started/install_instructions.mdx +++ b/docs/pages/getting_started/install_instructions.mdx @@ -1,4 +1,4 @@ -import { Tabs } from 'nextra/components' +import { Tabs, Callout } from 'nextra/components' # Installation @@ -11,57 +11,73 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl - 1. Download the latest release from GitHub [here](https://github.com/eigenwallet/core/releases/download/1.0.0-rc.4/UnstoppableSwap_1.0.0-rc.4_x64-setup.exe) + 1. Download the latest release from our [download page](https://eigenwallet.org/download/) 2. Open the downloaded `.exe` installer - 3. Follow the installation instructions - 4. Open the `UnstoppableSwap` application from your Start menu + 3. Follow the installation wizard + 4. Open the `eigenwallet` application from your Start menu - 1. Download the latest release from GitHub [here](https://github.com/eigenwallet/core/releases/download/1.0.0-rc.4/UnstoppableSwap_1.0.0-rc.4_aarch64.dmg) + 1. Download the latest release from our [download page](https://eigenwallet.org/download/) 2. Open the downloaded `.dmg` file - 3. Drag the `UnstoppableSwap` icon to your Applications folder - 4. Open the `UnstoppableSwap` application from your Applications folder + 3. Drag the `eigenwallet` icon to your Applications folder + 4. Open the `eigenwallet` application from your Applications folder - 1. Download the latest release from GitHub [here](https://github.com/eigenwallet/core/releases/download/1.0.0-rc.4/UnstoppableSwap_1.0.0-rc.4_x64.dmg) + 1. Download the latest release from our [download page](https://eigenwallet.org/download/) 2. Open the downloaded `.dmg` file - 3. Drag the `UnstoppableSwap` icon to your Applications folder - 4. Open the `UnstoppableSwap` application from your Applications folder + 3. Drag the `eigenwallet` icon to your Applications folder + 4. Open the `eigenwallet` application from your Applications folder - For other Linux distributions, you can download the AppImage and run it directly. It includes all dependencies and will work on most systems. - - ```bash filename="install.sh" - wget https://github.com/eigenwallet/core/releases/download/1.0.0-rc.4/UnstoppableSwap_1.0.0-rc.4_amd64.AppImage - chmod +x UnstoppableSwap_1.0.0-rc.4_amd64.AppImage - ./UnstoppableSwap_1.0.0-rc.4_amd64.AppImage + + The AppImage might not work on less new distributions (older than Ubuntu 24) due to an upstream bug. Try the Flatpak instead. + + + For newer Linux distributions, you can download the AppImage and run it directly. It includes all dependencies. + Simply download the latest release from our [download page](https://eigenwallet.org/download/) and execute it. + + Alternatively you can download it from your terminal: + + ```bash filename="install.sh" copy + # Find the latest AppImage file + EIGENWALLET_APPIMAGE=$(curl -s https://api.github.com/repos/eigenwallet/core/releases/latest | grep -o 'https://[^"]*\.AppImage' | head -1 | xargs basename) + # Download the lastest file + wget https://github.com/eigenwallet/core/releases/latest/download/$EIGENWALLET_APPIMAGE + # Make it executable + chmod +x $EIGENWALLET_APPIMAGE + # Start eigenwallet + ./$EIGENWALLET_APPIMAGE ``` - Due to limitations with our CI pipeline, we currently can't provide precompiled binaries for arm64 linux systems. + + Due to limitations with our CI pipeline, we currently can't provide precompiled binaries for arm64 linux systems. + - For Linux systems with Flatpak support, you can install UnstoppableSwap directly from our Flatpak repository: - - ```bash filename="install.sh" - # Add the eigenwallet repository - flatpak remote-add --user unstoppableswap https://unstoppableswap.github.io/core/unstoppableswap.flatpakrepo + For Linux systems with Flatpak support (version 1.0 or newer), you can install eigenwallet directly from our Flatpak repository: + + ```bash filename="install.sh" copy + # Add eigenwallet repo + flatpak remote-add --if-not-exists eigenwallet https://eigenwallet.github.io/core/eigenwallet.flatpakrepo + # Add dependencies + flatpak install flathub org.gnome.Platform//47 + # Install eigenwallet + flatpak install eigenwallet org.eigenwallet.app + ``` - # Install the application - flatpak install unstoppableswap net.unstoppableswap.gui + ## Run - # Run the application - flatpak run net.unstoppableswap.gui + ```bash filename="run.sh" copy + flatpak run org.eigenwallet.app ``` - **Requirements:** - - Flatpak 1.0 or newer - - x86_64 architecture + ## Update - **Updates:** - ```bash - flatpak update net.unstoppableswap.gui + ```bash filename="update.sh" copy + flatpak update org.eigenwallet.app ``` + From 33d66c358b5fecc47a50e582fe5339066eaa7258 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 19:09:13 +0100 Subject: [PATCH 136/146] docs: migrate to nextra v4 --- docs/.yarn/install-state.gz | Bin 349039 -> 464866 bytes docs/app/[[...mdxPath]]/page.tsx | 28 + docs/app/layout.tsx | 46 + docs/components/SwapProviderTable.tsx | 39 +- docs/content/_meta.ts | 9 + docs/content/advanced/_meta.ts | 3 + .../advanced/swap_on_testnet.mdx | 22 +- docs/content/becoming_a_maker/_meta.ts | 3 + .../becoming_a_maker/overview.mdx | 0 docs/{pages => content}/donate.mdx | 0 docs/content/getting_started/_meta.ts | 4 + .../getting_started/install_instructions.mdx | 28 +- .../verify_tauri_signature.mdx | 0 docs/{pages => content}/index.mdx | 0 docs/{pages => content}/send_feedback.mdx | 0 docs/content/usage/_meta.ts | 5 + docs/{pages => content}/usage/first_swap.mdx | 0 .../usage/market_maker_discovery.mdx | 0 .../usage/refund_punish.mdx | 0 docs/mdx-components.tsx | 8 + docs/next-env.d.ts | 2 +- docs/next.config.js | 11 - docs/next.config.mjs | 7 + docs/package.json | 9 +- docs/pages/_meta.json | 9 - docs/pages/advanced/_meta.json | 3 - docs/pages/becoming_a_maker/_meta.json | 3 - docs/pages/getting_started/_meta.json | 4 - docs/pages/usage/_meta.json | 5 - docs/theme.config.jsx | 27 - docs/tsconfig.json | 26 +- docs/yarn.lock | 4190 +++++++++++------ 32 files changed, 2830 insertions(+), 1661 deletions(-) create mode 100644 docs/app/[[...mdxPath]]/page.tsx create mode 100644 docs/app/layout.tsx create mode 100644 docs/content/_meta.ts create mode 100644 docs/content/advanced/_meta.ts rename docs/{pages => content}/advanced/swap_on_testnet.mdx (91%) create mode 100644 docs/content/becoming_a_maker/_meta.ts rename docs/{pages => content}/becoming_a_maker/overview.mdx (100%) rename docs/{pages => content}/donate.mdx (100%) create mode 100644 docs/content/getting_started/_meta.ts rename docs/{pages => content}/getting_started/install_instructions.mdx (79%) rename docs/{pages => content}/getting_started/verify_tauri_signature.mdx (100%) rename docs/{pages => content}/index.mdx (100%) rename docs/{pages => content}/send_feedback.mdx (100%) create mode 100644 docs/content/usage/_meta.ts rename docs/{pages => content}/usage/first_swap.mdx (100%) rename docs/{pages => content}/usage/market_maker_discovery.mdx (100%) rename docs/{pages => content}/usage/refund_punish.mdx (100%) create mode 100644 docs/mdx-components.tsx delete mode 100644 docs/next.config.js create mode 100644 docs/next.config.mjs delete mode 100644 docs/pages/_meta.json delete mode 100644 docs/pages/advanced/_meta.json delete mode 100644 docs/pages/becoming_a_maker/_meta.json delete mode 100644 docs/pages/getting_started/_meta.json delete mode 100644 docs/pages/usage/_meta.json delete mode 100644 docs/theme.config.jsx diff --git a/docs/.yarn/install-state.gz b/docs/.yarn/install-state.gz index 02b8c1549fc96ebd7a6af563344325dbf2631085..bb32762de24170741a5b1be06659df5aeeaedf5d 100644 GIT binary patch delta 446271 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¬aO9!2S@+=w=DzywHHFoMd$&T*IS0BQxL>M^x{*` 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­t{lOaHQaWvgq&ShFmyt~cbCBo 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

    +5XHlV|N$?vgq$e_pr;hADm4;PRU= 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%0ALn-G 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


    u`8(!(!Mj9AcoO+63P2 zhKbgg9NgjAb!&3}iOGHU{Qk>dUbpVkckjR4>XCf#NZy;_M>}u5nPDmvF#a3oep54h z0F&ro*2auNmvKd9MsXv0<(y0SNDYq*ec}+yiOMoK*tk>wgpF4W3oDM|?N}HqYuPA& z4~rm;Hq!7BW4*%l%)B+j|9qX{AHICLg_j>al=r6i(VpSggA8R+F$h6N1tBXCF}WwB z56c3tmJ3}pLvzGYygNcjh=p2zy3%|=*tF3HUb!8e78eM*0Z?A4V$-uJM50xIwT7ki zA0G{cz;kUHZf@d#{CSH1a(4?qdK~Y6&F`a4HQzK(;)NOzSE*%lu4<^Bo|M^or5$ck zrkE}AM*3B1$gSv(_`;ZCK+X*e?z(^#LM(KyA6rb%IivFhyc`SRQ7G03-_jDYkw>Jk zx!%se|LNEBduIbbdLZvYEOcM-Fwc5vK(L$IfU0CwOOMmeCHT3y2E}i{BTi3$UsTYr zSLKq%wN%%l5_CE0Xt)J7?=laO@l!ynP!W})5Dw5vakx{{&%be3xb{(s+Y72Bj`y0f zCz9DAV+y4?rEkrMGElm&5T)P>scaOfa`Bmc(-MezSdq)B%txvg*HE$q z0t&1}nDcndQ|-8sPhXtDb~Fa&LQ%a=*HP+9L-ZjQD6lY7TE4utJ7ph{!W?)r_EEJ) zsE*>S0sj;c6h($kLg?=99)6wTzx*#I_|YDk_i)wU2FJIo@zVv(a;Qh+h zff~oxIYo(t1|V$%M@gXJN+$Gzl(lfTV!slG@rd^-9H7C=Q;A>mn7G;q4k`p`+@hz- zR#09ECQZs`wF86O3P79}m2J6JRdRClbNH$UZRUDbg^qe`F0l=N^|FAGcPqjmTB)M6 zN|~PfT7_86V@_2eEh?bx*pMwk>V+)pPIC=%WNT)S%(`(U#67fu*PWJHi-A;8j*DWs;C0`Q-8U2p#11@`_&$`e@x$+ zK)f)>*wHEDpjal%sN75oc%Dtx#I; zN`RUZ3X?2W>JpW3^lt`jUq1u~t7xE* zp!my1eby^~4KLA-Hk7$U4$)Ev3BhTx?QAIjwxTuBH`*WgrtP))X`*h$FL5azPZZf< za(At!`Mc5HKY#hOgpF?s06lv2zD?>seiepSHZ{f&`oE$kQFkPAv=%Tj6`P=2LY%QA zPS9}NT2!r6L3?p4g+5feoycL-(h2F?;f`^(~Y!q!3%ZYf0|+=E&G zC0=b)+wbXEzuxo-7@X!C&4WlPW(Si^lmf-6Eg{s5LLDj{wa{S)O`tsaWLag;U@1JO zUqU<6qSvf{qAOG+IXdCP!aGTmFesXHb&KaVpS8JLcvG(W??1eJ`aC|}^!|PD!2K%t zmOqAnZ>6f*(PDK|>8mV@X?^C(v&5yeV{8pHA=;yM7Cdg98d#Bsf%bV7T!$Ut`i&lr zey&Va@IYPMW?AKrHWf+4en8vDh4XQmow<7 z9pUYq@G>u`0!2?u+x_!Fy#=6Od`GpeFJ?27MJxXB+yRI zq2}rNUON}l9UcSD?^2J5pXh(WEYsum)KS0VQoM|^4R#7B9VRXoeT-{GjdA7@tj#Nb zbEV{Ev78l~g7|kDNUY5=DuQLHh|$`TQ3vf7nQg@}D$I&Qlqq9OBm64@I5pmg2^En* z)Cv1mxNQ^JkBYLAhO{b%S^C^o4yQ&r2!CDc$v=Jmw|8qk{p(Hf;YW|%#mh`7^|iV} z3&P=$ES5D)UP%D4w&6MFA!Vebwyq7cvCfLaI8Ga3dO>5Y#Qb&y9QviH=Z9eRLk!n~JEJB0u2RptNA(~v0=-;$^(Cy`a5=F?j z-MPPSpKkS2K6>o#^|afdPo1XugzkaHr36Q}#j3L*Zp>cMo)_%0UXOf4Sttk=2(z{( zL;wmJj=2@>1AH}|08Vy7I|*)mJjjhQo$$aORD5v`u%QxUiYt+sb?T9)!sHOAac=7i zh2^^@aZ)Rl?b@_Jcle(b&Fp)B<6vI~hO3S%kgh2j*dG~`02GxoO^F&jK`*3h(ODXf zj%cW1RF2(j0j;3zuaXmgU^c(@K;P7Jdi3!9dRpsG)5=|mh}96^o9HEYMKaNaskLCU zNSw%YpCas39W@G{)6oyW-cW>E@L>3YkJq_)q`LdaZfD`}fh$$i(8i`aqwBS0Kh^`UK&EtQ5!utA?CzJH}Mzx#1N-)#7J^swD4NbP1oG*3}GpkZIObdWuZV%i36qWL5EhoAM>!QeBR5BcLF-@=d zN4KLN(91ESGF(4d{VjHK$xRSY>G?XHB$V0F_(2o|(_G4_sYgP60n2giRT3ZlKB#dB z_imb^tw+?#Yg_2Gi2pW3N>|Ht9@;3*$KZ*{7>$ZTWfW*>hHFiK+c;$xIn=g)z!&rDYN0 zR}^+WA0JNCCR-MKq>NL`9YRejoR%e$Hr9aUw8r)%zYimS;NsC+cj6OMxy0&iA^#H* zvZVz$-dv{(saI_*eQ8Zr@gkW@dfK0O0EI5n$)%{$VK9A%Q+TO)IW4D}MlTl9>oF1C z+J2>?L}^@CIu?O-0>M*{BmhDcYetwv3?oKTZ?DcF@qNvtpI*Lv9P8JEb_wStnlb zad9wBzl9O3IX6n8{5~VlS-sGT9#HrjOU01&j!2Tdaa%vufua~xU(SHrLC~Jn8jgBL z3~%SCrk$g>{n{W*V@tBc+#=LjC=nNhwWyyBZCl}g3G7yr%bp^8PEWP3L@C*)f>nAK zW1%(C|Ev=8YtZ|DhkDT;sI>n3nTatCZ5Nc5EMqclnx6#Sf9x z5}^@)pjo|Hr!~*vZ_GyPwMLX!cHzJ6j3_`4gqsc(_9q97Cxa78&0f$=q}>Waa}VM+q-Us&IR{s3G_lOOF!Yj zY*`C3dra9d84-9_)=(C@%9xt0VK-PhIwX%2Lgzpz6n{1!EJ;=1H({5ag5Dl81WrXU zo$J_GyGRqA_O*zk$UT$26TXv%hH#O_xz^9%MZ`vFoyPDK?6A5jMf3TL?nmR2zPv zzq}*u*cE+M#z%?$h&YHp<2+!uL8%iZ_EfB*htPhGS+TKZ!P3=GAJUgvRQ7Uz@>-fA z6n%3-F*tP!2wsbbg=HNRrw~NTWb@j61M-o*V4_BSo3y&Zs2P6ov4S0FOo)i?rI|%g zM>%#YH0p5{7vFF~Poh=0)gS{*LP0o53nTZe?Q1i~2f560JHH;mu3K^V!Gm`%ztS2Y zFsGe8I>m9bYAtN+7S})}p<^w7s$4B*J>XxiXRb7JQ!J@5;U`@c<+Qla*iC}@r_ND( zY>y6F&l6jp)fNJ?wN{IR-WaroD%4(23OV8?=qmrvE)~637Sbzb@x3hsc#B^IH?;7w z21n@=Qxa6BE#e+MZqxHhoS4?!8pjzNyf99YUn^x&wO z05^maj(ZxtHGsn24c=(@o>SJRAmol3s}Nk((#2V1>VYR(%37LlXse~INK8O`Dzzl^ zOPz4kW~<6Zt?Ivm3l+1wWKWMi7(Hr%kV~QD|`-NGBE1iX{#t-jla-=w#~V(l=;pcGnQc zs*yM@{3NiYokAEbh`uc0 zs*PuS5h?8iGa6j5qA7VUWF-;;i}{q3my`g-T)^oqjJB%tU{OFOq>mb>DoLUdoHp~b_9L(Z)vnptT+?}{Tp%8KnMEd&S;U(?@q@6#hk1e<(Y3YT~VO^>OLuV1q(5>~u{R z%#6zld!yZ`wRII2`K$KvyIXbN4<58j>C(5k^r)zc>(SzbTdJbpj9gHOJEwqwIl(Gz zMYfiM5l6PT=0$yO4}PI&z4Fdl`&{!T4sJRkmSS~(A|Bor0Yo7ejtLZ~ViG}JzKD^c zsFe2gR!+2q!+wCFkC>!K@D48)UNN5~cL{T+fX+*Ei$)_U=!&iXk36Y`>aK_ecLN_Ij*| z*J8DQnv?|~DS{VJoRnTDaYtMS#^CWcKZx4s0-vH&T1peSC3rX$=FYV>E?d`UqIdI%1S846I0hG;g2r#LT6t1qg(skPpN zVlD*M;@PV$VJIj}2mp%*a7i6C%p#FV4=+$kb3ZaM6#Pw!dE@P4h$MtDyGOj!DROLsyxsW}CCZaR&^p+2S;JMu2VXw=!I zi~{o1IC{1$Ln9oWO| zH*V?w?dR&2E%f{J{pTMzka+pw<>QC%pKrC;JbFCu9t#VaDD?p4IN#a`vIlYB>9srj z=>u|9Rf#PgTXKQLS)HmMA?K zVZ2#@oy{MyEzvCB6-gZZorzOxuNV|wo5_6`*QSi$ire<1hwW}icH*~!&$wHA8u}Id zL$%&ejbQ{_c;-xp%Px$Apm;acDc&QYKRDs0J|isg4dr)CEel?Mj{dcjS2WA4fn7!t z%43~c?Jd~3Jx)ON3Wn(bJla*L2_&uc>aFk-0yoNI^ez;-WU|l>CqxQj3wvusyo4{X zjWiVIQ(PFRknon$Oh30nvw*W&1$n3KuqkHa%Cm}KI>gy<&AzH7{%w2z>G|mt2j4n2 zeDvVm)m_tKW(^2`Rf_nEv!nKe)dm4<)xD84O$c`fBv%Gau( zN#7`9!S^}j(!O^N75ZXOV^t2bHut*5P%;uDcFA&zf`kEor>urE9*q$$j!INmdzqT{ zp%+xWYL#}4H5Lrm(@%J#GeL;=dg+=t4IGPhBBLFo4K^BHPn47-L{!j;OqyzqrUGxA zH0lo}}drR9E!slrkJ` zuvV$T6ZfYVNqg+r#A&rjgxx9@R5jqahER#`2E%KprRcNm3T!3OIgM0{-avdsh{k1wk$t*`!ZFPrdT~Pb zyKcRIThkb>lYj(LqDI2iH%_4)A29J2k3Dv2M+&{$UdlQKMD4UI4)I)qS@%)TwX_(J zyg@~R`rzY>QZ$zhGC{+GKEBN(GcXm=CqAJCv$Hxn!!^qecm#As{_7p=*{qt<_dl+W zxA5?zhwmDU>$js}&q*Vuvt=XSR*;bKNW&?A8*m~p70)V#Dag+?)EhCHZk5MmGrO?b>3D>oCbJ5mPCd5$V zv@4<{dY#eU6%Ms&>>LO4pg5iM*(NW4?Lv{2T?^-TNSbj-?zwvH6#QwPho0OhZf)=M zr@VwtJw_gs8dyAhccDUfD*h!38mz)G_pm-_c#{b1n^x98J-?q%FZ-rP-D3yt?IpVV zTHQ}ykuW9RvjWvUZ{=aG_4+AUpu;2y4^$+r!q(pCT;q;J9dg&0U@M$Nth88vp>0a* z#{|8c69NxBKi=ZN!-&{^R*Ec|wH_3r(se?2!9!7rs3yTvb9^f7=mH;t#Hb5z(GvWW z3lgCQ@yLqjiV%n3N3VEXXb_UOjw@!t%aM^@*XrP)qpgf33fet(B|S*g+=qo0o!Dhr z*Hfpz|K{NEL;HMN^W)Lucdx>KUth8|Iv^Zws9GJEC3qxaa)!!NbRB(&qi=&SzW2iG ziY(d#ZdRxi>XDXGlH?+OC#mY+1VyV-!O)0~ku(#c6nYN~vJ1z80zf7cYp$nE9H&ik zQWfeImRQJ&O1T=*@?x{_?|DqH~MkJa`1}&g_hlhBF!_!$^g$ zBhaQ61K#sR&C@mpyMBCX11*39m=f#eaNK(*;QRzPtdf(UUobTJGr~R(ooY4o5 z+`SWFHgwjv^I90L;-x$I|6=FSBNsF9H7#I}fNG2q$Dpcm(g^(+B9zVJpNe1kl!_LTr5!b`&UX4&a*gGCU9wyK1! zaT5qe$X^kao0t_$&`4tcia>bVo#L0aQ&(2PjAu|Vrv0p0(4a$!c@ojxx;TlI=s&^&nTE?0ElG?xO3xNC|XXGJ6>Wfa4rafvD!Yv^Co#%M=rPC3hO z+yjIavto_iYfpBI_0?2l~i=eEPn$JnwUQtX%^d2K5O1wsYRVr---5jdMdye$pqjh@3 zAdN*^1Fd|xP&w+pL~La&_^qZjyXz)xAHTb2c=hO!dmDE1YrDo2R^Iw#3QC2#WYlv@n%zs zSGJ3o7B7!~xK4s&wCgQ;Tr}qnTc_T797!yp8l${Q6R@JBAGBR5Z}y-OnD*R=h_|tK zsYsi)^+7+}4qln+_*Pqm?pB;2i&9*S0;;W{wqyiOA^^Gfl!Zf=z0T;rU!OjFeEy-` zYR`D^z}-7hN|OT?ClbglfYz%*R(3NSTME1eP^MRZ=20}9bBWmnyJ;KpVtJ|JIgMz& z*q9fGq&8g=>lJ%#NGjUvpNg{53(yi%Cb1oL*?q5^%?D=B&k!}v%`TnFS$ z&d+1!l+d zCt~qPTOn;Yv0$_&SsOKu)lqSZ2a%^u-wIU6>&fqbTLQXkeJkXDI*&>N&fU!V=<&RV zmLdfe;!Vm>=+P=>7%wWwqO@U-py$)@DPcDy`c?O2WjTS z0}8fj@mRni@$AD6x$1e4hT`~s2udW*?5?$=K|ypZ3L-`m8^hNSDRGCLEVX$Q#CZ)>7apZn8pj^mE@Kym z%;Y~kd=Vwsigoy%>Iu135>2GsZ*+lDRF{QFP)%*yfXb5|g~L(B*)1SZ#W*IyNn3B; zu9J*BRinE&bIgV;oah`^7D&UorZ26@b`4tt!DWz(@~BdB)I*MSj5w;O4~f-(+JTp+ z=i0N1ku1U0HcQf;)rMaPBnnw8%8#V^?+5{0FX{g7<7$)ZxzEoxx9+1y@7}EXT+oo` zzP}0*aC*5&XG3YC2%wXll(i8<(Ax0mUnNSCwUxAmf~|2KZK;S0NYe8mbuRvZMk9x? zXftl%9xC-=hc*Ok;f}FYHuH*qp^kig)c0E)lq-qhX+TYjIleRl6^529H{=_8T}^U# zo|~GIu$!`6KM#Rk%H;JItLLfL%++wZDtTkDt7kuIdm2$uIH;>VXWETqd@~ZeCqGC_xW}I|U2)D7 z(tYQN?LcMO>Klflzlo*PEfUFum`R)c$ojLE?L^Ov0zh55W8yJk`+(=x+32+t~RcR4I-Rq z`li>GK)OwwLTDE%_>FgeMm~D@u8!P4HEcvQbgiQJ(mxs+JUnVfcaAeLH`lhE?(QLY zE_$hDZ(WGUKk9kC=v=AMYO}<6&cizLNuqb)7L9qsPh9+4Q7){bX)|k$N@;Fdjs>oJ z^*7uZ`RI|nM{Oqxbc*t)cPncU^e|TMqjA8nJaJ8E@HZ$Ua$4?x^w3`qX6!IuN(LG996vkyl-p!JbLVYHK+gY&)PoDARw>hqrp*LI_9!id{;5&0xA!Ru*C>(#+*fM<|z7uhB1hL&HAJ$?b{6S3&qx+rXn^j zDH=AU_M1SX#u`J;Nb8emQn%eI7zXTRX)qRVF!YftveKpI>8xd~bneR$<&Ug$spKM7qR&TLX0*x1q) zQ_r=fK2}eEj^HsuC>^;R8U*u-9OG(}MXj$UcG)Ut@~QfRAt&1Pe*n@hqE$ zVcPGg-d1cd5h>?tXM7_L{r4Z&4=+EiCz0VhG5FDc<99J#h~MsX(9h&{UT`f;y1n#B z9Bd)9Y`WDJFlH64NW7wL6`7zjkppTo3#Xc5&iV-^f#}`~<7{mhk;zCZlT?Cy3g4{Zm9qvlfzm6|a4M8{Y-2xH?`O_QE8w(U5x zFI~WYMJ%oMNC!g4k7yRhVfsq_9N{S7bO8Y4=!KyLKca+&->HziA9k&vFf$@1U2hbd zN}vi?xkwPoDyv4y2aJe}Yg+Y~3uY69fGBp?u69iTaxiw7F^@o_8f~yRh$uKV&9!n> z3LL!Seb(uF5T6kN(neWR4_3Xy!xM$jdR5JTTUnsRFmI#>(*+hu_yKiK)D4D>X}E9LRqz+TjFgXvo3erdFlaE$*)25FRpAv{oRVzX*;%wdt*bO)1J{la& zSZZvv^n~moQ%MX=pH!9a()N%+BreK--bsv3D_D51b}hRjE2Z6o6=0o$?N|CLq=VGd z6ge9+(n+OciPe2=C`1Zc;J>I{(j5xCLKt*i`4N0jh%!8C?{eqiy+j*y1OvQJ#MdW|areRE;4x-skCI1g?AQ$hG& z|1kdovH7Ybp?|w|>i^)eyCzuowYpSM%C=0kNl}Pzp(mX8oJd$azB3^sYpVt5G>lkY zD?&^pF{aD(PCHaU6>ac=iMdmGB*JKoFVS+ypooJ?515m31=06GVec+~A|hT9^;$KN z$2dlqdUQ=zRRl6vdO2>iN{@uY-9^@0fz@m-? zAfX*$&k-I5Bg*=XD7VH^v=S_!f8~yeI{oonq{1^#zOf8YInf$5`1 z@2za!*Gh1-KlRmZrA2F;@>ij5Egf-%T7^oz4e0#ZfoZ*8oY_*BIfN6O!kYMBG(voE zaWRc~48*1_g;JdYSJYqoBzV6l!7}3I-V>>cKFeG^aDFSQ{f{2D>!Gm!sViNHs&WK1 zJoJvsB_Z!(D%wz52Q+x&f3g=16&yKn=Qm;_bOkhkmGy-+rxV%t`fqHs1PM1-I))rk zpHkSS9Mkv4w-RArr{I`;v+Wvsg;|wm}fP}^m?RtEW^0{LXj)@yQOofHm0?yhSf6e~+Mz#N6#>)>M zzIToOJGO1qX@mtEHEMv5IEo#piy$^TV#xe;v@7; z6aA*3@*0NEsc;l$e-{nR%PB7f8aRY_M%pXny=opC%L!_KN-Sk~1T@-^i^w{i&3SQti{Vs6hbcua8TqfnA#`D z`&%T?<5!vmJhmW|a_`aWS0GeurtL$(2}q>Z>-QAi%Ity|J}bg4q+#@ms9&!x2&)KJ zhV5-NHxHTae?Z_z58b^pCS2E=28v=-ug~_D`(_M;ip80tiv?zfu0>Q7OpuJA0Zd8* zxL0P6_>ef_;9A-$okTna9BtOxQCSodA7isn1e@OW=owA?EroPPe~j)$7HH!yf{r;_MRxHqWx-D6B*l^c?Hgy5zCe-^CdXgUk$ zhlrZDf9LLWHD!q+rglByuiSwsR|-ogRnmB^I5g*`rBHE4+faMf9Dkr{0Fw%J;t)I+ z_NbLgmOk-W-dJt-IT{YzUYI25{gkfFETTsaIsB)bv-ux=T{Yp^*_F> z_hUVsBd42<=?@;o>nYQ>%9k0FRai1dL5dD0e=l%>`Fe7ACTcsJ7E;l~IB7?l;4(@L z&`F+Ub>W#pk0LlgnA?xa@rtMAdvtP1#WU%pAMugu9P^-1{{K3&BRpw`d2} zN6^LUcjLrWvyn?u?80NQZ`vT;Zd-Jgz9XYtrtv_{s%Sv1(>K8l0pI1NC!`uNduqb!jaG{ZdPw_ z!K1+t`MxTq9XT}-j?>DXLK`M!%T<#2ww?i1D=i_Vr<}W<ud1%n0I(ZHY9fn_7`$C(5f~Javv_MBs zirk1CPBEk1sT#-ns*a&-dODsex3^6@!qY5K1kH{HqMf{&lXWm-o-# zefjw1X4(IvNAS8|^G{C8Mk|O$gWk+Go?D_xZ+sOW6Syd^=7m-GgiB8Bg)E+@e@Yzz zEswtF?mrdd03#HVQMDPW-it-0Q)ulv;zByfZ^JUg^#yxr}T z`q3F;CjF9x1dVKg!~UV9|2lBEW)}vneBkq&xn+R&N=Ex2ILWo*@@Z!17Jx^!pDVUp_p&{^XV< z?PEvq+syusnff8X{I=`a;96i`KjMx4Nllj+-NkToCIHfHJzQ4h#mJsVX1 zqNQ_1FYnrX+aald{5`i+qtyVz_1bx~oP(i);-L85$T)@y`BICk$lT45RNtESq?pUS zS1eJPyP_js5pmcEgkQU^#-~qA<}IK52M^rcQwTcRoAPl&R&U3Fe`vL#LI@M*-iuX6 zcj$Q)Zil?WAl7zN5-6Cs*V7!Xs>S}xz#Em5^+4(Uv2qF&(k)I;oED)*P>-fyrxLYex=Bf7)sk`HSgz z<;ysxK&<|N01tvHLGZ~T%};dg%=%G4J zcF+iS79mV3k{0OuDqH%?>HYk2r?m9JLwJwEE|mWRe~PTboI9X_>WH`o=3t5@;*+as zyYxmeI}2Z_Nzh$uO_ZO@MvhEG$2fKoR>?R=*QpejOH;aE8oYdZq8ieiN{E61TQi92 zY_`{OVevj?%V3g{R_@+8NS$b=R(BCs7rRS{huG}VtqO?dSD}YR+aWc#T$l$@-bhIa z0{F-Se+l_^pVBglkWpJfP*^l#?$t1#DN1q4;nI@gRUrHiU#IrZ?cJYla@a=?-#ue1 zr36l;0%aj$aooitqq@cPedJ!g2*}_w6Y=~L+fpiwUCU4iJWWK6l^wJ_w8-?!2yi<* z;HV(81j7~e+MPm} zokIPdwGXN|=@wgPoKhisMVnT~3|F8=G*#Fn48>+a8~`BJ(VO5@>|js{|{$ z8{#z}|I@F8hVM2=K6()Eo)gzZ1th7)a-oY*63&)cWGdKPV4j;HT62Uc%{I ze^lqO(e@LBaA6$J=$Wu;qOgkEzpbwngjaoQ{VYfl9WN2r3rU$~zR|fHI6E%f6I-Mc zNw1`JOgNbGvarPj*nUpa38fRz)K=5i6kc2$)3!zpo7ojLy=~?YdI?--B2|Z~+Sq6= z4n4x!F->P^*HTIcD8EsW{wM5l=F6YofB$Teb1NV}dJykHDP*+CZ%Az@u4#pL&&^Pz z8B>X^iysTeD5jyzoK1}A;ZTWU=|uCxJHHTuNJaS%ra2MN?*0cQLo3uFV0*=a`pc?kX-^9U6Cq`bC?e%MfWwMe@uqa z+c~-!A|#M<)riIpF)(`(JjG|eh_ z)F|4y167n!412PUH*&gZ2)!UZe`;~o9lKqLj}<7?(j`RYg}Me;UK)^2mon`$2&@kg zqsf^Xs*qC=i%S}R95atsuXsMnm4+7Os8Ly^2upQ+4NfbSr!~`YQ_bgf4+>{fK)!m{Y=ECl*CqANukZ0|Mj#7$WfQxrk=X^0U}oJSv-j*F6!3e-UR zZR)kODK#;gqAesED~yw&0RkJ^T&_6UUAq$qvQbDxaH4Q#?B)!#f7w9a4FYOG94}*6?z^?i^ZK5e^S~40Sm2q5P_CbQiSB% z&>JzvL{n2#c3&>IL%h5|h!Hjw&WX4SjJbqg>^R-5TVzg5H6ZM~b7l)(izpoJH0UD= zMwR30sQ>gd=_pl7T&JW@VND^oc8w8-O2W;0^VmfaMUcp`S`ymh)fE9Odqf9%6t)zB zz(N2K8Z;R5e@;cK;V8XD!I!eH(oX;N7Zd%ee)+ur?WZZf+2HZm;k*Z_JeERRugP3N z=)(mTn~5cHrC)JlT2VV@(od$eNFU?qoZKJ3;n2iZvXaa6c#Y@aP(W6^p$p7T1=tD_ z$Zbz2z>fYLH#!^wVJ+S56;k~cf5DBPTO+{w{^vc^tao8g)#qS8*tEYT@mYTCA*Rfx4l!WWqL zH(Ff$=wZ93IFa?W9WG#1J6q6&&L`{(-F6t+xTcTujWW48Y2Fh|FQOI#a9v1YM?r9$ zRU?G~f4QJF2F}%Q)YgpBjKc#4Ex{n5L)R}(Ke%|(%q%?r{~yJPM~~!nhV9pG00+*b z+f+e8s}{oSmo*bktu?b)*d4)29|t93MGxup>49r;kt`uRT9gH2cXb-)xDAZcDZsT+ zaN5nNovEyw~W95F{X`qsy8 zQ4e8NQJ+@Uff%*Zi>{GPCF5Hd1DdC0#1)ivwG1d7bc$o%idbdg72k*8i^Kb|W`FZq z@2~ITs7H_9Jsh=rJA7pq;Nh|YUO##q2N z3CVD8F`4H+R;$=p1!F8mlh|x*TIra}G|v&V9sqxf?zJuHkPXz5JH*lq?o!;5=Za9l zN^1#*XrCbt72YJ+fBA*O`oYQH4jpfue_%X#B=60zKat8+rw~9bMiaIxO$3n?t;Jp~ z^|%hJ4AYm*dU6r!r6)7T7$jtri3IH9xkFpA6va_(AuVSy@zbc$ETv0c^v$7JKNVkt z-(A2iU5}AlX_eyJz^OxsNpGy|X^|;at`xru!4Q@;CX>R6eX2{9(URh#CJixue+`7l z?!hkFF11a?-6p141(=mvIhykNY_8sBEn{hfoHIix`;A@FfB(e{f46^lYF|FTynBBC zr>A$%pV!BB)4Aip1A1?wG0yE2S_@q2o3BwYz*d~;B8h%-R=4RKLhhl#H1&5%YUT(S zEseSYkOB;X-c=CPHiyZW$ePu=e~8?7tS{l=aZoeVP)zSroMq-g1?Sa2DVcMt$4P3Y zO}vCiYv?qhfJr!1fH@EG`AVgAB^FaxFWymCupWzYE%^~FjyG1{o3=_|m`4gL4zUux zovDicb1A_!F_f;c>kh@5>sJ0RmxX_BRQtW+{va4%JrbN;wnkHg+NT zfW_5bCF_lqQ|I+8a@oGbE2ijyR(IKy4h>_Daj(;>m417fH~?_}ouXz_@2H2+BXRsw z7q^|AgL#}&^zfDXI1wwQe`AGAu|-iIt(}a@4!RxGIh2B5kqFDx@ZtZwOfbCnPwVsd zA78$F_x&v-{ov8OH_Q5-hWfcoU0JRAfG}_*a?@h9rFb8Cz!kbiTx5jqdzR#+4MIqv z)0(YZhEiD0U&k(9BZy>LH~T2<Xm7aQ`IJ!9B6k`0>e>b!HiA<~?DI5QA>w@9I z!+CF-F>X>STS|I^MA(g@q1HW@=uUuqS2~Wo5CJz=9ks2nup3WqhjWJ!o1i5AMxX$n zIElfDyj5fADcm#p)P#uk$hGs$6n)MzN2K~1s%ch?nX;!fL_P||PlBmpnVN?h(WnTR z)KgKY>5Kwqe~#lnGbt2y7`Y0K<9FYVY+-KLdXIpWAZ}NqhfwV@Q^9Tv7DcOomvJyM z4o&*YH2-hEnC8zf|0_`a=yAM%eJ>DbJmQW+X`gPC?x()An;tP93b~y@B}EU?MKo-( z!5YgMs2*NvzoTo4hXcL*{)lZ)ZJnX)!j>Ebb*5}OfBx&-nRPC_JFfQn&FekGZ~gfB z(ZhM~kkWBwY=tKAS}hpc((<~r_F}Rf5--SZlnNZ>4Bf}Y3HPGxG!*KscfcBFFM6w# z<7mlAoswc9^K*kl`{vi;*Cc*ARfQ#H%3gS&q?5!BMHv|$5htRezsGKHE6=t zMoctNf5_V>3g*J18%sHagT|>{su)Kre~X#WRHHx`agA}DD(DSTN|dshjy|bod}zdH zKJ{sDruh$FbuHGXPwl2`)T4**-n1&qm2=ZQY&ZbL_@yLX$Y)8YUyL&;l?^dAfdk68 zgkNb`+7bCm(L8O7+V%U|b`_O=jXC}dN^cvnf1^<>xy6djm1ySZLJ{;6D=^LIuDciO z00rPpQ#)Lvn;<~#9r}2C7tWQn1!?-w-+PBDyJiQ5n?+0--Bqd5TcV8DBTY7x#O#~ZlFKq8`9cZ ze_s@8l7lv?f;kDi2yAX;Dh;4-ut~A8II^9>u@r{ZmbmcBSo;P}f)h@W0z^@0Qj1Ke zrPzwnj)&NAq-O^*eCFCk@>|=fj~>2z_kUs)xQa|?&)#Ta7#he0#uNaTh#W^qjue-->T5ZDQwo_e`*@U z+R?ohB1K)4)<=b^6Rf`nGLUK&Xw^M(X6U_#Pdrill8F7v-fmh0ec*sCU|dHdWmi$LV7%9nhu< z{O_dq)4oO*ToJEsG^8mSEQM}5e~r4C`cBP{Ig)FUxx`A{)v)|*K4e?3#Ze8trs#t9>*h3+($k8$f9agX;}0zu zp~k)ASQ}}WPMe-4^vt!h0nUp*oJXo~#4(hWl(r1aR?ySy!yN%jAF1#*qUD4y>v;gb zRK-N?Z^37_^Oei~?fCfe>C@Av5A7zidGz4Dy~zD4`i16+AT$+8_!^ltPzVg0Q_2mM z(kL4@isS49&R|UCpl=pSeWc5J58f8mX^K}Q9!%BR9rBuXw94&r?$1=9p+5b zntK!%bJn{lvvK3;XjDg?s5p_1q|JiNK-BxCGTBqtMEd*h)@LZqe`>c*BOX0=_p)df zJ0?LJfwxYeVv`w7}8G6sn7;yT5S?#>>3<7-vV7+Y|)j_37HDnva5TS}QaS za~~}Z08`a?Sn2@Rf7U`s7#VURr8~KKNWv|f>O&zCDhY6Q6?t&VjvSi!?R=uKf8)(5arLVz!6~%`a*M-f z3>&yeEkmpIm}+HDcURyRWMOZo)MzQ%*3;LH0Iu?mvM=J_BIh(hX(Nf;2|NjOa474X zV2m=GLEBQpA50?LzmfX-JB=2Kw@)A1=UV{j(W7^d#cbjFfZQgfogxOvPNK{&>Pty& z#z!o30wa*+e_XZ(X~%-CytY$cT0)fuS57$fC;?X)aR+*KM)n#?B?;OkR;B|LEji~9 z=HJorm+8u42$wDAT*T1yg@i&pK0}q*G|-k9ik_CTnRcuq#6kcP)O04zpMDguN?xfh zY(_U1etJr=orIuI35JHKQ}V6nTrTz!C|DpTS8@L9e@6ZAw4dL%cklk~R_uN7(A_Pt zKm^!iL5(WF9JKR|*0y%J@|6IW_Pk;hdH}vRb4(Pq)K7s zxv~M9hQNl)igBglR{=GIbqkwlr9qg5YpzE~m78(zQU6(#jvTEe&hPOxSL{@(;!2>> zkg5l9e@LYE009YjYnX&)&(sK*b+qQG&-Zzr(;7Xi23~BCk{c1d>=oBWp>tDgux^2} z>qh-dhqTgR4013w5yFrtX^Z-N8NMneHz=8t2%3IV0Q~h6x7^; z7by;GrIp==>(1+!6V{TwCTjS+@MW5bMTl7>f1aCMKWnrH_fnNpOs{Mwr0}LS&tQ&W z1tbMJ^leA1*^2{EzEsK-8xe&`QJ?SdByFb(uxh(mtzm%(+zz?E-MuvZGJ=g_pxS`c z-5@cG(b^oF0x?u$n;u&cF9pQ&M!iaD{s+!{KRm6Med|o{!9#a0RZ%upPRS_?+X*o%qoZ`>oye?o%5p7xoH5^E?*RQjh-V|cxG{SWUxet8;g ze1B6e=)ptx_L%pT%CM$4jivg}X;HsfvZ%Mf?}G>Mx>vtRw{aIpIj=WUOnrzSQ)@H( z5erKO=REN+nySvRxYZ|7c%4_Ee_*BI3balwVH8voW>=UI)kiKOmSU+e9GWH@eMz*% zIV_k%36up7lizrHG=)nV5Ad(em09BId!3|m&^Qo5Ay4sVw9SXBW@%1;^ClMrpL@VkDXTZuzK?O_9s^?Lt zw88?;Bd!!Q{yp26n-*RcfLKUZ7OUTy%9YCeE?l$eZ2B5DMXVYs=iQmpc)dG{1`~;& zu34^H?Xz{1zeGOG|Hs|Ce>K~3W7nAvwn}z~Eq7a%ELrUiyF0q0U#I|(iA><<012S# zNWAqqWL^C0`}^_~S>)P#mFjIpS(GU9aPPG;ahY=rV9qh>)E!|~jT4Gsxa~(Q5S-hx z=r(ZOx8hC7I2rX2jlViVKqwANAuZ!g$^kr{BmEmW%oqPW-vhm`e;&DKJccx^(E+2z zms+k|56>q1;YPSXlB{dHi6gNt0xj%yD{BHbJG^-8^RAiNpcYyyF#aHcpmwx=Kvo@r z==isxN(PA`t!*y=0b=GP;jPE+_Nu@dsiijiP!;G9)La)I2I9DQ%8~B6L2c?n*SdkN z%8MVV9PASwQ$c>Re^5MRn`b@`en(+cH7O=xoDa|0cBTMz*&?%jUV4ZHw)o?L!@vI_ z^6Jm>UNiKohwm9iI^7E_mI+r|0Dqw1c{_htS_8n?PevGgVKvU7$pYXq!wS>t*Va~r zTbGd9U3?t@lH@(|AmkC$mIy4w!_e)@hL(}@fjWakX9vrsf4u8sLM5@qZ5wLLd0@o$ zSsfrB4mG2#<;Z$+SsYe)|Wj(`YE_b^gq|@3DZyy0=dlIGFLm&LUgV4yYnXdxA{Y zJXrEk1AD*;W6m-gnpvr+oWV;<)a*R-t&O-q^l&2t+eQER)(#?K&WAZd z)lq`bwp%&3fRUis?a+Qovo>#%SZ)z+-r@>M`|m1~5u9>cwvO*ZMwiy3(D=-&e=rxe z#T}c)4p~WGP-7e0wd)6b5lqW*wp_NIjahE-eb6B@l(%H9mWeo(tOaKuss?KVxRaMx zGdL50H+V>9K2AOV$hCuaIibeaBU}BOhZ+9#yRZ5;@3mdMdKjNiZ}nneznzS%fP=l? z(xE+=$yGAk(^P4cCsA++)X=~&fA#c=Z?_GQJvEMI-8HS5JHOo#$XM8s<4BRYn+)QqgDgm-U-78hv3j!H5=N|2YO)(jKlkhL!u&rye@yQ)Vd__p z;?sVO&Z2?>=2F$nGD_LI(%BuidnK!dsFkgT1I|G`YTV;V)L<-c69!eoX6~Tasb;V} z799)`$t<8i!Xdnopv6YBkFk@0{O>1Wj2PA)ne4vw;TA303_4@nD!etZhT-i%tZOAT z2lUbz%$l`-5VUn4QwXl(lIDld$44;rS6_a^pndv%eak<;hoN3Pe$TGsA~gN@Obb>! zbehNxjV;z>|LQq3fAPQDfZIWm9jBEnl_Ft=A{5jw!|@~6rf()?mbxA zMZF^ofy~B7kQ^LKb=3DaA^6X=+ve5d_{`>6?NpX^mfZCT8s9*i3F6M{dLY5`+rU#&-Z}MjCH3e&e{yc)79}gJxQp<38>}XV z`B8de6)3w+COf+lXlsQCGi?VbNo9GD5m?>nIw3z3a1>P+s59@-rJ0W@#V;+d#3Rf& z+p^g9gp}-uM^8Geb-qKDf^oOuoR*}XjIma-KVaks$E>^O=Dk{%7Z2V$mJjOD#kOmm z48hY_H`oV2f2KIs(fG34<9=sps^B12_Dn66gvmN(ELx^>=F|XMsf5{y4 zW!o^QTZUlNu-U9xq5~_K3>hO8Bhf8+T0W~51lh(Of5wLYtMUG8)T}h<_d3dq>QS7P_rbnwhgn}r;S;%EBtrqwz8W&8FAu`bf;_t$sdf1Kls zi&XpGe<8)I$MG2ozE8$kWQ<(Vt@PqCt_xz(y^%chSoRu;k0pmrzANp0ngW%rGF@&fAD-5yjcrD91ojh*9#L=|{OX~857b@ZX|K3o zA@y$1$nhF1WL4F#Ij2W-un5>eC3<8FfVVVCLw zf1oGHJRUN7V%R|ZY0KvfU`JN;KJ@g6p75u@R<^NMtf8=-=}d>DG?NYNc_bYITVMl? zvlZx`hO+0GZZp~3OOHkU7Ts0KzUlt}KCNnx*NZUzM`h%nPVTD*@!8}Ozd~;(kzc*o zU^M~^J^?_xg~>CnRAL%{xt=%1;23(9e_dcdNOQd1(N8c!jT&{;+8EW{a)zk|xwcjs zsmIbo;~Qj-480oR$HoUA>#?SEhd;0`N7ZOETT`INN63vJN;rbWW&+#oEvBjSAcR$j z1`9xc-5n^|ie^e#3wDnjiO7WC68QRmJ@9}N??~* zE8K_I)5ELo3dqWU%ywj-l6_OJN8zjzEEw2c2Sxm8VI`+#>(ugG50 zTcxhNlm<`M#Ki-wO=MdjJ&$>gaZC2+4a647=L0yPymst-H<)xNo$bvh^ZV| z^0ez-cghMVTLr8H#Uy9LY`a3j{Q|+VE#M(LzuQ&GF|a|U12apQe7wv1#nV9i>T&z| zWBS_1ke@kRN?>g`i6u2Jedb4sVQxI|;aRk0 zKJ%K#>a7i{oXf$BvL(_YiZFni%I*-eWM4@j;vR1_BZ^M+fGAb0f`&VHMGHH2Y#~)^ zs;}H6`9%RQug&&kDK$(Wm2w#Brpy2+8HWeLTT%#D8t6u0H($+Gf3?Ff&qR>>Lbnud z-3o<|oAs~X(WZWHa$h`%&-7181tSDq61T>%dSbJO!FD*kFsvj9`Pkx%7~fMzjmUbx zDvOAmrEcs=eDPREe0M?M4mixNgqX3(55H6;fwB_{*AZ^R(6P4V!S?o8OR+0~(>=pc zrX~R%)0}pAGCFs6e}0*^;GDUVG_S#AO$Z^Y7yJmQ1`g@6w4Zh7fh|vg@6Y zWrLM8v4*CIGrQnOCM%HFh_OC)Zv546X8*!}x^HLS%doE=zh^Zv&5FO3X6w<41+sO^ zUfkDRT}O{ix~3_oeSHLicJPnJnvf1Q%*K$aufMIX>+MFAf2g4OurbUv5&p_l*0A)Oz0a{yCz1l1M zfFDybqT2TiYh^32uCKMUuvb0QBWN;pfhh5TaaUR?mg4}4XsJG~$J)eS{Ey#!`0m|W z(^rq%v-z}ae^HI&Ym1cyU{$g*zjF%rNO_y&Ww*#S07E)9ak z;}Az~bq9#{Ze_z=HE>rRk+n(&(SftI&rL$-HJ-Wk^$ZMEnH z)ky|Pf0yOl*1!}t=b1uJ(3;SRTvvb*ZlyF0O9;Yjl?MI=k+i*Ms|&zTRril8>g-BL znaxh|e}|1VJCH6Gm$F;y-ER zx+QLQ)ysbwrvwFj~B7w1Tn!(axNA2PHdH}owMs-zM@tpdv1p(Y!=1TybbV0P!*r8 zk`9wEyO%j*$0}#*ZD;qKlK(J2YZ7?hzQ@8SR>DJX?AknUEr|Tsa`j(+f}TFkufF;9 zfBa)0>eXZUYy-1^)UCg*6tAmxFNduN1#f4aCAN`(<^ASR7ZfbDP9VH5@V6c0kS@C? zl-l9-2!_L&jt+4-f%_-G!2`FG0nboCouca?vZi3ge_M)*q<8_&o{T}87B*Gim`eUJ0m`OwG2XEg zwRuQuBjaSa!}VA;{tNrmKfRZ1Up;P*$Hx1Q1;zjfh&y&N8~Ebg1ZggWV1}Wgh|HV9$h=M7~FerIp(vZ=%Ja# zh`c~e;7WT`fvvZrBvirse@!dY>StSp9q2SWBX(5JAy&P;Jc({+%3u^rcVYI;`xW-$ z(d=wZR1M8VX;8tSuv#Tkpf1H%{SPcj|M}2IJ zEXsY4WU)(kQ>weLl->n9+ETMwSuL2H*MPJUZ|?$ph~Z`UlZWaQ06jVt5iFz}JJ#(8 zZbw&unc!U&2J-f`*Fdgy0IqXOo(?~%f{;MJ{jz=d`ipP+KfQN@^WxEaCReF@Puy5d znZcQBonA?^?2cwbf1)+!8(gD=3JkD@S^pCcyhd%HHNSz_bCB0}tth&_n4Z_{8FYUv zAYg6V;dY1?@Y*vdBm~vQ+fwDRsRLXKrX}bw61#fYdP(|$cRe2@W>?YED-+uQ*wB!H zyRCG$?0U27l(o-R0Z}z?M6@pI+X2$Dm5G-u(Ibtfe1t~Wf0@Kuq#5kd@J8G47vDWo zcz^Y{J=LllHh}XzCB_t8;_%)5RC11mLDVC~Ol|y#-};?2?Z8ftAEypCkd5OE*;~Pt zJ^RQOXX(IasY3y!#|lJmyvBL*hIv(M;-}IcOwgNhwezYZzycP6V(vB@tvIZYw(*y^ ztLy`t_pmbjf4ur`BhKP^ch3SnRwuF5)BY!~W8!_41!+`c7kp^h_6RfC4Gk1s+ctnm zldOB{mkir|JS+Shb-(!ZtM=uW-~8siefr|@dpoZ`I3(==Wre=T0WH@Ki#9;$>eh0P*i`gWjRwdF`v8fte>w6X8U@>q;K%K@{#w?yAMz7O zn4Z3qKYwiH=xU%Ee49zXn(YAzaCQkb^z>@obEWDtXsk zr8&LsuupX>S-^Xcvew~?oOU_08OxkouwRMze+-*B@5^-1%v>p4_R=v0lJ?~#_NlDM zV}s=X`-js0A1&DbR1ck3kL**kB+Dd~eH@v=X0vDtu5?i+_PZ+EZh^^ATj;WOLwf|} zj=Y9eFFlnFT0s;IN-IIJn`)7Lh+#<^>r}XIY1&(w&Q1+vLDo}Hhcxs?GDOobGE~S7 zeEA>e>r=Qktdfd_E-xdyhGhen8(3tc7hZN<&W7) zF&D2K-)PY`9>t3qbqLtq$0^JzTC$Gg!jnHy;8J|v`X$YoX25%-+rmNT5ccHmDF>Ak3<`n2S{e$4&lAIg507&Zn^J0p*7PkV30&m z9Scg?b_+&QPjGK|ge{VtCa6V4+)L%$HP7+eMYrh~ge|rX$qX3WR6dkd3T3IxtgN7@A_E4T2IYPjTZt!)B`ud3S; zwJ){2?qQn$`}1l3<@)gD`)#$a9@3|c)2oz2(Q!DXb{?#G26kh|lxt_LuVZ*?(luzi z4c*e+#H^~s2KTFw56GHLf2FXx#C~x_tM7Pr-*8$DTI_STkDZAbJLq@TV>?TO3qF?9 z?7Dqj(PBQM(NLue5X!#3Z@#iJr!}#@3G()6!un5JOLaFRP%?G>Bp#ByPL_Nlvjw1B zQU&JdAT{sI!lfwpCE3ZEaUYYp3HrkxkIh{F&-1DN7c7-tJ+4pPfA3%x-4=9EAN($n zW5(Jc<0StDRIIGR(7=)eigRi;nADXePnbQfd}*6G_p2Wkh>eZS7KydG!D?r&%LYJ- zB~0wuf`@p7*vvX+r*5@9R@fx#75AOg%D2>|e_w*P5X)N$UIh@?)j?AoWOj`q*JON( zWhirJ*Y^OpzQt1&f3+Zd67C_~!Ewe$&6u1Y6ZU_9Y?S}z ztN!8Z`G?7WujuC0L;4h(U0MRJBkN=WRDhbE=Pi9#FCt@84*D#oC-%D%i08hS>x^w9 zV{EIfRjp*InyKjO!-~kKQ{C zU(k&$TH|pY^DcBJNkLId52cvCmdZG)b9whRS|pt8CyS+pnE*;`gSy!t8twS@Dn#qS zJD*fbGT{b**)?rsA(b|b2-on2jww?0=gr=Yj6ykYv%3Wm<}EKzLdeH49*{-oaPbPo zJ3KH7Ygxbce>9IFs9jdvkdwDg6zqwh2RIR^N ztNzRO*(B?|i-s2u+~W@Y!TKS1*f{{|&CBLa5^Kr^vwBj=e8avktFlAfRqTg&WN2XO z;5d@HCyS}>DUMw^_G6yl1AQmzne-j}7{@$m=~bIn!gT-eE;#9U%am!_3E*E?2bQw^x6Tp+^=8a0a_j1 ztgsXMf40nu0o{&B1#K8^A9Nt~nlLFy?3$t2Xc|NdU<_+^Y~frUkf-B-safU)?8uR)(roI8o&pMHf(q&Tp~&nCRZsKI za$8%COTm{BqNaS69Yg|{Oilu(R5jExB(STIL>_w#x^`Z%0(lr^7OTy)x})n+2D1P@ ze|t)=Qd{iOATsC7%E0F%&#L7Z5V*t({?xqFjwH&F!tL|%*<)MNC0lF(OIN**iWRzG zAl=N5l=mNgYVGdHbmRX%&TqebUq0&9gZXTd1CTs;>Q&XivKxZkk(l zIGn0rf>EzP?t+(@;f~HW0(9=6QN@DQf6NbivG&wlR!IRM!7G#ihCq40O{M8*T-g-1 zjLbu_RO#^;tM)7K<$-ObDhc$(L&`M!r4$rnOU5Co!Gq7r{IWCa;B!M$-w-^(R|1<^ z2x||$ltJwC3z^i08R}D__%j&d_T@LKhCe;oz+*5-qU-0 zUVk(4O(6d*T9LOFERpnYA@2s;=&IX81v9KL=WGqqU{{$6$Rs+artGaNIEnqs+71_(Dto#+?SK#Y z?%uqX1`pS6Q|iH|;F~(!K*?`{c$<9-2XkJ| z1o+hn_|n-iYMgEW2Xn#u;%&RalHlj|PyoOl#lM{$#TM?)}L=_V?h{ zi%0a?OhXeGr$AcY(iQg+5AF5zxa$`tv!&N%6(aM z%bv|11W6!_Nhr&FsAiUP!kcWgDfdA|GB2mARxL~cR<&C|x`owto%9yV2kv>F)^`06 z=fT5+Z0eJl{?9*|>Cry^=6}Q2Pbd1-1Nv;Dbu&6`JTK79R*8T_iZie7b=!66zemE@ zAmqSyuRTDB+chkS;0a+P5SwjXIhGJMI}$59s*eJKjXGl3VjR7M&-J{`0s2*}NE%&n zo;R(2K%==?G8cqPJ6RLXbgJg3L2Tw}$~=w|XGrC4-CHVv*yKEK>3=CJBuh#bgRo(m z#}(C@wd2TvML;e-8RCN>iuUBM1RJr60*pi)82!ma|IOQp{_VTd{OaL+Hq8W$!_I|6 zEqDuOwgUpQb;YpeRg?D#7s zL)`LQy9F=VehQmKEPpO0ZMAv4QU1#;&)$;8tWh2eib{+PnDpSw>%1?5RZ+VOV`p`9 zbkZ_&&(3!tT-S|V)cxnT0|-b#pyW^nxYPwYUlY_Otu_M!-U|T_OveU#wx9oxpG@wlKWyRQ@`Y-<50p{6!= zSaeJz-S{Cu%u%na%JCOjj+IzDxuj;s*p3X9%8P!jL`#p4Zng3iH5=d)y!njnF@7^+ zDprzfUfgkKpEVZDqlPG#L6UOeh|zgzPhike6Y z*@)~q&f=`KO9HQL~GuEVQ(R_)#|{db!NOa(%}S%Edqm7onrCz9^kKGxz& zD@&8}19m_RgYxf8NDS5!KUV5x@6WFaRf4meO-<8l1AnBb0dMuJr+lMZn5o)HCl!L; zb{h*7L5DrVQGyNMeVbPf#gg2ms~e2Qt4R2ENLsSgtVgaaJKBTKNULx5CqVF@&h=N{ ze|oQ`>(zt$Y_b~2SR2H zSM%ucP=Ehm?+hdaI95UBepv^}j^lMR*jWu$&0Gnf8rnZ@>?|LKbn>J7Eq@Mux~-Q3 z)XHPS=_!4TmI&Av*=&u!tejR@S!2Y0taDf0A}VUb4jv+HuuzSz0x)dYdnD0CTgepk z4c(>Va@ejv0fK*??B71!)~_DXr^sx2mz9Ai0Dl$`s>kNF#8THSv>EPFv(Lu?(Xrgv zbTL{NRlt|5*Jyo_mdpB4<_Jt zyRV3jvm9D>+`rWXugaXPyV?t2tt%5em2E$PRs7l5yqSybZcN*ByiJ{qU2mC%s0<;? zhJWlnqJ5#|ww8dnZyU&5=L8EWi z+ZONOTaYfvf?Bpq;j{_PeXlXtXh^_d#q5foUrI@8I+369>Yqk%5crmUh~S@oeZ6-a z`r<)-O08uuy9!x+R-P58D>Xe62u2yD-RcWZ?8pm?$h5rc+yRfO9Gqvi`J~mRbAMo- zSFiGnUPQiN;-%?Y)1G4+q^i4J&~DN#SA)WN{Z|E1@dO0=|7~sB|_2OijV$eJ5vcoiL%#!nPCE zQ@uufHrapwX0m_#e5zkPq|c`MI)5e`=I(0DMvJpXNN9_NU4c zUhS}07{tP)pS;4xh6qK;mU6kV&c`aBfA`s^{L^e7-&I|C_2@lwE3YcR7mv~GfISqN zKa{da9x*Yp!xEEV(Rb1K%T!H})eMDSdk_0(!2|0%XE;1O@nTp{m3Spd1jnFmS`Ax*qXvbQQ_ujCEX=B~&nJg{#f`f>)o&b&kB*I|Pvdox{np8rTdV5oV}sD-)=S zLfI8SYFsSTEPtz08;GZwdtqbok(u>4-G6o`)E%&spp14goR3$|>`Y$9idt_iJc=eS z5yET>m?oxDgIjU!Iw$*g7Jk{-&MIb~TH5fwc6?onCBpyoz_5m-i%4SvthfeTmy);A zucrNCs-f543lTlc?%)69%K5AD+b`yCzx_BreR^MB=YQ2h`K+v#jDH(UW=-k3cQ!o% zH5r*JEL(OWLqmWov#YQ$v$~d>u4yFxpu7$LmH*lMp%8O8+655K?5MMhlaEeNIt|3U zhs*l{@Ys>NDc)D1_m3CPTOL}!opGFe>6-f4NGC1g>X4|K%2_S@85=zMJb*Mgvj?IT ztc2yw?tegSd|JNsvW8;9-aV&7)y|>y>19c|4m8!1^98MBQ5-$a?ac=M`4s=tr!VHG zch%2cJc@tBX6)KRk$^8x5i~K=r3vZ|$lN?QBv;hd_~hhW?U^hHWdbf1lO3WwE(4iU+<(G;s$2aSp0C+St$S4*Ae|G4MFdOt zoWxyig#&yAPh@+Zo>PKR*b@3CiZCS{s@JX1J@`_uQ7PBdWz5i&ssMk~Rq=^sA2ApIru+)`;mY9_}%Zm`0(}m=HplGi8R)$NAYPZa_WqNs#CdaYfXU02~{AB z9e@2)TA^MH-n>>yrP(cbrN(1`3|l!pMw`NV{tOm>Slca)A$AavG%Ey1f*Aom;1?+R z$tP=44zX>D)rB{8US}i*$D9b9RhMuZ4z~iA37{h)U1@_yvuev)WAIlViu4aKaF!yS zr``nP)}%Ui`&6yTy>#h2wQB%gRXa$4vwvN~C!R%f@u}b9dShMmw|BPvQxNp4$MISE z9emSvR|6-P6btXVRta+j3y&(Hz5+h?ORI1qg-#wz`%vB6&&uzXyI%y%xUBOZq%-1> z)m30s9iX;d!M8pEMtrc&B;Z1iYliotZ@hSw%xJKeU1?(-Y?o32U=a_kK_1yk_zo*M$pm#iq#gqi}nI~*t?`zMpW-8s4Tk^2hr4y@tHDDcl}4pn}T6MnMU6U$)7_Gj zW&?(1OV(!?kv}l#q@m^$fvD;7$A;*g-zRKt!}O=2EW{^S%Jx{@)!;nU@_)qXLHiax zvS)M@M1mFW(E^CA>6^L5qg4A*%Dyja!isfpDy^!&G4e=-4Pb%6mDs1cXd4gqwU~d+ zD+u>OZ`iL5fqRbgjgpI%kM7yuwU6&j>Z=Fut>yCXc`kggp3$4|vBSKNvqcRCwGz^@ zdAJs*W|^7>6Vt3NYnH3D#($piCf1`*bxFLx;jaaMB*pJ>MYR*hJS2k-`%z#i$9 zy>ad3(i7zIa@b4VbXAXm&#kmsY&KjYwbHa8*zYFIkPENhvfgtSfthK&_Np;2d6(r( z96$2G8>kVTjq9y1B?`SHgjd0?TrYN$UrU7)Moy>CH=+2yjd^`D=6|i`J^tXw`$x;H zUp=DFAah##RN34%jLpl+ZCA})LpsJ+Rq43jUSP1TtYlQurN^UuSehQkB&)LrJv@j+ zV7!`$Ov({l1%hfvR^~xMYE=?$>wCQGjsrYz?~i2w%CVpE03U{?Y_RxgE7ztRDcN{Jaf7D5fvV8v&GtgJ5^g_fhY(U*wY}p zmev@q{|F&s7eDP$d-W(j7SYEayGSn>BMiCPw-^upp{?qRDub~Y(vS*7LfI%q--2%6 zIv(@UD$Nvo6ujkP7r-?&H1)(yak@R6;M3i1-BTTFzNZ|JPk->g_tOxc{$_RwP0`a; z(PK}ZGFkv2%vk3In%LOrQR~cY%Qg{hZRc%cv=55Sy|oErWUBZPJ&u9N!&-J|u_ySJ zYu`$F1O!4kVSl@^I4^J3tJh;cQ+#L`{$X2x|JD5X;rbId_N#~Z*~X4p(Kq|<&Fa$4~_!F3^9^tqY zLSO>GouOq#<-nl#G29!q52zqnbro{Yu3|fES5f8U#VP?^T$5l!ZF+kMhQ6$uy2!&* zfkd94)Tl;(RSgyzJiF~gi>KQOtG7w+gj{F%$WY2{)qkY2Gytd0@uE*%Hj5v_DkO$Z`*QKTY{hlCK&0CD>_&hH#Ipde(+Rr!U|$p9{4cpxU0C% zIV{2zR*$M&wfivny zex*FM(SKZ*x>SqBz}IXyP!YAVKV# zy^?x!)};x3Rk9o?RLb2(8ogfMq2`BG&an=7j(=S9U@t*d2}sdG+Q^K+45D>R{Kw zu?mWJ-PR5etFTv?sRx=oN7=__y^N~wiY)T+HDq4!@e1+Z{y5q1DSEtk=$>`CO_qw9 zZ+|ehNCe1$!M#~~K49ZVoW{Ou&x%O&Xu+Zi1yZ=8a$JB|u5=xWAB~~}(d~Y*UDltR z3=uO^Ywh*~>lWEHyB&e-<0YpN_s?6c_SK{J)RQi*;1ySdhIaDZ=#~qR?9bq7YCWr3 zA_>4q;JA;vPc3TVvhe!?Fr-`8ZX5i(wSSW8(ebQP8^m>ie>d;^+*m_dbm7M~;I1kN z52dSo{H`J0oWSoo>7su?NqrAVgoR#F-%q$&iTA(kUfMCfBQHxyPSFmDL63u>yccN$!Vt&mfvp1|UWHtD ztvFbUd$YxkTxX}Dr81GNqC&k={PB?-TUWuXXmx+YB;74(dG&UqrcDh9MySI)f=MS; z);FxG1glJ04ZT`wozp%QW-3$I-|IJU1 zvpzSKulGf@UOkM@9XQA_TiGDzZC^vdSrubdU+z{fs1$uIe%99O${;SVm13V|ZvhmaYf>am}Ufes|_`31KffRnTsJy>p#<{j+bq}{8MSsvWxv@)xg(z+44;Uw4xg4chrI$RWR${WLlKXf>d42hThkyIxo3Fq8-Ma;` zuN}M}X7%5Gu9EygXu95J)Fk_`7_*J=(QS{|6EQsNTz+3M+Am}GM@l&r0!(r%Y3&9c zXEQ06Yw^idbzJL;t&8T*O)ZnnvXP}tZ&>@LGUE)IX|CG_>JbYAA#XbrZQ00%e2Lcd zWy`mp-|me$P%2nQ34eFI>*uC_>2SqhrBde1L1aN1JC=)j!5yx0oSwz+C*#`~6Mzbv zd{-@E@*7uV)3rAzlz;Kvr!PPB_p0Y!JZz5#&Og}X=%bcvyz-{m;j~^}v75G7^L~pr zScC?!Imvp8w1?X@8);u0&VKJ~AIfkZj5N zly zl5x4RiN`BCxYW-1&XWzn6;3o%AppQe<^aFB| z&(Gp;0G;9aEmRS3VMSab&uCA@7YD5`4oE8Bds;jth<{Wt3vf|jPn$wUOP@kd_YQb} z+x3Opw=*(wfYP|VGr#}q&*u02KH*o7;@mf z!2~=-Ie&a2+P-uigienX>|O-I6t4dsGeXJvxZ}o!R{_pJ$h#{Ob?je)^Yo@vF!4XF1pN zr~NbWS%ZwlYX>X2hb6TK)FS|_FZ)pWLWgex)_LA5p*cShfbFWRVZCM|@Ml9vGmg%T+MnCP*!W9{Ay1i`w`@hg{x` z&})am@{C;$1bn$nsarOKL6}Av>W>D`Vf%m*Zz^&tFGd*9@wi;oB2t?d(|KKfxTYfjo0;*9pv zY-&l*RrlgKFx)XQ-|AukQN+EySafFxJb$?9N~wBGrMY@hnTUb2OD}u>I zzXNFr1lDbC^CYK%wsg~I`JGAr`=3wpPuhatyBU1(a6XykDzpweYpal)wjEGn?2jpU zHX;c-NMCbaw(P(;?e?mt2W%k!mTb24*e9ucep!rf?+$FECJ1QQ^@j>NDVBArLVrLa zw^C&zir+=G`FxtCf7-dt$WJZBVhb!_goC zLLU{I)=JmogSAz6lWn-k<04q?^uBkMvYqfIf_Z9s7M}0S@_&9Z%kP2e7Z2u}IsTlL z3383)HsA=uBzUcLTtOWxYty!65r0X$?JgH-rn8xrH&e4K%wKkmoK$QB>GXPBEMOL! zC*iG=Wfbf0?5``wQR2mN-s4oTdyGqY+`1kwf1CZhj0YIGD{y9kzTI^DBBU~25o(*+ zrX(mBCqSlH4w=9?VKSt1LY{~PrC5E&vWSovB4s?hbo0PK-T&Fi=2ijlfq%-u0?8u$ zH|Mba)Sdi^RrA~Tp!JJ~^T|#&POWgB{XBKxSlBCJ)XM-_zNM zpz$mq3tn!=n?NJ=R@>3=on;c0>T{Y`y91=e{PzDqwf?V|N<+FDZrK)V;>!s&Uh z9rKfD4QD2cM<6$DY^fwN}BU{7z_vs6u|b43Tx*XW{c| zgqS1mUY}396iF5(-3V#cW|bd%X!jH~oiO@ZY7leDN1-hYJ%+2K0ggl(jj z>w1jV-iEaEyaE9!oN5*llJ!C^qaCrGw%VNDaT2E+S(Gn}3fx?z+<8GSG|AeHY^wE~ zt6N^afZ%ZK#YEShF2!NvUf^2rvfjOEND7c0_b9!YfrqOZB9`G&*g*s%U&_TRgFhl**^5Bd3 zn5EAv+1o>ts)@pF_gv-AM#q}TT$$(wA+s)HTwQI`-3k|lZhwfdvv?0@i@|#k`yZao z^!q#d)dTtre<`d8+P}824gC!kM1t32)CWK9)=zXSUUT+Dx;Dx6U1&BE-e(C_R;u+MR{Jc<(b> z5e%~=P_?BZjep{K1x}iQ*3Hr_M@6+s9=$7wVZ8>(Y^7#gUm=nQ$^=_y!oTwJeR@JM zoR$c8i~D=I`G5Oip8puSe)TXuI}icJUBeRzx z0M*&6ebFs$n&i0K+`j7km6KtJ4M>%f7SNfcuA3(?a|xcS)oLZ$7HW&$1rcQ@tNGiN zZ@%DFHHI{KRn5Z5&&0l=svsx;Hv)<76I#`gB07Oc zx_ATtuE#Qb*OBHMeTLqFD7wvTiu;3)wsITEG{yTBQ{qX9+54e}N!ZhEp00v7lSr=P z85oRnWm{~6lGJAyY;97R=49b6C)PQ$7O@y=3H9F?iui^r`xo&BI;xX zcmO9X8#k)_Gr~?FrB|G$p8`3^@H};59vd3SP2}9Y#a%Zvw?u{)WHQiURmR*}xEw(q zn14B61F(|yPufU#7TNH0qw2q*_1TJ~v+M{SmxNo7nsgW0g`Ex6EYJ-3RQS{+xLWy_ z_U`*>_tk^=Y;wIH^9cR`76U7IR};a)9@Nj(=NI2!kPBk8BC}5ZSz~Ko>|i)-NhcxQ6|<|mW;M-lX^hw|AJ_oCW$;oAx0-Q<+3%L{fv4$&|y^6%TGdVkH@ zK!-c|V&5u3ve<+dcaR}lE=8L-K{wj$jwAJxXTJ-O1in1z0_Cu$(&c`G&W{F9nUD1w zM_SoNT|(NSMtswnK2y^V}TxBcCzJC#L>U&fC*N;>D{vLkyKt9dC5JcN^6f}iBZkOgn z5bZhbNv)@S=v&Qt>DhNtH;07;PmsJeRTjsvlUbiCAQ7-`+>$WB-FRL?#-JeNXRQ!Y zk!I|5yN32gg^a_R;})Af3lQ0C9DgMB9ZHtnOrGK2@|);P+_LBLf+g^~TXv&@M$Uuvx*|gW z>xF$pF|b|U>S#5Zl9tnu|r+X8_)*c5F;O9R->iDgRMo(XMfC| zyB%pv=CQne&4*s=?SE9-_c^foQMvAY)cn#xd^WjCMRZwWn9zwM)++QYd(GAX8}rk- z55+(BbF+#Vpn9q@q1Ym+W7XS9r0Q?1+TQKNM*OgMVh<-Pki@y$F|t50Y@R)D(9f&g zMN0FL6b(K;tN(hXZ40VBL+i4xLRZkr{ZNT7?3QXVf3`%Q-halP5a3y=R8Y0P$g(hp znzdE#+*C=j{-3461K6uk866A$8L-aIf{|1P;IYU1FRpLC{N}wP*jEqRV^??j$L+J4 zS=6=(77Z<2Rcq34=CDXlRgs9%GXw(Q2fjSib@TAIX>fjq3gm>+9U7GPM8>z9e!82c zaJ1SBkat`A2!A44g{G_3TYbBLS?tZN{qe+kzZ6XcI_d*{Z4SC584#;Gg42|?W!PEcViq;KU(rtu{g1jzIuTM zJ(f(4`Q5yfj_vOWOTK#W-U@7dp44fT{1vv{(mz|}cz-y;QMYETYZRw^WjyX0+;!cq z&06{@s~^u{4Nz1BZwI+2a{?p7YHA}L8cTT6SBM=498*JQm`3jUgAU;f*zxgd-%gEH z(|)_BUSN@WAE=+#N&GATO|S!$UE1J{!)cw}viguMI{1^M0eY$4^k@B&7UK>4B4LwM zmnVZGUVm)l{Vu8<*1W`Q+1(r|miDM`^@~sQt6#rcss8G5`}usH|9Jd$N6N_bX_INsXAM3dVf$}U4cgHCV4lNLA@6k{5n&3G1pl| z{-x{nN%~SwC<0wbD<~LtI zb#Q<6_&sYd8Of`P67G&Qn`C>si@Ac(#Cwc`Tz(v*uOsH8jWfZb=eaYmJn=api(tvt zCx37}fdFGtPH%G$+4so+HCjmrDOx%;8B;JG6weTlOyRh=Yx6 zGv#)}PK{3j4t1w3DwTthI$5NnGN<-pDw9j}TrJtxn=0790g>z8GJig60MIf@M1R+^ zC7sXME!WWq>m_M6mR|51iJ@3zuRCBkRF=LNE&ih^oc#kgXLYK= zsY0f<0?Jg7T{dl|m=J#S@d7Vco_}ywFVw1sqxK8&TrJdK%OPn26c-z;3pp zmp2&Dnsj>T4#uo7#d$>)s*|ydk307JY!dj9d2E120ri%~p2(2KszgeBl$v8c|G)3s zdt&;p9=B)WW1xo}wpVi}e`)Q+jAhd+aozuVtj+5LQ&;iRP zAm!>M6~Hx>t$;U3SX!l|x)n=SixdRDvTK-YV@?>o^9U(+-D2Rpv(32nJ%st zl&>5t!E2zL$6Wfa$A|Tvk$=&vN9|b;AFto`ve~G*Ievvr&pW5QgCx%2F=LNgN<;Ot zstY1eq^mqjf=>#F#>DelTGaUGa$huo9jCo_NuA9D(B8CTs_klnbsHO)kRY;c*BeV% z;0!TT|B3-V*NB=0-;>p9<=9CB zBq0L4eO6F8v0uMWk-^{AM*=7mSuyumZ?cPzP1@S}l%dw11KgP!=L^07S<>9=cNk zsr#YBaNLe^JA^5wV(t8)W@=Q=oefZz2nHesduxw%sed+5=+)!)OqQhHofmpNdyKun zWxHmf=jbHd%eWNP202-1<*+3G>Ts#KMe^_V&j<>D>41ZM0?MqiP5+bam4mjOI<(ILb-lR{)0a~suT zZ`<7FXK_#XygKQmr`;+h8Q)N?9Ee4FO}j$GiuX3Q$dP!~-uA4KEG+R+mgL)y-+cGY z_05;>ni;%!=-#5C&)u~pj7Vfo<#xO=TU|prS0Y(1$$uEuPAz;`;4Hf9nEg_XiM-Rm z-H|}U!}BF-?*-ky!^L{5eQLF$d+oN(xI^}$#uDL7F{*@n7e}Y~#(X<~)--CC3PpjM%Us;x_U9U;cj38!@zbP`Hwhw^@ia+5{7iiSNZUCuWNM|QVs&;G9q<5Y< zE8^p)66-XmO^>)}+*Pvn*%&KrJNPVhG07}iJuG?Oy!@>ul?%ccj zm(l{e08T|9&$-V)#^M!##=#mxhcI5+(A&07&?T=vb;pT!HFzoS@Y0isYgznqznH9+)z15os((#CzjX47ENibY{jfOT!e!hUQ!+)r?7XQ{r! zB!B-5tYLW`c3tdn=Au7L2DDkcah_vLAW69x4!Fo;o9(iMaL%-OBtHVfcxyuPAP4rTIm7>Be)0Xs_x#jfJ%5-_j~@2!eZ9#dD_~Vwt9z0LkT7bU+swp? z0YuU0_#`RxAY!$d7v!K+Sr*Nk`}Z>vGuzSAss0+kp=g{0^Q`N3`ydoW%h_3wq|4q3 zFpqaLAV6JAK_R0R=2c^Ro@VN|YEjBk{algOoy5eLK{48G2z9J_p8)LS-lfg0-G3L? zHJ}&C+G)`6&Lgt$uOI{R{^Lq}RwFa9&kpOH-W(5p_wmD5*0#)dH|~qa?%9zq8U4x( zM?bYgOB+!!Xk~E@y#=8Y2l3s5mQW6F@y67By3OO%Bzm(Ss(4HP`|>?@)KUam1;RoE z%%BUH%GvC_FgSXCnXCZFY&~e@n}3a~7~KKlRP8A$E}S;a<*oF%`fU$?cuI6KJEk^X zv1+osDYa$K`5Ak?Zq8xT>gEN&rk@nJtPR6Bd$sQR36-JZv3GO>db~#^v>z3texfP# z%lY-Z1@7My*?sXSK092B_U+FTDs{wl=Gj^Bu?FC1IIMsq4@BsC-EMQ(%YPJL7k-;F z>SSDO0=9U7zwb*ckHV_G(Ex#|NyB+LuMpP;#e|5r1;XL&uFD5}Bc~hy9lPR%Iv}Y) zGCf#mb0fv__qE359s>mj-LGuf>2Rb7r`^f{h=%e2PG)2`4zlVF`#Vi==_D~LNu!B@ zE)goeUJ7e_y}kLe^GC&~|9|r@zWd#`^9Sp`zqpg{d!?i=9=vD5=i9!k$CMW^6mUW4 z0J>dw{lzR0$#Z9`EHa)d`G-d%xn59)rQX)E&^c`O6HLH0Y*LE#s=F~Ln{zPH`SZ;vjV)64^ur#g3Jj9$&E!8a2C(&7umz}Smr??^7O`Y z1Yn?$G1!psOVA+_?^+;to5rIaEd<}9oC_a$U3*G43P+d+ffh8$XA+dt)STt?j@DSr z$6YIRh%hPq)b0-&6n{@W(8Va={+xk zUQh*xm=PE+Jtix2)4Vh6r_Bme%X$k49;r^iesxx!oQqetnOACGaji}_pob;#itN9Spg!>E3!g7<~c%t z+_-=J6B6|8uRgXs zq2xI3M3q523xDp;ZeY0g9yJ?K|57_6@2B*I0Ho~T+HPrOD|;6y9xDMS{^!uMfAuIn zo!wIJRG_Lb;R3?N!ai?B!7U8ppc)ug*UU746XtA}Y63RNO5QLoR;{w;lA2nTOn+(B z3DP3W;F#hGp3;>^# zb-%8yF~(CeSL@zb-mr$ITqy|2d!FiP@$eWRdBkqJm1@UV@Blt98zdtU>lz0EZ|KTn zTSsPnr0xIDh=w@p}fGSpVzx4%OHqLG;!-fsZT* zxP+Zcb(`1i1>u6;iHO;r+Y;g0c^ztdUUBTa$2rAwov>huN6Lry)a$GX-qwp20I-d? zNE4*KsbO~~l0G(R^v_klrNdwk<*qX1RFhL!A$bbStD%C&Y*}N5!$P5So?#sx)md_S z*?+nWrew}GJ>21b1Kzx{50t&8So z$Hn(930^#u&+dKBrK<35hSs>jZqBPFz95qkh%cI}=l$%LJ=F}()j*UD7?O0GZJFP` zx;D|(`Ud5Tt8ng8?B?!J>FZQd#ZadTaes;$>m6pf0tN?^3`v{X8L?^oT)932MLHeTO8jj*wz#EEbY&mI4*~&h*BjV|mY5ne7p$S^u@>zb z!0)=wu;JObC$Cuei>Nksf*yanE`ND+2V+7>+T$I;Pj>G0&BuA0Sby{N6W4)P59PC+ zyPaKuv@7tE+EE=WFOpM-Q}wu?&AJXrp^kxsc>q33&JM+zwO|0EhLtoY*}b-E+0!5$ zSqPADi$sJfnxe3byDcPUr`i=KpRCC3jSKFd`O(FT2lMH*Jn30ML2oFwxPN;*AGA)| ztPRXNQH+RTMcA#4wzRmMEU?S^U7G;&I*0WEkV&E+TPB4|0X`6p6%mI`tmk=l%VzCg zIW5rJJ;7I%uRmVP@8lT`+u*etHgpJNJ0@vs4|SC_JT*Sxubww(x|pJl*H9gGX3DX{ z>Fcps({N0N37)_ckI`1eg!-U+L;|IAq>9G2Utp4_4lCNKV|Mfq= zd#L>CaeQj<6tvc9OKDS>hem{PSLbG5LO;caEXK0SG`6a9FQ|Ng|C34pz{T3sp^Ms% zfpsF#kv|Ru5n)UL&X3g!j1TH=n?1un+kFZSLxB4|av@^v$?%-kgnxql0mLB3^0e;(tXGfZv)f#|4Qjt-@|Mm?$H_JzHh7w8 zZ^Z*FfO967Qp|@%W@58u)8En7Kb?GgZj_nFl51&PnA?<9* z)N{g7FApTQK2BH?jLCkgU9_o@* z4>^uFp|Uzp5EPmJYwTkM5iCFNJ*YZs`z@hJMgtB_&m$gZ_CFlA6PG-4#S|Piz(SY?VV7_X(A&+SH zIT&|slb2>UZnLIC1<6x`tdp%3+xXu zuRnb44el48J&*5G=J)DVUp;OJR0Quu*A^35gD@ouaGGS%W%v zV0Ts^xpBWpb1Tf-1(bmTp#T}2g)1p!I|5;KS2odva(^lKk)U;rm0GnG1|puv>bs|C zk7tnm=tQ^yKS+7BQyo%`f0CYpj6{ib)-!00)sLf%O%))r7%RN)isC^FEj&84Q)1Qv z*^RBPC?7zLM`?mD*kT``8zAep_Fc7Ni1s89ynEgEm;dzXi{G`c-fa?xTn_Dgy_(Na(9=qW@;X>MpUc>5Nz52E|vCU?NQmoW^J$CL4hwXn_5FH0@1AL z0fK}>%a5?MG2MWqCyzrIZ2G>ZyXFE(XP>W}0j}oo{%2gGQ;+cTY+s}M@N6z3fXYm4S@fd9B!oJ-~JzX`) z)+YvUYmnjd(LC|rw2!~MBky~q$S)qbXLYMYYrqDeF<+KZjkO3P2XO6}*>?W6pW0T0 zn=&T7pC#FH1kzFjnOlClU0rX&uvFXmTYw{JiEuv0&N4_^A}y?K50_e*_Q zIX|m0HCYNY5W;Xb$covcZ4%B<|2*_)sxZ+&a&3 zyRbjA*?*1!Ru~iH zzeC%YT~aEE#hV}|^a^1IKIuZ60|Zpz58nI?0+8sb9>5W36m@=%^*C1;nN+FK%Bf}& zGY$t_sWZ%Bz;o{VK!{Oa@y$Ww)9HNmusxm50etY1S7Xlyj*A1FE-qiLlwh*NhGf&HvBcyDeLiWY={jiiFSrNEv06L?bB) zBHv_|W#JL-5$-Zc|KeA45_M^1RyWXi&__sm)6Z&*$f|DCKKp=r+kZ$kX@#oHbM}t# z%UW}~uQg{-tF=HEN6OY@X;BAE+|Hn+dM~%<&Sr{RI<$Zk($0n<$6uQ=7=iX zvquxVm_UA<@P^S~iGLODV&hMBLp?F7~w&A#cZ6 zy{_-uVo>Tlj}1r;mW}*UBhxLlR0656L>Q>5{(4S%h5d+!bAQgooV7e>urQ&5YDP&) zHng-d+wSiFjyzu%BCoMmFAI)6hU##H_vyy<}57YZ^9;Wxx{QSeWzndTGx6k|BUptoX&2hHcL%dhPEW~TvU?Zsg6lr_W=;7|ev zRPR{Je3NdwdgwJ!HLVFEP$kl$AeMKz6?nn-eSc%&l);l{PZocM%L@)K&zIJD47)Fm`Tjl_jKx)5L#<_=W8}m5kwHF}vHB_J|MDb=8 zi!E%t=%%BsRA}#yy!Kx`%<&ft{Zy&qrK9*>5}t`yu01wCaavaukd%3xt9wllV&7_|l)axv_^9;Lj~Hv2bNXj_~Fd~ROy$>A!>P^9u^8WA_QQ`U8Fnn3~H}U-uAN3 z@hZTSx_R~(73B&1#LS!8cPG(%ZeDGIg+~sY;(p#o1(Ay9@^S=sBH zVAg)H=Gi)B2xmPz=<|z@Y@F5(FS3Z``)A*;80v0zvwaDed$u*fl^)Wk+M({poBN)& zgD-!rm0%O;GFM=DN(7~7GarkZxOE;i0Xo9zCET)balhLw^6fPTekJxXo2x2ks}k;J zS5dD5O|u>&pY4~lwztk>LOV6??x{Y{4dRfl#*i4C;Q3{ zjaVfnCkw>VGQy3nZYjbobGU`nW&s7%(vE-KGBX}kBk8`yV{G}lY$zxv3u(OPsq`$hw;7XJ^4*W?SM{f#D3+T`J@e4rWzb$n#tgS&`|AM01j@! z3SkY`FMu1F%oY#3SostN6$)p^I4gAn{AAC6i)Qa+e?hS}aQT*HIqInf=%X_e{D*(7 z1|q!m{f}~Yspb)hNV$4CsCzM_zCxvMp#F zHd-M^9taK6-bJ8Sym7O!cUPgPKXzz7PVeX6f7gC^#*1D(jPFga((FwMn^o-zPEjs# z9*bZ`bksF?XT?>LmEf-&5YXeayi9*2&;HRYMO!0}+^!yDK7b3Gj;jnNv6ATmxF{NF z>ue3crE6ZQ5LT6s9`9`1?OK@kviQaTOig=%P3%u7I$}jpSu@2&>GF;_qepC zjx_>0FP&1f)vIR(&qQTQ*~BOOc8y!rQjf(p;nsSF@&}Mm_?9OHkMa4R-}-;WANmj9 z|89PI)};CB;d}2wC=}I@z0%iotY}QjG(A!a}&v5-u3?%>P~K-2g^HQZxPJChgoqPcjvCW-L^ zc^yGbKVGDJIIYV<5063lFTPCcyKO+P9=%5}Rer8twL3utm!jFRW!U`55sCZcZ?b<) z$IOcrM-~a>FM?Z*TD`6<=RWm6+Lgo$kV#?1s&~!sSo6 z+@U^4eN);9eF$6dwcEyE!_n;+AAp5=@xE8(&G|48BYXDJ7LXxmpkNCWhj$7f4+}kQ zl}UA-%_@`B4+1=!Ge@?`nE+qObFT!T;e|IZZ4c{zALZTt?8~fvX&`x9uKMD!`^B98 zAF5h>am2F#x)J7d>|TEW3+pyP-^aNPwPnF+XTRm1H8xOvp&cxg+kMa5MYX!RcHYVY zZMQ+|en-u*yz4rw5F#h42f!|Y$kaeQtwG%<7H@hZU81LyWeHMS=*Wb zD~c}G3ZGm7XnPT^*W9fY-K|L3Gk~|4(~OIxp=CJ>Pss19L%@IZs}p?fY0HNmK*wdr z{Kmp(S3DNG{jw40!+-qztQqLlWB6WjRm!opQ|fiu8G3fR8}%MhU&2PS%X*Uvj8m#% zo%ZnF+N@25OM<~J3ISENRxBRSl&)o1%d(b)WwjrNzI|*qg36hb1;Q@ylC_z6yuMYb zQdF3OB^JyoID&sCDANN%l`FM91QkPWJ@GO3D8aslcCRxNQnv!S+{?K%KC0fl-<1~t z%#ARe3-OWPD3>KQRR}#T+{m})_hYf!fBxOmy7E^K+I#Xd8Vrad$m~6_&g@tq=Iy;s zl6cu!yc=n$&t{`oI=~&*nt9*GB(7QI;o*>Cb#~9}%T9lV3Db&eK&^r14Wa?t3cMi6 zVHt$xrp-mTB;Jpei+eh4>oMPC;_TY4EqE0j$4qwG#RNE`dEWFu$1axjio+e$Ad`V zE7=O?Nvt}(wvwH~gk<{^B+~{$OS*>cDHFu^cq!1V9c4^5xLm!}v1%rrKvn#cv=|IB zRMuvAo#`%rg1cm4N41vB%}qjTY(jES^hBh>`?>5n_~-@ns)$$$Ok)BODTxuV~z$Mn5(#m2iHy@k_c(}Pv7 zn@ymtTGbQy_k8WJ=&6KhIlSuco`AP*lk$HNYqKUzLnBhbw$-`3R3ztz{dT&RSRRi3 z*oNMrzT5sn1l(WR6!#8pSNltbYo=oiTBo+z6U0o21r6VlUyjmw zYOxgIxP<4FH2@*g+Iksd(@_u(Tp>fS`J!XdbzcRXgywUozIHx}f&JU}=K6Vje)WG~ zzBkGHwpK4e194#E=@8VQndu~~6HKgTuGj7ncKgX{aXW6y-e^Hc88*r(od_i4m4y53 z7m=*xv(u9p(pqOSDnx$8azY?W@5#Eau^!{|+^nKDZxM-r{6|oaw%y*|`_(Q1$pBRG z-)dTGIt8PH$<1pz;3@F3~r#MzY~ejK``2xn%p#0Gwmxb?$W>s~&r4 z7prjJ0Pt-j<$*7C*MlzIWj^JTWgo)3^zoZ!PKAOSRh-2sW(e z6@IB>S|A_S9NvhlD$*b3_`iF%VgAGX{LDQ1)x-I2{Y9{at)|O1T?UgKkT*d2(JtZ& ztBEfIsf2y&K?6BP?FgG{prC*CB+RYgoBeitD)*TYNI%#`xEG!*kuu4FAPy)iNCVi= zS1`w(nk&6AkN%p(l3zV^?;ahmqPmClelU2cuid+mF|MnwQSDx7#~H}&CyPk`$8IsL z+Jh2ND5zh0{!krBPs!y&8iKXpk?hzRrsy0(8F%Pj)m-z!7n zcab0A>%o&$#)h>WOV#A0Nn|24uULGPE^=>VyRQ4ts;kjI4}<$$w$CukUdoI(TZuMr zdM663^=ywguWa~G+V5bbpSSxwzm|XX$o)K{|I8WvpT1OAwCmLFwvM>;HnxStW)cPN zdC9vl>9!&Ptw)auZn%Fik1zl}x2MD5*$XJ(Zd>FJR;t&`b+fm>H&DY#l-Zj%Y1wAs zZK{pxr87M5O;5;?ZbPJKd&}JSOMyIMRq}U%!hyuN6<*HHiG38_k(XwQl&Xx$qX>3& zFrSqetXr?-*qm+SJG3{oYHZXQ?>2c!(^A)SBaWXtY5nn@_Sb)Z)CRky-#*W8XaDi3 zwc)Er^1V9co#4IOtUr`f3b)OTnM`GzuElO$yLTC^?{binNCfZ?i|e|j4y>L{k=StZ zKVV9qaZq%NBo+i-&BeoFxurKJF3_6=o*c zkl^@8jI19yJgxCwE5vzO_+LGa-7C>G?sh`+s8_bqx1=5ksbJo^?*zB$sqGwux6rNt zm^z7dtQ634;>%6~fz5uE$GUEl2)KuzmI`s6pMS*6|Lxmp{6wL1?)aBX6AAueaO$z-!pgJ7?G48woB5$Be7rCuTB1@zM2swpd>^w;Cn z-jfOb@#BwAg@|4~knb`gLZ2#fEQuqXB&pk#b=l=o8swT0f@7%RvTrA&2XhDQSc(LC zJ4?4eagac!id0Lo{#qY*P(GAkJ?>zKfPiyoh92M& zXC!|i1+tDxs?|FEGXZ)nl&LymrO^kZG2AWVM=J_n6wh7srB)D$w*%U+Ukzo#4Ou^~WFQ=ik)+)D7sxqxo*Ja2_9 z?$yR93l{E!{A1nLMB=vFlt(P58nha}{04tPbU-*+cA|r|LFM}~tnTYUf_B!6zvW*K z-CtRwmmj(JyPWi~Y^v~*y%4-$LD7oxVM+2@hh>WW>Uzoc2&V^XnhK`}Tjs zkM*zKyWM^DXucb)Stxd($NjRxQ0GCC{6T2By+eE1&;33hO;&UhYC4>y!{PE_s{?#a zj>)oO6t5lPUE2!h-T@7fZKpIp`;JhPq7`VT=IFK`vstID#gE1#z}>!X6rnIzWAQhh zFP>ne5!mEivn9O}w{zPyrh_s#w`+gptJe^A>BMeBAGn5$C*>z1pQVwHcQEcA)$UaJ z+hn)jrja-~ae&&YvqX{+`&>)AFeokK-@r_xwYhjrQe%#MShy zfr|kSAkxZe*jBa}GgXS!DD(>2Tyb~_X^+O3JG%oAxI^Om1V`TGwU-_bExLdAeAK>s ziV%Z0DaS3lC(0~)7#7Pvmba#)6@yQ|K`aQb3W}ApvOx{Ky>I*k(Rl|%UC?28Et?nK z&{^QSvQtbhTj$u|PS*8;V)@Z}yAif#`~3~s!}7?O!79R_PGHzb3s-*1f&Z&1{> zqg`nRvYS4k+FG+(w=3!72)B=o6}fNasB6x~b_3D!A^C3P0!>||?tFB5(;T*#HCwf8 zi6VA+C(8%`E1<((?b{V*bzC8x%0qdCH0n-x*UHqheEZ4N+wwd!kr#i->Ty~lC#2d* zU5rRO`2xo{5!|4ebJrQfGPb8P{HH(9@H3wD;_-XWTQRY>i3lecf9Jc|Avr@y!Iv?& zb9nzY6yPGg@B3X%d#UN(!)2uk%c%g?d*6ZZwQM6Nm^qahEdsHbc0AJI|EB-`#~+x|-`KJHd46ag zzx`_-_F3kA@i;!t?;qTPLM655xCavSmb_ynm)UMNEn-@*l)Zn=%agudi*QrBDaaeJ zbq$aT;U<(yz!CCi23d>cP>+*wtLY543u4vovTD{<_}QWcy{2@K_(v4o^yQv5<0y-l zx5}{0y*ndTG;6#;+|$>6=j|7~x8^Z>ie4_1W7mZ=f>;#`0m#BztY^*(7*afKzIs`F zhuXKJZkhjQk8FS2Qcw`}vB%_Bf0*BAQ~Khe`*}+L{HIX7=by5z-hX=8r9I?su{$v$ z=!@NDS@j~xjiww6;{>yetrj%u@Y+rxyNS@abZvS^UZcvKGm;_BvhX3~CNU3UE1(2}mIdrn^sgU8=QdDVJFH zLq#qjV7Gt8&c4`#*bx=R;t}Gms7y&vlj`+=H?nq=Z^ae(=3)qF$gfR58j3R5Yty2l zZS3~}kas{N&j?>QNW>>Y0Nf?To%4#-1r34$NQ0VL(-)aa`C?MsrO`vvSL9aIJn!BS z%X2~-9x-T|#k)S9SN)T5JVV1T9k@$zBDG-12NIKA;z_dt?Nmgmy0;1DukOHVpp`Bw=cYFfp`4gQGwb)Q@zYcPj!i%0OfdMum%OIbf+A<_Nt%#ah3J_CU zdy`WI^+C(&^M36#?6OXJ0AFqHM+F|=1;!R$C)xdRS+8NEJUJ}xjW8HPj$Npf(gtCQ ztuTKypiY8p@wi%did{*kbYG$7m712tHs(Cc<)4rGSD)qwcInf;+gA_XFD6yjnDA4j zP11ZdfVi^7N}HGvC>=yTVCo*zZz9Z?gQ1#(v`Lkyol>rN~ zCC|)fJ1g0CAB3mVHX-I-`KVzBz9+TJFTqTQLKQl%Lro$j_L35-XV^5K?n&Wfg5zTm z>pvUy_fOU9Up;KU47lN&5Wcy-c!|Vx>|Kf3mUdov*`|2kk9fIsU5wwMP^BJJ3SWO- zvjZ{qqaO$KUJGZ1o(}~ls=~0_5J2)=aBrZ<^y2Gi#=q>LH~ezevYjm6Q^m!{dm!>< zI40Z!9Gi0SvTsw`$4eY5b1(kM+V$=h3Zi))um*H;!BNkP?bM=nmV#HIKkoALTLLu`DTBz?3*O|!*{>=?Wd3HSrUEq(7olT=}T!c-;k~y zSg1VDQ5m+gK=hMG@mB4F4fP>RMbAc+EKe_-Fa0{F^4rUsivvvUiHEmN1fyvk{JL2( z$PMD$VQ;&|Lf574__P$nI?eug3K8L#2dJPp%DGV||n|H=l~NUWYFWp-m%E!~QIRlXH=l z&T=T4<{h0i739^fJzJK%L)G_YoiWo_HHs-Pe0I8RQj6{5LDY;YszQ1^ph!R?^-SQ8 z;7o#`C%P<#QXk!Z{^YOkQ>14{NG~3@_X=eei)?yxxLHvK34-A^ZH<2qk509*+muB~ z)>zdD@8ZG9^3$#wi$o{;A%;K{99x1tXa}%|`_=(cd27WJF`!+r2c-vkJfIZwP^vH1 z>v4NlRndrk+2b9MDn#*O3e=-ys%y?QoW$LD#|h5-ZGdamO($}@>daMxY}P0X`thE9#u253QTKlxl881unK%Udgtc!> zBfow0p`x8~i_4}fD@!s1 z56YF}^|(p@_228;T5Q)3UgeA*{^n^V#fwMs@$TmML&Fd2YOl5QwC@)b%9{2V6t998 zDR;i*s2cu=p`3r#Tq*iJbw|FP(A$dZ)I}$cG8FAStsCBC+8O?}#@T9Uw&sWhSDh2K zm|6^g1v1g&43k3dW1^+KY#xdLb*~?R{mOt<6?vvt8i&^Fh zD50{ncE|gv+0f|LRDrE8g?aK$43H?ZU#wOUc$|M@_Mw4&;Vny0EJWdj#+>j1pxXi* zS0SFc0yf6Rkg|VTBu+lwtAi7*FLE5*IO`+dCM)?bz`T>b=)n<40KvjN**bb zC_K`to~SN6BiC@dlr(@rIwe87#XP6ni%n#qR=YfBdt|IUcT#}>Sii_5(<`)cFk~Tk zJUZePZCNA@6Y0tk$U@#b?};6`CzdiqrXGJhFxzKoW;;@YQnX{#wwV?+6Q>%5m0?P$$BtXV9S@t_wO&RQS+1p{<~>T;|w63UU?5+r{% z_~#qv%iGZk;U*S-pqKs2d=C{=IX6!NnuRT@XWy5%@+9#`5re;(?Ze;v@aeCgYCyeu?B3HUS0J6g zueZN;FV=Z(Wbp;F2cv^q^!){XLkEA<#q%afL=S=qRz@@8=Q*?}w}^Jux+%L>Z|hxt zebiffE{%~Ct{P|Nd9N^L&QbI0H}1nZnAR43Fi9jnsGUCld)- zJEbbB|J*IH%M0-35nELHeH?$olXQY7e+=NCwhoNkVl4qc>#a@P?Zi~y3#I_;BWba` zEek)O_~fgg^7Q55dQG{haq#Fr{Q2W|zxj54`205?|L*UembJWk{2tE^_n+uY);C5I zWbHMq#v~nw&0G*b(!}vr?=m@$RLik@Y`I`$qh_L_GNJozB*o~q{Vadvfl3BA*Lj)< zE+ue427qwI3Fm-@xCm_*mlABl(^VNdPK>KkB^B)^-bXFMCT`SG00l z>T0)(u&C&0W(D!cxm>p;6v&LH+KZ+d3q)YC7z0S0BRYXX=N_gV&ET27$EcZV)+KmZ zN=M*=bC<^%CdC3;736TOJk(Ulm9oM+?2!vKT~tfN$0ukKBJ7Aw<{E=7>cfjl8JU z5bLsd&qVx?X>|Uo+}##6*dbiTW0w754F>dWdM8LvlsjE!(sER)xIg#1O zNc;ugE6*8S)2w#aloM!Mo;7W@3J}7AT9v?K??m~P+!!=onIVo7-rF~uDISHOzKFFc zgZmH6?W@P|y}5rSbX#OsN4KNeJhUC+2{8OEmUZ}OmFM1W-MiaxX0i^?Udii%kxFo| zgN(pPF7tFq>(z0wt!^L6ZNCm!XYrz%V4DVLb&_+)I3qt=zHHZo!QI8cWv)=cfl7TvjY@Z$Uay#xq_o#z#j1a(L2Leey2xLIbW1g_7#!4+ z>!wD)rjS2O_D%QmzxjKfrJv?^Km2Zf_{|TWKfcp=_v*2H*Cr39+#>))mFKWDTrSIN z6d}AUnnbe5c7=~mF%SXyS-t*rC(oMTHm!F&yWOKFyd*rZ(13rfX58G=kWrmr*a6B) zFZ+qmA11I2>8rX#Roe}$98|!nlI9N0?+Vlr41dhU=}*4p4(_v zE`!^d1_)~5<=}F8g~R>gfvA=cC9>ZhVKTgJ_oOz@nF}!#kTYN^RtMB(X-hkmsm`qB zx!u}N)jFY#y#VmsZPm-g;uC1o8DbZL6zdXfgN8DAzDNGP7USOwk8WAUp42#DJ3rn5 z{N;b!UabG5pwO#F^j(1p&;k^cQ}cSCIWU|v-DQDumpQU3 z3xNIF4KBluv!%*M-T5j*;7~TJD2`6kWGNRqE z9h9icds20N>X{h#5w3N@j#SEH)nCim0*QZh>%+A?E%!A-gmlC1j>R%R#Ca!|MawqQ(}H|rRG5IEC(B)do_7QcGT9t(@}Pp2BT z(nfc89K@HF!PTT%H14JdQQzp>Uk^VImpziD%snH_oz~C z`&Iq)sXi-NeD%ov!T~1y<%fU2{4$|usxzu3$5S0D-t6Qoz6vyR->jY2Tu0xl%I<5c zpjNi~(bw=g*-r69pgG&r{dqgmsXPE9bpi;62Zfi;Jb+R*RgXuqIMi1Q5%8I)}YNI*EqMQc0r4uJ()t}uVY?b90-^zkCQ zN6FCKyQP3thca6?NQJFJh$~cNt4g=d$L^fFpYGSsn{!@0a_?OMT?!VdfI%E*JAfY# zJ?bhejL@<1oUr^FzGHA&a(q1)7}6>sOkVT?q^gV;FK zO6mmO76z0qfQVwWZ;hXtgj5zjQ%DT6{CZQ5pS^8$1#d|r+eQK%2d(zRMt56tKD$NB zO2CxIYxiG$>5G4?Pkq8)J#_DZ-?1_C$5qY8dKnjgiDi&ZBNrP+0>JN=sVK%I#GHG| zsoKJqJu*_8l61!RT3{4*K-wxL6JtDMYvhes3gJW@$;8F`jMx5a=7^7!F#;&IezMjRKt+;B1?u4 z1=dzo(0g4I+N+NhaGYci)ZMw|SVt6#4W3Z}SxxE-3)BOF+AnpfV3Z9Qc#y?lSunMF zcqO;WR-}K{Y^uW~xClVKKLXtpY$)QJ_hBsoK#XVxL$H(vR7`}a!xlq8k;{OuTwdT$Li4POPdeFiDmG^lhRWI+Xs7<>x_$DyKnGqP0IGcVzKUAp zoA{TlHT6OBsZQn=Fhu@~T22ok@u@9~cK4HQ(!kBCF#taGh0UuIugIDw`!ai7GHt>u zC&+*F044`ZDju)!e)ai>Pd|S6>-qbq=l?Gry7z?Um6U=YmHjAtk9OY<)uTXYEQuUb zgSxSNVNfcmGK57D?E~V~bGY{X?&;)jQVZI4H%(U$)-OzL4?Vqe4M1{;Ni4)S0L-&c2hdb5953c?BV-tLwR$o;8{XMv=h3hD&*%hncL zqS)F7M`R}gNeRsP>L(bf!67|BE_H3N`co(3klC`V{WnF4V5ARgetuSz`0Am1n@Ybh znBJADARQfhfG5D@?N2+E?QVO99S}7F5kI8L5V+8;(^K}%^PW>bXIQm|uH%cSl(l~; z$EgyJb(YE1M;3{C0&hp;VQSe~suzTx4{nbPChH7*DRkwXrF!gyL{PttpX8BEFJ2b9 zf)acP%UE$0LbYBs(Yipw^d1Dl>X8x?p((SjHAAKDBpjTei`Yq5nujy5!>KMQuC<;YaDPqb?YF+;{a(M zv7U$J^tb!tuqyV1J=z|Yqtt-7Hu@C-@_}u13;H*$$94+?ypRCP>{qy3ER zGLY4wlM!D|)*SqhovM91ERyDN(-wAX#=B+Xt9g$HQktCs+SQ?sqp~Qv!dQQh!g|KS z6NZ$QN5@tjrHwTNsR3C-Kv*reWGO8Fc&t?Xw||`CPjk&r^ZPzOeEj}*_1mZAsIMN( z_ln#04)FtX-bM>r#*{tT|JM^e#=JeX$@X0Fi41~Hgtf} z`sGyRv9*JJ%a$4*gO)9eZ6M{srq(RvSG>;Nwo}WaVCzfrKq+OoP>s$MNiL~PMsOr4 zPYqx}Q-u^A8H%yRo{4{TNA}XY$4LrX(Q$%+?&sqn)1Q5`6`+6o?&+MqdhFg69WPq5 zX@Qx&7UTWNVqpW0@NK~FvsjW|#DLZ)v`ZVa`*=%1u)Ub_38NNwZ+So2`{wxBCi4dL?TQ zblU2xD}%)U9o1uCg02k`*>;^2(@B7Yx@y)ugV*7Td)r~$z5TJxfW&TvVSiI4^Dmgw zU(dg-@6YS2$M4;FP4K^wZ2v0WQEg+~-c;Ih*=>BfX~Pl{VC_hRbV6RTS~ATk-PR2FKIlx80MbEv}WpIU{L_ z6K0>c9`GKoW0!P1)-67PQ%YjSr&5@&9m)4*n9*9q4v>G^3`bsCitN3xV~7=eZu1&t z*BHh|G2lp5`C+%VFhv*BHLqzs?Enyn+uN-rz2-h+C~dFTt>byufb&I`gJauZN;il6LB<__-KR}jK4N!=` z%~v_z`c{8e=FzlOX>qYZfTPE@?`x3HHlWTvKwjJN*dy>Szud2Wxq1EF$Il<1a-kOw z;k&gHZ11F!lm#4cWs=lN;!mPK3|JTh5gv0Lt@i0ZkYI$@<9H4J|Hk=}n+EfWBSncN6R->N#jOFMKDQNAm) zJAg8%mssl2%%S%uc_riB3D6{{A9*{g!9%L$*ZYDMUlRhX?^+^CM$4nv=xmhDV}RBJ zY54I3>d(LQ#J+b{{OZAbZ&JfCi14s`;#%tQjCQd>4?V};FMEjER-*-M^3Gs{I=LTU0t1pxHf?AIh+--JY_MGC;o+_3;85jbM7^$M)y1=+5=k zBlnBDoS)P#GrM}b9mR=qtStvm7m;GEd9^(Ae5`uOcFV;rD2q-q(mu*&9m_wi zy|K)PG&d>aO2~D|`uLm25X>KunV|}R7xna%8`Qb|a#oj0-dopMEoA-P)eK^)x44t4 zQuGjOzF|4u%hkVq+UES~fqOESo?V0;zPG`$V(Gos`=)?QRqG@~93aU($GdJ4|`G<7z1|*2}}*rm}fEN>@NGD7HL+6XX()dLJRMrAE2( z(Yxkl{K{Hj!M#QgY1SlutwDS|M$4mTE%K_m9a__rtE8mzJ7ZVN;&+l5=u+O6J>JZ| zT9aDF3L(zA6D{_1=Sh;&%{x8WnC*YlZ=c@ayn5uGOr~5Nx_j#OcM+3yee}X_&Mu8m z=}joHt=1+HKiX)o-Gw*(O)*$7#_rv<=O#eTjlr~Foei^Yk6$?dZf&;`Q*oAEJCW|K zVXz(h@%X`((o(`Eo77EJ>&*<7BzSfUa&ws;%w(&t`DQ{ElVSl^R)p6ozm0!6zjc`s z%$%KlMg?@N@3F`D_MHmiUl>DCM2Fm@YIkoy$2WEzPGw_OI=n-q_Pj*R$?gj4q@6XpXmUuuotNHJc8mC8(b}u1w^Aw zO`fw`&DqFT`w?wWf!$Z$bMb#)k7r4cjzj4wIK`1{N!cPG@Kk<*pxd`glPjiLM^Aou zOXe)an%IID+3LKMhX5;rn@FVWaL@QboYQa9$)n7skzE~iKLd+>&cg~dAoW?EPNuz* z&#GEpJaSJaQ#mBvN{1q?~ShMmZ! zukjarUQ8MqMF3^eF;dhzp|E4=xEMZq{bK5hmTi4wfzC3;|hi$t_slqt=)c zw|gQJJQTYnH`L=wMW@F?bcS&P;P*=;n}cPcgfL#JveJ>;**%%x|M-8yZ=X%)tHJH z2?B@VhTChcsW_kXxo3=z94gojOwv>JKEf#2H*h+C4VWutei9XMECg7;9ud3JA3XEp zea*?+9G>9Zy7XX-z-qny2%zb!@@h5gsvCLcr!WJ|Zr^oaEuMclFdoS$#$M0}p%(X> zu~)F6Go9BWzUc|6pE_!{dD~~*(#z?1JUIGurgO}1>u^Go84#{5HF zAVQe8Ro-1C24cv~Ppu(N+luS4@%E){Kx~bX&rII;{!_>52K3%YM#+$~+ZIDa+1wNS zYX8&%)Pl14~%6__OQO9H$J?;v7FR{*c7Uq&X`ZC~j?9_`q} z<>fO0DCk=dp(fs293JiR%d4L&E5D@47`udrhWi6IE&M*%)7qY?j9xV2em0*UKmVrw z*q;HRR}bEkaLW&#QIQlD(q6z_N-s1PGLKVhPkTGYQgeThwWozcu1Y1{P4mlpe2{kv zM=K!6ri>H=cmLTSq(s6{(54Z_9@JQIE}(k3pLR%eGW*;830@1Zi>iqLnIC}PMTiPj zS>1m3qZe=i;6uq40yA^F7t-ovipOr5ecyMhrQ2l-^iY15^muMob|0-yIBC+fb4EV% zy2_@SFY$je?T@8NGL-SD{?)US`WFw}Gf+D^p@xU*i`C*i?G7G02RVy4Hf{YL*Q|GE z%jR~NUiJ2~v%ow;*X|)FtKI~61RuT#f~Owp%1OrO?Pg@u>`q$e1|(yKD!}0=B|Wmu z`|OowNK9gtDb_|Xf|e7NJM{ha#tQ~=UN!W=%L^?s#Wl0VS8q3 z4nQDcS=y6Y{gAckRTtwQ)DB&#WuhkQ;ISgfx%~XQXWR0{7v2q3Nsu_H#dzxm_vyNgGU`YWq^3DQ_JX8t0h+SKPs#HTb?|2ZWt@PFb zv6p}H8C_U82~i)(Ciw5F>h%l=TCluCv!50RNG@N7!rhd_JI`_L`{6|=F|x|7yEO~Y zybO0tphrsqpacVUs<;N^rYC~(SmZOQkF##uZ(PA+mVD&(IF)Y8`TSV#)dTlzTV^|Q zs|t&kWpCc=E$@PMTX9CX1t(->IcuDCDmj0l(QvG%POL|$vrZF6xNaA(2@DC2KZ~t{ zKencA{jmmdaqu5%>H=fxvZQm{AL+?#v+B*NA4s@8yfybzt9p&t+qLXM{CyxPGh zE{${dq2SrsVd|bQFvw|lHrbs=nuon@mol&n9`P!Hs2Y1nVVXa?kYO9M>ic;K4ESVjaA(Oi7w@;Qlg{iDj0%`{$rF*CGt(H4Z)#oJ@ zNrUV;N1N=a;j!Df9#0Oser`-mv#~Z*==Mc81ukBE7f|3(MJ%LIGV}vH+xAG#A{C~h zo_$bVQd=fsGhulz3r?d3^j0?Zt6j#v%Q|hh?nR-oG@!0mQNie#k2ilO!k@pIKRlC& zeet+Gn@Y992e}_imzCIz*7|x=R}|fYK1DJ!AAOYbuKV9Mmerwd+^Kf`NH$Vh(Go4J zJ*q9ATMBThp`+O(udU9;Ax54SM8&4e8?foP%vBa8a- zu2B%VBSQ1p2(?;bc4(=Z1C#Qdpe=e9#B?vZ3W@yQb)PAKN_qBpX^_F|D{eE-8nzhc zW?_O(aT?}T??$~{Q(Vjvlk8bJnEwqm`4>#+$M1ifpMLYhxAn(o$@A6Y_bhoHK!!{X z_fCR;RGZPeD|ml&;Ku3kaR--d&HSw@rwv)PH`ll0bZt7OS(bKLyaf^gW!OlR7-~)H zz~t$6&@1PzW`eE}kTGi~!E0}v-Y(CrZD5#ZAG{&s3`Qr~F3YN;h{J+_`^L!MX)oJUS)rJ(l@NQGQc@ ze1>XYJ#bIvlGOlFjc~AA$-BsW+0r(3ltK_u5q^LdpuG#?q-Lkb7di5fOP}I1z{A-> zac_K~t({9p?t_PlYVZP4Iyp`|Q(i%dFCLRHbSXtK-e|6q{oCI4p(f1E-4c??hiI=_ z5=7t1V()(R)CHGG1-A+G>wyGm;^s1u?g48 zV)3pqZ*za++UKD=JM;H{^;}uy#bfvEsya{R{IHxbs0!A*?#z4e1aqr3Meu$Do@LAG zPE`@rr`6J`--X*GwRT#r#1bT+kjXsRxH_D#P4$27=f)dpIPJL_%ub!e7|LAGh_*j& zO_dmX;ypFO(@j=^vO}{zE6ueyELOGFvz1DWj4WJ&(N*j4E|)~si+)3T(}xoJS{9F3 z%{9*zOl93$nxvHs3w?8;5A7W_dt$U7FT^~g{oj9E$2-CruO7T7^Er1SH1HrP=hCxv zj!l0Z?FV*RmxH zBH3|zipD>Hkm?hO?jDitwd`y*24;TNHqQk@Vo=J_58fVj!A86lQ{k7S(4qV91k_$p zaY1dO%b5W7gw_Ux5JL6Qp!j_;o0=3fm05qGv~Al+b#;1OVc5O^T~BxlLpFZ+?wPd4 zi-+!6uF_g)qR9^E9)k{Iy!LTcK>B}~ zylI%KPFTZXLd|?;(Yt`nt8Ue{T7?#<)sU0dmMr}kz00ra{j@(&cNgop={Qjn2VYhmi>(Pzs&*vFGbZEW&YYn++Ok4P_SE z^$3VmJRN0ieVk{uGJ1tPG|VC(rd~Ud3iO)J6Z%5XWB_c^o7=57-lsZ~=XHr4ET>mY z7j6y@y*oy8(N4?G0rJ!`ixPhc*~_~&#|F*txJMd||42=5E-j9##| z7~F8%ua9dMK7QN7$?CnmRwKbZLepRpd6F1Z5pIO~&04DlW?8$%E6oc3%QgbCfWDq? zlU=3gw2`;?StV5&)6~3*emqh5ij;3&J#xXzZBg=wM&0wm&dK%I$nc%5?__2Z4 z9z!id-;+W;@aA-@Tk6Mc8R|*QOq;s3ta7LvxfC!mB3O8yt+P8eoq-O~6qA{N8DL}G zBc_&pWv{COD@TgM^KO5BpMk$Dn7??y#O{P_JUdNL?&kf&+gFd@lYm>52U*?*K!i%U zPa_H$JTC&tZ%aD{F3w+P(2G9=hyB^?OvN84XBtSu+bMV8PaN^8|lvUVOr(7h^n+z1)`@ zJeNx9yULCin;a52Gr=oqa(PYlyZTbMXy23V0Cqr$zrQ6P8Va{+PqFt;Y@o+phJQf8 z=+y)Ftm^&J4Vj&M663c$_l;#?9mgO|uNux*%DvS zt_d#N)Orw-s4S}=oMmvzJh%k64LElK;(CH$U8XsDyC2VI$P=ls zA=;)iVFjler7e=4;zf)a^U9GYv5S&{ALG9JO_se>8#Rk*iqrv~p0nQ#ZOeL)!}>bj zkQX3*gsFfvZ}o_6D-c}9Wi_K37z(M$x@8g!5u0+0TFF3vHg>pPyao`yXg?A+3jyln z%e&U6m+4CzzC~OMeD!wMSG8zCkY%2icdEg=?5O%xASjeaRdhq`-~I6PEaBAy_v|bI zRM?ft86~oI2@pXh%OWq~^p3#p5c1SbmKD1@7pO!(;Wp0>mdpU^suwtF71|0wLbU@_o`+x z9^Y1w2n75V94=iV$_pth6=khJ9xdc8ROJnZ&LDB`Q%x#jml`>MhsEW*d4p|9t5<<$fC zi%lASRcAEzlgo3~( zJgnz`mmcsfHqTZ8qnaLSY=2#yJm(vUz)R>VeSEcZ`RajtR4Dpc<65H=HExckJi`^0 z`?w&&rOo3?aR*@$BkTkYvGH74&0e^ZmKW-?LI0rAHkgK0gl$2lz;GQ}Rt=tc^JHY7 zhZo85*7Q)F0^Yc39s4+;%l-l|-)6T|ATeHlUTGzj`T+AfP6Yd#lZHSH#nv;Vd%t{b zQdaS%4ODn&G}?|?^RCN7+^j_p1W0Qhw29_vR1{Oxw9G6}YNLQ!9?#?NtL*Q;tG{`6 z`T63Zd#~-f`h8VD<8A9JE5667(_I6`OFj>I-%HFMe|iU?S@0_C`D%MHdCCP^gC-|` zv$t@Xxnb%zAEA7Gc##)Hs#ld2^e5hax`X^2EDYi0B2!(MJqCf_FW3N7;C>ZXsiv z{lViZ^0hO2M8?d`_SP8YYpI5R^|-x%na-ap;@h}?!c5GdDb709fR0;>MLM@fZR1JC z{L+se&l-DNA$RX-AsNx~WmSczt!=CzLVr%sZ4j#6cZpQq*Tx`*q*efr<^eg$q@DFq zo^!4aB9$wS!s}U$H#V;ft2#2}mKV5U(M(Uz+P)^URv<1Z*WR`QPh)F>eTTk(4ZD2- zLBpJ()$o1OI5KQwW5?R}%l`nReB`b}Qd@8P0>5;T{rI%a^VMVb3rv*0U?Q)~d6HE% z*|xX)UPdZ1Sfan6?aJR-kbh)Il2tF~p@|_ZU=%x=c*fbg=62_KoV!6GpU`4m?g|5! z)DKx6cK9*7Hp3GU0>?P@t!5i8_20pg;$CF%AV&~&e^5m(#w%G-Y zsNJ>-?eSVuFVoV}9D89h;W+T_p~v1(E{iR!Ga|ej;GxqMtOd%hZ}+qt!9R&A>}HYG zfNyvMnT~WZJLj7M`ToOyci+|T$J3+SR}bAUV(#^&7rWo~>1r(0SnY*m^;Bq(V!t9T zVB1A(*DIBGj(P`LsB8tD(*OC`SVrJcB0Pzs+Myo%rTk<`HQPLLC@zwQr|WgIEujHW zmL{HSK35+GTO`Qq#3@H+v8J5Z} zP^G6G{b-Yv>%qOkQUtuE1yvUH}CM>REo#22ilYO%Ha(EMW_e8VRX%K&toninO>%g@5-U%(O9* zjJLG$yp#gdYy(W1E#U|&^rDr=EcuH+M35mYWiC%(En7glpUZlVXwxT1*vK}HKt%ik zinsHTs{F<0y5^@3?YC<^O`NYDy`LxbUpcA&+yDB1m-{#2oBc2Um%sd@KzZB&8H{1? zfW)-v)^x{mdz?X&X;`BK)!!7&TBP;e&M2rY5ZY3RvMSF#S#(MaT0)#x8E`*aMUGgN zgrDAV3`xcY{|k0RLZ?YK`+URN>Iak*#IP`D}G6@x5CpFS-bJ#88o2DfClSpCOc`^ z4`#X|RbHvb2#i;a`my8w>#CW5_29h|h^vBz!PGL@1;-U4t8SeZ=r_P18)Y8=X~yG> zppp?h!hkY2O{hSgB$aVS)++0^m9-b(DhQ>2geXeM3POx&Ei7TCn0km>Ie12$BH#Mh z2k{jZqP%+K-pj12c6WJg*QkmJRx?4I-CqtZL<)hy7Q3j&t?LDzUFf>Fw1c_s)ba8)e&n z`bl3uHjpH6yq$JV0kP_mKm%H)O;EA#o~t- zgaw|dH3HraraWw1tfNZ^nnpsJ1?^vd6j&;(DsLi{+X0K^IG_=s^mWKYHkG42LuE*h zxJTui-yGI|J*rZ#9=Ko3=l;h;dP}xn`yTk1NIL1mR+tR`Uh1C@V0t*q2xWsOun9<2 z2jM@@Fi0So+_hWsvIj3{^Q|5Ta$EMrC4S(9n+3KWfzaA-B8Q44$0YnT&pW?=?skY* zkKQ|zx@C27u9A*f1sZ4TyspKCUE`tswDKFwc=8zR4;#6xn5-*+D-y_?Z}Y&T^Jdy( z*3va5zWo1Xi%&6sS1W_PnN^&W_?GUwp2_fSJ{@cBkV^x_mAX`R!~?JC zSwgu^Z<;`3bHGdf`}oAD`!_3{R=|yT9{;0czE;s%>LSa@k;>5OfM9LF5Jwm8Z>0Budn zPEuT(Lj`RhX@G1@yFC^OYytnyrNQC^)r@GTb6eU6eZ3R<>XG|-LjT2=)1$Ecz2l=y z_J!5=vn)_%NwDX^&^Eq*JQO=^bI4m$q&{j(d|BpHuP~(mx?VQj-lGK|vk)DWFjM70 zAQNCaBR&vtyhC256?4I0<8ejFUIFPJa80#MgP=)?vp|gb@Sx;^J2$k zz0i5o{?${{SC8K>&U%9-4S$$gf;}9GMGfTIH-Na-f8dQ6##$*7rC>)h6@a34h=c~s z?k|WidnvJ(F1uC6QHC9z);Km%3nQ-{W4)3coO`ju4r~H;A*2#cJ;${C?J=i*b^W8S z9=|u4^-B+Fya0ZGwd*z91?DWVX#Y^LySiB|F-iui&ophVKE-0W)pYKmTuR)LDoPJ0 z%(%CjyS+kDcCC`{$wSH~PLHz~(7La#9MdISt>n4%c-;H-K;Ksn+{3j@_~wsMIKtoN zmEmll4-(PPE@8CA7f=1m+5Nh#*~Gl7t_%oiaAJRUz0@2^sffmsIkoPww4e&LdYAQ&uk`0+foTSoP;`X(CI-M z=o9Y!cuoHGXk5Q~;NAgDy3!sgdxp~vOS8z-y7Q5L)O6h-JE(G%wCsjwtcod5)_ba-(!&*DzK-G z=<3#gay8ElmB0=gK*#cv$MUj&`u+UdXSwv%qxSP;{@?%E?>>I|@wfHc|M^h!9NfsV z_iPvz1edd|@#J$Z;2?jZ;DCN(6@t;qNm!g)IJOL=0CL)D4yFsb;G}Sf#sY*R+$}$S zYEO3FCn#*S^ET3feDCD2cJU7X;Y({yB2fH)1lNLPA0EU`g4U9VtM&ucJ{s7ub=}NP zK07eayncqs6afrMNgZD8hf;ftn+B_s;xOo#05CzK}b1V zmZ`Ky{jNXxvdW&F%Di~ozJjHdPoVK>in#l2EA`k8 zkJn}AU-X{cE-J9|wJRwwhjzoYpJ$%k3tx8U4E#q>sh`x(*45h7QoPBeKZ00~M9J*x z<|_^d%27}_EuarcksPNLxrSKKHI_yn)>#q5hM+IqCPwFgj2&Xwx@~Uvut8ANHcvSmxt@_1UjJk(z$|@La#~)kF7>b#;aO&GAk6sT>j3*K>h| zt*&9Qj*IM@>&)k7o9DGR56z-Lls}27O=$Mf8{7hbm;o)7C{0w^r|@Hv8)^rU=nZyw zM>;Iw22AiSwvoo`w9dH$dXN5iISYYp6X5B^Y6K?Va;Qtu6LN)m3S={XIIK6aVZsX! z8x~h)hZ7p$w(!jRT5gSlLPlVFEbIUL zyy%Bq;Jdd#U!!6xL&d!$5!tUD3Rml+EKsGHZ_rz>3w>IEOGvpA2R{_Ho^! zh1)#&!bIx&8Pxy#Kl}Bpi=~tOe`LcH3D%?wEAyJx!g}d%62cCYr zi1w%c9`(Ne_bPeRwyM=VswRiWa-lyJdVTo()Vt%=Blq*-`oI2>Ew1yA!Vc}WKxpcz z!OJe5J*`Q94!<;6ncDKPK@}*t0#8=TZMfNC}_rf ztXt0G_HZc|=%|d#3QYjWuz>7M0E0AMg*0w!*8zNJ$51P?QvcY~a}eJL{KcM>b}!qh9Q<^YE0xgitP((RutU&CTw5g{-q)0PF3&@6|@m5qLr> z&!h@}5P`iFDYPRKWMT%>FMXZK7M;(S0{k-rft2ma!e(y~x2)sg&@_An;ua4{Gz;At zN!}OEz|RkLc=Huqrycwe^3Qh;|Nc*ZtlxkBvG%|Ixti(=#{X#+pV?`?cpQITY5&h3 zSK5l(D12-^V%`==3vRTt+K&>Ko}Kxq>$K;8?*RU>C3a8!VZIRaqIa2&X-&mbEhH7k z(0-RK0)?_!s;Rh;TPT$+ukI}zd?(`CCTd0QfB3_3`SzjBAL}>gPs(5uznw>yf8XbLec0|U%iDB-$fKjreof6I08a7ZkH}FIR;N?6FT+rO zrPEIuo(b@I#$@XK1UpxTy zvlRF(pzK+A1}OZv6)iP8NGZaaga_hL`ung=xqV58AMc@}qeT z$9sZ$HSPL-hp(S%(MXj4+DPSWnPPc=Q&ISbZS~l!$>SD2WobsmVmT!d4wpvpyo7B4 z>mi4pIDUH@_TR1j{p(-tto@yr?Jq+aaZd95)>T4u2C=-7Js{oldQH#Ea(q|)o?u4~ zq18)9!cw&vGzN{l({)b^;+-ZJzv@1^_8%{9%0gM&oSi(tx6bu@iDy!Jg#t7nJfysFED z-B>vsVQK?O;v|Kz(|H$8-;>i9zv8W&#*Hr+@;I%-havZuUKAg8|CUpKm0D{AH=x4L z=Bod`xoow{%Bw)uN&j^Zi%>AwkF$0vL6hYHq)si*=A%4NO=r}C`B+-)~RlPwaSQWHoU&9O12tDU?c6eoyPaPT05TIp4tk#jNhlbWNQx? zw)2s+sdakZK3wppC2mJnFIVpTw$SF{RwQuXOST**1c_#Xz1G)a7melT=0h zhV7UglwuEODmphl5rzpi$>+~{2!HqA|MU9a30(hw8|?R9y}t}%zs3ej|B(OhAl8x} zG+XBXrX_tosbi6U0MPldFe!!*#xC9i*bREusz!jl(o;e?!1LdNePv8Tds;7c@TRc9!<#KZRG5b~i1ssN%`}{m zt~TiK&W@I_Wg>__dYMncO2fV}$7r61YBHgJBqC&lcB;o1>X}wESBU=) z*#A%afBV;e{HOKj2C_fye;$AQ&wu~V`;Y%T{&D@at@b-F=`qmQQM8%&;5 z3@wEy$G`_s=j6`zs1w(oA61c1of3zmbM4d30>Gm`Uv!}b%(H@TAwSS* zEumt694Bl{Tew&iCI<2)`UugHZO1}y%)e5QIJ?&}-bdw?R&`;C`02pLZ z#IoFgH&3T-y;p>a5RSm^1dgZZmZZyXuK>*%k#{D4 zs(@Gk%4}4T1QbJ-{KrZ&QVO8{E@ z?vgd33-8Nogy&SkUe{<8s&Sq$PqP)OpE>}U*6g=8`^!$Xt>#X9-J!=?YCmdf{5P>n zkG^8NoL=m2i|+wC@8)fIRzf@W7}fzwvRk2Z_332wIqGP_Xj%TME9)-ZHc0|z_7t@$ zYMt#R<{$W+|B7-l{rLvzyE+4ZJMS&T{%y^hybc+gyJ&hlW_HwrJ+V0_K}p%L#1Tgk ztv7+XSb=uHI1>Em<;1ZCKHjc_(ER%+65t~_L|MJ-Ms6ZogWcEp!JXJqh%#A5v3{#f z^gqpi`^LZ5#VKs|?nYL#3Il0Z2 zoUO)(Qtk;xdf0W^JF<7062R807SQe3iPqcBZzQ4etC#hWwm8GQFF!b{f8|f-{|d~w zjW2#$SC{r@od0LHigd9wQ5{^&xzqUV3bTjSc$a96)*)Se81~?0^%gjsej*}=3f`tZ z29fkUixdypUX?S-N8=NJ$FIDPB#11)A?6Q9dLe_}9&}~BX8Ub_*x%T#*zdi1f8}cb zbbV`!21|NCD9!%tIQU^N2lM46S)x>Pc=ZV2(ZpgeOC3FR3Oo%b;q}C_r1Z3GBc3|L zFaJ=BvZSO1p?Ku5hV^migfm}}4SD{2D|UJ0|NMXc4}bSR{)y#(+UtMafBM5e{j0g) zPydVG`FHM<{52kdZP)F^0wT}gn5zkxXwKV2+}l~YlI4--!>LlN zO)aegni=c@zItM(=%sBq4v9qh#dxbb>mjZYs@QA94c=CN4Ro)P~2h@exEA_>DK67qMS$SHH zW|xmSw!OB*)$xUqTm>HLc>sbvfbNcM)gRzJR~DiH6f@wD1Xa8WhUSqtcO;6C`uKzS zfXO&1^Cc~RjdYi4sIWm0Y18q}YO^@81#G|`VV!{HthPF{#Obsj8EtyJztwx-g=`F< zdR0(mm+qZK21C3{&#oXM%l4-`m-4OANZkTO=)?;{NR=cUIkG!hRmxBPF0!W!w;!{-*>#rA#^4Iw36!GDIuqSlZyz>}fR?SmtUWuB#)ofh6Oo)={q*mc3QPdNyr}fCNzXg!k0< zyV3}MoNlO51$5;*ZVwFmH6Gy^3i#Jhs+|set)Y-Zu;KsRDVXNjeXkcw`gA!iIZ6bp z9nO4L{Sp`;6;;II8qZfP10kbYc)T(4B2D4MLEul{yC!?AaxMr$X{7rI+h;rrMxo;| zVV!>^+OI<5PdgsSB)`#@e%o@~_wmz0%C zC}k-YU&@k0@4&Tgj)>aR)wcj3o<<)25}=Sn73K>#hL(`dh`Of*mcL!AQH95UmJQ)* z1yBCrZh@Gk*ym>oH(!$*Los+28?HhI=K)470J7-i+>!lC`13@NZ91`<130Yw!hSzq z2HLy7F-|B=Ii&=CgcQfe4z2WAxP!b)qZ^NM=L3oD$$s?%D^t3wK1Be+NftBiGxoo(*d2mf=Z>${81%+l2v)v#Al>PCl4<}@QbjOW*0a5Wc zQ|n)~egMcC7qYwr!$Fz^Q}UV5)O3JF4jj@!Fe6|k`*$7y#hL`Mp>_&?Wp&5g;`FOsZ61N;?*HiIxXIGYnyNO|Iq@hi7reBqD!*p=<2-5Qd@9;Z=sIkIhDhMk(l{!jJt@izfn&YE+iJ#9?#q zk4^eIKt_D?5!h`cbJEcUnFX@ae!WB{S3~xl-cA6VU5ej;0G~d7SNCNFnLu{}AMdnx zV+(s3R_cNz@n}WiPy7D(E70g*E%JGxZQ4SBePoQ==*ZH2P==v@cqGVS?}xCc#10=B zmQb_OoGd!0FKC;U?8r|x*}uFAN7!PEkaXtariRo)Ah$O};Jc{HM{4Q2j>UX%sO0gA zB1m#?S^$P5M|k&tg3ePmbDHmTDB4zkUG2O(^3S8{1Wd9 z4@*eT*2f92ljvxFpjL4@&J6xb3n&Q{AeIA+)J5pVg-SkLK%O&61v!A}l4?pE2}ojE zY-9cVputT+%XjRT!$8C?qnlr~yCN(sf8w(7dXuYOC-jHS?rhl__*&s&1;UnO%ZEyu zZ`D-Il-^7=@NvHlo4h@5w))2+sj$M=QwfYm0pE@s??Bgo;)k8X_XkzXRj!sY;WQXv z-s`lI*{g51NrGPl`Mu38h6+d2Y!Zw%@l}4J0Xoj|5+K>7j%VAb9K11PKa-o%{;^-b z&3phS_Bu$X8jSh#DjV%u16TFA+W^;qWtEgAf%3P4jdj_UI+#x9kGm6?3uNr<&vRQB z>;%gmGk&yxzB5Y>YMOodn|uej$mTaI3qckQ<;ylc@Ix!7wU}t^O@5RuQP& zdja8X%gCXOX&C{`2QAA53iPPVV8H1F*pW5Av8{H0z1nv07WMR=h33WE4W;=UTi?%( z3&Gz86(8zU5dEh_@Tr=IJ0}N_0_Ckth~>BOm0Y0Asn_?ZR3cCdK)vuJ#dM{L&g8>0 z35;DA;9=Ogqtjc3bzP>}ZmO_r7;{g=dA@B0HH8t$7tZ$__LbiQmZiz#cK$Cyi3(wx z`~vNNB>TPhDyV3PGaUo^#C!yBzZe_{3d@E}mRhU+;EKcOr=2v1D*AS1RboU<;GSjY zG9<|oG|<)YoeI9-+j1UL;0#ROBKO2g>CatqIQDgsuod5dzR#kyAi%*JAwtji?tYL- zm#YF`!#|sL>Ymc0I!}%ilyXc{f`DY24Ezj#4h$>yh%zBk0D2B{_kw8%OBI?S-LMX1 z;U^6xD>%c#u02?`=6EHrZmE{KR69?EeGsC8xIpF}r&2{zEd#bshyEp30r0QCM`&2L~B3g1dSr0CpRCs>wjw9NFYKib5I3hex79f^-u0ivE zojnH+c}NUn4<~vZtMkrrx*b8WkQ*fl`BiWso$Bo(&o$hpS@Qq#=7^{ScxxcBQQk&w z8&>9tJoAtKA>EunnOs@WUJ zR6rRHBk|xNL_{z$90g#Xw+MPTcEYhIhSU+rYylhwe}4H+g@g$evQaSQKxo{%<~P00 z$(oyBVC<3O+|M&7Dc5Q7D;`By)k@&v^)72l$^(E$195f?01D$-;1mB;F?z zK2}jp5oBx?45o7wvE)ph?{r{)Gnsd6*6rJh0kRCd8_Ca?fQo<5w4O8gO2BCF!ppgK z$O)7JDa#j&ivmFPwOOGj!hLMQmK;#z5EFU$P^L|m<%Es zEAQ!OpjK^apRgC_g|9~i3r8e}QiF0T@d|L`5pJ`r{B8Epm7Y=t?C9HnJT>8CjR89r zYrwLy;xFonnx+brz#}JS>sO-9VhbGlW1{;h%+(Y@bKx(1%`8_X2eT;7ViQG(pX}@k z73ZIC?*_MA;eCtzA;WH>lVYSsPz(oUsMa;vSsEkA9-*?z1dN(&mShR`Sw#M?!wcg# z6X`B*iv!$d_?JT(#>*GzYo<7yEUWryS%>Cx9e#OuK@t2+IVBqj*u+=!{7phMyN4J7 zf&w5`M@)fJZ)7O|WMtB${1z!ybAre62zb_+NDd!+BSbby^v0ck?>#;LDm!s#2tFnA zs}c*M&4EdlCyMh90F`72Jev6B{6vdRY~J(+*omGpe4c4Ow4lI`3-{q<6SnWvX!AW`M72={1+bJoW=R(v+*n0 zy@0hqvUqKLdy9KPGvbFM(D}<{?@v4LQ`S%|Sd&ZjAmA*}3j4-Er%gXGCGwIg5_JpN zA@^`AAiyCGr2ZZ@ILGKTN9e3Af-fD=BRv-W?IO{G)`Fma3{CgaF-rPA2X2$Wr`j6Y zmXR?O?~(!QQ>4JQ%X}DeKR~Nk4ukxE-cZjDQ3qr-ohfaz3trAU*%|@j3gp$X)l|_l zLnG4fvw1mww?DNl7P^7z;L=d&W|i6T4%tzL-+EhUw$#`6gR{-mNSiNE+iY)9tPlVc&5P+)j(4(#f-_M?JsErM{ zJW#X3U4eO@9tI(BD*2h8Hw7ejJ}3BuPY-i8EKL&58Q#yoe1i_zFa&h3O|vcMU-ot# zth`_LZjxCSZxdK1Z?3vG?ycCIsazd|j8J1aXKD(683gwB1$qAr7zc5HT}0xpa+)P* z`&MqH79R3WEA7Q9sP9|Wl2>i5%s&VH!Y2UgmrX@hs$bsc5MPD;0h&``e_76nY%cXI zAvHYIZRUIj6y6jAG6pB~&PLD?uuKiyb?;_}57vSw=i!8J)1S%fJZ8bqszoExI&yq( z+*o6OSv2t!fH+s*C0;kv9$iNP9VVbW zuOmvP+(=Y(WSeiXR47y<^aL+plPX@W!T^`s*99S%Pg88gi_hR_fkRRf#}EnNY63js z0@!5axi8C_QQe9IU+2jZFA36M&nssK+ZaxN<~{Z$lE}y>JS7iChTsoKfgqCciJJI= zL@r(lG5`h18z4}u2Y%jd-p}lC3yA=b|OR`C1j=1W{w{AU_w*jak!u1j}<( zUPO>BLg{9e-WgB68B5F?w@9dQHc~Yj^(g?wbvm5PI_p60%_=8KEikQKfQmdcD_<4n z9Ni{$SbZSh!^*8Ibg=X$aCyIAz3#bxB$I!S@3TbS=2KoR-16jO#0I~wM6@^OlFz#m zlB8s)jqFp`gcA)o1jxQu_+D>UwL2)qt1gm6Sb`n?6#84dL4xFi7bW*yL%<={<{i3v zW~9VQgld3)ZJ?L*nh-!leA!kc3rBYyP;!d3n6RSXvLgq@;f85{%K1nu zUNAXLN@S{_;^+0E_vCg*1R-jiRe*~ib+BBi@Qga$5iK8&ae(J(8WbJ-CH|;G0HVKp zq!XobT3#)IS;$&rlcV0yb&TL7OeK;5)I4q9UWW6g>=_QQK0e2|pr>kL`;P9VE{_6b zwyaXEf!Hzv2~1Mm`n?Xe@6}cg^&`+x{__nF9KWs zu`TejY_rQXb@JJ`5wTqf1I3efJSwYa>0UhTVEbS9)V zJMRf)y|Uoe&|hBC`&NQfAnlPTbnO9bcPFZwJ|S_1eF>gc$%z1wao~R$UgF@yf-wl-HCndt!V$GCU8cf3Ta*o zNWjU_wio=U05g&8d#;e*1-RJFJSWx-kNhOG~9I)f2uOBd>ho(xg62@>)&Taiz(x}jX1{tDz<8NCopZ=@T zK9Cs*?*-$Si@IqsLT=#_Q@I>A!AG*=481||c(~6ap;OBOl-vm!Y;v};RfqBf^Re<; z?urIEIs4t+(jZu%use7x^mF=C1{I(*mF%vI|*>GDcS?q4%dN##B`N0V65M#T-j#75lX}pQ2a_FcuPi8yV{2Cy??x*pOYx{*;M-@b7^rZLfh&TG)K-+*V~Q zuAfYKRD|JtvE})7UTS!$=jgPj6fGy?H$i2YhA~YOkaK4tnjTBCNSLbiV>Y9F%5Q5At-f|QHD8*}P z@MF*x&1Tbocfnu|SdwjWuRbE7YO9N~NRVDezOEfi6Y7*?zn0`Whsa^DV+A7HMRz-T zvTvhh%CZ7j`qpCRNWU#TcT%tSF1m^2VUv)0tDP;t3XvDB-8PsV+yLzRavJYv%-(jn z^n3w;#400lXhG@q8LD)W38RP)9QA8Ff-?WrOMwD^;4vQCgCmzDXcFCe*NY%^FEEut z>ruOc*H&RDE#S4}^?aPQsSg%R1vs!Z5%H!$O$6V~IpN7s1RhPGkr!8_YHM%zQ04?w zQKg7uN-7~)WF=ZY9!ASdDBJENqMthtyU#YrciR*8c}K}=z~JN^1l6d=6DWgp!l8uL zkTpqvNnK;Mr`kFN=qL5q;0(HpWZqjOBsITY-m#UPv0;z#Sy(5Cq({{AW@yqRx!oh!mv?PO$j*jQf93F+%@g@ z^D^wYZ62(j>P(gkp`)KIc5LKk!OFN&EJ+@JrC>)=4E*uFR^(}T-J^063KU&S2goRk zbZ^>%?clKX{D1=p+%HszuV*5^7d>E9b_$Pv>_e;0cE2pKAV?))^7kaQa=KOPC#)fM)r z#BbBszEBb1PwpVJrD-1@cUV%XdSeS-o$q-T(TmOEa#UxMf5^`nDmdkp^e z!4YJ-x5MG+-%aTCMDWIZtMxiuLUsdSs?PFG;E#nCUK!BS^_&9tII6vjD#?0(m{%#9 ziP#=96htR9tBjqzunBq$rD3zKqKfbYc-RDp7~QW-=WR(aKx<&zR9@j9f}r5ppy{DB zPlHtGoqfgpzlXEwL^*uowQ5rwZBXBv<9MPKeP#0`d@KcjMmo5ndw__fsVd0a`T&g2 z=7`G4*dn@m3qzbMcK){PDE>VrTC|cBoMqu zh|E@vDk^X5>i*z)6z1prageta)UWOeIq3S^s%V}Qzkp*6*V;Jx53a)8syxotb#Y>}3}!PYwOpfxuCyYw|j4dvd% z7d4ZY_l(wWz%scX{f@)AUl~Y{8{0zk)TuYx>s)bvdTh4Q^Z;zDln)WY z4_+-PYqzF?Yyb}~HasxjThF8>ri4S!dgHD@`Xe&D_a>Sbt3e4STPkj7O3N6=`w?eI zsU5O#n?sX^=WJfK1|d;L8)BA%;z0+f6@|JsLOYlAm2Q&G+X!YW3t!@xU&8?3amXPX zr8pxFw*v^l6Ct{PuYY>4yUwRX8QWp%Wc=#$`jG}x;9DAp0mA^KQwHSTnsWz+Y*Tb} z)&k10^x-DV0|#_%85|kT0P7sc$)xt-z$0hUYBZm4v%utIA|6?zc_IcRk2M4`1C$Ej z=W+6p;B7Po2oLCcc4m^#`q+VNN0}tb0TaGp2SxK%1Y4GWK>1-SKMq^&p$TPiv5gJ|&$`c6YW3i~^HWd|xmjHo_y>#pc zAjxY(^30EaBulIv?93#7_7eJ!OO0SL#q??ag}g^G0K^ZhtSIR@aQ6&nCyX zYe!HfFy~tw&^8Pb=?Ahr7AK&g{Lt~d$8Xw4o(hx3V>~oxw8L$ zrw6E;l6Bn?bYuU#X)54Tt8yf?&NuDEdW##j|J-h{7$0`>E$Xv6kYB=#rq+gBn#vA~&s zhx0*yBvmqZ@+Y54kyZ+}`ozTlO@`n}^(Ek6UdkA-t&wwLXW&jdr7Q2S{M#EEi2;!MD z!MFG_XIYiPY6FHhO}5!W0r_M}cv`_f5&Gb4bb$$fY~*{zk-E~ru-qy-TF{`ZI9$l~ zM1o_}EU<0`&mYogvoZ-d?`%n+1d#;hTyB3t-LgQ-w!~ARlSYmUqRCl;|2q;%9+Rnm z0L8tf(I)&Zcy zA)j~Mvbh$U^{&wRR+yFqct^NjYZGV$E#r@(#$h&q*~3I8>V>f1EW&*D#Ai>u;+Yl} zmuZpjb-eXopT1!Fqkf^0Px(};ubPGIyPh-s8joP-%9|hse24emO3GcL{XzME{;c$o z3`y}dj#V-aRfo`)`C`dJ2s1Y<*GJzPH3+$-;&kJJnAC?Q+p`L6Q(bv_ZbXI4 z`xBG3Wef|2ju8T#RL*t$)#er}_qK1rF$?c!$zR`)k4Oc`(ZK~w%)068vUL-hf0e&$ zLzo#S$oyUXzCAGn( zM3g;vn@a#}A0&XS1xqbjD?VL~3Tr60b3FCK?(!P}OZg~#_N40AVtJuWP*+~e!;0cqWiDK$BCi~#FIpt$~U zFkT*4#bZ0On-Z})c5Y~@U8P!B0Uz1c2y;w76?ypvIK}*JFJYFYuiXyh zT6HM$${{zge;=F44>9Drf59vc*b}3Yp58n-X~2(X(M_8GNNC}`{>)${oLcAd_xh&vTi*)BR$AOc`p|~XI?q9U6@or{;ziyN}jZ#?>M<7Z0luYr_cwd zTz1H}|BUbL@)zX<4Hd6N@C20i2JAWxC5QBVLk>~2e~H&%?dSVztU~{Qig0HGkfL<) z<9~rJmp4XmEI2<0Z@kW660l%P7L&;+PzvD52-&O`K!!@Oe?OtyKcCqmiv7g)6njqE zy}R?iA=w|c-+Ja@P3O;Wf>&+>=6yriAi6smd*uVR_s{pny-MLsA?o!Q9qk7ODYWGs z+R!|boY&-fZOag z+9+kiiYYi>ZiCq`unMcgph+o?BSb(75QlGgm5lW)WY>ei)f=DM1;fHlBjmr=YVG4s ziO4=&Rx+AEIE7hnlr%cT2P0|Dg2$aow(DZ*hIEXUf492)=G%&G>v&G*+CQv*`#o4J zP{sotgo0W&zG#MZ8rR>nSexr~b zvjl?q|}yUozBIr5uhg&*;Npz@CI^X3O2A|N5qKVF!5&!Z0a z(vTzE8@IwDI{M4=Dtvu`ms1XJN={8Yu2TE>e>0=oxn&^B+sfoXp0*=2Z9W=Zerl7K z7*+Lo2w8qg;zLv+gSerzul1Fv&|6TU1VHt3*JM-aXK|PlQj}TRU)3#+ES4QSc527z zZ0{Kf<53mraJNT@jkPW8dF!UP za09?4#j~~MaA<;+eU|2QTCRIjxbLJ>zAY5QUSMIig@i;HdF?Q(&fj@sV{{BEP{a+X zFVWeGThyv*(7s9;*sLyo_qL_RpfJIViXmGT0Zj5Qu%Y3(k?*{$q<-HAA(>6>4#-|j zJf?zp29v6;X(>}tooLhVcY#~Je~ipadi8?NST{4J4n*O|L!`Y>ii*%&4P&bT8Xb^? ztt^teZT5o&#P5CI^EPW^3-GFid{YXUPJ36vBqjlhlGd(pG+Xb(XZU`zTD z+BxWcZOzBK?2OL**JR0iY4ctiu!e)-jn)a#<{{wGCf_Nq#3MPa6xB()e_|0}UYN8p zO>qG$Ct)bYrBldp`F@R6$d)zH`}%0r}~^D0du^prlIxHU7|&|q04KBk5w@xvmy{@ zn+L0{6yNp{Y-nSVHAICCeSDB$QM|kkHfkcprzL?A5=fn_C=r1FBN_4t?kLd2uB!8x zYEpWZNnQ@PDLjEtMka!Vn%AWsmP`QrMHCE3h+9m{j6ulspyh^ z(ED*j#!6f{+H6KYIVXih?|QcN0DIMKs}`F}*f3vna$$OTUD+hWX2&E{{7=u1(tCES z5%yDWM-OMa3C5r}F&^)a2-C_egKN~+02i>j^Xe`@w(_{6e-*`Up7&MQ6@ILJym!Uq z(xY@qP6h5WbzK^bPgu{xdEsOb3|g1{X9pna#g5erZOe*Y5q7h0bJiJ(~?yR zb30Df3zG4AwxpX`y!x6qv81gG#q}7w1yq8dKWn_lKmxdI67%R@andWE1vvy zNSPvGqw3B6xCTwpKE70SG2RcN?JcOk@2t^Kf5^P9WN6jx%!q0I)xF^@i?dx? z$h`JnUFPtTEIEj&267=8BCM=5HSk29pQh<^u!+yC&5rN2 z5o*b`S1`chNKlU|n~4-%4{pbNtj~9+p5f#iuqbO|ne;AoIEr0;>FEh#Vq%ukUJhvJ z@A84Ee@dO*!rdfy+mx=Z$+F?+Tnr3@PD8g^0di-A<$pj-LR{4uY>C+jy1T=NC zkvIAsdew*uZu4ub!ky8FmRwDgTB}{s4g=V*fAbNa)3{=vt_*lWv&dm8>~{hkJ`s!h zoRC>kPf%<4VKKY~wQGQLV+u-LL6$ed!)kH@!x6t>$6b!U#v`!83K4)6h^d6Sqzj&z z#R-b&`P?phNh+dpyi|&_ItuPikNVgoW`ZP$w-a{@yhg9N2V7|Myd5c=;5)j`woxvIW>Nycgn87 z(p!N>C{$gf#-l4D(G_1F8aCeUxp%>r zh}lO8zLdSKFijD|izd-3R}wIG1$#h!!7~6%c#M}}1wb&n3Mn0aW=R*+Kr0o7jn91?17)(OlglHFv?79jThPiBZ%<6Gxe#0jDT9lsvh<0;t@3#5C~v5LBv`*`Z4KAM&4DMJ2;qMdvaKhf9R?-5E%uk zF!>tV0B5^PzZU=kMG2q!;1YTpSnV|5QjL5o_g7O!L6+>^=8r&BHS^-?fPGryol%wc zg&Bbts|;a=4;c1vVBYuI{CK0thd*El9gepBO-osbO?WmGiBMo39=Zrql(jGCD(@uW zP-|I1U}7Bj$3PhCKHh0Ue-%{NbgboR3aaI$snI!0K@Nhw4H|E^O#l-4sfBqQD^?=$ zx#sRwb?|J7ho2HO9;t#V&@OwI#mu)A`&jFo#TI241#hvf@~L)cpDd6uv-}}hTH6*R z`B63mb$(J*Nx}92P*Mm)lSl+=Y6ocgXo;=f-o{LhQ`^lz$L|idf2ci4b-lN`3LLpF zLVN+IPQ&u6FXv5Hhtd~lP6D#2Rx)V4sXo75Tny5&9H2)nW9j0^e4J`&sE$_tlIf_vqqE#IOgF z9sF$$`|H+QasW1kfBJ|p_v`!Elx}Blu%#`Gatt4mc1m>+E;JAJ>RHrO?WL>N5$`#h zO#|k3| zVJ$i0po-N{F;DYJJ6`WCOS?eME+{8-!RXD==m`x`9N&ure>O9z3S`E?9dT4s1t0qG z)m~MKS%e7*2z_iK!u#N; zk@2>+fDTM^j)n@5QNge3ppP@?Td#&bZL8)ia=^dM$^F#YAx5>U7JNNO$S+Vn9-DOR z#D^1@V5VRff4LxaUr`j2LOV&isY27#!t}7=2zmKHhPx8fittT)e+fD;lL^6e$ns9! zuM;(gfO_zCtgYpvBq@Yn>6GE{6|eDv3*WNH$`B}Uuwt|}CEbf2fMNI)1k`gIxT}U( zv_TlMV=qtQ5Ie~*_3hDQNLWC+3osl4U+%By7}!aaf7ZO!`J`i4c~wgh(vk=_PMB7^ z0LgC|(%yJ=XgSC);)p#aVPRZ~)fXf56~HHffpS76 ze?5~o=72Wy+SelFI^H=%yAOHzXt!QeRu<>{bqhoEK`eGVy5$LVCRdDkg0bWU$2arH8LpZyt zB!K3(4q2#_B=hHKNQG+hsoi%0NpM{HSzgEzl*nRZ+Wa@&ZosZ!5>U!ec6u*>f6YI{ z&h=UjOCO}o64|4GqWWyhAyR!^x)l(|Az377y8|(O>4p5+Q)(NM8dh+M8oUVr6OkUr zbRHW9;hif717c$*6W+5Z1S#<5jOjC_*4qqWK z>~y<1cWAe0z>3sii_AMp0gP-y({gsW_%Eljb*tF_Ka#ejIXLY(#Of* zvS+dZHFy8&RBFqs8o(4NE`EG9>!b>-fSJjwalnDTms6hILe^ww`92FHg zKb4X$l?i-id)q!v#mhlbsn~8<@6Lw<)59Qg@>JmOT@J)^*ldV2E&$L}(jkm#ZK3bd zPqnM46#aDQZ1%o!**OWb=kmP7x}&|Aw4Q3L~G|CF?_lS;`l ztDvvNB?lv%d$UiAPj(Y7RD81aIVZ$;&eZEr5sWi+;@5YlN_XXv^Obg(UO|kcE@x59 znAL|>N~2g6h#|=6(RKsw`S3!$+sl;z%<8R@ct}#PxIKZ9TQ!bPf6eezc!;d~SS0%p ztW=F2wyX}o-Ooi&(D05EtIme7wE|Vh-X%{Nk`6C6F9@gp%fntW5$&Q7u{5N&|~%mmP8zM|agWaS!p8LI;2fY-jo7We*C_e9mgCOYf5{Nanb=}@{onow*?SN+^wMkvO3z;<^#ep z8IUz5Q)=1=e;nAmD*Hr8-%elVNxXGCl5%v;BV4}K{tTm;kDI9A*TWW!@huGJ;^CF1ue{4mM3jmdbQW7`3|bMaguF? zva>PN?jY_sh)?RMOAAToR20GghSFD#e|%SM7O3Rve}Tlh+gNWlUQMDNm+M8ow`@}@ zsNpDxL3VptDEk}UC3`(TiX>3|CpC!dS3eb`SrhMhLGi&pg;E3u>b@;b=BwEzrxIBF zsEi}uRKo-^XV33<#80}t0@d%@}U<4=cN?O|%SB=S1HYMI(1rIMgo z1&sczf6qZtb>CIonab!nQ%d~GJn=UP0&K#TEJ#*Yg@^JI3S_b#Rj@!`hw~G*ip^Re zfu=Yv>Ucu&n?l@d5jo}iEiX8~WzUk(RJ_^dzT`^{$64oS1NtpJKc ze;scHc}=gXyq|!A+R;6eZ8`wn*CI)C#%Sn3ASF-*{YRbV+0~oNq-K+Pc24d(r#Rs- zt3(YxtBl>Y$M~o(&D(*(RCa?POB#RX((cXPQo#;7Z;{hZ&fMTOLscohi;Bv{i!Qwk z!jFB2U7s*1*dH*$UPbR~N(vg_I!^H_f2_l@Ji3lWrC+A)35^8)yeewlNsg|#VS}qS z4MI3huZ3)&W)x#;nq+YpkVkM3%s;BGcMZvY^q^U-HWY__oIvNn;L6I3!O}^oj!JmL zH*8F{lW7uB4hLv#+o>Ud_D?A?)pn?GJWeE}g*|<~trl1Vvh!B_vZL9N8#`PbHwRzmg=2YVeMpauOd zI4*ZeVjiH+r{NuEzYr4Mp+;1@e?5ip04HYDG0}K%ecD!ZJ@6LWQ!SAiyt|s;T?Jq( zKg>QArAD@<8?W|wmQ}o10y=pI3BIdEjq%VN(*0g2!FIdgZ$FH`{JHe^sltN_Ol@ z0FXNmIPqP*?eRFrP_pvcq1#SMSWz$Cp3ARy6?X+3R{|LL2DSQTNYk>#?ErTE=u>_1 zA-@|cWr;R9aO4NLnXk6=$`Xq@nCH-^b3hIJu!x)+tfI#gFf7#2{P}D%TSKfGL@Bb0 zwyIHS?D!D9(=}is?%!d?f6!DpsM?HvYHoM$|MVX_3V9I;`d94bP&^!ptr7+?(ZPQ` zxLnxG4^*&VI~B*D`wycXRxmnyUBe)xsFLBlY7SoDj+NN54)+roegMIN;{<|8&H7kLB3@IGEf_}N8)LtF-`+Wpf1HQlm|wch(gZ|K ztJ2k05$95A1%%~^(8aqFhe@H)S-3S+pu5Hhd^bo<=|$ZddB)o{!L^HIKzcW;dX_FW zYR)-2$)0?js{wHn0^=2JgpW1F%sE}=6+xTTrK(UeKl5ILzeMbqoXF(k1Ek?`wCf|qwqVZ3X;e@(OB!tOhs6n^`$$?}E2)H{6tDVh?RYGwA`4Ye>WentzBis3DV zCC33nCvCvIaWn8c{iTNl(K>fyDZs$~SF3jB@%R9$_Zj;MYM6$ix+!4(ypt%mCEixz zpJ=5EPWb|1mqr%^T`1W@*0?>3DL62?>a{c6iZ-|k&7vPWe=xu6g?_>lPqVBGbh3Vs zltS@3(}|t!u;*)AuB_tA`QEbIB}8yusVY_eeQ@`vpNO;WQ*D)7&r3yBT!;4StBv;9 z3bDg+Se*-Uk_G=(y3xm?T){k3$)Wd(jbmt@ZdI3~qtA7m;yA(UgQJERwxYf81sZ8~Pp&sah$EjH>D|A%xJQ z-5M(fKRr5*X^Lu)WUEf|xw8J}UL`C1YiKgj96L4%Dak%8t&X|}V&{D|3+yi-(y%;y zdllxCAYbb$QjJ=$mCvP+fx^8m)}QQ3zo|$uJ5Nd0pqTMLYaEe z5lYO2f4#*kL@+EPvAnw%VoCrk1@cwO&Ma6v;5~?&$(cWCuLY9**X>ui%BZxGLV+%NAXr>Qt?f6IHpu?VyrACQ(>bw5qW*&z@UBVgoJ zV_8I@mdWS*r&Zyo&&5%ib!xb2yDPaVv}4((D0Aivq)G+V9@$|^uoeVL3QnuoP3jOR zG~&Sbr_I}qzwQW^d*R+{vKLm-+MsA=q_yMLtlS~f+rP}QmbL7_D`-ZkL4&|qcA(jh ze=1lInq<5IlPc8(*#?q0`xl#PwtI!Ce^@0osJOoDYQ0^bid?@y1h~TTTW^~bb!k&| ziEyL`9+0G8HKlyb1v&pbaV1%WVK?^2|7Nd=`YXilA#9NJUX|uIDZ<%BXDY8IbydUd zvm-I6Yf*kiGq<+D5GtRnSOK;W^%Z-yf8@igvRLY|B$=96n2;v}B(U)9rs_F1 zFp<<~&vWMeZ<9K_+^recB zL#0;7yq@?TaEX^jfA>ph^w`Fl$Wr!4)vMvC!VH_$Ubv`on-0a= zT0#|5QvYvit^tby6OpaLyl$EffBNz^;4a8j)%UO1C}d9q)I!$%I!tNY*U@WuZy^OT zP2KM|lGP;TjvnReTej?1e})5Cx_JpJVMBwDs!pJsY+pS)t%!)qGA4KSv z_1v+yqvGYOObQ#<^1duvG5T_y8Oa0Cke3K*395((*u(0{!CP(}*+8$XfArO4a(qdb z=%Rw^DwjTkg}$zUnoT-vbRwl4Pvo3p_moaduLEgOwE@s=S2`-_57+M%$1m^*b_780 zElk#YZ6x=}JQtxie1SY_(_mAG5NZtb?MnZ$m-`|1SXUu)Dw0Hw=DXS7waAxYUH#_a zRD60k@;P6t+ygdBuX}4 z+iMS{dK9*vWY|NVHVp!9h?Sp8aE>IZENLfD@%meH_)+q`x3*qkx7Dp#>k0a)GVwSp zaOxD7h2TZK*IM6?i=PcYgbG6N(~W#p1#O+8S$)Y0uLs&8_$hp1f7u?)+3#3E5m#$g zr8SG()$*HKQNbj8JrV`f)b21t7i)gTkV3$IW#nY#BAM-BMI4k0V? z=*2qgxm}a-Mgbw3qv69VpQwu-zq#2?MAWW2huFs;gTETU%Ur6`kn|Ur&u?p2vnjkv zqYSy6LdVifVpC8#e;$4{vQ}6`=ksdrrxELCx4RW9D>{H!-i;*Z)!VC3uBK$m8z1Mk z9)+Mt=A-@^lL1>wrE@r z(VgfId4aV$;siquwv9bHwK$)~$zbI{1NOp85**jRX^MyXe_kDe^wqO8#1lL|gZhe4$aXYz_B=COcytb!9pQ(-8QnwLSqu%qFjrn334wGYqy z#ShecZ(kt-wg`8CVz9h-wj~YGb|~>W34iL`T^Y7L)YoN?lJtnMQ-ImaoLdDY@c zS6zuNHa^73e>PfgKJp+NI!%8}BWv81}u@BiJKf{1HBYv(i%Z<8(+VpOm53YTm&fC`pynhOE@doyw*wN8|yM+I- zuEV7Bi==JnWSGIdWLsuZVLf|CtMaqz&Kxn~gd&DSFzCz>vaO^~II+n=?Rgtdy(>|g zX0l+Pf034~TehZVMf*->7DG)1m87y$?rjoyyZQ+B@D9(;Y$Gm&!e z!2PJR3r}AM%*>j1CHbo(4VoU`{snt=2&n?#YuRhd#IkVMDk)$F+e!IrcDRC*^F1h6 zbm{i7I-qz5rmHGX;NzjUsd~Ea(LDf|a3$EPe-2o{8v9&{`JogWr|%VqH?hq|f}n7# zn;syp7^io4AdQ$;=Qq{Bk7P@h^*C7s3$;(JD?MimbI9NnAE4Nl4MYXIjBApjiEm|5 zPSOVEh7Mz)`|J9>3*2g`?V1mN)vn^g*XUmOvn^giE*w~uT5D%T<;`*wQx6_TBD)tV ze>G_(^r)w#v6)01c*n1~l{UhztT*b-`vJ_gDUzlK;AAdWO3qujt?_zQAzgDw^_jdN zc0AYqaT|fyMl6v&COpDnkM$*ev^GYjy}gxV4BN0eP05Iy;yy{$Fuih zr{wc(*7wfP1v4&Rv%3+qzV^gU$lBH-e|WK*#1BUi`kt@q%vYQ#S585BFc2r4cyP8q zeSkl0IQd4_vaMf`pP@?0Y5CXo#Uf14Q5fK8>g5s3PR(2@X^Hcy67j3<*v@aW1!QVw zH~D=U#`7H}!SPAD_UV5H6iHq{YrHuXBewr|Yyqv^gkKfpi6B@w?MS+(af%i&P`O##hZ?owgdM8q7>H00DWb}E?4cfQ8h1aFB zdL`l7I8~yHxyLkGKAc^dBP|fPmyKA{B-^!(Y_zg#$)GHw&fncDLuvYF@l$6{m-* zGsbp7X&>QewbGWZ0#8S9e*rMLMIBM;*Kk%(0QI=5sP75}x-;}QvjAJ*%mGZU9EsMB zd0QcKkT@sRra@?cF6F=H;<#S3UU1hLtjs&FZO|b??K^Fr^)!mw9!+gtvVNYLMsaw& z-eB`Am2R9t)Q8iy6nk)&jisEhsw#uUxAc=SXv1yFMh0(f_DLJ(c%<|57k zMbPu=%&R6-y{I7wd_Ro9IcOz z)~5|r@A?^6HAH@MhkT2(U<43?{;x8nrO3GrZe;xFHA*?8+<8a2?YEn&=yZ2|Wsc*r ze8ll3HP9SA;}e2|(vN;SE38Cc)K5=#N}f_IWTg6NVL_5(skQKRy4@yQN5tO7Hzio= z4$A2PE=Ffff7-LU2Cm}5sohL;I}+1Zi1tLOo5|^0k~MWtZCJG&?O^k9FOz@BqOU%y zgf5P0QdsB=;-a?{>P-PZbvSqp_2knCA7;6$mQ{Ym`CWHN(oX(C?%`%iKI0OZS~c3= zD+ych7EZXG2t(fmuY)t}!HDzP{pb8v1M-Ljp#Rmof77V-14!y~``OdK$Q0yX#ojp+ z#p#9A?lg>-xP(zc@^kwg)6Z4r*nK4?4y_htv-wUA zHNCqyj-X?eX^PX$6X^v&T7p&Srpj)M&gG>CvUER^Eza-0S8Cd`!H)eyEj<==&}MMZ zAV9-=z;3rEOU3hZ=o~wk*R{%7=;sc-vCCR>f2Ka>Yp;IfFHJ!j&)4CfUKf~E!>f^8 z=+-ElR8Wo!1a{sl_yS>Le^=c-l+dZVmA*qSrS5$b6n2B_#QvnZO-_|dYPP8@molz@0~LWw%}#%1rrBxn}4A@((`z;3j$0%XtDtKax927 zbUcytl(dY^Rn;lNMNr9Xp^$(*8kdBhQ@ z0=|M4(t3aq9zZHm^ks#Tea(h;V4#B^p#gV9qpMO`-UzO;;9ue^2>AN8eB(IrfVu2e z9PXO8qxcqH2(vO5FVxP{yn-ZyeBLqsG>Ug;G|P7zJ@{n}LIM4KvISmzXsSXAy@RV0#z(eJ zYI;YVS2#s8ZPCI<&q*GNdf414k3Uvz|l6D*0RK4+{<3QvHreNuC^_oWf{8Bzp zvk3jEyGTAGBdoUD^&$0oS?tJ)sb#Cno&8_>TB~(x_OxvJXoKnSCwrr-%oMJ5AGmcv zw>G&r>Sz>gkpWIL5M+8Tn}V=4IIbFu78`Q%3a~b%1g?vu4)Tv(yIuJPe^Oo1@{$zF zCj!@hKMi5K<#K%{&+X(^7Gze<<~3_|g-9d-ov?1>>9x*zjM-|(!y`a$ zP1lUz9|6Y5@JY`!8OdiYm(QeRKh$qFeUq#NaF#h+T@L}CK6RVnOng_&p1cER`(C}_ z24|(zYr#44`f=UT270J6e=ml%<+xmV2=IIGC~k8XC$8#!PV`szM@6yMHXz>jYO6+N zn4+4#Fim^0h7){WeR3tTDA5?z;k4wabIlk;PRHa^5VEWkK(sugEmtJ5CV|g{nB8`HG+gvhCtLNn3t~C9C6rtRmYXd2}4|Oe>YZ8g)zfg7jFq* zZ~AR&V|mRRnhcTceR!&~9V7|2o4{+C;LRSVI&kF9`qow?#Om?1tq&x{u5-bU&XuW6 z=P$v}S|Nduix<9tNix5F;DQbq`Yi~K;ytIF;g(9vUi5|JJ}= zmHhZv;^!&^)@P~!f2<3mwn^UGL|_Ofp}xEgOh!E`GW(~7G`s!T7Sor#u0Xh+b#dVZ zo8BuPN^h4PDbqZ6lK=0NjN*ZW;4vJ^SgbMVtlM=iW>6?uosj!wSk-0)klNb{&j@s2?bu>`$uKT(tM-;eE&SNvf1u>oG{HK9=SV@bc)`xU z17Y#LAqhi%e^@fm?Ddk>RdC|T@~#)_gk&4$G^cqZ935z_ia3#^&nrwYZMt)Q>AA8piC3KR(xo5qqe$_m>88~zlKZ`7aa6FG zhXx_tx6-bUeZ5qGE0a8vm9zAw12*Divf|)-kToEze=?S|)bk`i>k!QHcXOhu0^w!z z47;o~^03>Zb|55QeZD;9WOv*gv2Ck5569}cdIMx6sFY*R_F{c^SQ|(WYjL2JOh5$V zqbqpBw^h19thuUv3*fSkv}vchT05Lc*oNvGJpFCjh5tQozP=rh;sE6NH6DTd*vOKk zTqUu$f0x#e_ZnGGW))p^66VY$r+t*T@Zx@D)$|lPCHX_nNY~RgJHYt+wRXVH&tUbP zUi2zEd1bjuv6sM#&0Akjj4eP$#|uYvK#L0P_2{KH+45f9^V(1b{URGbk_@JJqh)8< zN#x&{UOU}qwd<|Md56UJwT~w$C>ZZeQO?b)e^UN!;DY0aH)dW%q;tEw*k^kv732(z z+fey}1|wV{lf0Xqb*j)Q?)+&AMGOE(DYfZD7mwD9?zdiCcv%X*fH}VWoO#D3tSldS zgFwvb0Z2?QPH{P(cBjY2>(KxHyg(es*&SkBbjGP%SsIG~4wz@s_IsQ;R9^vrRrM(x ze_v2t^qG1lHb<{Qaf;DVuS1?XG8^UY9p6!l3O;1!XQ{}D$xA;{KLLO@DA6ys1$(?A z)J^g5#|~gCX5Ryuk$FN>ocUAB@6|X?39HeTvZ_|NzAW?660O?);&d5-$|*!bFGx<; zPttvLO!xynNo8W_y7|HJwsL~=2@>q8e?1T2PKp)Sg!xf+rRj6HjDfL7r$ECdLAxZn z-vYbXi=XV5Zwpp-aKizwRK4wg$GdGM?{Luy2x}0nb_Z3G%82_LU7?5gT~}D0w=Q@E zhb6mez=lxY8Wc9ugVb3&z#u?z>*_-!RvAafV;6db3XZhdlGOyz*mbxqalyPDfAXC! zc6E3e(B+44AW457q5#3ni>=po)9V%@<~YGZL%DrH$;&P6lsgNr%XhMo8#JU4Vs|DP zc(D{8bhykbSXf6b*9~F9zpGlq|Bstf#dHHrbd z?@Ru%;sR{xUPf;%Aw(;R#sw>1e?L~}Ieu1ile+z|q{Qo^;S^jjDR2+oJcXlywWnzrrJM_CceeH5+~Pf2-C>Pld)E z6lEF?={P@RCC_FB4J;d!_0=1`ct6yYpMFV7M0)b%)EeR;w{ZH%{e=9bc>^0ZAKhWJ zVFIcXnZ~~Q3%|f4s4Qdm@@9+09|wZ1d@l+9N84J#ooOY!DEC@dA(yx7K}j+YDtxM~ z>59!iSHMX9fo*O9N{}|Ke>KH0Yja5YWL`1P<}5ALpwzpvv@Sm+w>Nc9I zxc^mpV^~9Y6nY2TSv)@9N24uQCzohJ3;!VJkt~{c=O>5cGw!vXko^_n&hf{bPt#oB_Dx{ zLJ!ZKS+MN;NI~>d(RCa$Dd+-){`AJTJG2Djg2gK?u&?49sm-R8tS`^ZEL@e1)@t+6 zYu`Q?Y}<*nydb|4sXFJdyj_}Z`-{cdHRWRVq-&o7%ocVue{FujRMUx5#ha{6Nl8B) zkeUXZk0X~b*{K0+^cq*i`pIEY;#jF4?M2ix|485g$o>#(6VMTQ2-x0V04;-0lFc|( z8SCrA=Q?sYC%Yuw0WR$ioguyIG|8taN?QV3Vp1zzvf%WngKL_sjrrpNxOfEM(bBWf z=HhC(MeEb{e*})p?9hSk3=N2&E1h=1wxhJ#w{Tz@NZyL&(E-Hn!=JW%FYB^Z6F(Px zpnu?T?=u^D$Dm}msKS8Kv zUsd>r!f2nGe#?SNl-!ppv}_t)z?fZZG6e?~f}|*he`?N;Ql@sZfab{YtlGEXo?p5? zN{fA>1*kW?0XW^1@r&0VtYv*#^8=w)C@!nEq#;sKoGy;WEB)v}>-j@a&>~)Cqm`q) zO-b(V(-5lSC085=r$V$bvLNK-7E5qb_nEJivDeOdczNN(8Y=R8g_c04{R@NNAc+{x zu)_k4e}T_!zuh`CI|;yngzI`G$zQ#C>=U?|DWyMuF8xc0e3S$%mC3JkC?Ed5`vq_!`dCphWqyQ zmYhLQC`Pd|zr#aL(V^p5;^_J&!M&nG7dS;ke>*ay<xqvh%A% zdiTHgj@3lCO}1iMEeM5_>~f7&hwpYN!c7i*+U8X1;{Ga;1@PlSC&!-76Z;X$4XT}N z2g}6IFTU-UHc=uk`#Y`)=q_AhoBzlSznwMN9agj~7}&7-?&0zt^c&d4vm!dFQ385a ze~y|KQR z*OIz9PE#I_T5(Svit642eDhczjKRQHf6Mu;*U6V3H~6+47{W&$XM7gla(4J3gfdSw zU#q=r#n2wLi0^)%pM2Qs7!MzactLP*$W$>8?$<7aJ4gH>vN~O;vc^%ja}4WkigjL= zq~D|a(lc&HE)`4Fc}a1CTM07=3xC@(1(@N40>(0MU0e6EC~@rbY^PY2DO126e@uAC zYR$8G#x|PV$(BIqGY0c=Vw_k+pe22@sh`@=^~}vGf(l^rgb`RRT+w}ZcLN^>&4pB8 z1>KpTwi^ifEHmXuTFH^BraeFhbCj|A!c#sSg%@V1DA{-ij13T(KOxJPKl)f9;)nNawmmU4)DKyU!i_5rr>b^XG6c*<=9__#c(8 zQNju)al)dB4lo#YG}T&v`LpoD1bB0~r!@5nCKm?ulia&@@luyZj%5G1w0h~y;_UVM z&h3m$=I-vO#48Rrd)>6qHr|aqEAgK>rPocQ{7u;}m;baB3azRTxFx4y;B(dkf)3%V1d(!)c2CPI*XtC!y0Py4fXCnGf%`bs zL{hxE^BDH)z!*n$tX$d~2~AH}#TiwGP;E`gVd6VT`w3SKcS*9te{YULjDG7}2b_-O zgyR78xm_#H>S!;Q;y|)X%PZ?898=CR$NvRT>jc_WM;!oCR~pD5JPMMW5{Sg3XU2Ts zYwpv*(9@-mu>r$MpFXw8UR46m1K8qfPGZde|7#z9e1i+=`Lv~u~(@pbL0-6s1 z!gG4hG2G=)-lt4le{@dx2rl(4LYLn5i?8gYj@4P-4#-psE>O)&$j+*JIPVrJ6#D(V zALqdKe>m3qdSjO~FP>lCTEUCKot)Kd+ilBR&8+D}mfmzny|gn_19aU{{nD*Ca0fi! zjVX&;Jp*)U!BTo>T)maM1_=~p7zy~G z`D;`lp|gUyX#_2;(uClI@sOQiZg`31S5UgUFb4$9yLbrMZ7=r=s;V!e`w(F^cVwhK zh?6`}U8Sd9e7BBB?_^z94#*SFq z$Ual$AUm*pRHXtuAke?IzNQq3%WqbgmilW7?`lZ0>_+|s_4sl9>B`~&3UovwzPoGV z)~|k#rZJB6`gMXFN`Txs?Wus}qk1v}-;mw#puN6Z4|HeK;R)Jl;nUA23r7mG9z$ z`BL?k|K8JS90FY~ny+tVQ!da28LZjqa7MQZ6Jw1}sY%@pi0kk7Ms$AF2dcvbFAg4< zC~xPpf2&fnWLijSb8zZY$PVm4m{Ay#AOBlD7B4vkT~~yWoOR<=aIv~W`+fFh$=Pd> z08%sqUVTz|g59DJyl=&V>go;-66ICr&XN)xtRkJu7W9vIazYUqf{e-;N8O(1w-^oh z0mp# zN7L(@m$CCFU?!GB5`sD?LBnMrY~0GBD^GGcW&;BS)_%(O4`&>=8>6?vOkaTxo)AUR z?@)38E%ni~$9B88O(6b;Agv)?d2rHv)1qa>i0xK2hq(4M*K?8pW<94dO6vd|JQL?j^%ZD>SmpN zt2G%CR<0&?+uNxDzprwXhYT%%W-MRAxUQ;{CWc@xZCh-BIrQbS7r}0-=XCYo_$@b* z$eHvG=cWKYK5aSyT1Gw~H*Brn3U!)e^(h1V-k{FxALrNZmIVr@jOf%`6o6R$F|NkH!rwQa01B0txob zmws`kT_t6m(BP~Q&tQ^DUtMs+lYy&^m=7%Fuo8-nu77+m=RN)RtsceyV&Pr)HEF-T zXn)ON05IDgQ*%p=kvCMQZk-{f9$QN8++uV-Khc^9sr_4M)D!%tZ9!g@3mPA+2RcIV zye@~pF5AgEacrPQFAiaOtYT^D+Do~KZHU@aq<)IiZjx)_I zuq^;9Ys6%-ss<~GEX;q{dU~Z8vheWe27iYEmTsQet+K5kXiC+izQC;qPjEvBu_-HM z_}LkJ)YAg~s@y=h>O={Ea#qd*2HXHhkF?#P5Y|e*Iex9E^8N8WbTqod_BWaV_TD#XO39>=)mwt)e(HOW;2{&Y z%&J+I6O}nRW3GLPaxVQl=i-_U0NHBK(L2Gt7Y?>^-~!9&EZ^K2`S$>L!G9^NR<*A^ zDI8VcrF+Ky#21yR7UOv7L!EO#6?QF}8u6BX337&=su{vliLzmISKNCJ<_+V$I)INt=Qq zIzdSEbUP`uIf%u!eht3iTkD%#%Ev=BR2~LYwxy^@*G0e$5&u)5Pk-JZLjYv_@>{!M zImDB~yj8z5NbO@Ksz3~;5;2@$RYbO<+V&Ziv%$$^xD|3$+9IkfBq#u8vQ}i>+R-^v z)&A|3K0J7BdK8FzRIt6(l4u0tV6=*u@W1Pe4#eR8SdqUqRv|WK=NpvO1^+wG?Xq$> z?ItS%ZV4YD3m72vhku9~rt6yRUYvxYoS;s`gKRMLF#lvO)@t0XfX!{imUu1#Wle5V zOh3O>yWHbG&Sk?=|0z{`j8kMoi)W8=J}^`V6GyZ})B#UP`_(#1dO#i4o%s7rmS}uc z*-;NjMax7*;PkrOzPK__@_N-$yxgPah_0(SX0>#Ld<*E*AAi22>&Ybp$VEz@S)A)` z5$b2^qG?;L{p#&g+ZLX^MB2AnfYr-`GTdv0Ohhj_*+7RnNQR*PZb!6>8b(7r@^bMc zI@&~c!mdNHy3!?y%2dyh)0Z4i@+n+!6h+!TV#!Tz;(tT)>~6&|HP0j2D27ksI39@w zS0KxAu6T7WEM`qzJqCd66gu2IL!DzDp`!Y?TDbA_Gr^urYq5{m`TW)uk}u-^oB_&Y zP|m4y@11Yf>~UPG2HKW)JpR?0mv<4SBOy8A8uZI0(ZO1qE$($5;V;aO*3x;$mIU}l zTMWf}HGe2ky+A(WdVyZ#F+AWDvS)YHoI5l_!Jdl*=#r(IiSB7t!5a`op*nChC(Z5S zYVbc2|L=Vq8sp{cN4rqr_O^QjjTwH}C0R+|i6d2%Q$A`Drda#GYadD>a=iU`Tj$oM zn7C${rk0#l#r~X6RK|5D5TTMjO3d9Q5z1@{g?}EZP)+jRlvL!W4bn=}KS~ikozOqs zFCW#=-Re})rAE1n?5#6m%9YDil#86I%Im*S^>=f%ge-77PH(?+h8n8-QMWFtyE{Q= zflqVxOJmM8vyBWs`-+x;`XL%W3`f>rYDu%29#XB5DK!prI2GvJ1!%W2>@Gw@v$7aO zd4DQJ>d6v{WXLo5l_ba*cFn3RTj$|_Z~E@>Z+PWZeXa!gt&6K&wn1@g&F*lMPP(vT zpu{#n!%|kX3|vrA)|eckF1n%eh17R5sgPK)x^R)t9zzIX7HM>jaH#e1pI3C;`*%o+ zpF8DUS&~n6FAdg7&`>chEhoy={iTs&PlWafb>O%Ka zWq!L55N0oc{Nsi|*f87{ql?m$#4(o~LoQfRCQ>e6?aZtOgc}wdPP?Yk+5*apjUhp* zs_1Z4J^}yaGSHRv4)bWt8e>_X7BBr$EZfb_naQpk=&rI@RG<2-yed(XU{s+B^M8!X z9mQ1jEw@Q?YZJsDcf(QNM2GuA<51#SHKs)fwg(ixvuKYu2TyIj-gD(3JRhzUvGK>oCdxvg;4&GFwbq4t}& zC*o}lDwb5#y$}L#NXd~i#EH7lmCpdfpGwaXb*M`LN~~Q0NsDErc>1}XL(hBnrnnKd ztE=^5eYSXyd583&Q-#CI#OI7t*n#u8v`rY~jj<>S-!*5YA2YlfXeb9dawEKeyj5cU7&mUWzXzRcW5^B}z&YelB`%b*t(C zn{mweJ0k|noJq)cELXpC+5pKUA5CLFiEV5ZUT}WxBCIb%&l`B`Tv-j06rvyM*zqeI zP2|^RCvCvqGw%3E-!v$5#QkO3WxCn}BdlNLb3&yXL=MWG_hJV~Ld_(MnSMG$A z;&1&8wLpGsxj3v^aoGcXii`CQE4hGt3*1PsM3NISyhLL)l0m6o=o`9A;CjcUp;zi& zimDbz59vlyY8w`cr$fIrD^l6|Z9D3QpH`bhBkUsK%OGY@&1-WTti*XP<>#jRH=e>f z`RHG-0OhUW$*Tan1%ILER**`Yr2NDLzN7g$Q0cZr4mB(eH4*;Q?EIY9kf6XC)u6CD zLp;%EDl{^>hA>OAn>EF2oK<}vVkX|sLD2+0IgS>6ujx=48N&6mMXa6otvEBM@d6oz z+N}}_FuVpjJU{hSU9;Y9!81Xbx4Jwc@uH%wOGo++ak8~M`F}31A(w|g8p?)Q;S;xa zR(00&SpL05SN<){ieQ1(EpPo72z1rbDp%3PKuh~d2daCsjtzL>XLBY_{iOaBt?XT- z8CCar0PpKgYuAcLQ@UZ5Ma{#T__Da@1OzBnbG;Ipk%6k)Jpg!!k_OY@6K$VkjX2f` zl@;MzK1$dt9)HQ51qrI!rqZCcqS|0WuAy+{Q5%Zfzc&ep(68d7m3Tw&(Pi$QS*1?P zwHE4b#aF>NoUYAVA?#-7D?hbMmP^lJ5a!z57edHxuaN^3RbRdYrS;V0Ca!07wm3Yz zGfOQN|A5=~I_Kx=UDdjA8**thai`E*uoN}*A@XggRDa`Inp!{>HL4JDz!NgikpM;p z<1NexSx%GN*Jv&tYA3BZD)(RveN(#=i>kAO@yEwy=5b5tG~9ZN$xIPq(ASBG^cJYvh?LB8l`}72$`zX4`<+70fagcK+LRwC-*0aj_#9cQ<-!hb#zk8 zq2iU0Ic!f)FOKSl1;HCFc!Wn$!IDgE5y8FoFC}B}FzZnLOjua&yF@axL70$%=EA@c65tZ@^`)1bO%1!G3(wMjEoc4*4gkSvIk_#{GDH{t<0! zr%fK~Ime9ad9qnOqndeyI%(BQKcAx%FYi(f*&O}|@A#HhyOS52hUx=AITu&l-$mZD-ww zq}-D4kHI{oK=3(%M%B zvC-HUt`;T#S=6Svt-JG~zqFn^xj*#9u>8!&1)>uR?^E*=ei%>!7JrupxPPcFVL-03 zY1R1+^NOa2W#3&T%liqLD~*>#kczxC2YxQKl|VmVvGRX?7VGXKBm3Hny^adQ=Ttdv zp>lpOYgha%wd&TSt|^DCPxWoyB1O^1#la_yx~uheFN<^M&-;q1l${1!Ii&lA#Dd}z z5SLpz0|A}2bE!JekgWk-fw7 zI0{ZhXSehO(vF#NV0B(iE_N2jmw`~(`F~!O4&v&qzeFmSGh|S~CxTGD2>;W)wAe5v zXSqbkDdLsiD}zyVN|_F5>r}LhkWD9D628rk3-lrcalKdPvpdwG-+!h~%zTA+;pn_P zps`ftgq2E{#1vlCd%d+=PuPa?69HNwRH!m%^+`(yOXA2i_Nj{GaqS;suJ)brcpvhC z3|=j((!ToHm~?WedQmd5e5mJ2Ub|&~1z>rARxgo({n zs%vPmL&A5NAx};$>yPt?m&?{xLAJtwTtYp?Rel31B-gMtNq1bY+Fs#j8sXOK_r4re z>W-yvE!;Rfj(_S;vyB4l{2BGV9;GPYI;rcdTXhdw0pb(r;DgB!x?Gv(UB3$As0O5I zEs=x_LC)|(K}U0koI;VFY7K;2^V-i()p52mRHSL5WOcs08Vb~zy<85})A1!hKFtK9 zpcKR~GNrC#gd9Ta%I=@I^8Rq1NM%X2^x-Pn-dfr(%YRZ!T`?!7^x|mKeMa!kMc7{9 z63yN0>Uoi-U)OgyOUj4BkcnW5-x73ny<42>C&ug+zeY1*RB&o8op>6jldNUvQngpxo2Q^h-+Hs?${ zdak@3Ku3&%X=&xlK_FWC!X}63I5neDvTbv*tJAUfBIFFEXGKrs)IFVl*W7_{53SAm zOFe+9JRGyJxR(pDOZSsobE@SfbFPfntc+Gw)_ni z6!)Edaf!-#YLLz?8hUh?3e+T(1c{3!AGqk$FNYYz@dSgMVnaw!+Z`_fRf1}6FvX`H zCx6$gW`%u=-b(JY5ls8Cd;c^LLRU3w_AUelC`ryiSliu2!m$Ev{kPsbrot$Xxq+Z! z9av(`Ddt2qb>*}PcZyYpSPIZiZ2+fe6DVD|6~zM|>ovPtxmOMR8&efT{tP)5z<%6$ zOA-^V&kgppxJVFis3@vZ@8@!|HT?Tl!++cl{ArG&)9d9pP1$-T>an77!2NTxdEJS~ zc8+Z0%oRHZeA@51ZTjuz4o%k6MJ-k^1nMUe}~!LtfQNBnl#ps{p+!cShI-l+iRcYkTn z0p_*f16!VP7K)xUARp_S_B7xJZqK=B)I(_88|lzB8LK*u?7U^wqOCZZ>a6iMPujOm zF*|i3{H*}{6LZVJM@P|<>`+w})#m1-U|;1HT|c}K=ES$=qS{Tpqyy8lQ-@RUJtZ8u z^`r&U&uzi1Iy$Y{%Zim?J~XM)7=Lw=w$e&>x}XVxB*`x|)l}l(*I&{dd0Nc@UqTyv z#C)wSk{sTX^;WM*S1{{z0hj@4xpngj&=cBNkR6(ONYj~(K^)v#?G z5Q8c3qkgL0^FNBChfaa(Q>6IR`>Vu9*$8?;N+Zq_c4ORsIts0MV1?c81%I~#4orhd z-zT`7Elt?+a-?)dgEsp!@2O1zQIz+nk)^i41p84nz5!fZ(SRm2DZcQ;8lRJ0I>vEC z%cbBDNKaOEY5-_i;C962=>80`m~seWv$&z&s|+m3ek!0ntzrDTQl0SA0NP>3_m z$J1j&aWA(-ZJ+a9s!cx`X`u zRroDGz9j)OP@sV1cUQcLvou53RsRC`#OQ8F*kZTf{S}ur`5JHe8y|rm#?^O>h7)4H zP1)gNWuaKKRACVuW6yKD1DAE*a~b%xL&Il;klN0F-FnnRkr$X%uz%*XWJxKE1D@t& zI`@pPbq{Yw1!y#T@v&$9X)Q_|cr^^18~&y-AwP_CpeYEE!Zuep6bcggwV)pWC-BOy zhW$gJgi7pIEtF%0(88Nu-L{nA=qg>pPRrdnF`baLb$Q%bOF0X`$;B*=zC9<$8X+o| z(okGssHZZ^MYDOXo_`hasytD1Dv?*DSv!PuEnRt>gVWUWz&v#en6Ln_N+DnJ7RY>h zn2?EWXsKoacbQkzp#OmP*!Q@)d?2rqKL|H*{OC=88WGLOMMpqlApsz?)t&qJ91cQi z9`ZU(F6Jm&Vk^p_(KZkLX#eP@G(YlwT#8CuTE3#wi;Bu`D}SpkI&{m~&GPXbb%^Ko zntQFh5_jB=)W5we2YA^FCCVv)`VdWs!ZwdU>#r>t;M8-wH!^sJ1OSEWdByXXBf-ku zAu>w`{nEZkfbiZi6F*gp%`w}0tQYXBwP>04rpVxVIAr>Kpy)#QCY&jzcmVReDm|uL z_~mpv`$Y6oU4PbHZ^)aLPY!t6lNTBf!JS%JtGqy%#!Z6xTz}&uJe-{t!Zqv4HnOi0 zLXopM>ASXaWdn-0xs_emNVuqu)s^ES6L&)~-{s(lF7lAZ68`pKcm17cQrNsnR`khi zyvHv1-aog@{x?1X$sFG3*59on{pY?G1YLwO+lY1CtAD!GQpnkyPD|r^t18GV3QwFI zk%MrXl~(FSQHHE!s#{Wo@z)Vhpx8~I*4V`Up!JfZm2+qSH{NVfHB$$aN9zM1Bfxn% zHY3zt+j^@yo)4IL+h0pAnb}*;|I~{d-Mr zv`I*cJ`!4;XtR%Y6kvOl<%it?%z9IzaXC^QWBFOcBdv9}^R2TBXb<*my35Ty*^DZPj(|>Vs>-tCSuWvf`mpC={YP%#143{m1 zn5J|l4w>cG7E=L=!QzL4f@(xNFB`KwuI4$b(g;iZdam*1R7jQdIf!I8RP7f#aA$`p zC3HdiMz3B!E)+e(xpdAJmwG>XEcfqke1yxTSrx+-DY3TqRj$3)Tp(`Lo(j`(UD>6Wjq>U6(`Ubx8H$KAr z1%(`gtyX6>KbX@Q&9~bbNLL0H_om9tBfYTcYOVUxU`b@_1oPC&TC)YOqWZ$Tylecx zGk8{O0YbQI!eCz4)Dk?|LZTnx(>CmKjDK+`&}F~A74&FQS3}fsU!La_hry6pe(ENqO&<~7&^y8bFKiw0)Wddpg4u6 zU$h;kuJ;TN+SSOZlFKI0y@EO13v-1TC-!Vpv6A5|V~ zu-hh1my^ijIpvRh1Qndz{aeo$i!T~!!x**ao;;}IqL@Ed`TnhOt;+!Sr7IoT>CJ>E zNWjDGQ_T<*#BIQHa?5C+QD-*P>-6@Tz$E#lL+ zt8q4AKo+22%EUY1Z1iAPcOmbNF6nl610oy$>}gh_oC{Qna=WkcFBV~2sGouTxzY}& z#>B=`{P@jownj8 zpQE1nZ+rv@=c<;ixh~(QQAX9f**7DBw8HU4;TiTyNO-Jy>%Oh$63ioDea_F)Nl6HC~94AX;54=somw9Dy-bCkIZuz6Jr!hv2-p6?m!giYd zi*XtkDEm`MI*Uj|?tgRa_2MMC%KPXru5%3`U2O%P>C|NfZgO3lH06hW$EjCRYnu$q z$4n>2lKRw}I@^%kZY2}h?x~)wHc`&>eJ(Bj=AhlVc{DdV$E{kuI*YP|Bo5$z2mKXJ zvSvb^7dhAQ&e$ZF(Hni$ zKOHU{SW5mX|9>aY&u81#ncqQXDeuGa-Y(jX&opacV<(sWI2F6wN8qT5M_hFEDYymL zx4KZg)f$dg1Y4Ig!Rkih2AostR1N9maj~$hdPY&>4WStY{Ymo+s zcII3Wjb5@H$K8c#8dRmLGDhz z(v{32A$$Np1T;E&Fz-hE$)uA{i5SJn`c@ep7=KkKFW+G?%dwplkfL0WS9ypOaSPot zav#)fRpr~wUzh9HkO>3ycC`A4)b%skYDg9^8lkwT_5CcKPjf#W)b8|Z-a!rH+qpVDD_}XByYVz~apuv0rsq9W3LjtW))EN!^*Or6p>I6! zSbxq~!vw)UkV!thxB&BzrwT=Bp(W$G4J4JL>hidX#mjwf{VlHNb)|TZF=HW@=+A5B z4QP!X$~otWKTBK5T(aa3KxPO#Ubn9`nS7R^CzS-`2%RkqDNOQCk4ODhjq%TPDxin?KnZGq#J z=+lqFUVd@EkQeE?h_-}xfwU$C{D8WECD=gIn91gAcXMwzXqU<`eK}(4^5Ik+%Z>La zaS-xG`1IPN&4F-_&Ne*dPf09g^nZG>A^tfl=sZii!Hw5e`S)>|Su-?CQRJRO+&>zT^Lo2&QuR@g=DKsNAS?D;&$Fk5JUVXbHzlqLUp8xFMo!R|G-nY zTTV;o>r+E}RbMx5-KuS?;WiXG9S;Z9bPP7x4)i!Zp*9UabAet|!*Dz7cF_IiZj+jz zpbkyc72_#<@FjyWUHukHOHxNPj6(mwM@T$eq8E|f$(~yv@V(k+$53yK&JhRs3EXdO zd#8OnH|9uC-CGo+Om|a&;(t-^V7VRD2FO`IvuBbP=2*)XgG)}$X~32B8dYlK`5PbM zsXFm&n2X~kuTjeZuIWhBP!YvxE}&`Bg?#?niumuNEfayNoX(}! zWuvH2Czpe`?2uWV3Oy>0L*zIshvk)%el8tA{xbicJObvuoJ}!AuYXP|SX0Fa2X7rl zTPhwCQsHxwIgN}!>Dvs=`f6tTDs|9=}u5y7?-zIK>H(g2PqxuxGVp7>n zPDrep#}E10y)acVhX#V6eAfgo&Z0ewuU|2(p*%Mqg%_eo0+=00qk76zSW!7YKB=^R zza+xtaCJ3zoivo*<$s~B=jc+&s?QT99C?Wp@D3FW`jxA-T)u|GXvJ`u*IWzlJhfLDR+%Ej5H*#p9$U${nT9xLafR(|#I3TxLxO=N^8rwglSf|L7(hORhYc2ojx8|ITChhfC z;`r}B!cMBqbb}a(iIezPWFP{=yhWzmbLYl^JX^!)9IIw-pm7j(vOZWsM{xTRRea+j zs3~L<-hU1{@Iuu#z(pa9L6_>}EcAD)86gu0)*mck{cR z^2Kt(ANUBwBX#%yUm%WTe$&iOLBpccok~}vRDWe%qqC=wZg&G=m@CNOsv+reJ4Jj6 za-w8D=U1;p;9iDOX(#S@n?&MKfC@M;?3m?xKY!yR7+##ywHfRzHEF1x03c-4cSn4L zx^OME39Sm?7?e~)zwG$LPa8xbxOuT6){DN~Zn?SI)$|B(EQoY_>ycwydTY;~ot#{p`w523x{z!>y@1?ZFd%nN%5t1HcN>q_*?DV)u3JL9Q2|#sUrIEk~ zMaHn!wa)#{4G4=R4ygUjgzb0DoUaf3>=aLm_rp$@CVXwHMC3YZbOtb8#>` zKY!yRkXzKpwDqQ&57cJ2Img&DjK1x$HkL(%@X8JN^Go^COv%JI~qJ^i8& zI5%gq9e8ExBBwUw#%wTuzb0ay?+WfPe)5d zBfkA;xW=KDku-u3Z{|#O@ZH6`60^=Wn-&hkLzqYNW{htAE>tlh+X!{gU72 zU}Q@wG{1l2BXD&z9eM#~`fkN|+;`c|&nbsoid$arkkpf2ZzpHKTy>nw zn)NcVnTy_HJ*FvSnyQN-XY)hS0r&SNv)?wO72b}0O4;31D*GYy4^3s(aFe+6Mc|aK z=<73XICEF?*a^@g$bS>yf@sE5G5?t6u3C{TP1@LYtys2E@Jj(JYu)~*AuxWyUlw5E@I;J@O zz(;`GU!00dS!2g3*M`VA%%U{0GE~C}Lc86WD8|LLpX~b5&4Jz=*LqDS<^-|Laa9hW z4SGKVcbLzWw|^V&*#)x4g&r^~|E$0^v8?`$kMKGN#go^fZF6drZY_Nl@35Z zcKl&AU$Z&9(tCv*W!EF{D0JfFo%_Yz5!}+1*2r$CTn!Tc>~?hh_QkqCqi>C5|4P3- z>p$=jMs@ny*<)p*FB0+utZ&QawivIfet^3567r)7B!8H0^3$NQKoK2)t``ja_U+o= zQ|*2@u|`OQN6zoGYGy^2;A;PpX*Fr$4O_r z7Pna}yth~}P)RW>W&6%o#hCI&#&-B3mJ|Mf-xL?buuBd*e8Ja=Fan2q3<6ia-yOD? zmvfgr7oPpAPp9&vfKjez7-Z;74?|HF=W~v*Ykv>!G?`76t{$9j2B|6k{tyM-uT!-m zOkJjeo<|R6Qag|4wiaR~iG%IPnKf4T@{~7eh1lNTVH3jTI&GJ)mK~NhK5%%57K0}x z2^&`E+|A~fURD(#kzGYO_^E_L1dwBs&>hu$J3tXqX4WtXx80pDZ355f8qR!nbUsId z(|@Z$_i7GOS}K2ZO0#>f(5V&*3h@ALof4VW17G)ht8)JQ!Dc~7<0HFg8k*0)@ewp< z4Vk!?*QUjuno=aDtuTbz<65Ti2X4=X2IE72l5_D2vQiOYjCU(Uqjp z)c`nE{H0527d^UfryH^goG032=lfz!F->rFt%4U=^9nh>T_pav^EkKdNadnxI?$suqv zH_4&p`jxe@GvRdxMkHWsb2}Q`m)lTwdq6CF0TKYy>5 z8pOWaTM?y>@?eEONR3j}xOvg7}_!&cM||3Yr>KK4#h zZDBq*+f?w)N>~0TI6=PW2khR6P_{~l@|PQFMcFhs<9m4=AC+@vI~B_4Ab-;dIp(B3 z%JA=!vYqRw5m@UiHZw0lW2<_LuFa#*T>rHj5R*^BD=$ksSoh4cGuvA&p`y7`sbTfz zVhUJO z`KVb$&u~^J37lWlJpFkbyZ|Dpz3R-ubZOPaR7Hfe9whkWdpf(RXSPefubwT}BMiIdzGi-ijMQ z!-Y%4IvM(QMxb&_Z@1%jOAe6fUkDUg&QV0?erIsitzrw&65JJjUC*u5RQQ6BppP!V z989?W-T6ax zm%1;dlWal5sJC)3AW}7g_#;5nn#%c}Uq$-31N-PgEagxYT5&dR&a|~_Rk8Dhty`!e zORA7gsQw8AtKTHZNB`Cm1sC}NimV7tlYG$>GxrO;8KBxP9mM$v{e)lQa{~xgNb9`) z1IMc1pT-0h^M3>D>) zCcPwA73i~S%N%CF^3itLMe9B9tiY-s4n#Ld+v#fGZ)NH-53DId;{pQwMsLusOjYG| zo4IY45}0)7Yh5vmHB>%yEquiFdw+UO9C95!RmfE3gn!@i&d=RR0_vwI`*6-p!zW#p z`4${Bf~o5L#Tsk*oS4ijb^}!;b;kg(al6Cu@Iqa|ReokT)l~>Ud%kI^bLM!fmr~&j zbqbOLK#$&R_mt|~_tYu7DGIXHq2ZM0bMz6>HM^=I!Xb*yP9G&O5zbj-PwoNG^QR#W z(27wt=YIhn&+BZRb?Ve?B&v7c`R&$LzkkFQJIVJ{vUutIQB%m;jyi#SS~<@Te*N*? z!6&z~NL>pT7tZ(vJ#0yue29QmT9_;5kg7?SpU&ZWdGgM+lSAP=oY7!Y`oQQQ^LWq(5+S*pe1znnpKO};rky*NthyuW;9 z*E}AF;yGs^I)a1p(NS@Gz=QW%9k2E}|8H^tf$3K)>H z#D7^+CXCZxKNqzN$QJItw;rsDJ)Hyq{CHz7oj6ookAqc#S6%q%8l+a<%GMhS?Cv6U zDjGyS%`w2oJx~L*V%smF_ZuLALsr->0PEwZtGA}rQ*sf$x6Z`ckDi+G^6_%D825~i zD{(o{cT|?imaN^rPCbzjEm65Bp=h^b<$o>P#!;loO{5_APjTap$Es=0S-Lx@{{j@W zpmB5U*5>pBR+RcCAnA1m?w07-H{hJv-?)|lS8+M-bK8= z=gm5@I#{Edv$B0kd;?V60088e8c7vuLjs1NIm1h6SHmNKa=gBxt?#aPX#;Wd%dp5BTZ4kVse?NMk43wRaw`m4K2su)HrB z$;>iV+vTPvcZ%Ph#9WVzc z4w3-ZB4sL;K{O`Efj!iOBf#sQ_S(_*JiDg`tZN+SuUtyw^WLwmDe>2M8A=_1mo1cW z8oiug7v00ET}w4S2p^y$wK|D0vC`=lr%<+g^<7H^@$n3;{AUH1pMN*XB*{wO?MkT5 z*_;7#DAa2}-b`lgH8m~;p16GBDfN=(As>*jdytP$;OnKjtcF_v;Fu|oT^UUqZ@+y= zmN@MPN%=lyox*|YQ%{B8b{7ZA?PkBDhI1n6nJ^xTeP5{|uL4s#i66vK(2H7qNeKV$ zmvW#xP&RkDLl*h1jei$qrc|ksxZ=jvR90*9X)P>rOt;>AkL}N+6Ys?}IwEDF0I;ZX zB8U4?KoqjJCeq-b;q@!Jq!0aw7KF#k{hFdU-nu;aQv=1cpTqkFkW%)7^l4k76els% z+82Z9JWw3*a17kwu0;9c5cuow`&2%ZSR@5U3FF+u7y^7A)qfQ@i^Cam{-zU?E*no> zuz*ARl%TsY2ffsDA-~8>dwFFn9JHyucXPAP#(##fz-NOBzI=tLRH+ixJT;|VVH2Ou zG`AZFT48L!j@?0y<^5TV_KoI!ep}3zmy2!|59z|EpsN20XL*9W?P~6KQ*WnUF0>@o z4tSG9;q9QXJAcQ3r>%CQbsg<=m2%T8Z{DPi_cD8OL^)RNd5BGmtU~tSjF9SF(0%p; zyae3t@pEjQj*gfiZ<`Q8r;DU%`^&vKjWxT=-i{Tx=rcnvL(?jmhx7633Esy1P}2eA zfVZbDmhQy3Vp1^80*KW@Dm#EUQ~=i5AOdu`{EIwu7=OtO%Qzh%3ZXeGa0@yi*jyJ` zd0*9X_uwf&#a8RwYrSfw+a&xew}~uLr!YRvcXN_fA$fT4=H;2DfD7%@SeZzDc|?C+ zB42pi-k`llms=PKte(%HHDi+LLq3bnPr8k3qt(>KtY4_A7OPL3N6lGs^vnz?C33YP;x z0P;a)S~_D!D9PMJ5P`dJVj+4AqxcIez?JM z8h@)k%Vj{}+rFnprPjU)-pk$}r%#z1@Ss!2cd7t zlMB7)+WM1~q6ITMZ^=pWHYB%LL@Jz|1ik>M6Iq0WVfHWqrsd^ia+=K}#{%kB>wJjZ zh!T8$!XUrVjF{sraB)I>o*>QF@{z8gs*I;}U&XrFL$Gv{9Z&<9-OUa4>sc1lRDZWx zUprjH{HcIp&$~HOt?>>Z%&bKcu2#)Aui4E3&BhA^cZWI+_ou4n)x`blRqv>iZC(Xf z^-a0}qpE}y`-cYWD$Ozbk)C6#h=lZ&s2Xq%oKUqIs5SEo-@3mTT82(;a=^^Q4uXLq z=#K;3zs-REo=1>v3`U`^qaEHBi0t<-hR}ZuQQZT}+vH(kN!DYuS|5 zukOZnMSw1%qFxF|8!&F`)@EZlDze|MA);oF7J@7P(o&K++o14tkk1_u$A1dI=dyX7 zCP5O}DX~>bss`DpQSD@!84C=j8ceF>y)QkX8>Yd#6;QswC{2I7ZeBJgKfAmHrOKUw z?Lw)m;?wrT53GE;k>$pzJ8x>awlDGbG{qheraO95Z**QbidVQRZ&mcx;^7eg!yxq1 z`>R{N$Qiu9bW?Yy;Z@TQG=INs$gA#h+eYI<5&%9T57dEw24q_dE|*hl5C6m~B+ZpO z6vD#VW;v?H|FiW9#=eyr%QsI~uwJvG6Ho`U2ygY(WYRi3w^bjA%PuPamsd#~;;71H z#d=l(U)J$*ahLM3Dy?iT!P{>I%J~@T%X0u@!?>#o&Rv)N+yv1nKYz7pS`=wlJ;~t$ z%^ECODRk=+QgzjjLj=DX*C0UMm)Fm>{&;7PQ4956z-C51#hoqB8)|eoQR@R5aqmC! z5v&ptE*}`kx<3WA9v4V}3}4o98o*)&bA3+5*^z)ss}7qC=BoGbpo!vuXTVM=M|WX8 z4%FWpq*h=HsBY*n+<&w;v|go3w|U#mL60K{+9dxOT1zF4A1<-pgORS!GlD*pG`lrI?nEw?C4YG zvTl)ByRY}*_=vguTidLtu-Q>|nk&O+(C*?Z=W}|psYqI7k$>GaCBOqfQ{j6}JRGc1 zE8|tW51>lU8g%hP`Ku>%tAeW32- zjK^hs0%d=W(v9s>%fD`!ukDc#(${f%`5D2}3y!Li9tl%vRIXSD_1Nq)7RRCr43{Wl ztH%L+;Nt3l0e|oZ)EXd8SpJg2^`A3CjWE(I7eJykRNzhM1oMSKMNS?gtEU%m$bczG z)Wt(lVB>?U(zogzAhN7WO`s4E#PF5r@oq^!6nN|Y9N7{mrGt2dk4&# zJ2rU0q-VXB2*6~({N9xxWVaT&8MXz5H^aXnt&#ua?(ks!E{*;qP)O@sI;4LJQS)O| z3b~DLAC$ZCcgKHns7gNp`RE999a09Dp$N8TSrY37bkqb8oNb920^5JZ!aop`rSwn=oKrF`wf~tZrv<}Fw za@d@4jX~8C-lOj3d~UV)eGw9=dtK)f8tD^FuFHjdkoA9|SI~8<(dxJy*s;DL$S_Dl zmvMtDq$;0*Ydp5RdhFISk@sC8J-b4k?Gt@(dDy2y&y%+n0oI2g2R+8aq4wJsStCn?_m1^dYiEHJ zU6?(JZmT;ntu9^C?p!vc2@G5O4MSYRw$-y`6Zq%g!6TZ4w-+EC>Ja1)s zoPT$6xl#n%dg;zZ-lOy4@Saa>8wC_XMdON*RE`fz-@mhdr5%F(NX1ZK*FF>jxD~|m0aNeG^d52 zbsc-js>3-mO;~NbaXSbt{j$^wDo8xPZL7e&B%SUxLgGZKyVqQR=WzA0gnE*zZSzaZg2Mrhp`cD$6ifOoUnhI)Z?yN;T~A-P$BgF2?3m7G!sWTxV9$w6Glw1%7EQl4C8;$`g5t(mCQHv_8+$Fx%;P*P~^x1cC|0%t^vQcsrdbqF^BAt)! z#(=dPGLPZN9#q2ek!lc{t?)}8U{!zbg2rJpCnv5NJWBORYo7q`OW81|W_6r$?mLC{ zIk{7euUB5t^@PY`i$CPUc(bZH)T^B#;kDJRqB`s%DW7Q$fe@YOJws|fPcCOW-P))T zAU_C2;?K+C!q3IUE!ebjc0}!!2*=~r^?0k^{n*PX+5iEzqQo)PvfmnNz3P9i%%brV z@8(wZ;ugPHW7Vbwj#VWYd_#vf`4#}nEOas;yC7H0x|ygKp1YjGTAc}WQt9RGJ<{nb z+dlhjdS`VkqP}pcqtpR`2TW01(dV1Fid+g`WcT+I|zQsX}M<(bbtu z26lH#h13GaEk)gzIipXU2-o9_AEm2V^-`2w{kow>Y>pVpZE0@Vq$* zB~#}P2djama5}5D{6_5``Q2dF0v=Q@pBQk6=mc}}A$PvJLKH{>^5rP%6>mWCBi$U} z0Zp3%qa%RpQ)UX1r&R8){c|1Ld^tmw%Hi&$*-=r?-UC&7c9;OL>mq*_=g|d5XEZsU z8c0~l(p4Cs%H`zE@y)r?t`w0@Z>>5m#SxV&{2NbU+%BAf&^a_;f^lDbfwym^j1958 z`1OTU^)poJCYx(|q$Xaqa7Fg((NIf@)F)-Ux#w0vioKKcM6rkyn0O34AL6bH2q5#~ zo>r{!ZRhwV(HEk$I#7QPIHuE`(|T?UeVT7rPVqu&pdmLW==7%z&ELH7MZM=7Y8{$5 zFESDOy{#Q$I;N{QO%<939uliol{_-%cTb7$n(RpBW=Y z4b>(hh%!7qik)x1?RycAyVKh|Ul?O0sSqFayd%8mEF#GoT1<_m&?Ik9n-H=mV2XFc zPqf6Karb9hw>1aKA+rApz%Ty`c;M4BaH`h@J1N%vEd+n^gl@YeDkmm8c{iM3XjrFQ zBgY;PI3Fdhj&_7D;$#i?+IcU&u}iP_`zm<&DfE4Xnh^kICQ#ve;21IQ$Om0xhDr!u zev_La|5H?(-5O7q5?8!<>qSL}KE4473Y>KU%}c+5rtW4OE!0(nBg;sdk^)pMEw3nbcG z$xhx+xImK~xOA_(vE;C`mm>ssOj2BR0v`Dl;}xK$w8H93{|`rv%u(>IYX%a**V4%&Yx`v2wk6VEj#3#}D>n?GNime37N z*)BMm9r5Js%9=BhwIe!N4buU(<6nXIc>bP<0Toc3vW#o1JKH(0=FIZB@Z)TJQCwa- zcLgJ@p+jP>*c9RtS6)wux4R*F$SHsh2koYEUOY3Agr!diz^%q80c<8`M|nxnfy>)1 zk<5P?(Q4rERbP(w(iih_*5Grb;_~aaSN)~OuA zV1jgF8!K+a{o4WJk9{f&J2|7NYT<$|v!&=Q_B6OJoY?i;08yUvqcXUwY-QZ(z!cnE z1ZHx|^)S{4s5uM*l@3uZtxtICYPeP2uws9&R)78%Hp)&OXk~5*k8|F3$VfN9i_KWK z-!A3A91{OF?`UeHlq&HTxb|tV={QWg9f1I3RXGd?o5#;JhmACc)2zm8e%IlOfGHhp zHG8+vL&9r*AdZha3mz%XZY7yp0wsoBO#utXDzt5r^L+LNl`d0OIynrcam@rgUzdOL zTuXvVK;f%Efp~Imt%b7pw^V?52{KKIb+b$iq;sitfzC0NKq@+ZJK~ltL2`Zajy;Y7 zT)KZdia(XKN+GVwIRK5o3DtMA^A4-!!2t4{BZXEqWsaO~9LG_2ZiN=-fID@PS9k{4 zgHMp7T88B1h@Sb6Qgq5yM-tpaT$O+7Hq)*~g6@bA6Se7*IN8%0W}2$9e{Ebt&f5*O z9@-td1a|QhIrs#2y*j294!$xMK9aRd-Pe`JG3Y$ob0r+t;SHFU%&CtukHFNilwQ2u z49iK8ac+BYq*#=o2%htHuO?hmUvBS4Rp{kTF?j7X$wgWnB(AJr*vLWXjskxNgpraR zHr~2=y1&EKOmDcJ5{G&rk-_J6_W^QzI~BJn9bL9pv!F7!ul$4m&O>q>{^6xv+)#mA zZN;Tw%7kWim*+EI=O*b!V@REe_PcFV^Om##y+E)K5BM^l)P9n32P)2yhA(o&2-Q(bfXr9iVHY)re5jD)?R-gnW^uuz1_-* zA&79~kgoRVHV@zcYPy2oorO~wtr8nm@ii9k;{YhmH1OdfS=(@jrZrwn%Px%AW}zup=@>VX?Ajm zwwqD&QoXVKjgOFDXSaW2S?z{O?C=WSCfl)Xo?Ab*>7CWuCP8&yjSl2cAGbc`69CjJ zEMNJLhbsmtazuha>XOZ8H)eAoba!y~qPgRCK4nF&@U4YF1Fx(x`yc@2dYwPK-=sRc z6Sg(BogI3skJhGyVW27@rg*!~u=1Ap%J4U>W4#5|H2{%2eAIvS^Rk#Tp03(62tpy% zM_;BlTslcC{c#v&|9nbZY8fEnGcCd0#1IQy*`cD#tvp@QI(Lq9b!%UE6!_=eY2v{h zefYZ$a+LW~-xnV#Ip)qWIYS+54S^v#=hM>ZZ_GhkG~m&TO?22ivNMu?ebTn7DYbR? z!top3DLOYzx}|@{hsp3X_sd_HFpMmP3>$YA&>d~Ew@R1@zV^E`E_N&h7DL?7NWKtI zVvvM0q_Of1eH}}mjFmJz(Ar>e5++XqCU%@#=a3M(IPgTV%hH#2ZPus1uEK|rw%etI z73--^9^ntE3u?%BQSc54Ed5)Kqt7Qy;JRAxj(BqRpo@Q#R12<&L1Uo5D@itOpe@Ac zS3zJhm+A$&cR$eI6`0;npEW0Xo9WxVZ`heNy6aY zqMdz9&MkkYQh|_qTkuSnK-z{whst))(K#Ic8P}ase3FQ{#3nUxdr%+7(C@#>D!zi zV}?N70AgUf6a#-RyiuPjp)IVQ6R*Ji z*6e<(HIp3|Ke1Zqkmi1s$p%(d`;0#izWe)H5X5~cs_W7nM;J(GntC8Pa0zFF?3_Sx z9#DT@*F)J&C+#7+!}3}>AHCy-l8YSi>Er-M#87s-eio|inLPe*1~@)lJELZ4Uyq*K z$y%VVy+1-Mw8{a1nDld;`72hG9b(jzMwgE_tiL(AytBfwBhGH3s4fxFKh+PxDmRf^ z37_HN0o{L(Us|R3^za^^48oUzCQIK!|7(A#m8$nCq-f>=eI1PL`UuTC;ODKoJi6jJHkZz3SPj%MC(;CggV~2)L1_Tu+$|#+O za6O!T;>H`RN|%C7bE=S#z_vsl!>4U6-ofo+EAZpQ<{)^%(QY{Mr6+pm5GnBbSk0`k z+I51~0yDQ|H?IG)zuQgf2bj!{nwEcOs`_LwXa2R-s;0;B=<077%qA(7gd*^y+lk!87a+_7H;h;HuY_mLe*fVp&JST-=4uFIlKC; zd+6p7bv>rE1-leHcSyKjt|RaanhK&k2|dqT2T3b~->g&cF?k1B@%R2oz_Nc5wRPCrVfPYeA$**IQvZ0(V;H-|1;<>K>dM*F(^B5-_QfdaB^zINmJUSLeF$5GN*BN=Uf zCa|=>5y5ZwoWJ54o!iVawo3oNM{uU~e${(XD^oc5#p-Wr;gF`Qo5O$MKtXHml}kw! zJ7IJ6aeGU1QU}BgIF=Zzfka9w9NJIsWB0l09Hj27LXY!m!YMKx2?$IS?XehQ*OZc9 z+m#Dg0OZRZo%8aE_@yc!i@4UAcM`cif)$IPt#X$(=vl;H+-;glf(mV2w!A=nro{5P zXY|4XIrVkuwbVZwRJvhZ=v-`T$#={I;qba>R|~_7HoFQ|Ln?nf$ ztok-ii*|7%4(}x^mc4IRfO~V8TLD3U)Td3B`wrGx=RfIL^3oh6KO2?r?#Yc@eli!) zY8brEDmdwFgw&YJOZIi3fJKS(M}DmH^8Hw!7d72{HZFhir==hXF^xIJzHZC78g;Cu zf{--W@O?T@Z_(Pt{Bo<>SQQ$9%>v7b{ckY=+C1CM*+#w**H6Db*aslNYxO)N8J$g_ zbb@$o`y7*6`it>%Ud#Qk?d{aKlWA8C@WC_qTp#2+TUAO>yPNOBw*#;bKdFmW+7@e! zvn^P!EM|Y?)9EKkyy2Zce46Hu1S)ap`-mZAXO^edTc6sl+${d36%;L%_p7L}2>f-v z%f7E`0-gYF`BES!b2NDvmg|7tnpJR(T{->KYgrKa=5Agk@bWpHD|D5)AspVfJTdR6 zjDp$EmB_pC?nBq-E8WI2@Jyt1yDKBb&KV4KQmGX~SFU%BihCR2(|PUW zsD5)zOb4p$xMX!cR<|k$QdXubs00HZO0ox#M!ZGjL#UOQY!BqCE zA5O`qabJg09B16FLTu$f00JD}#Fexi-J1L4YCpbCdL8cF(6|V|=DF=k;2j=)t@`o~bVgct*r^d**Vv)Os`7WOyi&gAO_c zRw!wKvcu21J=65nWs@SE@*BT(E=tp0m=lK~hH5icz4;)wdWR(TWf*kWjGLKV5gWX^ z#EZV1N#(AG*BZCU*hP5a!vmC@Qzv_oIh=pb=ZNcAc0rt~+vPl2jU{5(aO%K1z(co9 zfqdsZ$bG=F=ENcwvsw0V#L@i%xGssnIZZVYc(-o>dB2_!&Uzmt;sBjm2ha9(sJ4wEZe%Yl8D2umiAxMs0R82#z;QXNCMqe)06yZP3NWE29)W8m#d zEb~}?qSQ$(YTdnf`c1$CTE2V zLL%Mn0}C!KW$2sADOLg0^67Df&I)(_xGVR(oi;F8H_yin!m(xnL4Bki`~uvmv)(2zAW32vxC~41_wDj4%P#O@9(vxb4Gvk=2WcK z_BA~*6W@m&GU%IbulyrfRSPnG4m-b19b=dAG`JUn=db|!R5a9BLCK(ZzyXfi`2AJi zQSBEsKFP%o`A6ZGWbYJyPbd)egtojh_*aZvI(puuuyzWo`aaKlJEqnkb!0`*mC7{S zEO%_+?GQ3OlXyj+y_4fZsSba!x!38w%Y^zZ`+3H}QC&h=*X0CMa?IT<-p$dOZx77gqmtDk>dKZ%Sz?8lV5 zAUf;nAWXvKtJjjgX~PDh1;3+&R&h)2z|Kmy$3NFpB8*>d>Lad`ZeP`rPgq!h9ImYm zakg~%`08&EPuP3s8+?|(m>F{qO&T9F>99i}N;oo+|B?!WA}%8fspulrDpUejENZKT zU+>si`w+?0089_h?*4yyiI5%nNuS22+PHC^65lLUZwSG;s6DQNskNhVb=UeTwB|d} z%ks4jM_P1*O5DSDe(q7l7r&jx)TVwCl+H@FC(q*U@q&1$@9p|{^eF+%MIDf(@|_l9 zPQ(d64acr#xuz_=E$WK`p67w|bkEy@K3vCkjLZM|Cxl%bFXw-%1B9S4O%}CM)WTW< zR{&}GraHY_Vz=BSR_!rG(UckGi1Ud7sK9kg{=9;xL>a{~79I-}S62gKPgR#ItC^iO zxcCGIuIJbumIL$JZdtCrfVVnBml6)j{ObAX)Riq~;j5mXyx;k95cIC(80uvFavB|C zZLNQvH5X15O9`pY5TcK+5^BV$M~SdY1wL@bcIzVa{s5-+m z^>wD#IuU1ZcdL>EYx2===8~oJodlsKs8Lj&Y~nh7WfMO2ad~tLt%UwgGW@ zEXu7Pj*x(uOObst?ua>reL1SSti^u0y45&6fhlo+krieRj) z5bUjA2>?agKE(`{fCKVd$@NY)S@g`!mbJzED))a8+bf00k0o0X;@t>#Vh6wrWq*H0 zK%DL+G$f6#3_J$5!jV;14)X>j7!y~jtI*gKQsO7-yY^T$a;x@@v5@cGyh1)C*N6X$ zX(~JVq{4UqY*|7kfty^zL#W|Mg3Jg>_Qk(*{^Rmmfsi0U0pq;yNviLPmX_rZfI``aj_K%xf>-$|? z>-z<*1kMKsWDvsjmvYSQwq#^$k}8};Kcymj1)|!POe|iz1K5G~(_T#|o<)n~rT2ej zpMo|twiO(@x~xYK-mNMEt-(ymp&Zf#WGi0!xCpD8rC=BgDT#DLLMmSKPMgj3xOr|T z@1ghQ+6qt49@jbg(18*-<+0HHF#sU)Wlz0E?3NLe9SQ8Jw3SDeVo~=7`oMraXBnSu z|IN1sheU{~HtPAM%#Vm_Cu;%DYj}TjPE3)|P4)!C?^_vufT$K24~`X)p0=wrMe#V@ z?k`7XV3ZK@ruK3?9DgOi*sMfA2eT!P(Q+oIm+QHQ*3{`KW=SR z<-W_BNR(L6{pPLDr6!`(D-i=Tu?IA#m059zCcU<9$6Sz~S6f7XfMmwIxx|1yIVV9C5QaeENZa7p!5O`b$OUjM)dbPUZyMF-->Azn|cLcBFPp<#7t= zP#c`&zOTw=u7u*0NF$dr%AhwN0kl=bYO9vraj#52yzJJSmw>Cz>8qy2ye@G zG7=J=E&kxX!EX*C-dl+7KqPp`It*d(@Ezz5lH)cCx6ITOm$@&PH2bb_c6%q3IlZBn z@n{LEJI>vfkU6h+H&-_MM0TdM?4zrh(|x=Leluy$_sACU+8%$bwT9z_5FN7X1%VyW z8a=-%SPy0uwKdVIoX^EuPM*=E;rlVWRX}p)15{O4)izCbKB#dOtOsrn;Qn3 zyJ_U9HiG^OOA~+cSNSjq?NCVPT(53KHqSrrL=R9#dkbG#Fik* zalZ&J@F3MypNi;33)|EiLsEf40S?}m&Q4Aas4Oy2aW7iiu1eEDL_4vv*Q z;Lpj4TEkqA937UgbOv;ESZ~vS+~UV>#nxx=)<1u=$QG*_d1OLhmlCb41}tWINcCUIT&(AX80o1dzv2Er~DBr6p9^D%oJU z$ESZ$L?PPfB_~Y8ZdG*&rR;{?*94Dm>c44Jt36)!U5zIy4Kd*o#8q#K1acubc5WZ4 z-7D8^F^0tCG_VHjMB``aI(O{P%_kArfF=$Hzt&;BMu{mO#Of*V4TRz<5UJH1_a4NA zB%LPp02mVq%$w+SCS}|nxAisxHxnRk6=#>C(!=?>Zq6xROgmbJOK|~(ZpeM514nZednIy7P}^2 zrIxx=etJ%-8+w9o55Xw5eYpZ{g zjRImP!mK@E1K;KY=SV2ca%MhVQV%`qP@Js8#-RF8hbkAbeovL12#(ZNMn&YDR8@Ai zD>*Pavzn|`@tv~9F8W<^^577wG2l{HAZf+Iu_-)NFUsY{8r2a|0>N=YVW47GpqBK6 z7^BTf%St_%8d6{*3(TmKOyp6QuCssELGr5zYE{M(fM2h&IpsU>2)F*}-m_FYs??hY zSv?n2g)b$gJ2>r5sc`V0xTmsNe{VQa)%qRqa4YRLA$v3O1x@ddsn$z%E8PzN*k3X2 z2u~ne^$|Fj9fDZ)tc>*pUwxLOsWEjaJ*cwUa6nJ5cydU~%85_*-W9!J7;JyVBl6?#vP!G69%uj>q&n~Nm_|e*;4&|4i8*4i=5cc*IjM6D;&yyzgfpr9TI7*{;@o4dg1Qbq+b7$6;ezDTa;`jU85b zp67)9lyXg?a3%v0Vu9^ldO6J$g`8|5zUA$Ec9m@e=j^EtittVTN+W;So^_SKKpscs z{Y9d_P8-`6ac*4|H(D0kJGeIz56ox29ms~Yojcrt090!{YV1mfjK1v)wxEn$g;!X7 zr2_qZ(GF_##y;yi*N)0IREb@s`(dlJ;xNaar{qOA%631&!KI+5!yrNnN#w>!+iPb- zc!{8xa~mc+MCWCr6I_2^$*DUh%e2E;wg9Cz?Pet!_;vYks-Ks2s^acHO!jgOtAL8c z3F40nR0CKk_dLd)LE?yv!}4)Udc?Gv;X_`G%$pyb&h0crVt=*-j#Rr;V&tU{3K{uM zS=+HDA0m(dd4!eC17^Yo-Z)yX%bBxwzKAdsby2LCt*-FO>1=qI;mLxJK%exG(2x7dS9KP$6Q-W5?edhN zzxqDu6=s)a$XS0|`isS4fAP6U$+ja)Ws;Ke?x^j)Hp~wjgW98Y+mFu{ofo@{ev1xA1B@+v+#ZsE3e8>g!JLu&!$ zyoOVGAVXn{kzJ`KJF|1dpo&144sQmH;rt;qFvfcMocG|Yz ztsAT?m1cG1K=6}|uLP|&i53dZPNh$psiIldU;ZtS6o>)dx@-j8)mIhpwS;L=%CDnU zWOI4b4F`X>U*^!o%yI_t$IGtZWo66uYml|NcBE5M?NGwxx1S4OHJe2-hf9Nc#F3o= zNLDdpX+#lX&*JjA5%i-bgX&!5#HilZv_DG;Yb6Vb#fS3KndhGHW|IXGs;flobU^L4 z3vmdc9bq`u$7UhIc13XXA|k)uBotdAY>!ILhE9LD4D`(-xI2KK=OO%^&X2%%nlm%k z$)`RP9=NSD9yU-oU+rKTUL1VQC!{`mtJ?<&+69Afvtxv z6(`XnXwrOdwfwUYCzN~9tOxWc#IY-{I=v2r;eBXncWOAIOo9#;#2er6p@B7L!1v2) z4bFf00(*G#8oS;KUcK7#9GqeB)oOO3HHgD8-6`75DaY`l#o5AxpLteA2W_7Q%mR_0 zv|AnEbn)y?@p2yab?+TC4}c%fi$LmF?0mhd4KkoYh7J-j;oTNDzqPRv<`a!B13--CIia0d1-2Hg@_tfZao#2cq8Y?s^saIVS1Mu3tE^vb_TRyFQL7xCB#9 zY%d_mob8fS%76xk`4ouev;$OE?W{Ds@^(ksEd|QsL#;c!T!y+w^c5Fu>9fRi{jQAFpyL%y-i@+useVhMa+j4 zFQq!X2G*})DtY##3W}IuoTbcR-`(H<1mp6RrmaDJn|=)KFSqiZhu=Pe12XgwJ0P$2 z^e4M*f+ek|E0st#YS3@;Od;N@8dHB{#hhR9gl$Y-ZVXb~Xq<7Y8xxpa)0QDt1=q*a z+TNjGl1=fB!P}XKOy->OGlh`1t&j(YTydZ$-HIZw%jix%>%!wYNCK>G=vrZs$nVqZ zO|tV1ehZugb{rf`FTZAOzi#2IM^*EqsBs6rf+{$ibxy~NlCp5c=1EZw8K!>$fox}L zkO#YOwt!qvoy9`WbLftE=g-iyqLp3E{U-p&9CsPKdLe&plMWm8&=2%VO1Bz-K~2F;mF%x@g}i_C#DZzy>6XP6 z9kHb=lr4ln7U$>ig?bQXO}`Ey5s7UUh?jFedcRz7^h?3~bIXka(Rv0XAKqLN6>o1q zwO!@ZgP!VgEW-PA7|=bT+op=Bag2rU`|J+aJX>>6Q3~R|rb}Syvs!;r;Ee(EA5C2~ zoXu+O?m4UuJJfb{SKN3_76PROns^mEXu5jaRbehNm@P(O>}%}9%gUg{E4%tur^@@~ zE@AJL({mLlM+SE6xdoMK_==ATj&jg*0ZsdDv6$Ct0Gt~yc!TOVGTU17%;1p$L=nI-`LRwxKG`D|gqCUdSep^Na_c^@<^^^c`l^j;Z+Ib1 z!%Vy=0IOg8cd~!Q4nSaYiUL@Bpj_XJv8{85;wPLxb+-q6`wlwHC|^q`dF)gz4w~41 z0!8#g0X-!6+5qSa5F4=8wrTj#k@{V?NtXi@mlxoiHYNXnK^$azVH)q)4XkHK-%idP z%CNm7y$%J%ke(ty(5B1IKMI$v5bAJO2VXhw#XBVJGh%-$Dmjj+OKiIdO+bb{60jS# z-TmOfu)ErvG}eY5$fpR!&;#T(o$MUZ9C{=V!e%cUwaEh6nIV!ocy0Gjujx%?1uJmG zoXlniO)YFVAq0xBdN?Q4Nl_7{W;HU=vyH=Z*-xU*fu2#iBGeZ z?4^gG0)u~KL=pAj00bG{3+LvLRkK5UkMpRYo;k$H{xkT^%EZ+OUgKXbC35V4Qb$^A z5s;s%qree32+)JXad)pa4>0F87FQo@IgsR3f;TTt*paO48*{XWgLo^TOU5Dk7y|h3yL}+r9@zWt1;EFx5EPq4 z#ZxcV)l=NUmPuJ~4xs+tAg^Ep*3IsKz}U6NIaahzsa&F;_TGw12sG5%;!Qyu{G)lF z=rO0p^@I#dU{#qth}F4Ut1^g1Axt?C2ZA_B9`6f5l@62v7x6IR_e4lrmzFY7F&X1a1>PU-U=7p zjvSjeSo*Fm=MK=96-@J-RaV}s3~JhdR5X8GzUH>^b{<*P*JsxNEpy({v6^Co1&~YK zlA#Uzkrd2QgNJB*K0#O$)kVAE*>K%QajA5jmhnUadtyi*_~wk>rEu^)$yAE2!_CRh zkVxQd7&>4%58HI@a290BA(g(_<)~AC5v767?bpofQj+o5OmB|f!!~Q=PaI3TfwO;| zy9?;H#TDUq9JouT1O17L{#OnIacmUg;D0R9dDWa9HoEOps|Scv&Qm$@WJ3jDW7l`- z=-MHA_eQh;v^s)kYdn#P_Yj;d0fX$xvF$lk_RYQFV#2!>+?Lel+exWg(Pih0&plxP zm|1KSC_&sEezy}7<|c=|U}>F%TaT;{VphCV3PNUPc1tg;A3ZDW}5w4PNiq`bv#WsYVA8JxzUh?Kx0YSYbf@Ysh1z zRSh9+m77VKBXUx63Q^q>BjvgMmQ}^x?KD%dr)`{O9bTbXNDIKdG&{=&R4ji@ca<0M z4tnSiwvMex@mO-vPAw|=bUI#kY%ylPW{*;~yw9mtyvmy#P=S)Q<-oq&7DCo;Bq6Gi)Rn}(?ac97yXb=$yeu!qnnTU83Iws@sTiP| z$s(b%eL23%$qUL{J3%#rn?V6zP*k7F@2U4#BS6j`RM3ImTZ!z~>(=NgRuF9m*d50v zy8Da(6#o7Q+Z2i3-59S_}8tM-$fr)@f-fR z)=T6XO>tl|bi#fI$hDq6fL3Pzqv z_F2F($Fz0Viv~_pQSwK(u&i`-yLHJX;#fe3UbWFIPJ@5?KjL+sg7M<%l+b~W+vqVOo|c{EpeEz(_GP+rLxx1&p15%8|bMWB!y z%B3_LWKKKRy7ijCftUP{JX4hWhvkF-)HT$Xu?g%`Pj7b>@p8r&mMUfPl7vXakK+h? zO`}WT+P%kco?Cy@pddW5z9XfWbLjxAtjH?rZK~tCot($1Wajfa+T#&Ewa(o=wYKmp zu$!~ml8M7X*)SoS{q(-#+Wycc$!r(t>~05&q4Le1NK&8vY$?07E%|V zmA^iZYa4QuzQ@62B0lH=4JJ(bV+mt=uba)`JH}i&k4h5OMY1A9>P*NRVhA_ux(mR( zo3KsW`CfnTe%gHO_SbT!x^<1<4rm-t3$|7V)4ydWP1?K@cU;OQ@nmDrF(K4yb4;x} znxX2D5?4o}IWSD2dp0Pd(g(AwFWQ znmfSN4_U0YKSK$@Ew)-7N!@k=lFI`2be$@;5rcmk`CP;8-Vf_q-4QTf#MB)R#4w(r zLEjFpmm+r;<9_ec6^m5^nD|yjoWKv{btvmdpdNb0=e4$=Nv z9xZJlwZ2|21KxpEAl*7Oz_HfPWm%UT4y%7(;JZ^M-D7gI2;0s%u+vIx?Vp zBmm2#KNZj>!9DjDSuDxH8(aFJY%IU3)wEtm&6YD_OCyM;lbzEV*;&-; z{RnHP!%Who#GVq>n#hWm?gFmkqlSOZZh*I1=B3K5c5o(gHuYp}EMU<%&nlWL?d#Q70lLm^c`+)qtqT9NzN)?0RNp%2O*BXnH$S^OkD7`0 zUMy;_Yxm)!*D-r5UERJ2c7Jq0msQ#d>2|VM`KlVT^0V{BPHo;N*z%H`IDmgc5i`Ts z8Zs{WHq}kup0TH#(1;qVU$)vDHmdOM$unv&+mt=Fzoibv-aFq~^QtsrcUpaQ?{#d# zo}gVyj@m_V7PFHX^J0sKtnW05g+DmoUH9CL0{LQ|3SD*7`%xU@R=g%nZ9kJfuz+M) z`En3R{dfHb77^uM=h5a?n%jTcU8P%pXi5)TO}0qZrPplOcBs6iRS7`T{^u+Nbl{Uk zf{sXKPWOseng`E!Hua2&4Nhw8E6r1-pQ6E$$`=Y)+0W9_Pz7PIK%NK?3tL}vApL?> zg>Cy?!fcdP*SNs$gBZ5oUDrytNiUU4<1j^KfwE3o&1#IYV|zLw?Jj@xl(qh}$bRf9 zO5NH`8V(RjEw%54^mhO?siv>OPw7jY{B01)0jalj7kfzcXYZUKD`%%NNBO!kOVO%& zgPUPPkhT)~v?|)I;opZ!kH!&ihOBzJCluwrPt^szP>gnsoqJXWo^sdVjeocQV2os= z7a_d(OJyzFdoyS_pAvuZ&Mt5h@jQSXT1y0QU-c@Y*x>Ee2di-(cO++J7&egSu~xvT zQ+uFw^Ou_WBW;2VrV$g^Om%`QtzDk4EnG9nl)`3{|*BARo!ShPnE5k1R- zSx512&D{wrR>4%dfcb`Kjc&SArkxk;jc3ouLxn=w`i@yK1PFgdBAD5*@hFqadw{$X z4=$JP^7j%nQ&Xkm>5A?iQS_(U-eb$yw25ucO&l5yHLWma_9~?{i+x~SGKigyO|K{0 zN%&0!<=x}f^e9NSX++JF-D;P`GBtp@{>1HsZmMaPy{UJQ&60$*O8eBjN+@~Qbd(=51L8s!iG zoF!`H9p%W@p#^;c-Z-QFoO&3r5y&1a?z^!H!lkojpx{=DxJ1sN#eEyjGHm|@Uglu~ zCWNYQwT}~qqeFI7eoblCPm zS|H|tRCQr`6g`;)(@tn!-ZVgS?A=bA+|OzgCab}3t7Pj(ldK87PSq$}gU-Ow@o5z; zTwc`xl=QrG2_(BhGyw@p2c6m-R*R*N8g=~OIro2X&H;Em^?&jv>req~kk;~69sn*4 z$UfiE_9Rc?WAJYYpb9|4=~dw3A3U0+65zcPnOi&z_+^sanIxZC{TSV#2T>N=|>)<5(3c*vsM7goxAoRru<)r*y#c!Cn(W z@7XuZfA%ERv_Xy#LLzo5+cr5TQydZIRoOe33Gr1)z2{i~kga02+O4GmZCo=cgz-C^SpJvlWdT_TMryPK@!ZTZH7vGr|C zPWGHB&A|h(bU<$SSkb;$o$Zs2uaH2~^P>Vll-hLa>S$I8^Se=Z?DjLm0Fx6sqy^|g zb8=8aQUb(dAah!os8{x6De&)BTgrbk6usBD_n=M(3s^0-hVH9&v{5yJm6LMRS|I8D zaVQ?eF>b?4)7PdUp8*?EXrs$4T%Z+4nEm&4p?$9ouyvZccltoU4nz{dD^Hu zMb`Aar09hk$iuu{uGWYnyz`^ z=>+ZJtUQQc$%YQ?ll3^EZH-!C0AxU$zoe+Mi1t8p^N6D6O4e#KDwW!SFpj!ARcwor zJuvPz)oh8h2d|4KiN4XpW4y#Z?&OV$Fn^_-L2Xuf( zyY93*STfsnIZmwDdS&xo(eXliOrVp>J3r6v;%M3C33fmPlfmAUv&$+{ugK;m|LVM4 zc}KTb$vok;*fj)`!!q!pB9Wb-ymgl1mg^{=(O|4o&n8>P6mGD6vFJp9c8Be-!8y~X zb;j4JQm^O_@3+jpSF`sj>BZ93goE%Dm;`uZ=IxX^wK36u)SC_`KfM!tvIEa!+m@Es zCfA^t6vVOw9^u&P){;e$ww}$)TUT=HyRjEK4EIu{QSC2a+qRs$AJUMBCv!N!l*J27 zTbO~1#E${&(317Jbo*6*phuxESb|mm%KL_E?)q`VA)R&~`D=i21$zjblAU1FRq`hfWXKCZu)f>R_vM z9&n0!oV?r$)ho-1SvJ<34*zOv2w_MVVXXY8=%3oksB?FC=2+ll(R zOC0P~IAC|cUyms8f|6v3D3*m8w!U$=8lS5kE{h^z6`JdRRF!%W^VP`1k<;02-qn4J zPbX@tN-6gVL2_Ke35L3745uA6Z4W3InzTKfWLm)RR36shDo)QHj8u<{cdT4H2TAdl znaqDmIjOR4i<50k$Lk$sPm!0eSPQWNP64mpa%5_QIsK*ab-93yw(uSH`ooCcjb4^@ z=)a}X=dS*LpZ1pzojWxB5wmfmuWik>eSBcDfJet?z(_ohh8;tE#K5PcF znWp<*HyDCcD7-$%%V+BlS!j*Ul%QzRn#S`TxTMN|$wjbLLEYe(H}cgs!^&J z@de_CtWI?c8yx9UQmZ<`P9j_zX4^ntg!+)Jt(@)kJ@KL2;7+pT^T1tT*=dE!&Il?N zIy?a!XW8nu#!}ji1uNb%Z*p&)q5HLy*t8T!lL{YGaiE+vWd~QRu!3wDQWG?%ffhRm z2N`C6NAh7bE1lMhlCbi=E|Cd@EL)$|X;bwg9~_8mX9*twwxzD^?q%WohZodJZ`5SZ zf>knA5R!Ms{1kSW^Cx|maa5JHxldUV0?7cTz#}rtI-Tp+^PUr$)nB*QOm%imfqPnZ z&5-{t*k|E{h7_LGyp?hI{cy}KJCmH8Tn5R10aTCdjK*W-n}b9=V$YqhC{+S0aEhqv z4WMS_d0*{iK=r(BW+Ng&s(cYvxL`Lr**WH+YN=}0nlTeS1{vHO0nodhoZULP$vvLSP+# zK$>`SC@we^(O$dLcb7idQYwL5s-iEiS|NiY*%(yx6}AkA;fq4w6btaNqV&@ zK?r+Ts%Nh^Gv6^I9sCxDwBf#!H}AcX;5M}tX!ojEyo&)Ncl2Zt%=v;=R@RV5f-@)cEGZI=ZMSU=o_&53k!WteP8nggrnc)GhqJK}Gy(5+$K$ zaB$dP9GMhszK=@yZ{u1gs5BM7UODN4Gn0O%7-2HKg6g$jK0A-K3wZ@PWjfQu}ER; zw6&jyR{`?7t6ND_2$Rld#!28EFiwv?e&bruqgA^M4GF3L{9Av#&^ z?yh&>L^KVOIptn->sAPVsnD)iXQ8O$d$-GkwPd?1UstWQv$a4AO?uC6XMgjll4Ehh zNf5OI4zXyo@*14_Qf{Vcj%ADS^v+S~E*`Mwccb@J^_8-^;@a7Nl` zNZq!k!ojv0+538OHnmM5F|swh-M6C);yn(5QF0<@YUOfoONO9-ia8`yc%#N<4fbTX zGUFYoxDobmoywcb1s{uQ6^$Fvq=zn;@7d;&mq1ko_miDXP}ozPeI=p+OUHM{v)12AJZkLPVw9pBtl0SVsjk74-ve&QZer!9E7X|ZFy>(cvtgKVf zEc2Z223`nOWo){$QrM$H4VM~=$r`Gbe{iGtARA zXeImE_NNl2*0!&zd4fd=cKYdbX3%^=AuO{Ky)N8&0dN2d$@2;(kr{`yDO6!?Dc$`l#wj`K!mSa7u~illn;GI*WK z4swokI)h{ILkWhY*rrT|zp=Xv7N!n$lc?H61=SIu*>Un*necc>y?6;KF_A8Io1Nn1 zZI5R1nH7fO>^Y~Yr>Yth6KVdHVD^1VfWT4S@ipIT<}9=x7zyYZbY``F2G z@(m^OZyTAxuFT=UrXpCHM;*7_eQC)8}-anNF+jW5S#3ff>hVReqL(^ zr3qI-48UKz*+YZVsuHbxNqDu$3{D*w7J;D-%sb4habG4t7H1!1)6r}i)l)cJS`FsN zGf5HLCzK78mD@7JYf8f7Z;@PHYV(rP@*nwsJ6}rmYZrUzvC-2L^8IeCf^K_O9*H+_ z>*0M-;3?VkUa{EPb~fiKAMjznwTe*qjqK>aM|0@h`B~zz#vVh21T)KKP#{Xxk1J@& z{5W{P*}4xEX)WgwJXyf=-Ixr>`fL*N4gmJJdRGwOp7%o@Tr76A%th+5{-X5Z0gTmu zeQWB;EJ#-6BD268Ab&mQv_nE(6&nX%fpd@^9JSQ%^od(dm_Sp{rb9*Fc%doLko&DM zqH*{rLHA!UQZnCa7*K*er)2dM4^5z*my&M2-Pok#0c_SrINk5c>hjtZ?Ho zM0uLAxz^D_1-KB%X?7z@#u-$yz1W!o@I-1kZUbE%YLtY9rU#bgJ~On#-IU(t}zs&+V{5vU?~JH~EBZ22Ea1nE5uS1^nDa$SF`LGYkLwNTIfLLrWOHz+41)K(uqzv zB&U~^?o+FMi>RylX8F=aT>>%?7HU8+DA|{9Z5TS)jOi8hJ?&rR!+?~*TcCVvry0P< zk%8Je!?N9bZyD0O2unA#ayEEfQs|rIwBM5mKX_=nNQo!Tx)9iaJ&>Zz5?JewE`y=C z@TmY%09q)g_H?XhcNmC&t=1KjtLEOo;$1slk%sngLeI~!TgHLsN-u4>Ou>fDj6v4t zRLQ9jp&`SX-L)0|?euwOc5vWOwbe<@$8vn#PUEdPELyec)9<>gCS|C!l$fAEr$XcL zRS&vA0m}Ai5;0rsUrtM>+o*dfj3NbbwnO;ju;tVhhEy3VFV0(kRM|hPba-pErb=IZ zl;RXdu%4r$2OvwRPqtwrDQN;+NZJLv7dE569U@Q!TP3#(R_PYWp=n)fw=M@VD#=;& zi{y)5k&~0>R^C{0;KlQ->R#=h_;5Qy z11o}f8TGn-m8@ugBPMHwsBY6m=7ntW6#_45D9PxEhpN+RSg#u>q}ZUcI8hxur06<{ z#Xf2nz`0dv%GNij+B)f|WlQtB@d!&lv8bBrq2(UP^0s;696%_2zet{eV9wz)L+K_k zA4Lyn@=H*mm~U8nsXMb6<+ zIu%P(9VEDamyPKHm0^ywL0T0_2mkD1C6MV)?yPcE;oQD|5~p`$J5w%_E^HqTETQA+ zrp}L7GzLDZ)9Fd)7;_c~5e6=s=J{x_>U#w}U!aKmRrK_iyoKP&hL>XToI=i(s&F@H zDMKs?n8FZ)=u`KJ==W~l)K^`-Y{-BYWv=*TXlUDiB`^5<0dbm=Zn1`uY{|`tQ| zVJjOFmX#ttG()$sdg-wYc2#MNq zK#Gp`vd!4XVH?z!W3cs<9@mPAKLI(|r<_<_6SSshA9LDs-6<8I=r#K@b&2v&=5g#> z@!_3G&36AnkJaGNPs>IDU6fXbDzSgy4kx<}OqG;XC|*_o14z6{U5BGZCmZx%Ji85l zfCi@)9$-30p;fl+ z>p9&ei6GT`Xv9Grt{U#z({a=-&J)i=f3>mu{n)MS5RGK&T{xKp`>H6zsXdo}7R;A{ z>a-2T3AbsJflgec4ZVxhHUtgQ>yPGy3c zVlXTjl!jNSl+(0>c-dhgM{dA(lEevU+Q`dW1U4aLyekOOIl&jH;;Os-mOonpxNP7c zkmd9Ly zUBU03qGo%xR^aWQic=7O`AxepxUBn}7ZO2Vt>nnj+~ak-uc>)w>DcR|YL+$aqS$QK zu_*w3VP21SY***tC~*r{WN*MG+G*2C>t3{bh1pr|Qqy)zy_$1#!y=-_XH{b!j;y91 zQy&Jk&sW-7pRCeD{)4J$d3DcITL{nHvRma=JC)zkeIPawrG_@Ur-Lwh< zVgoy|qCuWGQj>}Ls-u0~cIH{S%s0pvFr#PgLm&l?Y;~G<;1QxO-ny^wBl^-XRbLrL zF4uXHDEl6m^2#2pb8Eo8$X>UDav?j!s2WX5I?jmln>NxqDHB^rm(P7UrsQB)Dr!Q$2_-xU6FJ$O)b@JWg=xfXKtL- z>?C+$kCXS`ja49-m!{N$LoZ$cJ@6ifA4gEEN6iPli}^3*k-a>0|M?S}H;@oPC3j+Q zWJJ&6i*%=*Yt~uZa@^6p?bFrBIrN8+PJ$RtQIu=#M|cNTVd&aub;Y?aWl}X+Th+VC zq|S!b%=z$tb9*vvo(1H>1_6`~H$)U>&plRLm!{&ErT}Ml7|R9~pV~plIWOBF?`}V) zeM3Ysg~d0UB99g;|KZgW8<1!ys|4(5h2-W9opu|6f~$TU#8)5$InT<*svyT%iS-~) z#|j(C-{P*Kv~dDJUBGC6_IxyTY6==@b+`4Bj(sS94?VaR2cX66@wlZ)y=_;WMyC|T zrfhyDahavbeNo{-5+iT6bN7eD{vlh4-t`}+8`{wwSAzr&!d+z{jmPGPt1S{J~;Zq5R;78POU%NJmwFlS`}1<&`ZzPy1e{tls<1=i`%4S9tHI zKJLH1-uvA@_?RX8^wWNSv_Ai1{nPKyPsZo({rpFtjLu4a`OI&73E%tK&(^a(TOW`0 z-p~KBPd@v#&p!o3eDMBz-~FTOv(G>LN>{@BOw{me%ne*9~H_)mPg-utP4;P3sr{_uN0H$M4ze)t9d@N@pnT%WFwc|+sF z*A3IEWpL7q1@GlFtd^!=A6x!Z<1Wz-ZhM{D*f$gxG*K@jU7bl2)xH3kV9jMKxA*4s z@2#;OT(H=Ppa3i+pob-)a#Zi(8;MX3B9K??Us%doLZyqN%a1yv9W1+)vC#7oIG^#?QMzcD9LF*dlTv10% zSs43eZhdcbXBpo2r>3y7juZ=yZS(kfkq8rc*CxTf-$^;nqHEEi#O$qqu4*uGFZJS~ zzhS`Ft;g}nUj7Gnr{YO=m2=MF8==_U5beXtI!1-C)DKet9xegr(IR~}dmXC4E${lk z#iZg>r^lkm42;Zu@Yu?pWKG0H@#)Z)O71%hKQ@sN?4Ota@s~dM#rMAV=~|!t!LJ_Q z5B|FMzW3Gh{CBS}x?lW%-EV&95C7tK-XDI<|Nh1=?p`0b*}3w?>kGEG+4EhS0#)p4 z7J-0kje}QzZTg;0vUFZkM-+PiHQ99-%weRn*>6#TcG@gS_XsB)2UvOM5QhR718l9Z z@DLWnH!{WBjzeE&iubZ{~-$y>LI0A3pwn^w&Q)!uv75fBsf} z`0fwC@}n8z_0xPMJ^Z0R@b~}0zd(9`(p@$s1i~<+;3j$oAZNZ4rw&->+`G*|w;Z^& z!J0zANWb2)X||=NdAYVTm+P{!bDMK)5ue=vp{3ZgFq2MxM%2HdmTDjBZ0mXXpML3s zzy8O)_4|{2>AGuwjuT=V9luYPz4C`jSfI$b$0x?VpmW?_i`LZBAmZp+R~*L9!wnH&AKUxs{rFp({-?kE!f$`iD?{QuEK#D_lbVWtmO7h%TT;HgJhv;c=&{6SCwJ>D z1_!a4#Y?&~1Vgu?w2k$m-XORBJx$+@0S6PW)T-oO*R?r}vbEguJYo&y<$wOmvFEic zD2cZiCh^V->YIntTpCboSM|-OnQ^8Ua3BRc3Emo;6xh8ttJH_${TzBZNrN<_WaN8Jr5oD^{?&wx4dqD4ek3k5y4x2 zoHw?}FMRaLC!eqHuaE!ehtHpQ?-%F#e0=udr@ysP>^!$UGG03Nu}PZ7nNHae{rDxl zdaVIX3EI7FJ6PKr*(xjF3PiCtFFA;J0mJ6?&O$|AY6CG*;_++MZCQF=idw^QnxhfM#{f zqmbNZy)`#<9UpzbAIQ{E_6>|h+lxRgpDh}`o%)e$G?Mg5dzuahP>Ltzm;dFLKKQ9` zh-S8b254rNu9;4~+#n%5U9ebdJC((Ke!JjqI>&wW6)tV6ZM&(?d>lXxjg2l+%bFm& z(4L_Z8f5(_%c0fBdFnf#Hqexs)X3u$x2vh465iNwZ~Jk+5rTf1jlaI%oD^A(4BW#) zw@OiID)Mqc4IS23YEb#z9CU7)xp9gdYv;v(DS4D{ThwiKY_an&+K28&hInr|%cVfg zW4oAxFAj^>XC>p*smJg7;ePuafBW8MZyUt?L}03~zeSD3Ee|{I^gPeW^1{V+AUtyO z{4|vWbTL<v;PJNdD~0( zH4t*Xf0VB>&Y%AB3%^YeBEtRg!rrE_Pd+%v+R1r(!}^Hf4PI7+SE=YU=mWe)<_?I(6yzU_tk>bCp` zKkZ+PU;W^>9`^UMPyg2R2lmeVTYi`b|K|G#AAa=3hadl)aC*Uv>Z$(mT%#XTI0<|>t)@_5`oq9rctKjgguADb`#QQQ#c=gki!1Fi67r~1b;J*{E^SU|HUW2wm$wEk$&6j_O+avcPGzp<<$HQ zojvaWjeZW!eOz_f!?JC_Ii%Wkgl3VcRwXBcl9Z{B9-ZGjvV!iBa9lJQup>O49I&~z ziFmr9fBkA2Fu?$3QIcf~BdWxF9JSr29mlJlz1?r_x3}DXBJ;+6`{|F@AOGUB{^n+T z+l%(Kq;)BE`=N$blm{PvTU;wCIkw~WehP))GSr0$wBi@GtB`%j{4I34CWEJbR4 zcHKSQ+hvDunvV21D|R|03F2rg7DYd+Q#ElZ5*@*LpP<@b?G>SFRpKG z+v!$8qB!NQPJ2(#j7EaVez51|fA=X;b&R8G({S?RuiZJ@w#4ypA~2kZAM!|?OVI#x zY29{Z$Go>oGrKYAp;p-$j?oiBW|;2dqCl!`CWgj;`6>s>j$QGvvlrrs+ zI?w*NPE83i%Ru*`a&Jpjf6M1;G0*t&fBw=Qfo;0D*Op(m_S_`;VTlj^r530hgrs1O zmRF~L0!mc_);#v8#KlWIRWi;;cSu0HBbbT!(<0E5aYuq{|1I9x0*82{8S`i80YQ^S# zLUIP`<^S28mTY}>eZg~1&WF@BYah2pizK*n$4k!Vr?1R5S(4hD_!yaDCE|MOzHTByZFaHl5}ch=>jsF{_-G@g3mGSlTyCC@#WOladH;M0cLSrR^5b|JQ1X?X+s)+3#X{I z^{~da2N)k&$EHK314nxK$9#&DUEug!Q|i?jDK^g}`e#?ityCxJsam}@bd&D@xoV*WzmOTs(?On>FOWuHGkkf-Q|4uq+knDELk>F}I@*#!X zR!zJh$r;vB9#wl(M9xpu*eHek@=y2_P!^KJp_A+bl5IyjF6|9st;el@)t)US5^;q2 zlxjx+C&RsGrZ3f0VVElCX@E#vSBIf|aVU{g1L@?>c>W(n8!C)aqf53@u>EKaLvA4o7HKqGG5`qoo zd)ed9X$XiD-gW4oQaI6z%v~V&L4CDLYlQOhPwg{eLW(mx6{sZ`q>AvuZ?>|lAY!U5DBy4qlW?om%~+IoYkb2yVb$SGlN-#9fy<5|42YIoE`npJR6Mum?0 zkVpP$pMn(7bVRzzeaarOZx)e|RnRIvA4BZ};S%XsJJ-%LIbKR0J!ZCg!2amB1OJ)` zo|khb_q2EaP?g@>`9kQ;3iX_c=ybsZdE$%o3jcfgXM74}Po8am4WwG);wVOy6`d&4 zm#<}&G&r!=HG~_yoRhRNE_FXhcIugP(1#|8O3&K}q$61Z{$vfS(pH0Yh_0x9$r4vcRl~IX` z&m8_k&}<3X$k`}=znr^M&D}h5I)7QoFIg8pMSJ?w)KGi*=k`eryH3<23$^9&gwe!C zPSp1Dj9-d#v%;WV%@%a%8su6+`z0y?W1M6l#SYHbn{VQ`N=BNWKQq_-Z17F|9SVD0 z3P5e0oRm^|`R9EK1rrag(SuSetVeewhmWXJX2_4Vi6hj1+*jxHr6G>ldaX8GajNdD zgylnA0r!_-?9zTzNe{&kOBxNc`$^PR_sccjR@Mr9y0bM{v zAzh}*FSR>=h9gkn zKG;nG;2=cgploq|74+KB{YWpjb5}_emmzyZbvaZ8*O>Hq`IlZ#Do1Zd^JAL|6EC&> z3VVl--2a zN6;mIF`dNjl=KEXw7>!3X#G4junF1@tB}u|P}w=bgr0q@!Z4wE`A-g+lc3%6Zl#?C z%vAJi0H0{IsC@YhI##^=tKa(|e{<{AwXIb(V{OheP3PqZVwbo5K&Mijm{;3_lVwMG zgm2plMX2k3iyQiK$L zdJx@9qQC%qs#n)t_J$Ik$_GW=;c|4S_S8_ASToo@fR!P~AYR7p<8UR-JYety#9=?} zqdiFSV-TkuhJCZM_borpH@?cR^!I*44;CQh7-gxVF@UM^F6XU}dY|*jiucW`=>_P3 zgE%$73uL#v^t+08aIA||Dv5-a`|lNh4N)h&ADyF5Pzy?n-C)G1k%p=>r8wV85HD}M z&$r!%_-$9@kFP88ZO=8nd71N;ALos_>7OgWPHRry-6?+#V@&GJlh&efo>P~UM+=v} zkg&R;qZQjQ>iGMJ>9Zv!GWIc4vLSVxD!CU3TD}x6x7I=)D0ZZ9xGmu~WuFRvxIm?? z-)xHfeZPFYf4-ky!|Yq0Sonz7@U_5`plmb;Y?>b&;B zR#fy%n3JM1>a(g@1g<|VcWbUXLruDDPR`zA^>jiEfctVv@A86Hb7OWDX%rCt;rsmA z-}lS0Sn`hFwk-dpw=5I6qo(tJOAohQ?ss6?@~!HqHe6j^qQe0Xp8J-#bD%Bq-TIxM zz+kA>;<>xnJ|M=+hKmO*8+1p;SuU*d`@5issT7BpBzu&p*SxweT_DW{hDbDdu>x$3g z6(WcTVmeI@F%Mp3)@z)9H+LwpsjsJ{23@f01<%j-)Ug>%2b)fo4SNL1cPP%Sns)-a zYfat4COP7u`ex6_+pg}vvDJS5S3c`wJwN#9`_I=J0^at@eeI4mzt0}~>UiImUwG&C zTsY^!u}SqAnm&bCE$tl<>g{dHY*Cls5*Htv|A84?%BruC!68$B6-aIVph>*dso?a2 zAYFn}0u4D~DA5gH-_7Co)KoO+?M_4*?3nY7J@>Y2_HXRD?|%CIk3RhM55LyG{I*x^ zYY{HlqV$yr_xj&IhNjN5uTv4c#R?7mC71W55MS1kS7Z@KyIR(No%UA49yMo)vp3bp zo~VHm0YJ%mXq)qYF5}V-qJwSAHLE2w#pcdkJ5_eFr?!P9i8uGlzxKT!f7_K8;+NN- zXSNuter*_vXf2q0J=Uwk@Kz-qocS(B1zGEFwod1PnvR-Q^g1jgLaoW3wGavUS3!*n zq6mxBRj7korFLS0_aR`X&19Pzs&z z-wp)ppPhM6DK6*h?>S3Lw1}|^t<9-jc$agO z25>!pY_fpru=lpZrO;9f!bh?WTD~znFIS(eET)`t2SdKSaJi8VLd!|upKQy$$CCqI_=!b{_y zY~@Yfa&*`?kBbQ)@l9mih2H8rfQ;*PxwSF+q3O)LoO?bd!+p72t3-2}HdUyRBq* zol0?^EFP#s2kzaK18SJ;J;9=api08u<>lYlEpDl;5n3D?6_habid}P-p?x5m`^p4= z+n@`@GYQ6k;QhOv4w-7@$~N1m#lPBRHOZ+{&g=m>yEs?mjG!mPnHA%mF*|*-4%VqF z4Lb7k@^AVSk+rk!Nq?D9pSTy|3Od8}6%J=1>|SlH9RYsG^WL3T!YMohiLYtf!M{`n zxMZM7J+JE+XH;tl2y=IB*v4(Eu4X=ewllIAFa-5$fk7|-)^2fQmlDD>O0eJe(Qo29 zY>{g7C_GN9D_d@Pijub4ifk_f9kQxLX+HEIil&2&eCb${Z{G@gB^{4;fdrf>1z2!0< zd)_%riz5P%^qQYH+92ebylJ+TodBvvQ$8G#dz$@k(mV0<;Vj2^t(SjiH&iX9mI(fx z&oK4D-L^)&bY;tPuoUnlM_L|s&OElg77rKQUTmaW*TTAm&k{!)t`kENeU9NxF@d8F z_F;Oq@5rG+@|pO##YU+f+RMLxyW4jLlq%^7?dSq$v-y8kKb<@|S4`J&-^wjwy$24d*@ zUHFPt&79NinfZ+LWKfVp0(p$cXV(OTs8FURu6_5*6e3(tKZ z-UdZPYh@c!hn2m^j%3+zXYwWx1;!;bW!rTU;*J8*sh7S0oky^LK?i!d4y`-x`v%bE za$kpoHTrYv2U5sut8C|265JrMWeupcgd%0VIimKqALkoi35>LK2~KkEkJ!$rF$Tt#n!k#t_r zauH7E1zfT3IOw>4do4i9w>@p&_OyN5)Anso+qXS!ejXCvULgocZ!H^b@|n}Eoid53z)xX=@EO$>SVX50 zZ-@Zr{fLs&u@<3xJ)P{w5f7Oo8I-APk)DSyzwpl8Ktra|f)WnJ?hfHNZ?stD4?ys)TvN?b$KS%NK4YAcv|fs7`%334cT^`rzwU%Uy$pdS!i^Q9KfJ>N^WP?1+fgG)|=4s zEni!_>0U;p>z}UgfBwa1AAbBR-~Vj=%KGD8P0V%J;oX`3u6n^J#wBOuzZ+ZE?Zj<4S_VrbpjMp#x7zFz2J&6E= zbkAph<_Uv}>PH4zq;@}q2M)^w`yiwlT6bztqpw4&^SSTmfQ9z@I_n3 z{5YU`4jF47HG{!NBTesG#>v9A`SKrb)sVtzwoSTTSFuU~iD2~~r84T4K73fS+G03* zvA$0v=z4`_Wkl+EJPIrv2{P4K*364@c79!dv0fVGs+w@|#)?h!mzO99Ig-G}g8}CI z%YXE}KbNh;+pd;&u7_T*oLrcr{j{@^3b6#6#?IeVh)OCxm23Zjo6u~<%SV_Ogdb9JO`QCPa zfH{xfydwEsFR}cdKlvwr&r7VY|I@y$7W}1G3ka1*z73(42etD8vwP{BZkw7G>@5@h z8^rTjg%Cih9PFIi>TK67UbB`#Iv`y1Nf724o^ao)-gDyF5}7Q{M za6NZsCp@v82kCRwD@e85YU8-_8GNv_L$FhvEhvLUW+VhFsYO(IoMV8afcmO8^(3D= zZEZa;c=QRi?Ya4%hrj2+7BA#~;a#Se|775kXS zf4b$4GH7vue@>9gbr$TR|(< zA=sA68w9dCV|N?{GNJ%yR?4>ae1OsT{No91e$MZL7oK@}G8^%EMWQnwjs0?#GB{Qv zoq^NQyeOG3|M~7<cnSBf_@(;^4q_N*$_8Qz1@K1LfgGx7c)qlaN^2S}2Gddh0s zgR0Yc^{3m3p`PpsL|Ylsx{lea*zrE@=zu3|=x#TxjYo=LfbsHQyo&e1*1>btab`H- z%HcWfxpVlBbO>CT6FOKSg?y`8Wf2w@<~6_*;1{^1>XfJ5S5-BC#cC8tw(cFI79|v6 z1j@k{J)abHdmMvMitJ)v{Fht2FDIqBixTdg_X%sb$iyU7e(?*2r|D*~&NCbQ$Fv%js+N0q6R9tODf6ExznR^I4H)BQWlrrT+5}qLBHa2c9nIPlc~d* z>cmq-n`$dr@8CEROw=zOyJM_3wm}v(u>{j@*Vl2=l3xDXeNwB7 zh5?T%DoPfA4o|U@72cF`sCsFU^oj z@LUjxu16QxRMW2aKQDjAr?}5iIFi{>Alwd8%_r45`*>7msxEBxB`Vt^$3$ZtEI*;Lawzo0ye3^nBvNcg*ziXSbYU<@lbK zO70`8UOv=Uoq8!R%De3$iIChsu?!w>#0ET?uVc4Gv8 z8|s*l2+YVf9XNuj?4fy0X71n#39J(#GtaXXWT28dG-pTFP7Y(g7(SPwf{&aa>8&5< z^FxTA<$pbWxt^?#*URTW`n)u^eR6lLG?%=onrj}htFe;mSLKQpJkssM?>MqYo zHy*k-8w8yrU^BC9M}Mg8lET=OLz1$8WdLJ9oWJWtWyp32f@_zNGVD|xE2P~@FLJR4 zyx%~%W~ zG@yM}W|iCFQT@Jkf~(P*$NA#e{gWr{M?ZXi zfA`@>FFz+8FV~B!=SxeCsl%vCM`Eam8l(Z|6)cE_wb)5A8b z0WU|O0H`BQGnQt`MI{E(E68aa&Xlk8f3OWhegM_7R+nHtR0U|5=B!6@>&LlzV)(mz>+8v*Po8}G;oZ|muXwpE;_hUB zbfsSqS~b;s(Mjs?nHZtIglC|jb#}`N#ac_C2gJJLIJ!yQlpL=E&gP=-q19erf55Vq z)XAelvbIYQV2PNP<#|WaD5k=TEXvYGA+o-TN#1x^_#Evc5 za9z{LOh@Ye&g#xd_wNi=OUIo}Q{Tcc1*o^c@Sr)63$#&v;GS@2Rjn>*izUBOQcscF z5O56$vC>)n=Vonhe_U#eL!noS$A_O60HAkves{W3VgUgZEs)v6x6gCmyG*nNmf3^Cm;f9tKnQq#}N z)wmN?T7dOK0n&swq`)>>Jf})=K)l<^0`xqwH-4O}6Z^rBqw}x)%2&i?Qvvm4M~R`! zJX7cYO%)$3z&!akX}GWH9E2!GLJeVuchJGLc(fouHEMwX0#uM}0TaXT)Kf;BUPDwH zkWmHQcLH#$$g!3VIwbSXfBn9o{{5ZY`#ZUB#GRZLu&D6uu zhR==V9CB~{IMmMS-C3$I<%`h4Cni*4I*7ys9a2KFVaXOmQKvLWR!vEI!hQf9m}=M2on_e!15&dfUf2U7Y*|AuoI0NB&??OLFW`Dz&&R0_lo! zLy&%kE`6E-FZlo`jfTn6ImeLdkN}Z7%p=4)5rXz{?6@|2SJk<$v@^|%VYQ0=!Vr+ z6(T-*J{~3D1j{Qua^^6=Nbm2{fAjb0dzK<4#c7>tn^!1KS8%3Ew1ULD{BTiPjo`j6 zlRP!*?+S|be<8wM;cdZ7&_Gr)$qX7|RbqWU#hS>e z;BImy(I}cwgw~0rj(tm9QMq&*TL<7Fc_NjTXo@oDYJ15mQ&%_Ad`PV}&$3h8>05R0 zS~Fr&-4TR_w1K~Toahgm-Cwv;F2T!u)SiFx$C^{Y!%zIu@BIC`$N%n&AC5<}J^vvY z>9Z8BfBf7ZdGF`i^N+9o#WcPWdsT{;ml1 z>ED0;_rGzJ^4<2y-RUQOEogE2(a)P}t~|%rf2g2g@?ZV?`E20yW54V5kKI2TI{n}; zz5c;p_lte+cfK~De^sCIv-9r7%kT1yqaEnA|NK^mr37TyVX*9+TH7fKhSwIhlyb7} z`QY5y=SfUa&nj_5q}-PPNQ$Y=B6n@Vu};U~1JP8In`Du@&R0ev_AlasYqAWSMb}n` ze<*i3W0+gpx}753Pd{HDG3Jk+w;$f?>ACU1-D|7Jr?!gx5N#C)`}(vTu|2;$R&#(e>7$|w=211`Ocr6k_F0O0eOgZcN~(<+PCU4 zR~cE|zPYoc)WRvlaI} zTpz_GP@7@hsQEjP|7;WD3KgEp-vW(|%is9H_rCSejV>PG5G85dC8Yw)_eR=3I(|%1 zCZ4@8dbP6`gPKLW2{Iyf33}183WZwXr%1stVl((puy`xC1}T|lVg?IlAPnw(WvW3F~rw39k>>3f;D z+%{Ws(9LwOO1q?BkRkB#@;4o#Y^A7!jz0`iH|qZk!AJ*(4apo!qDmDnf1U?z!KWID zw$KGty6jei93ix|)-pOISHTT9S~kAQ4RtD5Lz|o1sZ7c9^9Zp-@MuXo4hfgP`6%O3 z0q@dTFCSk#3yzSnrMM78E%#Q{7r`W$zC$M3>9)8TIZ7-8jp1j~VYJ9=7Je%(1D>sc z#q1`3nb*0e<#H9K9IywyZkM0Ap&R%FqKY8Q8E)MRdp7|pt2ebZ6yL# zTVzNn4|~Rj0h6_GVX#frS)c^qRNm-|YCnbC6Y-sZC!^#h1w=m#Zad+nB48IWSKKr#dl`u3bpFhi*Lr1I@B4Z#!&P#!hnGDCA(>@{lcy zCWZ0xsjFI3*ZFEt^^sqk8%TCEPgYr+pRFTqTp9TJf%i{Btv*jf_?~-(_qhw1`k`Ad+H5UU45OJ!0 zBWxd4r>gTNTS#!vmAd`d;S^*guVNahoglxuUf+Mr8ne`dTnFoqb+EU_f*J5|gb z^A?9ns*4H$2{+Q4)~$X$2&at<4 zs6L+_zj&hOI<2)^kJ%M(9CPxo18gd-siq@Y7bSkQ#pZRNO62K=(HH5FF#TD? z6wX3|%Pkzj77Jbn08*AT4LS})W0LJwbIO1vOsN3`{%S3{&Fh2zvvg){wDbVw#Ii*4 zt)A%$8?YpLWca1wlR^u;uQ~uz^lIrLh2KBa`M5p*fBvHn_s8c2ck6+>y5Q_-!94_} z>xW8&Y)q`G$9pv3h+sh2vA}QOHH<%mwihQ&SoVqf;I_Zbt)S-_1O(wEJp2&PMV zi+}BxzfDg8^X7*P>kibW%O~S>I!B0!-Few-s1T6pg;u1HcmyDk2t&#V7TXn&r0C7C zLEkfZj7O7d>z;%KkEH=mppGurhwp7FAVux zDz~1Kbm(Ji7N#B6D6OofDx%;Zo2ozRWq>=2flaUFiINgJ?~JPlx($_Ph;Qid%QLhN z(hScSiMd)TX7rK~x%?d;sJrxm4P+WSSw?17a@$H1E7&1==JY6yzg(>DCMzSuk4i6N ze_3E<96_%vZTP+!^j)fA05O@3Lt;u(a=D&m<5hO8rYTogkxcw1mQSf4k&MpwXg5~c zKLw(n-Ot9SFCP8i?!{eya*tWwdhD*~_PCR7k9#MRAE_X-afl7efLvB1Tj;J4nxu_X zwk!t#s;U`bEWtHCkeVtRIgo)eTV5u7e<}8%0&jJiF1E_n33fH`H_f{6M3AjzOh(nA zfh7~BG{x@SXcU5(&ZT|P8CenX@CmjDrfP&p9rLIP%o+k`GDFW(BoPJm3i6ErgY7*6 z$t5lIKyKCBdnjDjS+$WtkcZhNABb4K1eH;Y;{9=taz^&w`Sj`Ci5&=o`Tgz%w*$1FW+_Scq`6q&;e51>_lc9zoz z*nl0ER+x^M9XEKCtguAjJvi7a8Iob3bQOjJJjhjnJ8Q2NcBp80ndS0#9&sP4r&LpF zmc~!?s#kL))#7_w6?R|z;{P5Ke+o@!-AMhu3o}{CPxPqr8I^-48B#V~QNZfdWd%bU zGHtNxngmAWqDE^K0OiEng5m49{9UgOSFM92wyc|z)Dj3l{kgGAg>*My5edUPB3&~q zFdNl>K3o~DC%1CcDVr71tW3K%s;$c;{wnn;0~+I{)Y#<(bv7%WC@BX^f1rJU%KCcw zyWhgGCJfo@_=CCHP#tMeHNE5}L|#&^bvAR>g=w z(gy6zresz~W&=f8DB7ti>JIqR4m+C4y#TCY5TU;FE5Pn5vlRCF`CRG7S2ys_hp(!jfA_N$IeAF|&NXI# zMfevu)HN6p;l46LHIJeRwMu$m*sMO{4cPFoTA*xQs*I5R22|CkAyCz@z+0GE%ivN; zCrt8MWnq{q6V`j~-?zTGJM;ff?#8q6?8&p|_b+vCJaAW{-kbd2J_P@N3wHBuf||t5 z$04+mdV^r7^Tw!-eFwqc^KJ(Dh<ZnCf8+`u$;bT)Y@??`-v796 z1%%e&rw#%? zYMBjeZ=?`qe+Z31H;8UJb6R~r^ZK~+AGGhY54QRl3d@|vnj``FHe-##JP?5r44RqrD^$?9OX9Su@_ z%XGI$e{(yMO4OgjOIlrZ$p|t@mmwb-RYl6(UJp|E2v|~KpUFs_RMEtglq}Na?|m1J zkIxJI#*cF@;`{XJ-M(Ab>u$t?q|E zikBd@-M&bW333IBufK#zr9^ze>@fAQB zYnxRqJ;0R$7mwS^BUt*5Qk4&ed^3jWeD0Se|a+M zHPBz!kk;fTi`eHQ-SQ%ah|VwRv{yDW)`WR9;}y0&EO)Eus`Zjcc>uQ^zE zbcCt{w0`*q4$(q+LV>_`oV-Hwgw1Aq_mde}Q!9c7maqAmw)gfuLD2dU*Fbo#qpny zzc{SOs%0Y4251PNhiPZKO95+Td6rhmJFcvg&sF$mkTB2}Hs|5jy~|BG7+{U0dgM%5 z=SW4~w@#@-HE{e~^~4K}j4SLvCNd28Pqg#?eU0C%Gnp(~=6J6xaZH&(fAfeE=$N41 zCDBVOE0?`h9|$5&LH`?2VWb}b79;aBw_A!>leHEILeaLd?HsB_S939uYWc#(@1&K+ z3QH1AI~Sk6?m+o|d$~TlSBrJyq5J<$56V43gxfyObwPxWuA_Iim{4gVt0K=33dlrV z;x@@jW?VMH{kYU|%>pY^e;4Flj&KRGo`%($BbbVy&HogiWnW>Yu5V23W)lTTyTubQ z33Dkj6rQ-px>sw|UiPcd`$!VwEz?O^Hu@uu!EG4TIrz&lgYNujz`u~Dj0{1AJaHht zlI;(*D&2!wulnn#ibzSLG9e5U|5Bn{jb+@W&i7JttExXzFUFKme^U70tMIVZZ4N?%LS=BPH&!3sPk#8z-%1-^S zxlI0pu>~-kPRZdJ(0-!AV>{`}f9t%zBs&KDW zdLF?^y{AbI1)M}|8KlZ055xd@Wrho{!dQiM`A6P`tH^tYf7iEtoKrsdg)iOTt8nDy zqfZ(E_~q4pY$$GFEqcq^k~(ph2{(bLNtiHMi8@#w)#$KvHt9VECyAaA0BRtsNLDIG zJB2;ifA8!92lEV4WEM4YQd99z^$HW0oXkf<~M$vGZp#4 zz5^;eDCZsd$0!LZc;`+Lf6pr}6DfS?BvAX%MoZkh5`Ad~}PmC3fA ztOU|~9suhWhW=soJoz2f!lWt6!WznDl%wZyG0>}o9en^}E!}ILR>ueD{eQ-Uw;sOV z8oRf5f1rHltgLk7$GLu_d#si#v4m;ekmCXil@)P3Y?a9ogo~v53>~b(Uxw4+n=xJL zi7O=N_pajCN+YCw-U5~(t-7e2tE!~6ng!QQlAoLmBsX1J?Y7FZL8?&17Vo|a6yCZT z>U@lODVCT`L|1@i~e}#m;t(;Os?6>Oq;P;1>Py?1o-aR+4 zZ&f9pYqh!Ud4}dCs>tk@3TK3Vkl1y|0kR}9E*qrzR^@}M(jGDh@Zc*m{;fgOdrbFM zG2L6xBw*w4fQM;`^3ZZo`lwq%l1YNNM)xrZO6%cg#zCum**h+xQt$-TBz0c^PDzc0 zf9;QR5gEo*on?3^%1}v@`UPS%F*T_j%XM8<(`n!9V7c+hLSmwsx&Nj|BwtNH2naT&DMnni9Cd9<#3yJqTQn|L{Ly0E1V zW268f-H)IeN>y2`LmOMBGzydKA-B`mf5P}g@hlxWXS|e3jklM7^kB<3_5!~AV~0V5 z?h^+AtU|v1p?lZ7jaxUfNexqO&y;v1*f~r+PA7v9snEKphKF5rRHgDiqhA@7_+(_N zEhCmr7TQFQX#KDiz)~cMysK9!tE3%sxcuX9Ly^R(CyXV!2|We~O+@WFT_3Nme*{-v z#MG?*uRP-*aXMc?Oulsa%*t-hC$((>Ll|t!%Pu25{g}td8$2SLi7=o$;CSsnb|GU| z_LThKIbGa(rhhZ8&$k}JtCei=RLK_Ky;>rXeQ6^)?HxcF;78@mR=VJ>gU&|dVf2pztiBA$`WeU;bA?IWayKF(fl98Zn(iuY14Kk?w zy!38tE&PSe{mb_B#mhFn|2YzUr91Y6yXP-IZBOoNiA7SLI)wY`Ge`}fg=@NY; z2AcpubZUW}Q#R{l_c$PK(akx-+LwRggYW&sd(Y+f`tI-b-M>lt?zdKI{ss$2ZykKg za;WbiyG~*uIR*#=sZDIpL*xdPZJ?^<*yY&9}EbF~q^lwHl z+CVX?IzEWskM~@q`@pHL5K=lr8^rI*1UVG22NA3zPbthcv9;V#gN|KIDoJ|0RW?eLZ zF^Vkaiv((=csJmEe{z-WKEe-VBTdHDHK$ZC;io0I0t#)CsZ))|t{XVJjs|e!XH&>j z3wi~M$r!5$6p`i`lgl5xj!VB5H7gO=#3P0=#3@QB2A~jGYLd~Ivcr}RNbyH(8f4-H zGzzDrvgrH zyn(^8q(K+uwc55MAILZ=WVKbA_CYaLI(|d0xFJT8_Dy!|L}SHk(xZNh{WA`rvwbv zV4_`giQzMcJP<>e$a^Lawg=ep@`sLE{4UXZc7lribj*{RR|Ru688!oMAw^03ahDAI zRE@vd6WDQVOJW`@Ph5C=$A9Hjp-z$_(VYu07JO3Ff6+Z<5T~0R3no^tf)C9{lC9g9 zfATOQhb*)8lZri|raf)4_UO(XJ=sAgQicy_65&})T9q?Kgp+{Q2QU}_w+z6}Tlpjc zl~|%xy^VRQT&b;GvO64~;oR9t0m+4fkT;Xds+WK2sBAJ4>G3LHN^LC*sw!D_Dz1sc z^6~^)e^PzUYTH=RyS{R+LuJsxxiVzOHWO)o%B-^W;2U_1!2+;IBluu=vbNKGX=^I= zQhk#WyXQ?V|MXjswTXn*EK?*h18>`6ARIP;F|d<(TEU_!(CUN*=&prvi0GIa65OJ% zs`9RFw`H!9+z8oqwexSbfvngwz$|`ytSwLSf7Uu{FY(f9jp8hp8=mD(a*j3 z^pj7XJ%9P)(a~gk4o0^gyeq*dp7cfHgIrTAVmupKRh%mVZ6rHwVYci`LQ9tyE=)?% zK)b_9R;Xv8jlHu_b>1$>&3&m1T>UbwFAot7>gSZ36>zFbW0oB~r5{7g0+8&nU_n6T zf6G7f7LqWdnB)-!Dc1ET;SDk`S<30ynht`P8l;KnFh-Mk{D_I=r-syCV~&C#A@()x zv`a`; zdhD*8$=5g1@T;#MpfqO#vn>JIcR9a|e=)%Lb~@EhH5anF{8KF|KLL4r3zSy@N?gH6 zok|5$E;~qCSASgFz^8C@a1Y&blNe&0DLTcw*j1tG#rYwxOl#+VUH;j(u=0CNMR7>I zD-5lS$PO()9sIF2m?v-t_sHWEfPG=EC0q&=iFiUt1lk?sC|6zD&W?mcCV}5Kepk^oayiTC$W~ArokbP+?24jUZ#QPSw(eARNv8t@Jp$x+Qy# zxf;Sy2PpPKW=GvR;-Bi#saewwe>%$KVx!|o*!Jb0J1i=eia1HthiM_S8|2=+0e7ib zlqBJYx{jIOPRIc7No1%H)wCtmi#jd5RuV!x_>zwjc3o`B>Yy4v&`T;#8CxM2kROFn zyAJwBhB{yV`47JL+a9iQ=!XQHO&3~T3a-+A*%0+4hh*|;e|I`bo@9Zj zMuVbO^u+inZpIc_I0JeHXd*Ht^>;ce?HYCe#-&bo;KBP*pt9Zc&&$b zNVr!oc4Op!-jv_JdpaLI+viPr>ruOxh|-AHOZZ{sbD}_nsRG9Qm$~YT!J$V_^N?yUI zB}crr0jg`&Vc_VX$*#gO_54X>iM^O&9gn7OaJ#J<2}jZ`W_484Aoj$J#Y0b+K6^it z#C44;rCd)W7~=KKg8~-lZ^JWH3X=zqNdmV_FELJC-=tCXx#^;KcF9dH5Z@VVe|Y!u z(WlR!s95sFef88Ee~;Zg++qEj(k9<}{f)1WI|hMQ{c{aau)RtxHlxO-0e*Oe_u0VD zO?_7qlqe!fWppx&z#RChE{SmkF%M{x3K@rVvuzS-cFlp!pi*ReufPF_>^7svgAiz)j$OH^LFgCwd;Cn$?1&-D3#e0Y`E2Xmz3uVX;Q}5 zJfRNgyg!$KfBoUFHGQ71HdO=m^6uk%JK)wMcs1(UQ`CKs%MSipo3i0vBj|d58zaGG z8NQX^{ZLu0X;FD4NGxkao1_6=3p@el6FU2+AAZCY+&tw?0TWMhbD0&YX-%>WT~in2 zWauEHUj0#)=oiD~Uli^RVCJ#ZF$#cln_QPvL2V2?e}=Fjh2=cwp)Zz+9N7%xR+qqh zlk6R7wjNw|4atZ>WAkwpwr7(&3^Ndi8p?)hEQpDo=(J+$&?;So=Xm*-j;AoTh99;F@-Khz4)jc2{*||I=>mfoz)YU-}HIBRhL!J(zmqo|H zyGcUKyln{Cq#y|-8S69%bMMnaq=y$)Cgqr;my9&!$K~I63ltEbz6Jzi*Ok;#3^gZ# zDs>baw^Gw`s^^1^gyb9yc-4J~7scZjw`%%4X-n#grL0)2Wb6qtF?6|#!-mOmf1nx? zENIG?8@tpUw>#sROset=fMe*tg+C@Gh@EbLN@oj&FavzpS?1J&99)$=->VY>!M zp&BXxk6@uK_c!LP6hP;eRSvw25CNrxrF9~LX%JW6IG&RnO_f22HQ#uUP` zLsjcBH#2$E4e%OjFNKr^wmYeMv8IT-VPF2OhrDz7BJ0RvLUE0_VupMmRBkIdxzVgI zktj*DVZF8{F{7k|*%Fc;c_yhpg%tdu%h}-*V9_aM6{75x)x(r#5PY`D84^ysR3|L_ z7)lk_9p@7mlE9o`Pp`W_f8#xIdC6v?0YTH2@O1|j7?pL0Qf!L`ehn4}c-LtqQ6ya^ zA44v7JC?sH-Xg1brrITfRD$G`4x273G~q$LLn6$oewpVo)1QB>%l66h_44J99t|zs zd->KPjt`WTk0nDfm4wxv;*jtmmZH__+(y2;8vO5#bOt9`UmV}kTMAzJdAn8_Fhk{OR zmw)G|c$-8WTXoR~6Oya@k~kSzQ-WS{3zk7DQP|qhm4k^0gwiAx7TLaTqeq4m&#Kqu z-^O%Bw;Faxd=z|Ae}n2m{bCuJVHp+6;vG;XSY5vSyVp6-aqnlc+`*EZ>B@o~vQL^X z0OykA73|>nBr5e+0~PtW{q`hk8&o>}Ji{ zowPrRM=-2fLbY*93Ba@VjcaZ2uZfS;p2!_Rync*u`qBL-hNbnS=-eb!U>nOiSo_6poP?Oph zfXEbfe~fP_lM<~-bDKo2%(~&?sa2D%>enrGM$oH=_o$`oTq*x_efILv%a7K__d7&x zJ#ts<)Zgq7F%Qupa`lKpsjEA0Q%t3orkqE*v2E~@gj2J9(pg*!YT-3e)mqk+uKNgL zZUux-RUg7ZyNc0jlmI*kz)Zrlng@+!YP>Ddf8{i45RvZ>TMLP=1+|iae}PL7ld3yp7MC{*d^O|| zBxtOr=N3t;OAx9T0_n<@gynTWb5^*#_2Zn<^H&AfL|~XnvQ?ouF)l?~Gu#T3`0WpG zucT!(;h!c!^t{{b;T~L9FS;s(S8q^>e@zr&I(11<`0=GqJL1qH#!P2AgcXj)Lfp2> znp6G9ES>i~{14T`uj{1Qwh1ajXMov3wTbfSTK906vWLB%?2wjW1F71~kv4};#j-*{N1o<7p;u-5CE3?bBELe_x7b zK!SqEw@h1{AzBk2)ebBDni#et$94W`7v24{DTlGv_~4gjPCcV+>aycD!^qPIvPJ$& z;b>l2aq?Ya#80ms70Bie`-VOUL^oJ$QtBFuq*>Nq^D|!;KnMT#cTsi#}+wK z0DoiG)^#Sxl2_;QSw};vKRXAA8=sVak+FHr_2lyc_2-{Hy;i$+>#@6cbebQ#@MTBX zZ@vD;15~dup2Gc;$UA0~w*Stq=};PW2+SnMW;VA?-ASjL2qqr@KY|anf2lW8S<0&} zY!jqsiBm>3#8eTINi69hdjhvYCP=hEObUowfmYJbmw)eVwCa;oRdF)q2mt-k<66iN z*tzPkyCg7ruR5#uF%Z6{9DMa&d9j|X5FtyDb(2+A37Fg|S4)~MvQ}lb)q~Jy)0q>& zF+!($PBpJA;|hO9tG+B2e=Dq^cCgya3!pwhC=LdaGnh|}q#!|1M6mqJK4kiK^FzvF zK`xFu(2>kVES8v>!l8&vJ~g|MXXV8i)f=0ooW1&BpmBCyVar_*3Ve?B8*md3`)Td-QyL{OskufP3rFyV8{XMwi}i zfA#g(54Wi{SACDLTYVrptZo?gb;Q7dce5fmw#V(e?&fyp+7m`R(yP2Lz)TE z!ixvdSrX}d$W}w9E{#A}R>3E*%U3YE35AD|;u!Ai*tYEBDP?uge<06+Q3GSyZ$*A9B!B_$7k=$HTSXjr_l{l?`# zx?U{&4xC!OKSXZe9T6E@eFs^l{BK2-7)0e^la5+QMZW_FCb2K zXMf)>+w}Oe-}}e?vMrB4dw&-5wa#MLi@I3^v=K{onng^Or>lM!12>dOcL^mV%N*zu z5){Nw8dl;kDlu!qq7Ll9QYcH#fF$@VI!Q)YovPd(iMPV;~h!on?c}M)InlL8)sQzgRz7v!d z7$tzPYOZp~l`jc(YPOzJx>d}fHw?dJ>dr^(s^laQdgkAfxK!ggvIB*B9hi{#_%pT2 zNqXq=nM6S5%sSK{?E&=zP_mZ=%p*PU^UNq9e?T7a>`eK4N)0h*QUxYl-_M@kZ05k6qgBuUzZ&}+;vn~*=K}0qRAqzHM{^PfB4kMEusMV_C6mX>JWhxg3v*YnPhFs)$ zoz@Td=LvO8j9L**)}#uINp%H`-XzpQWmih&bDmg|7JwbH%&J-m^_Em ztERfQ9ya^Juo_W5@nf1r2#=o}zKNFNX!?T3J51vAR#cLg9AF-a%+ zi_B+Akk>b9j06JPkiA@uLrPeXdS8;_j%`hYldI^YY{U+k%ME&;>X;TltkKIaY^Q$t zPabmBe?Ft%8c*(itPwM%I44)0;{Z%9tdM(kWOu1tu5wsjz(PT*IT^^$(3zSCf2QUj zkuE#ZsKHCiq_KWg<(&)gTO?&FV#B;6EX(OQ#smnNlSGQ$67}c1=k}Q!bN|m#|F?7+ z^s6V>e>M}m@zDL2Sqd3j)K>{k$~@;T)yZr)FpMl`reyc2zM1XibC}7>6RgWT6_tpq zy=JxQR1esv99Np-_xZU>3Y&fVf8euD^<+<6RKWzJc0q>Q(ZbMdHJAVNgLi-sUjDP| zeFX0S68?q)bKO>LGf7vwH4p@uZ|Pz|HE4m4b~DH3y$-u(dA(1hcDZJxm*8rLb7JTlAesa5phF^4tt>7criy5&ahd0{>~7hYZ2or-qed0@w!J{RE_PwVRzgjB33dd) zF(mMx<+mlS9SL7HnbMjX30qsE*K^n2O)@%8G33Ds zxMq(R$!mjB?5w*^^_JL5bj&TRcKOebll2;6WXKwEvsF1>!nT@JLHVs*lF_yvvQDZ! zvne-;m$azM45O3E5`lRJ?y*L;EG`SoTcH%GaAd#1r{w0O#%Q)Kf8lv7py1%a!8?2} zUH*&1m2Jo;vq;C#R*=u;UACCC8Hb_Yaf|EZ*DS#TmajwrYR$`5C|x4 z9_Yoc19+ed1?j?A;ZDnFmFNpAhXIswm#**`>T>xnkG3>|i&+CU0%9m?gJt!!NU+d( zdI5#;a%L_5u&`&ce|6g878D1P2Qq2WVUQVv%tS@~Z6|@Vgq;s|9^DR2GC@t^f@VsR zS;I{b4H7?Tm;dT5$Z!}UB2$<_)r@S&-DbjGoGMC-Izn_4PEq|-hmA@~Bpy|D965Be zZ_8Bk-HuG7dTfsFSZ#1w8h5dD7J{x|$pR9;g#NOm7|1E*e;#vB@$c3t``0?dJr`Bn zc;xQ)Ll@B7m+zKef8zn9mrW&Zdi7&0cCs|9f+Tfp_fi-gUS)u+Zy9aE*oT@9h$P2d zI(y83${2lCIV4p#D7FxP_Uc&zC9)n97VI_cV)@7bVw{#}!Jra6fb*CC`iMnrEonPu z>m10IxU5=#e<1iSo$a)N<|)aa)nu`N8pOmHz(ZACkufO!j5tVWMzj+I7p{!Qm44GFxaiOr)SJx2}lpBmolngd?dGSaq zatO&JsWHK)h3|*B?k4>X7rlfCRnuu#V`d@D_)wER!7fJRXM_Bo_h!v@F)E}{cjIBZ(vkh9>Unwy)${j_ zCGQ(cf8O7TzrPcIe<%LFvE=rT^XqIZscf_ALAN$an3liH?1^W>#&{CwqckFc0Xnf$ z3-H`!I+@Jz*Owwl?~pwu+}wLJo0NVOm_hinRAMt^jW2Y~3hN&+kD~jpD8;T+zc{1$ z-IpRo*hiy1ZO?!7I0o6x{k~tWUl&h zmQ<^ii36!ImE+=~L;n?hYH%V)(@Dcv5Oxri*`K~hOAqXmv(v!(D(mkK| zf|<;NE@^eUs&j-HECASkZheJ6=VXh;W4+cBg$u5Xc# zi9pf9eVQ1Jj%mraavofy+kNnFs2iC!Rm=bHhf-xuK~fv%E7uzz#GGw8#)}tPe{$y) zck5BRT5ID^wKnfy>xVkUJVePW5CFMgxomnSx+LjuPXl}d=(D}dlob)#nqh&?=eS!B z{5S#0GuR}x3S6mK=F&5JCK;5it})%rfjJGMxP56Zs%QsbLRPHj)pqL^gX44f2r%(^ipQe#Arw601+f<*ayR=t2QK+Z)LduYJdm7 zn)HWDBmn{JeTYV796}jz2I4>;lE$BGC?HVDDVwx{UvNNYF8}QZ??92kX`SBsajquh zW0~HEe2}puwJ%k%RD`e+H(WPy)Uz zEqW%nN|6ufz@kpf-_qGCuRj}8sZumKk+=YJ?J@5!INEVx!kS_n-ef3Z%C8a$_I>eG@@ zU)BK`S)XxLpYvc-2tr#T&{Uaa28)E^VwP`|^tG36krRw)NS=!aG6MqNoc2f8ag$ZC zWs{7uuCOov{UNhBgJ!276?& z(0I%V)@r)W?!+Mof3;6(DN#f}be&9QntL@*)PQ+H+>35#;=KG1htoxp(>mdpSyFQ| z`HCmV7G%!WXDE2@4fmEde9tT$dA;wxAnj8f<)a-ZxijplItni^*}LnWJB{>N7r{SpjaHoD#-YZ1mso|bAsf0ZI*Ahue)mgDadMqt5< zS0Hpv_P&HnTa)ag+3E^4+ssi5@IOkqonS}!)p?*=?V+bT5=_m}gWP5G6NA6}Pe&tP zA|%4reVcn*39SVJxwepFN;)3Z$buD{Z86Z z=Q~4k`Ckt25uF~h%AkfeDgCf+rBl8S6}c$|SgBTfe;%N~$@n*@LCE?!)|l?INqCV2 z#(b70Y)_WU6ZV=UV5ckepgY63;e|3UV9z%rD`L^pk}m)2u`U`Lvha)~1r|~!1a#0E zPw$G8>q2*|G#d$kV@)A-?_hvZ`3>*~Bj>dc1OS{sW535-(<+pkWhUFnwjs+*aqt@`4J5vDOTI2X5i}em5lvF1nD}O-+lWf6?k#?l>iDO1__(UT%|Yc0LFk4$bex3jh-hZ*?iwwX>@%y0d zs0HQ$n$~-h*zWRkGTBS!L6u(`7{L6Ed8EnNwLY-`%Vy3BT9MFpuIuP%?|0J4iy zav)LmUVkj=*@87O2H;1MQb1#Qt$O+2k2+N+Ib698ZXIredSx4`rf+_f4Y`;LBM!s% zslAs2zYq}FUnKo1NoDPD9lVxVT_GUZ!^wo9X)4fLdZMwsoDDN$#-ko?1JU!^+g<*T zcfw`p|9mIfm;bL1zV}NH?!MM_=$m2$(N|fT~TP7PPNz%IwfmKmA5v;Q& zZBe63>gsrK@-7vCD@ie`I+mHbd*lsT#>jjKser6(;0DHLLNT~*zzbE4^bPkqy7ll~ zQB$yw-5Y8O`udyib#%7Ex$)y%zdSxx%atS(L~Te=y4xh1t3k}C4D{slO#>+gHOd57 zO@EmQGQ?A;B6t8-;fn*P#LpUm&MMzl__-zdkuw+n4Uy836Ubr@uR15tv@S&lPB9&eqMrALB=IA>Ks-=@DTv9)V=BRsK7!f z%qAOHVy`D0vqX+lE-$Le0y`Q8SVNu2tKwOrZY9A()fqR(uDj>Rd}C^SUaPN9K7W4L zo_znlNzARs?#gw8IbAnAfD5>GWOHzbKIPO48;9A$nXJy}m=QKs-2l#)(9OEH`w+Smqi0Uw(H*VUVKW^9#00-q*`KAO_p zmMy#rJAzkr%_K_)l>}MqQkc`pbV{}?a-3pSZAZAQ{x}zy6W|NesCsl2HGlFBooooQ z0u9f8TKPZs@ob+*=@0kE=cRw^!Mo~>>rURd4*}44dU=L`B^X;7ca^ByWe0+Q7()un z(%r_G&d4Yy51lcw4TMqy8@zcPv&pCeyxB>tU4A4%jlXW#sR8uUdI2J7NUXG0kc+nj zSxbN;{R!VWQctS`z!Y?j5`QFT&>=on9@4B91GNc8d8eB(b+NjS=AJa!t4=bZE{aU= z&{TWHUz8X8QA6fxs-Q4vk&cHvKst`YmwBuXgklZK?kZgVL_LK|<_O0b9G6ueUI@Sr zZY)7kxHwGTD6}aWfTy+NbvaNre?#8qq;Y^cVLEwnIJ}U(hxBZ9?k2vMTn#EX>t*JcGzx$g{v^W}NzENX zKlz>%Av@UAL#U^Y8&oF&FCsGS%s7&{1232v7m$u>P5D!>n;{FSb@`LOb2K5deX^X1 zD<9_w@e+4vQR2JVsefyou+}~A6f{8&JODi+dXm-D&kp;SmO}-oRL0W+AXoynMP|o3 zA5v9?tZ1+AeF+{|J~LS0jLK8@pVky(q$)eWF5x6NHU z??6bM#pDT4d4E+Kb%&8QO#irCej&InM>g#u|3?ufTd;)2XLw@qQ zX?LwT&wFo;QQRu(ViP)DBdh6l>5`S$S3$Ob+A90arGK(~S!l`#tjNR7DqKclvyN*l zp@ca|Ef($lpnB8dm6Fbt?yR%p1C!ufBeNQgqXkq9nHG z<=`CZ)>O{kbx03COD^r$C9{&`;~d76va_^_)ng9lvhqF_UhaB}Sd%(Lq`qRSn7I_P zRl?ww@P9zymvkX!<;?_Fm99wir;{T8#gW3z?*aaFOQmhs=-!O zb`M~%C~pg1uuip=cfx~OxBECml5B|6H5NGgfaStxBygK?kQ-06N2fj$LwA( zjgS48wHAK+tFPY&)Az^jSB~95y)ro6(#?YQK!yVZ(Yx&kR$CRBUeYDS@hQWzi@>Aa zihuKF;=c}BA_U&6LlB;Cy3UAoFRT+gb))i&QB@D}`i4J4IfEmg3>^xnx$g33e&-zs z>F2m}7ysiVj-{5CmegCtwFxMS*Zv(%kv zWIo*GWnEjEO?FqMW#S)6UH-QbO1Yfu!GF!xaxlg~8hnW!WC*F&VcR%d-{Ig!s;(aP zv~yNr$ya6Wo9E0w>pKrG4N_r{vkaC9Tr)=4w^5%F!DEfCo1*4Qt<{#SPBd+Ka?aGD zq>}~hut91v2k}oTAayLWE*}NmD#`j+Eqw*v%4aCvxi(bjJ4kPGk2u@gdh!D_m4CUE zeACt?NE#(fPh?OqBk!?d^Q?zvZkshEv%3vEl~r$GRTZE5U7?3&+A#*3I;jPiWuO}C zttJ_8AZtfOxNMST4Ows1Jei2o+WpD){KIp`y!D7(rMl)sb>EIE!Pl#g2%Gr;-R#gL z*#Kozlktd7jY?v0OSmGqs!o$62!A2ljXH~UIw(pVs#hg0QD$x-Z-RVae>k=lA$hUo zoa8KJRkNkrLTCyS{Ub;WyUtgnma#NmhqseF+q@bKEc=c;K@ix|=nJIZ*vgD*G><|s zumr$Ofn~5Nf~$&VyvvEo2(^Byhd)UF{%NR*b-DON1&0y(tr8d>8D=a zy?nCn{`h+U?bgHgOZN6Th44ek*kJ6%JHGA z3q*&XRm#MP>ClGXgtFd<_-p*Ng~`iwwY>@b!U zMwKHXe4pgM1Tm6)Tx22BV^trAM7vW}cQaf+bvB*K6-v!f_#!$tJb&p#JG@4~l8#*E zZ4bT_%_)E{#&9x-#0?-6`;po`+G;uzT5lF4px&Cz472S` zl*)!w(@Z7a?38Q-h`16N_f$8lh>#Xker_24Ie<1<)MAe0TGTVFF|4a$c{x62R?6ki z`Od=&9%TR#A*$$7fqx-ULAVo;W0XnO66iQuhSn&_gNJwt$6Dx4jd(0O0MOXm6T(cg z(4xsmnrd}H0B-l25C|k!;YEW)s7bL(RxOHeA0X=7U3TL!J~Q$4*&6MmvjIJ%MwuW+Ae%Z=+{JZO zHA0J9Qnj!l4Sxqyr@Q=ldJ3jhrky@UwKGSSR6hY9va&{Q1XI_*Gf8 ztk)1;Nq6?D#v3pO<6W!CWs!SSj}xq}x7AQ2@s1A?q=Ls&@~2TeLQ89<)kVGM#=T?oFqhIFeVv0$t3lL{FlxeG0DX3JUl3L~@h3F`u0aSgm zz}dwf)^D)212k$#oeGR?BxlPHIQ61xZh;6swrLLKq^WlBM4TW-EmfTpbk6JT#*yW; z-hSrA-G@)xlSk{b`^EUT9=WS!j`>vP_n@xjX_Sw>h*I%<%P zps^uk_AG;AYB8G>7g|vH5W`z_mKuml1P&Wu@f(7%WLDEh1I}&dWh29<7@L`D-CWOF z)pFY9|9kFMzcJD}uekC2*$aZ)C+&w%?}>ijc;v3!L%kW};sbf+$bJ;mT}#|%CV#nr zIC)9ybR9}v6RBROMUlWQ`NY90LOVzI~?NcHX}Fig^%S`rnv zWPn|>{CPrwTl4?m4M4HWUvgBDd60yt@6bV}ME<5vYKyUw<}(@-m8VY~a+N%nDv+8Q zrY9KBS}EwK6+wntIl0NxH=8AS2!GXs&Lv6&g6{m%03NG>HcvQ|&Yu>r@$#1*HIASb z;SMh$$Fg}HH8v(S+Yu^cexk-kRfz2jo*Pw%wqCjkTXj#cqv6$U1n6tCm7!2mnbcd4*dwRy$6nHpQQOlB zQI1&A00X5nBIDy6f-1dZUy=wNo4nRXmViu=nP#*tgDRSBsztT(hktLXG%*3RsoE6i z)EQRa`0(Pi-oDLDK6?J?(?_4Qm-npdZ#{IsWjz$L@!U2=NpjU4Le0AUo;FH#WJ>O- zcinc9{acr|Av;3+)axb|5CShJ5VQa<5cx52BB&$fuPtOamw{9j z7edVQ@|S<-;oFA_i+@SvjHuJ3DFf07y6Yz|j^$V(07_s-8VT^sEL&ZGWS!!uVjy~H z?T!t)^Ihh!@G=v3V_>4;L%p{S=xYVBz=K{EEIILiVsN%e#OB;McVi59TKK=?#Yd~N zZXS(iAAj7Q-gCvg_2^x_S2Cx2rH4THRbrdsF)gr5i-e*n!0~K0HPhtQc~hWWdOKjX>|E3 z-oo17>ZB}Pt~*(cHZ?@i3rL{MeJbbw>y$6<;q9apP5_F)FNfNK?hdDBDs=zGwUgadaL^lXN!&()sk_8eOZuu@1 zpso@ivh7kOV>o)dWk)3ea4)Cr&I`ui2`4u2hT-y8K7Ztj|6(>Df0r-6dwlWQ7IV!d zo~_;`xW$&}(A2GBD%4#x|rdx8I_n9Ou92rP7 z;9`(ZUAJaFeI>MGm+B?4KKDWtAED%rXzqhcIwh)?rK=Cl8y`z9Ld0_ z$3E=?&!5DXhz^s82hLZdYR6yeJsREX4KAmsL9P9Gb`VzZ*sCp zpk-U4I&%8y0JIA}?iHCj2N$B`_H|5~q~&3=;57 ze)-BWDO1ARo%p}KS-d64s2}y?;atM<3m@N&=g&TF&%gg@efDxa)l@$E_!{HA@i1Ol ze)hz8A4b**;2yz{x;P_$`J-yo6X&N6iNyFlZ!#n($D^CH(~xp-3L98RE(To|DSz-- z4;(VFn9v3LT?zzy{-s3a=&e(-0;8+Iy>Rru$3B(r?`cci_;IfHm%OqXzv2lrI`NKV z2Iy$f5ILPLM#qs(cHNL29l(J3z{kzT)w*Lv@0t1gBRY~JX-yt9BrmnS>qmD}LX!G{ z87T*Oz_z%8#K4SAPqpG?tZA zC4>!wk$LPgp$?>165JF)% z33`B1upr2d-0SnTmxFo>tNMyDf8VwQm6)Wq+o(?ElN&dpFy8 zrB{A6BMqf$1&fw6qmn&RyX_iRxeWHsp%rr1LM-(X1G9Wy%V02okU3 z4oEpK^QjS$mXyM4?u9Qm$pd`E@_tFDDU#v(uu68s4}wWxF-jubNsb=A?1sDid3uVl zWptBy`o4Ew*7{m?B-NO56~T<{)Oab4_Q?}0brBO=W0la9oPUT}sKUZ(7eAQ#5K$u6 zHJ5Y?X7=LAs)RtI??aUohUo=30k3Ncmp}hC)LTJ)$foKLmCA7@enYF$4xrK=q;jl* z&xdSlCCFz<%$HfE9MKqU*Am=Z!ij`hqr?kA&pp;i!lIehM!jp(59&1relFk?joV9CQ6?1 zUGg$#4V4?8Oq~8+ecTPucJ!V%anmJLlH*l@FCVvHV&zDyVtAwB+6S|ZI`RZa! z^-3j!W40WrjP=u&9i&l1(i}PuW;qbYYX_L5!=N_ropkilj*AJS8^D!e9Nv)<3ZDQd zm1CV(57)WNAW2iA=uU=QBR3=2Pwwe08BJnU5EKSoa%Mp}zmc#qvrevo*{3O33MJYS zP*O8^C4aaOFP$XRC3{=<2D$apC3~Ala$3xt}(M)kKT{$E|N?u zXk;J`LY_T}+wv_0rYirt`Oa1JvN*X8hoK%(=Fa*++(?A;7G){2ENFO+r4D--X0=CK zNj&XD@EXgKMgg#Vv0Op&gEt8}>{C%^mjYZGWT`6i zLD6lQ%YdBZbsZx)MnLxO5R=l{9s#FliGMq4SdyV3BU@WF#f9kSFqMz zja{^L7`3V;*}ke7+l3a{Fv~&=f}IAEsN;^>x09x=nW`tvZ3|8U?Hij+j=%6%35{hy zgMaK0hmMp-hQl(7UT`-rwi(g3t9}-UZKRtOWXkBA+A;MZwjPxN2%vRLJaH1 zsVctlU?6@OG!dJo4xENKuNtZ6;@QH4e-!9YU(yN4Lkv#V){>Ek@Kl00>}G>TE!=_^ zkE{FTCqL45xznn9+kv}Uz!pvgY~ja1OXczxy@nfZMNJ z)`qOSxPs)V`ygOQoD{&Nrt21i`&z5`DuVb@}Y;3i>o zt4e2<^9}dgv+Qp@a9>^a-}u52&wd5JzW3q}ehe1=U;H{2{_;hQ8BCOl=&f@gg>^=H)IDf}4-PZ1~+-$ZLdl*lsId(%;VqtaUHX?s)Bykc+ zXU@jHeDjQ1y<@R=>&wft}lb@1FP-C72wrb}9)->LMlxMsS>U0)7)HhpwQuFgmZ+UHl;5xU4hwL|V;G;`~wLxI$82rK%|tv|_c)1SD@Dz@02BO{Yon3Mq{W zcL3v&)y{JJXQY-e}i$8e#(d1hcn64a5!GmlIvIu8|fPceyD$$UVGpWvv zMkWi{0I(#30?bl@i^$C?#3vch%V0uED$doTkDA2F^IOkbRU=73_}4NrChPz=_JkwS zRX|!CeSB#*_}+6#%0K*j?jM*}DZawS*k!tGh_$lLlVOyj&877jWP8wbv#tZ9v9{UZ z1NO56<^~B^gK&e(%YVe!+RjWsW1MzhyMs3alT&~MOSM5dN#0=2>Im*RwjIyarnAmK zm|o%VJS73tP{Q)00y80WGuyR`Q=fN*dde|L*LQvuW;aeJYlRNM90QbLmI{_r%E`*J z6bMqgm2GR378A(Es&1A1qN<(~F$dyXyc#t^rnb1Ece@`tqV8mqMFrrGY~Y?UY1VeI9aolQM_Afn|`hNcziqcYiq z#XckdC9LU)&rDf(nF?ZVi5wdXuv=PfDKZp3fXdlLs(xAaRfpTRj>K_#5lSTE`P~U=pwxh@KM+~n<}gA&fgms>mi31E!)xX zFuXCVc~|GVQAHoIx-rQ+%cUtA%Ti|Ki2G}FtGXErwtwGxnee>&%q3{L+UjaQ+{KQ_ zimC4Mm%e{gSJd4inZic`tWPoxCT6JYPxbH4FfOsj)?I^23~5hPYrA*L$?%43GFvmv zc;{wrCFY%1*ICb~J(SqlZza3xi0rilFK_n5o|Gwg9W2DlUv`W|mqdvp{y5$vxawsT zZxp|ooquYbib))68CIMi)vL?&H1MRLVwQvFqgyA{HEF^^ZI}lJJq;CYv#di0LqNfa zf6J*1ETnC7a&C4pZuBVtgy4`nt?s`7db3_)Ead`&l0<&E*&Ii)XBvpBNS~J$F zF>9eo+L$oqrh%|SyudrH4q@_Pn(mo9sm_tVrhiKNsys8|YVt!=-9ia<)XQIS%t&M8 zr{o7?A0W<9o^DvB@%~ z$bXM&YqlY}5Y&i|tmH2EV$x^GA$CY)~rF1kV zwPB}9bkl&#RXq~vl4smqy>Q?{X``m20e>_n9qdMVn+M{M5SVv%y~@w?)|L!!g+s*M z=`(q$rN(&xQAo$1Tz42?*_Ix!@Tq>jhKB9TNBO@EN$ zYAQ?J{y9oBZA`ZRg6}aNOM<$Ylpz1mKx&_>Kya(*S!CoU%mHBA;?=3 z+tp0x# z8oGET#?9#YP?f#=QEhXeR=_vdxYlKL@@nLz4D0}zN}{S2(6-khuvL#`l(9xVdS{n< zcc30RxJy8Nk`eq}7p;&0*_*&jpjyTaXcSRJ>z0|w;{O5Opg5IlF8h^$xAhb!v`BLZwJ9h&zEtb7mYEvDq41ckjU&>(<;lyaI zhv7Gv&K+&dk00`I4<3JVSLp24BX>nv{^b^M^JcbyONtj(W7)-BF+I)ZMoc5X2IQiZ z0_35y$5iiG3*^R#^R(gOVn@Q#tDmX61Yf8ImNv-OYRwx#KHfH1wvUO)feCeGuIya4 zPM?}_yysc-rdXx{Vt=EnmDJMmJCEoj0xYHKR{4MF`;T;-S+j|a&C=O(9VC!t1tMuN zFlgd6MvydHsV?;-{i3d^eHP81izj8hYc<^asj-TCy!#5tr zcYdvJLl%1@;qV&(7~d-VdUskgvt~#Pnb(uH`mE8G-QBipRDYvBpzYQ3QKod9b#9V# zk{OTzp&l2utv0u%>7xsfA~B1i;}A=DVil`Xed)k#S-!J;*BFd7qz*>v>h|i<(fy0l zER~`#ZW20DjP@FT*4)bMA<6cuP{9&+%i3)vv+X9Rj_K!aR>d}e0(JPw+pb!>ji zQ$t_($6^J<7`%m8bD5WHivY%X99Sh)g}iqx*6=U5H$v( zN4CvAsr$J0vs>`nnksHRj8_dK{K+uFze^SGQpLMe@h(;T|GYb~_2>tWTkZ2KtfNuA z^TpXJvwxZ0RY1AqV6dW>+FO%u_m*!LvAnusbxYr;Pa*UWCzG>cCLT@?rvgs%$6nU} zq4cq{w50gU+Mw6QI{y}F%AIdcZai{#x(E&pvadK;z4zh|-nc{0n2BjCsK{BD(}m=& zgOVl#i(Z+a5OQMbvYdz=V1U>RUf{c{?1-3}N`IDx`Ch9VZy7_cW4KvYZ<8Tr_cNm| zW!8*p7+2Q|<6se}1@pY-9G{V@R70$KCdt&+)LDySwfAdm)8vc5pOV0xES<7k)YeQo zAndHgWYqJigKQ~=vG?~-rHYFAq#oRfSXwH4#hCK&)&_##9Cp>U!x^6Z+7F7(_mjtu z9)EoF?2$s$<42F5eEQMDabAYE9?Tz&vd?qe_}E+mQye3r3WRH~CtQ z$vZ9HGMMG%)qMGD50yf@LrS>~set!bq<_R%g5gKgS?|COfaowKkU)x5H@ab4MZp#q z(`;&X8&b%f)urkIdeQ>pGjh`gin7DVedH}snxtOXY31q-?2FQPzWjC1-GZe=J4^&3 zt!FBlo&M?X?yj*IX zXL!N(5~^ry)a|2M5lQ?&3He$_CVxobFEpu>O0u{df}x{Z1H5CwCp`(D6j*S}jU&>M z9tfXANV{EgLy|e{Bo*c5*cf~ZMoeMBP?)t-sDJN6$meID-U;b99<)0lJ)c5)zOUjg z1Hj8es9k!MiyagsmP$@?Y^`A|`+OZ*yIq&Sy^MKSW=Xx(8R?}uJEIK}9en_n12>h07S6mXaDmp@7il#!P1Kl?wj70M~ z>3_}3-}oA&?6U{N_#sNER(}FMF3n^uq(dEMb4p(|sft}PYy2L_6LJhyk#wqIDu{ag z9EmX!Tq8CEmz!tFAK6Vs^s4)>5?VVfRSUsdMYjM6-|naicezB9YZ3`15~9g~#Vi@B zOx4EoCXI2Hp^7p9uZREY26t5zF9Py66nRK{Ty@xE=AKk?Bt0;u3x8ZyG7K3C3sj+%4F;0Jm-*< zVH3FHY3E>nl0FH9@_!KWV_g2GqtOQzM5a<{PcF_nf~a(!z3J6?`D*bw>`b0aEl_Hn z)?n6bf?O^bsnyA0sjB}(0YZl6&Sw{6B%cyF+;07-6`Dz>t%2{njbv5}JZ6N;-~7Dk zsR%u9S&{?m8U(4VLSTmb>|NB=Fe7WoF`~me(hQF%lLOVt^M7@sj6bvRrSSl~uEUxD zqG#=Rud-@qqPNYF`N8WAG#?210C!TfD|b#dZv8k{tl;}+n_zQID<2@9io{Q93-4BKx1gDfLqt?WZ(Wnm163^Lg+06x!lx7EsQDWY^ZrH*eOq5D6 z#3p1w2u&EJn140^H87P|EpO0w1l~&T@Ng(}F55i^%sQ(nhlpE?#Gc(61Xp?VuwF)< z;9H*NXmDWf2lz(T^OmwbOS$Q(;maMSLe{S`u~k=NuLfw*3E(4pr>?fk-*WWyMK#6< zkg?6DQMZdL>f4xy6*{{sbXF`0K^pJugy3@?N#2nu@PGMD=YPKOW!7puo{*x-?g2tY z-eFeOiu!&sSm)701VQled~Zf_yUXAD{u|KP^Op7*!F{}HB3YJ^Eg9|3ax583lQ4Ie zAIM0Oe@np1(t&YFowV74wh6y(sG%oS0L&zYgVFb9Rtc+#&BWqnJ%SyXtZvoFG*>BW zR5dYHm48`ZKi0i>U3RzSZWXJfzhUQD6`=$k$u4c(pjnuZV^2tsi6sg=^~!@p5@FY) zwygq$M^{%To7cl%3G=EA2VLn7%gURGHy0xYpo40X@~=+4!#LjnGSK{9POT>86YVrs zes`{u@TG~mqglMQ7kyt)DD|}p&sX*tX`{#k+J7r~Iu8l=L$-~8DE2nXWwA1dH9?yF zcBRZ--CmMrY^o-2)-(M3`KN0l(WlfZoVfuW-GuF@<^JX5fB}4Cdx@j+Scs9 zATThRwR|Lj)A4Vl0{L{BVpXk03WT473yvP{kyH~#bUlQwi6cIy=G?yg?XQ7<*<;>; zf{<9Rqcj$%5tJruRVxb07e+xKw;?*^e^%f36S@N6(UPy(~8%t=UgWLCbY>~=te;B|@r zd&1mQb_G^3((FI^TCm%S4xh6u&bv+|@}V36nr2?ikRBy8X$3DK>A13-8tvupI1WNd zaT%swy}=ae`C>*nf05-Vl1r8;Om>H?l5Dv+q1v9wmcb%ov@382jAd z{mB=KDt2HAHojewnoSzIL1FW%ls47@F1q}khqYkqNgmosP92O!%0gUaPIwRu?vR3j zerJJUUI#@9Q)FahxD(m|M|BdNHhJmFtH?@6Ro$^w1$B9}-xUOnzF@DxEv0lz%RNub#q5i6R7M zP#yi7oGH~w(!y+{VleX19i0vXgb6z&e8a8zJLX^NaUITNNZzgt>9rC) z6WLf8GC}}x+PMIP#2$G&NQv+g3IbV*?pt zjKvb&t6mM3k-^D6G;P`Y3Br~u81rQqZePIgU%2-|ycK1@%0?hH23Aw80!~HuFa7W- zkHyFd26)TV5$k|Wc89Gqk#P7Iq)v>1t}qc~E*4{B7ZLP;rGHB&|DLGDq_AKo36CgK zf>djgu;*Ec){zVdehKip4#6>InMh0|_p(omvLdMLQ8g?Kf;Tu^MHtb02AsGvi9Awa zF}nBYa=Bs0buT5(?9G9{a|;C2EJcISpn{-{AoX~g=Imb_vi;;IWc@Ez%+v3V2j6}8 ziFXg$lSe5$cz^Wt^E;Q^w;sp4=d$r-An@LcKlp7Tfp7iNXksfX|xL5wX7 zUZ_Xl>#j@i- zJA{tKcYl&;Npk8__0da9RsO|w>t=8#pqOKS!!v4%0Z2BsunPlU0L?PoOumS&NQW~( z!`1hyUUVCyCzSckU_1WjPE{h*7El1BwAIVI^SE6d24pyU-VVkn?{n5pB;^z(8k;FR7v2CKB_gN!LjojXEC#qz<4a(}oTGHlkl63~~GvC?FLUcGks#(Mhf z$yyJ7>*<}Mvs(|})uV}cI-0l-;abM3O}5fj{iig3;V;b+!MBwK%I>==-MG;S`+x}D zV??n($PfI%KoKNBm$u5Avd(;?Ksfj{Q=`$NQh9-kH%7?UvMgy-(YzO70WRwzzuzy9@w*0 zHwus4;yh9+p zc6OD#LA~{?ZcbP!V`^kpsKcFloO!Mtq<^jijb(-TNE(efssKV(qAgexV}KIC>JorE z#XF~Rzy6hy+)p1rJ(kAv61eC4;m$GLjYsop2zI9s{O+pu-Bs<6Lb@V>(RJDYH)mxZ z^vovTXDOMl53zzK1Fracxrc=12Ow$61caFa@ainVl1mD+AwmTM(D19;2!1#~V}Arp zK#XgvROZ$-Hj0EUyTb7uM=eCM6ElX&+LQQl)5lS9X;Sfh-RR zAqUCv`v5zhxM}qzxFRwWMs(t~T=#daL6}Op~RHkhhN93;yp6QQ+VAgGyA>S0}a`UiehJQhOV3v;i zWDHd0ViNkOszTe|*6WDwCmzi^Q0~^_cHQ~HpPes$$EVx(zv6~Kpfg@B&T5s5hOOl% zIYxD zK;#eereFfZ%(i?!f*W4S4}U=E%yW?j-PSB_Vbxx=l-dH!9tDCU71Q_3YYd;{65+`| zOY>ND3paJ5s-sNZfJO30(`lQI#oXbb+L>z`O5t7k{xTbuwaF>g{qhU;aNwx^*~5?L zH6n5AF}!lK;!fUD?tZLUZ_M!CHo|$O8mOu2)wC+9Yv|Tcm#Z;4On;I2ll&}zL0$%= zx)$-N5WZN{Q~Jp)`#z-Jv{@5zNG^Qow4VjsbZPGv%LCf5imqVd1Wj%y*#%I5%n_EG zSI=rSlqnS8zQlM(5d4GyL|uLKp=&Qcif;N;247|%TEiEtHk~;_V^nDeT)9Un{#2nv zvOlB}7{}Z4urpbs;(yN}d%>;pr4Y0WfQn8xIp>+Z@#CD^h`t&I9zK0=JgSObpFDV8 z194}bBX9*C1UoiM4Ff%737ynPF5SM6MluAPY3w`-D^;zTJ*s4Su;oo6zYsd4oK&Dy zWw#+kFWH5sm34FLA(K%`;wsclE;Z;IX;>>G%@kf$^|f?$OMmD{Q?g9nIThY6woTZ@ zC!m^c3-Yp=@HIz>D!(A$EIrkb`mP1jx55anL3}D+l?F48?pytWv zW%r(RVLyG6(g#VnMAa(5 z`CF~Y@2Hk7$N#ohj< z+m<3j)U_cdr&aR)SEIqR$3*%wAh`ATU7>*+5B-E4lwRm`0Y)CN9$dRs3%K#e{ z#qkc7eVZ}~yiUn$%C{bLeEA2Cx^pH;+>@NOHZBL!Y|pV`+xYP1F}F?ttrO`3GNv zVY@e)HvoUxC8#;wNx?VE!Nn57GJo9QI~#~V5@ZDvB>*%NXhYmP%D3EPoh+S|sO;Ab z>GI2%Sr&WDvh+%09eg>z6TAUZew1b?qt&UTbYjJ>l9Pr20R9QaDGNfy$`abIDrj|jhBZW$5 zZs#-B`t`$R@Og0ka6fv`K7009G3mj_51*|k?c+Pw**6}|tG77*bc=HzWo@@Mg?x)V zDzDfN@+PXIm__l02lr|CuAf=bK?%QmHGiLz@6`vllCpItSk$a5bSxK{1p?U})x+flWsQpqApDulpI)XFrSk?dis;2EIc?5V#Rum*Us^!S)a3aVV1_%lN z4^=_UgKfrfJ;M%V$o*)l`7Wt5db#y!hC~-Z3G9We2T;>XBhac91Fpcwghk32u79)Z zcHG0-a`}gjYA|^)t*Yj5#sm0a7@XaUx?upaU@jAMQ=SR-DvDzSSDdwtsH-P6w~$Hz zBrU{70`4|TPgqtxA@Wg$ca)8MhKPZGYv6@mx=+lA;_GPyx_>RV(4vlD8QFrL)y^b=kCNjgJF`gDMZjj22rYSW zgw}f_e=kUsDZ{D@3v_-*WaqYzb5`0qRfCO>+LJb(U8N~)00N>{8TaVhZEGY0ZAghB z2YYO*4xH&`Pqoq5P%HD;i2WJ9On8Tp!Nf#kqK`%`|FE6qY%G!O1N;F>seh&?`$&S$ z{2aU5_U+h;kJl^0?!6(tPFro!^%1;G=gD0)n%<4s+D=3IVX?snn29XoGqrDZh@Z8a zwK+Dc(5X*=Ctot{=u#}`Lya*xOGGU929q3)Jf_Vphf32IV8aOU-04cozD`If@X96~ zYeOA?CXD=M4+CyswFdSNeSc*8^5iPKCq(djP*Qa~Z$Een9YZtPqLS4qDT7OZf$QiZ zE0&~b^C9xq$5yXQl5EB*>9k;e_Q^U{%TaT4$8Yn-LwBt?*PNSk@4=q@4M-0Ao?&OO3vhL9rSGL!xhgImD)MGi+ zuCfcHk)*ZNN6%mFZjW-7YGlJ4z{pK!CNo796pqYd&Z-3kB?H7k*b)}wi{w#6V#zQ? zzQS_!>otKY+9;4}r+?nt#&=q;JdwV!%E4PAx^Tt)ZHb?&!7Oz0Md+2xFDX6tY9i=t zDO0i50yNhHI8?|l)vgt_Q{|r>s~DYSPqXWnl)83?UvJP)j}joYEEt$Rkh9A}0)k{q z8k1cg@|RBAKl6M-&Fea(bb%EsT^Ri%HK-&Aj8&(>X3a@06n_APKzhHh3ViYWqFrR- z=E**-sPiGlu^@hqHKn7}wD9q(gWtl@ z+`lqxx~fM6xRth3e@1__K)30w&b7`V;2WQ=ClB=}cU8`AJ#cpzv;V-pbUOL`=eNJ^ z@qCPZaUyDO~w zzrs?Xd6=#)^nqEYH)JsNfuoWsJ$`D!|+fW7L# zKf-bSj>Y#NN~@Bet`6!h=Na}O*hL*Jyjc&t-Q^#74M)8o;1T2QL-i@9Ns!iq_pFl& zF55=sjl)fq+jW1UI^(}cwYKQM-WR*pf|Fa- zBal*x#9YTFQ^Y%!gmT}IFow1KTGZthi77S1Q@S$PtyaakT?RcXtGS-Bt65DM>LerZ z`z+&Vo<&-2&=}YWY;movm21I@O;*mfL|=yTTJY-XoIHQ%+UFyUU-+CK=X&t?lZPLE z_T;li?XDBnZHMp5*=|1FqvhXurn>*4E~uI*>g}wfZlBexoZ#ltZ(%4@jW?5Gxel|& zs%a`Hv?haXW@^ZeSEu5~c}1&4u|W_64^AU32KF&Hu=b_8ry90m6x6{=Z)I#Y?%8`S zO1dV8xT1f2yLEeJ`M=J`GG|RThAkR+ZDO!%XT7LAiy7g~=Yl^yp+ULH?-~W}`c!K4_PdG{GI!S8;|7` zwDj`*g1@Kxg(GX}q!nAHv|@FX!Vv82<0_ENgKmP| z8~=aibScrtG9K2^msBjQQnJk2-Sk^Z9@^dj)!Jd7a<*VMrzj=tF@w+ZE>KnzUs*1Z z%Aulpx6vD)?3*i2z8YQP)Rwm;=T8DNBQ+->A<6{}-dvJoUS`OS>~A1`EoPnL^`m2X zWG2oq7iM(h8~@gg-SSCeG4+wpr+q*7;wpdV$@)l}?%cmtM7E{Z>w9M zbtEr^Ow~2cZ9o~}h$2RM?%ht1idhmpa?1fmn+1$)`Mwx4r6*a)AQIjqbLPF}HM5;- zT}ty?Mz2BYfeQvs!1C(02lQCh+Lq#5t*`Xfd3Qhe<99!&zOdbQeBPQkikiY)Qg?r0 zu2BQxl5sxdt_Z3sitKGG&Pwy7Nt;NX17Mx%avx@s#fC<27_eM8be|ouif_4exGp`> zCKn(t+l~NJyZq7j-+)V-cXvqldxv!I6(oI>NwQ|=I4d!-N!s*dNE2?b?u`qf4~daV zF)6YVtBaWk2x?+E+dQ^T^rfi7pG$v!HWZkL#NBpaXL}AhxGLEXHUj@@TlFfRk-!QUGb>TAB2}Y>h<#*cQWTx6-I8~x*K0?0s(l^ zs1)A7Y*vbUix{wV=eJ=dBnG_l_|DkJ*0Q2oNb#jFuRXoGyP0@>JWc zgi)mVKVA<$eE94RYrcQ+0A6zn`@p7`ox=17_n>1bHAKM0))7*aneqV0L-n&v z`*;&;(&bJ~^{3JUo4EwG zTs0E?oI13+{G-aD)px)Gu!6@R@Q)eOjW`OE z=d1M~q4LTbZN5~3g6BTQvi9%y}k{j`=#TeJLN3(zXaHi>NQ#ks=bVpl-hAy z+W{wo#3_d*Deo8Oq`^BISOwmGSVJXf8BYj^$#oa@l-Bhg`w&k~j?YgF;Ov)w;!rEM z0}#fmiqa?m6vV`k5;l`hwys0F69QrmKY%4}3QC9G5&B{MJm-Iq`BJr_|GXMZ-(j6o z#eYuLizCW)5j3XS<5-v`>yAE@$spQ#`6r*NX-3HcN)|Tek_#9w13%PsypU5jAC!TGZA?b7h#xqno(M7+AN4IzoRHvX*P9T0NeDuc>#9EGWYr z2~C==@1*DSg?s8J;q}2Zho?+$pTUq z9kHmk)s26U0uw}{5Q`8vU=XF0S~Wm~6jlLvcOJJRYqD>BE%IkHtsSDQy$E1-sFaab z5#!94fi?F&bj+5C_mOz<&mF5%s<~BmX#~&7$4ZXgdD+W@y0Zsf$YjAX<}>UF@FFHc zDrC`+H9wZoTWqjWA%g@co|hmZX9D%*kzzo*M+bjCkqf}JRRDg_Y9jWu;quSF|DE6a z!-9uz{n~H7$baAdLE?Kb+mr7;{N%y+Qus5><8S@+<4=_*+Q)y^AO2n6`Q6|8=GVO9 z&^^5Jnm_5WFfxA!8_*k|9`_osgC=jqGoK|k7e zU&{LX;UMWeHVcr-yH%HZ8i8urPACV#7oX1zy)j&uj z>Jk%-S{BDA4)n*ps8M*fzW3}=dv;ei?Z%^bhX|F^El#nIIIfBB1F^gaG?n&Q0>uAd~nZ_q-|$s>mNQ7)(-kJ<6`al;C?+0h>G} zr%|1@Op7}VDG!|jl2ok(NO#OKDKdY$rRf1~z5$L?O^~{{WHIYH2GDtS6dI2oJt7+2 z)k?kfxLsLq{`Vq|c- z5m_bJ^yrCB0Q7V?L9$)NdzxydmI3R60r?%-D9S@Xe5R||4lsB=3Y@aI1GRq&Pe;{! z3`uN(v{Z}_txbtA#yj#ivPChO6=;JF+T?^Rk>#OA_3mW{1`n&^F@qHeLWRy2BS~tV z(yM$k8;X2eH9TsBL6V37~(k-q?h-%A&@v3BiyQx?zVv%b;P$)tlT@|ENz z*D;8YAB1+eX^@WbiZJENzwjCqQd`Nh3NE*)IVAm6l_TkF#+C%H?Ts)bBPi7wAFjiP z$D-d&{-Khu-H@#;IxU?uA0#Be>q9Ju+zbiUu`s7xq;~RUiu-y&O*kBoh5bwws{=gdi+2dEJqTYH0uLyhjlVys(pWgC!Ivzi! zIv%%fI(XLu@j7}SZe4$P@U9Nx{_7xaU6=M&m&v`6^|yL1QdW|CqO5*5tc0uWQ=DrqO~&fXc2@7 zM`IM0?uJ;U`SLI7G*ogNHV}&-6_v4-AuX9y3OM|!A*5N7AX|T;tj3rP9qB|S zG1+98(;gh#4rI^b2F^{?c;TY@A_r>ji1Oi^Kh z-NC{Tq+XMFp^<-$A1h5gK;Q=_D;sUyEnc?kLliuWoo92LS3+_?7#=s_gItE z3_R1?-Rj%#`rjyps3m8Dqaz-Sm6*~P$L6c>AHvE|$>bs@kl|#-MuaPBbs~aw>?tBQO8Tp{(O0fkXN}Gpjz7iL#bp7p39TD=^j-)#87$n-AUJ6f+YLL9s#pro8v$ zpYq#k{ON22RltO>$*8+ z^|N6X;c9;p-qlqck7XY(|Jvb2m_?s#bc|I6g?qUPk|2pLM3A_3B|N&s4J+}gs@G7( z{BcT1QG7cS(B&I3tt0fvAW;P{L*;Z#^pO7=Ar*o~;3_=3oVS*ma){=;rOUs5+zdrK zq-WH`8BPXwl|@k zRsv)usKS6@g~LhoE_Cvu?sCD0+V$h|Zyc*LSZCys3H~u^5uKIqUVWKfH%K`V)mxKi zyhd{5ngbhHbu{n_ouz;Uo@GJ;g?#JD|mc@eS zb~83Cem0?6He}89a0=%QZD_rSHnR!i`3bGW;h7Yq1^YrR(wvm~Vg!{nP1n{E7(zkS#;Qm`B1G=J~MD3AeB3c{(-;wj6 z4=jw>$mB&9w^<4YGOtVk#lfT*knKvWHnvSBu@ha+`bxj`^zkR-6_#eV9=a=CgYG2* zjORbUamVyknKr}ANO!7z)oBb99EpDnsvI;#eRc#azXM=b(d20cmr;qf>av~m&IE&O zBEbQ?iH2RarMj1K``~s{?3>8%o$7ovrp?O^*vxZ5W)$M6YMEk!U@WEBVU_~EbS=o( zs%hIglTu9pSZ8xS5uwScA-d$1c-1b?A5DeNB=9># z8NozPKqu1!TX-z18(%4y_||(Y-s<)kBw9k)s%a~G@a2~b8+5ERo!WO)NHru)>g9kA zP6&IGYNMM{FcenQVJ!e5L^yx#y8K&*Of6X-q5$h8?vuXU+WeLhas=BM=A!acJjmR8 zO4u|DZW;PZG`ShA;h#;x;tAa!I2Lh7l4@mU{3qC6Rh%LJ><$(>cG;){%W?@snp z!jVnY2Wlr*?_SWIGI@(7SH+gM0rN>5dCX=GH4SLC5>N!(^{68@>lrAR8uX5c0+May zM2RLtN69eRt6N8V-7o0%8Y-BM8d3ZpphikzOUQUj5KXDYzm+^crKO`$qy)(WQoJ zBI>lATuOFMG1;_5cB9THnp`sbRNe0YelToc95@28c!Tt#J4}D&!?^t0NAYcrRVo5L znwG&pI!*C~RS%woY}8$Sa^P1Ic97 zmY^%@;6?>@UWL~XqvoO&9MDO_<=@d$Xz!M8r_r^D)A_OLqDdZh=Ml6CRpOy55zo+0 z;S8@VajlPH0lEizKNB*@bcRIy+!BFrvH$ zsLrsH5`*jqb)URI#}OnnO*!uP8Yr?Grg!ekzjr{xGG>1Qk!}XxNhI1r_V?jirZxjY5^0|S*Q2vwi zb%`oBaF>7o`JvZlf`XDWbE@Oq<3JWvI3+6HLu7%Pl7NkBsemh+ZVX!pMD%u`xVQ!$)=17trC_fP&MLOuI${Q_ROwD+rZQ|#^ls^4+w{Ncy&_pGfPRi$OA|N zWF8g<1_^-K$l5k?YFEXm%D!UTg4balX1lw+>NXC>Y z#4LX`ounXP+`7X|A+;#e(pB;>W3vEbjKwaNg5hw-U<=r{z%+{ba0z=N zw4f-*znZ+(OsqMtw(&%Ik!Xu&HMFG42!g2B6~m#n=+!h&;vp2uMUvSjE;h9U^Nk^D zBs+Cq?n$DTWXY?*DG(4$48D`Ui7u-EN8L$~5xh*k9E_W_hkfg0-!4^79G7*HtdxIV zAe@Osu3FK;&tByc8M+W90AJ@(KFXE>m8=NZCYeGiSk%=*$!j`a(%$-UPSgAopMCz> zmB}O`jWtrxog&y)1`bv&3*;|8#8+L-C$*C$rfHeP`U^I<#beFm#5(JshIJ{24p0S= z->P{YTm^{HRTdOPEw(AiTSvaO`g?yh!T}H4=_b~E5RcP~U%B`D03DKhMk@vknNnCEE(@sNrs`Ew5)FqKSkNU71S~d>6pB6AW}Us$&h#R84R?G@S{Y8j>!8 zr+nN({@K3b z2Y2g%`_Xt5-T!R>Gbt;a!W1|wnG6?5oy<(KFs;@Y1Km~k9fkj_8f@&8Gw_tPu7RnL zZ8PDsClS8J{>o`7&>JA+$XkC6kI-1=S;PnUZiBQ$jERuR)K3ep8nqir3|}|hBna(w zVktDo&3Wi1i4qJTiVn~KsvTqwt$>q2w}8B=14x8%o-I_?B}vM{&!aqL!% zD0GunLNyXZFwjw`*ZEvkiRRM>{qdt0Dd$f4@{Nb@>asJZW%ma5ifn&R;%%KITBdqn zO!iAeEUE^otI;L9j`&DRs?V|J&ypXQcY?u~=! zs;DLHn3chwr}_@(RwMK|2aYBnvWRwVJ6-RkOdc?BkfP2XhCIvVJQOlQ(=m+>M?j;{ z?8KAATw@32K`}SUuS0(pyO+z5Eyq9luT6TZJR|}Os zZy$fQUR^+c>yf;AP-{*HwfE6LQcB}XI2hjUO9nnJ+dW5K0B|BklArt-wn~c;$eJ=w zXo26%SMB8}N{|I#1c9#PVkw)PK#GV_8%b94s!=UFcBwYNKqY@tP^zxEH2>@JAHIeL z64!}I*>+M)gLW_*x-t=R21c^+=V%@zran2_n20W6rYP<30jOq`)#9cKxXdVNOI||S z(`$P#l@0<b!^jh4ZPwTUM}lZWO)oU|#7ZdD(Tr-G@fsYrp`D z*pN0^6D|k$1(AQjXLcwhCSPYaOU9uL9s;kf6hQS3Myj2i^P4*s|`5RIvwb zpXvjNK&LF-Fry&{NLMhKd>)HzHs)e|mGhMu@QwYQ*}sVm3bG^*s#7IMRAY2il@U9c zU65#7jJ+vSLIf_6d{fOEuu3!wX|xIp(Sc?d8=e*jXjy-^Wb?R&hU7^&e?io@VHuEP zty&*Wi}2^4tVfSOUk?c7JmVeUdF#QuQU?%UT6E8Ue&ZJ1u}^)@YWkRm{x?BFcG6ou zd8y73bwiy~%f&&?tXrix8;s>QhBWA>?wbHvUTQ5R*Uq|$RdlrIR1nox9pIhgSnx_Y!eD-KPc{m=t zkZLn%w=(&ukh_OEz2eb1BS~E& z%^81I8fX);V|Aq`dlKSoI5%y+|5DSYG#Sq8?$+aXRaM)aRJHHJ*6`LnS8sC*7^zlD zU`y96O!P|4<=#@zA!~BBn(cezL7^FTiYDtif4P*^pra#Wm!Z)TH{-v>Lpj!fp0Koq z+jdJwE3mIYcR(pJ6h4qc;VxOlY4%-Zz#o4rO6kW9Fi?s0!D8YiUS5k!$3CSx7z#tA zs*>R(^lx?~%<^kOTSm6dtaMld+1;x^(e52njVTuuBnO>Qmf`a(*&1M@&$14%y*fB% zH%83f^~-;B+{wd@d9`FTlPc%H5^nol*KyPBr83%}VBN3ks4;pytE?a-& z5g9VrD5;tOWy|KNcZicO2&s{xEfc&|`oMl+^IA2%NenMt{^R%WU%u6v5>_pl@sPaS zNJg5F5flo7O;SihWm!#OaxjD+;mYjc4h4@DXrm30PNN6avVojE(vehwQ2VTW#ts}Y^ zKYe0Ww=S@nN>tR5%09_$+3u8$T2WzlmfNzLZJHE4j8==4i*sjDkG$;pPU@$YPNeU; zD&2b2uBJ$PN|A3;ZTc~ihl}zreDH1l;M*^L{NT5qN)_Pq_VL3hX{cZP;%|Sy_!EBN zJ3o1>)S}$Q;3jC7LR{-GCD#B;@GW3P+onrVuK5X&07^)PQa)7#A$e^R7v%*V042c$ z=UF*>?9!v!vZT>ZB(V}^9@87`(l7*i1iN{|ea_ZPwUL=P5}Ks>3@=*h;#95VPJQrz zA^H|oiq3Qn73gK1P>nL>8_j>ljzA`Y3X4&FaNEj4){-2_fKk5Uu)|?=Dy*!~xA0fo zgUF=X^HsB^L^-Xh@}BzrxZ;g;%eTky9N0A z))X{V_&1$IFj*@^=0*BdL}|6(IY84;N2eNxt@IIAPNsP^5(3~`^hAFsZBjXYA8lsL zw=3%J%UzCDm;dBlS^FPbW$j0^OA!E@06w=45!0iyc(ZZTAlHH3DtGY|ln5g{&hHOY-~ltXrvz2GeT*Z2_VDcEhy_#DeN}V3x=w z(MA%t(y!gpwzVDjoCcE*jtp(PEI(cKZcE86vp5UHfJYA`J z;89nxNRqG&;0b63(UtaYs46XC?e$^25^YR;%V4Br6Kw$HFZm&_ZP~GEmFEZk6Zz6# z>b?Bb#g-4;7n^_ehes^m`q|$+R_nKqFL*~x^reF)ceqMViDIiz7>;4!L8*v)!+SjA zDV29s9nG$iV>Q?^GMTuk1XHU`5Gl5e#BaQMYWoVgHh?TqR8p2Q=pNemzSQ~%Pa9=JOo zBz|B&_=*7i?|J_7J=|&P+JKcV1M{R9t6E$*C_`E^fowVAWXTX4CSgli&=qzB--WMA zc5)l$&o_T&gv(NIhg~fdznD)_b85OKkk)f@5QHkFJ*QT7>j`tZTe$qE*Y7lSB`)(< zWy7OKLpYA0oo!HjG-S`icA)JxV-jUi^SIW?1kL&BK(rFbm+p0e-n2-hff_H#((C3{ zXVbF!)HP3UUHE`EP(|+4!38|$d_#ZZ$N4f<>92o3{^Ia!JbrRbHbjPBaCFJcH<|O2 zM|F5p!N9%NsbftY`Z(xXkm7{IG2rouzV$+Gw8D!r0ajv3{ zUp(gZ!KWX8_Tj@%9z1H}$>VDU%#!~!ht7y<$@u7=qai@COzdX&`W1?nsdu62%z*5* zm{NdcnaiZ6(lp&l_nZ#MC*79&=pAf>a2p)>dlXSfrNVHU+0vKf z`nQ8MN_`?olmQgv)p0T$0j?4w)z4C_%GkWxaN#*?kYn=(4Lc3Jy@EtK`G8 zfSs^o2~%w%o;NU}H}bD`K~*MU?K7Ud_2XQf*`GOP_7DESSL{{rtS;zkVPB=JI?;bX zjsQ!!K&p}2ih4AI7omVFD1k1ZA^~4Na_2On|Ji|mL=7@@VoqMb zH|b6duE2vpFbdPLFeSg1_a}~U%;>H%%A(6ElkVw5=AmCo40^hwF z(M#-Q!}6jfjgWP_pkdfCetC2B;LrSxZ`$-h`M`YhkNlBu+Wf)yKKP#gO=Qq~U>=y~ zKh)WU{M}cQ+37ca^{c<}b)WN{ zZ@gTHlhpP#h>yl;`i(A#C8{{APS#Xqw4(76<|axK7gu!P<)v=BV~sc>ir{Ec2bBZq zw53{0OF%E9tKYn=JZc1>cOri>1WvK8nwM?nd?RYqfYscg>dnhob_IX9oLGvU)BzHZ zh?C)ILM$dHR=T#ngob2!#*-hHLhJ!PO5$}a{sDV}FBvm~E|3p_AE;yvTJUOv-||@l zqz#|Gl&}4Xr{5i4-12<1KK>Nycc%d7#v^ydC=FujUouKN{@@;r(qe$6I=)0%eHO?k z384YXV z7SW?Dx|ZreRbY`;kzD5vsT_#3$Fx`|d-Hqya7D|YgSNpycJ({HxpAaix|C>*WZG>x z$XA4`8vvbKjP{WHdT^2@Ax#4lR`b(lf@qaF-XZP`@*;mmDLV0VaV!;bBoMV|U4-WO zZK@6+JD)Y>v!Y&JzWo_TJpHIWx#Ng>>oL0$Z@vHO<>Y%W{@`~WZ%vegg-VmxFhM%S zc?n}Dd58jYdC+nwRj9iWOdPuCQe_$jJH)7i$alU=74vdB|Ef**wmMy?kxex+*l3bu zpkneMHhX_2z`MNaqK)D5pC6*8(6OS*BDfKlFUsFA?G;sD)PgO$OdYO}r=iBuk9CWT zKvK)WNwP-u&N5QWl5hDKRn~<^Y)`d@3sn-m2EA^TcZV<-a_%E>!Lxg*}x0oC=k+3gt(_S56GWj<&-F zo3tu*BL2M4Cq>8x3C=U4stZyV8i-rU9g+^`Uja7(th$AR%Q)=L(cceKm)M z3dC|uFM$%4V=FPkD`TCiU5AYCAP+)I`ssfiKAz;h8dTTmx7WUAwaFZ+O2b1QWaB7l z%PZ(^*RlB_JD30FkXDtWqI|HE3|u4g**sf?6d{cW<}v0d6OaX2^}>BcTDGv+q}ITL z?j=UEKpA9BV<8Rd_^^bRu;kYmpcbpMo+R4B8%CwqS}dt6Mzb&f?IF3Fz$vXc#vFf$ zItZe=73aw%bGO-fPLtwT3N^;LSurf^40+mpZ@<<>wO94mHVk)<- zI(IFS1XmTm&!lmKL}?(#nzg3vAjMO7sxT^pz4jlzGO#J7Ld(Vyj< zO;k5COOx7^l$7Yy3TAn{DBExOzjx@Ul@1K+cDtrI+Yn(dMPi-a3yUY+D@A$D!don% z!G?YLACGv^RfnB>HJjLLeeb>Mku?UuU{-NuWC39nOqQx@)%2 z;_4u{Ih`}>_NUJ|*t}A^UAlh^+av_l+ISrnldaW3d-9<7xm%SaR!W&tP9Q28Hm=lqWx1{jb+(&h$?|__duGqt;9sCc zRn2(fZZ(f6fhI=Hw9NO-HVs7~2{*Vyv&RIuVv`<`iCK2UtGTjUx%@AO!Es^zL;6b1 zQ}umr7huXTOpJ!nX5r+z*a2*WbVye59+sW6m#V7R5N0JH4bQdHz)LkgMuNmv5gbshX$#q`-*CSpy!cFT@2TY_Tr;1y6 zIJP=nB=fY05NxbYLV_%_n}FRAZykFcpp7Rbsj}upDWrmQ#6W*ySk%=R5mhcROR_s% zce3h3>Hau}B}RJ9_SB@3b7W^Ok+4C4iho$!}5mD!F9MGe1^Jgt>vq;1ZEApz?WN9x)E*dQI=EMuDu!#@&S8>aY_~{$Z}TkhGWv%e=|8l!@cX~{@X?3gJ{Ze`@3yCpyt`sD`%7Q> zr7yi@f2iNP?oRyG-}}hQEYweDI`ObeEK5SRN$?v`PO|HJ>-QRo)#QWZr z-~4@dpYm02`YY!*l^gIYzSFN>{oPl+^Pl+AZ}-n1e){xlr|Q+efBk8G|CQhW+9~<9 zuX~{1<||$`^1uG-hkDhAeDhTw@-;K@t*?E}D?aHvf8d8ZO9ASVT4aTpx?n$G4zOm( z6e+eP(V?(Jlt4hhkZrHgO-c=**7D;`EF2kJE$Rc(oWMRJRZ zO#vxQx~rfMQu|p<;?~jY?6L54J^K8veEzKm?askn{vf?1nDhMSH|OB)%Ypnkbs#+d zcXc29?&q@8vMhs$L&4Sp0wjP4Xw-wq)bfApt$b#OWt@$H%8+AajRBk#+Kt|?!_m^M z|Chb@?y)P&t~`NhP4%?U-6LenwV57C4KxM=M9uL=fW8WWV>3fVlOTgtS^8_d_uhQi zncuq1swD4w)JUjcKC%>2WhNsS=H6rWUhAB_*8&~bA~B=Va|nP!d6o=N(5T+Xg0X+9 zafFW!NH+kmty`GKxz^99Bi$Nbqh#gBIL_-$mv0}4&+$`RNs)Bzr0KvK8xmqxZFE#U zeyc1i$j63n^2IW3mN3E?60Vk@iRzaoxJ_kE?^s)#{AK7cwNcN4Cja1_j?Q|uFLb7F zJZ@jAfX-5@+XxIA!NoCaPz`AdNJoEF^_p-C-v;~w*gcsk$skxA$SxpVgmr@DT~@Ib zAU1a?XEe*q7g5`zPuxg3k+H0YSro8++g+rM;o_|4_IVdtY-=t%MVaISvyHka`UcIm zYGwfl<|dn&2t|g9)HaAAgh*&+9#TnK1d%q0anR`uk<#%}UKRMC)l=t&lTUwSh%yhZ zNs3Sof)!xM?Q9(KkDtGK`Sp79Al0VTes*EHeB;5pa%u6QP>BCLg+hYlaYq&vw-J(^ z2`7$yXD;3f+Rl2E^l*291b!}P{-gJ_^}pUP z?)Ix!4=-OmTwIymdK9mQJa-CtkI_GWYc2aHY5h+jt$&!@@ZKuoA*g@J=#}{Fk{obq zToN`hfIrzVCpC44=yWPz=4Q;@Tt%uPsTY-RZrued1B{@1VrdqSPSmu^OerkJX>`^G z(gj8v=ZVqh2KpO6&M5}`;d?RQ;nffB8rR&ci+bV!)3Vc1??O}#WU{lw2O%}b5?3qeWYG`Lk7!^YlBQ(f z!-W*G|8+0@ZPnDz#o{-9oYVaNtCP_6%U7>owCDGKwcgVvyE57GCa>Nuc^0cWngtj( z5F0R|gG=T;Iv{oTicX3xh5V$;>{7?lacoybc;g#%j|iYrTxWlI1{uM|E;}_VO@TR= z^alsoqgWVQpGJ}a=Bn=Xpa101L8%G|Wirt7ahhy)=9LcXHCJ?59kj((j=FKJu*&Jz z+8J(KtX&hpq|;GIK=*`YrZbl!d7P4sH(AByCiS&+ZJ68!<=3GLf+czBQ1Ur85Xr%q zjzsI^oFH4zK;nPYMNgCW0`UR75ULJ|lZv;x`cu_*LBQwf2?px6VLenyr{{T;nU*wk z;BNv;tJZ4B)4AyCSO?-PPmt*vDnUN0*?slR!;9y4KYw*U@7DA6;+mM)tq1T5Ff}J& z`dP9e;8M^5zR|r9oWihSQqH>f>3g0V3>MQhp#tr_w_L zL2PQwV01@JE2%)q2GAc!tdv14ol+wTJ*n1TF3soO|1L9vD1%k+r8K>=PJz^?uL4$C z*_X~dhTgK*g@ZFhdI@xeql8Afp)xiE$7KksX_9Tp>Ty|SgqU=-R8lcPHk_emX){*iXzIn>V!APAp+tV3)XgF*Trh9G?iuHZqw@F=tUOjhP9f64&PZ0xYn%YZx!4CJ*`p2yRSBI~GmmOuX& zr^KOC+@Gz7Z(hH8`}H>$>bo}{${$C8|1${GPkG}hZ#?CV+vbfrH*Z;4kXhh;Si$@S z+wOl!*j;{ux~`Qp1;d%O=^}dyHkwytX1ki+no*~lu}0z*MMvhk zvyuZmA$hm>0bc#ZU!on@1<$zc5MId__H^_2Szf|Obk`Vf*;6XEgF;39hk0giSXiNH z>SHfn7xt};lyZ?vqbV*d1KpI_oy%PZ0?>aq2fi>t(gWK@&G00ny5aXQDgl;jy843I zvNr58FAR=bX6bc+M^3O?ec=ktNsz^7sc`TVGni2eshTJRhg_;=o+;PdtaMv4!Ca}v zs~IUL2eI~7|n#XRF6`f7xW_oMwbuHHmZ5 zl2!Vzz1gmMSJu=>Emif(r~^qFP=SBgRus<6F47eO{>+?5s4*8EO;eYw?r;dx~21Xt#fS;rv!% zRvAWJ4CkfhbCD8p36)hr#F~~6$HqmW-) zmbctUllJt1ORY*}R#^%e1Jgs%$_4yF5uk&Xun7dJsXE7YKj!EH1TBc~xah z>m|r8E1CuLmax}o5_S(4imbPOoKqP3OZ;yK17#94z83Dh1#o4ko<@mo}vfV4cX@r{5qRw#v>dB z>uZ>4?6RQ+gn8xD4z`2y%Dr6rnq`ndxB7{*yqqj?l-&!GE7eGpY5CEHB~hOXA{@Vp zQGsGPK*pAunePID7 zB5T=gnLm^~q0Z7RB2H$umipM#0%rs- zhFr0G*ee^N`+$E7_XfvUel5mJZj&~pvz*SYALk-}e0VZ6zG<&nHdl*g+HeB2+k>_{ zv&@QB?GkOo#P$f>A92 z;M)y2k}W(M8@?@Tp!_n76j)&CN%OrKDaDzw9t z-0?;B__%KSZ83JZq5P^6J5}3<+w@IG)|C z=?}KmC18Kckaz;;&Sp)Drf&Xt`y*YyFMdrBi2wr~?gZ{84Dn3R{)Sunn3+l<5>ane< z9$&JoNb+Uy;3Jb8$z7cZD3ZYyw9ncXvb~>&a~qp`HNm8#B6P<+yaYmekf4TCMvAR+ z^N_1d-dXO{yu36Lq=&9vFM`Ebk!(32V1}{%^25okNARjOQ#e^O{l+%|pTYk9qQgm$ zd9{B8Z=IwYj0`h<%Bz>4Sv({PYm`-z6wG21kYPzk-a`G6qvgogl7gnGaFD+9w1=Qb zSo|3j&ELdQs@9Y2bXf7N@}&G(LJ9d4PTZ#oCpI&(emk~;1ujEo^geD0VkAKGldKa`>1Os2z@Mg$devLA>+T6w-)>)q*lUA;t>?t+4DF~EO*oF-IsQIo%>u{Bp1U5>{GfqqrDECAVjO=od-flGrPSUsKwbyd8IUREFSnMJFu4i3^G}3;sZ;`0G(+a9e7Ed8 zrD~sZ3hMkR0cHSs%xc$aT^Fsag{0$6sc;V6uNf(sF#$&Hhh#r%C6Zco62{j_0wFU|mG>atlM?dQMJ}{$u{u;K1B#7P=lLh5 zbxKugZM*1mzwroO1xfY{eLjm{kR353kKLP@%~3xIG$DZ-xl*{vVv6omfZ6od}P=y5t>mlkrdvB{aYGRCpUT#bok#EmYvik?mv+J=y2SCMU%)IjX+vYeFQOOe!35j{vv z=Z8LL9S?4@vF`8vW|296l^C;DBp(aaGx@_sR(_~>Y4U;cs`$#1k11C5u?8mM;H*QM zu`Q5UmzR;HZ7iNf1dl;JL`$O4jipwHvs?CBB9U;>kTR+aZl=q|aS$oaL!9dV859@1nB3(ZujmJ>pXwrs%C9^1>5tp*EiM)Hs zKjgllO&FZqDQur4N;dS;dvuAdhUgU~yIdDyR{zz^)<_3;mKIgS^x=Hw_W59|r!tCvBk>r=7?1Y(Gr0Re}sp6)0Ge(+sm;N`x<$^`ix=A3Rg zdGJVYTK1_@ipf%chfj_;yj^eoIH&piM?c^9&(|H$@(tPcS}vH-QAy)fa#IOz zu#PGb*b{tJKMN}4(Sl^(WjpF48&2))M{(~YCIgYW4-nxoHhjSBDhY%l%~?_)Q%c;? z_3vO^Kyep4KTCiaDjtkEA zRnXmc2OFzcp(ROJ7$INYMsSGSW98!kS}R7r9i{=Ii8SGz);hFair|6Y1=PF9?>By& zvsc40t=EWx)S0Uq)=AWo2`}t;Rgp*~0sgnU=eL6DMqjOmJ`%gNjM{zLUQ+bqsN){9 zY^YHu=g8`RH77$*iF3zBkd_{tvV>6>A6b<#&aRpC`#zk`^gU7dhmU@yMF4@PsOrIK zMP~V1CFgX6Jr0BUJ;;xdG~s#yL`WAN=F9K{T!LRJXc~ufebJE(i!}u@4B-jd13HJ{ z?lMCJ(}G3dcdHb(ELcJkQs*GP$h~Bz3Ve$R+$~jqbXSzAAI{} zy`8UKvq2%wDDzG3brP+FOoYzSsW7XZ5dA>Kqe&5uF7^Drih_kh^&z2f#ZNU zRbwte*xGfvkezikxxskrM25MW-UF%zd5DC}lTTu^4McRvDv<#=27+(=F5*#<2bfXu zFHFUP<%w$1cg6K?;)*KjRYCh%WaaO@{rTH}^Gdt*h+V8S*>b&aC;jf@M{tc9BxFGL zV896PTbqcK+)OoW@Bu|3rpn!-lO|RRq>C^{7np~pGax#vA@#!o`93R~M7QP!!pfam zqWNH9ojpXrAy{6==3B(8sz}JjXaDh6N6E7HGIfUtB?e}!tyY4RYTM3(ya8cW6^rXpNgLhJHJ0n%7Vqx^Y-Y;jvFvar@siZs=WT@1b|++gfkV*7I{ zwRhOEi@vg|pZ#ZFJz_=dyWRB@{`iCNZE#kOkSvL;CxgpF1g8Yv)e&--t1#z(y9igZ zXeZaK>`F`c_XLu#9mpfx^N52OMoU@og0q`?XTx^ zvg1(H4W0xlFipx$E`3{VHwiSn4NGc!GEXOoz;Ko;gcQ?9Ob{4J&pNl%Ql&P*q#@J+ zm@xq&kaLi@(^P(R$8|1Le%0B3c^TclR6ow(=y!U%zdRVb@sM3T7;~qCvClB`#SXrg zixB~g0U^4{4yfs@QbyXL^4Ctn7f#Bu)~vqx1h54>J4;ULDUgq9LdUAHHD=;vM2PnGjK_JXvkKcU(WLs zS&Z2<`CUAWQ3bmdrt{{1uq5?z#SA3#DEcs((nJ8w!5HDa-un>+U`=Syo=DJi*%06@ zOWd68I&b|r=f0is>cxw8_hzy4+ryd!fuF6H*Dmm?1cXcSHI3m^vv+g^1R36k*b|VE zR3q1_1o*XX_s&;E`L=}#R<{%8)aGkA<#=s~V? ztH~~XA9B&UkdvT+ZZCB}39tlSIKsKSpX9=mnu03xKUEs3wu?#54)MIoZu~gs>i%zE z^U>>vU*6rn+|oXOJxVOERrjkn<*&plP#~F{Rkccr`S}{ z0o-d=Uws&?Es!^O30MyknEVQYY?c3Rf^<$@a!j^egf^vroOOyQpGZeYoTg`)3J!In zWJhXEI`V>VvV+7l)-+QMzpKIo34Ld@dgI4A$B^UF|8EjQ3_pBpiw+_=I92WCY&o?x z6U7fexq~22aekksjhTJiWMa>XEON{Sd}sygjNXQI5QSBEfJ+N&RHGen6&29?7;*BnC48 zpHAi@HmL^DHOJ_q`x9lhP*PN`n>Hw?~At+C%pC8 zU2TYPr-q2f(EGi02f`QK5b;^|SBY7>DXAR=8{Wz|nGFjfO}IpD&Mn`f0fWf#yLK>8 zm!?R6;44P#uG%Pmu#;%3M9_iH(H?`VH08x!?M6 z&dT5KHAG3g_2t+1`2?(5B2nWiD~iuvTNR3(pIB?fZ3t3htKu`BK#I7@xh|5;z)1`YS9T*KJ0)NAdL*1tBz#q)Im<1q-|5ZyuBUU zt`}lF(QSeSWI8Po57j|I`^ojL$qROM|0U;(TaVpU^Q>?(&w6U0dupJ&N+fO_pnuDM z@`c>(i0X2iaV1zXcu~<`fSpQ}(MhK$!*PiU&a?V-hFq2Ny%`_|onJ>enz*1|x~*P6 zLoQ$emPiVLBD3YmEu^6&1wAu$upq9Rd8=8jw_QJazK|^t$k$ZTSsX4lwo@L>f|H?T zDfwmfZ#Zmpo500edWE{V;%ZW^NhXwkF`ElJ&d&G1`dok-_mn|IcBe*`B-=WG^01^; zldQx#R@vf^XHl0TKewo}Ajn|sY|jlsPcm#bY#oWflXH18!a<9NVf%{Yi;s_Y$o2S?7>-BQIR+6}Xd;Rw1 z!~Khkta0lRd_Qaa?zytFEF`tUAjkPpTq;Z0jV`7f1+=jnEt% zeMv`6S|^K~%C6K+;$ke-mp;d^rfXE-@+*g}JrqjO?J{wsSY1m@P=P#wQ=eY*EXlQY zaim40Du5D+$R%(9+56~ipP@~E))z56%D1zm++y(o)KPeTV^v3^5bmn>zGI$B9MT_R zrxTV~j)ADKo2sv?^^)I+WRF~>`UjN+JE}}$oNqn<;3PNm=9e$}tBV`=TaV$Fsx`e; za_K!uTS7}iib0G+m%z|)AV3cdgz<;t7+>8z+sqM(@>LQoAdeZ1Z7R5bwd#z{Mo6S& zcT{8>0+W0&6B#=fvc3V@F1~b|*rTd!F0R}@@8i_dqPz9r{W$$kpP;}oK};Yhs?{TH zd4R>3e(u(d4}9PtN~#yE46W)7rWgHGMUF(lT1nnH5**XX_vR5@+fb&e;tBbZm%}rp z!D2yP(HM2_!%R#dJQ#w1!TGFrn=%ih!E{uWv*2JaW^Q+ot2hiGOjS0k5Cs+!Oqv4M zxC$uiPW5Y$tQl=k*$~raS(!~0>D})@V3SkU($!B`KxcQx+SwUTL1+y%vJU9CA2YvZ9w2dL^u(>!;n^7 zt3@^RmcU{fNZ#rU3P#sg@+_+rcGsojw$cyJWt6IFTNS5&s36L!Tn(mLw_exx2PTP_4K}f*{^8Hy z6za=56#GJI4FCN19=*muy{(`W*`5>z7^XQKxexk(1749lK{HyHNzF1#IwEas*Oaf5 zu07@Zkw9sik28!_hGfuAUpiDgM(c+QOoEP@CzKl=P3R%WCpcJVaxSzrquYJ6;7Jf^ zz)^_SaPM2q25X4{)p& z$$@U5QV2?0%LEpK_b?K;W3ajSE&uFVKUQgfaBEYrCy%mE;86zN=&W9ry-4pQ#egJq z&OC*WQV@*Xz!5MZ%!!eO^spm3FE9_2r`|^I3{JGEn%pPxW(BEeNK%8)L`*Y7Exi^N zzzF6ka}0hW=`Xnc?7#ZzxLJa+v-tchgj`}-7x#e#i`&iP=A6`=a_N%xvph2pY8Tyq zgp<>WkbQ3jQ7FQcH;k%wfz?24S)q7aRLwpZJCHDuQ{sS2?;t!01<-5lT1B$*DPi7_7<>9Z|>}PK*$Tx?FpI_TRi43*t9$y$rRc%I6Ad$aAX0C64ZOMw=vM z03ZPVKzmfF*n{!J|ITKf*>>_%3tldc!^>;Vt8ovk*{0@?*RR1dyF~?Qy;hazt3Or} z_0RrWJ;kks@V`J^{wrq$LV=U4qGi+MQWnTP#wsewp_LfS@D~ei^^&h_-t@44y-tbb z^~xTDJoD!9I0a$lvMV-h&&Z?_>c}d!YFL7%H3z*}^QfTo`lNc5KBoT!`^YW!8C0zR z&vt9i&@>?YCWc~+y5$1kSuN9Pd6n+qy=9UsC*+6>2=wT_g`vM#okwGnv#Ar?5(X># zGxCtpBf&icL?VM}dlq{s^GFXuy`kj>lNX#S^uqG@o>n6$14oeFP{F%2?1}65Fq*hke9k1J^l3INg z^JInSsFsPpURM0*kU#p;a^5BBh^hj2R!~z70hoMYrMjwfO1HY}HA>ol#1sjlOklX} zQgodi5;If*Gh}e21)hbX`Dv}Pw;Yg0M-i-V6-EtJ^#*m>0nFgyUp(Z$^#EQ%e*d9) z@=w11#1rIyy2ZOhhquPq&;C1M5j6meu>iSoTF9*WfO}5tmobdDgWaPr?yMxLhUy)b zV`6Gi1Bd79y!x_SUkg-!nwbBh(m2OtwE?h9WltR=OPFnXSoDsq4Cc_L$Oa2%kDyyW z&aYS2+m~OrZ-14v-aNd1J09M?Uh{4|fA#X(`D0_URjHK}dAxHx3BhnkEFlhgf=5D6 z4?*UpD#Rv!IvtyVoQPwYI5UD9GY~+HJu`;^ST`-ki<-_n!lsJD+Ob_;Jpcn-8z=U)+)4ubybDC?3Q;)(XTR z-OKTqP9kw+jarwqW(&~Q)uW_}rQgj_HZ4EvO3+Fz0(zrXQ^*!9(^41c@>+@|ALrqv zZYT9V4}&GLfr>_db5`zUA3d$OH4Xf&V5N{rbtQn0A&wqsI|dw-of=49x{;hwL@8?D z=D}a=>}CL4P8E|oYnIO>t_tI+Dy$oXONG8Q$#JR5Y_7O%3H-MCy;d7JI|o8C1$K0< zE{RX9^wC)94#t_%++o`18f1Wg!FCEn$tCG(lc<5Ars}Dq8>#U|G?nPG9u^&5i zL|##k1YY17nOx>IX3)S2si$h9t`vsk$8*q0MyqamcQ&a1VPADQV9{oj zYON+%E?=;JsNHR2rIK<-frChw(ujYsau`twVuCWX_@ZZfG%hX$m3 zZ>8K>2wNlzqShWxE*8W2MFJtDSwLovu#rNLfF1%gM>|@XTL_Ks&P0!r2%_GVj+&OMcgv;*R=27)C&3cKZ)z-mNemiq157KdII3IsgHg17QvzIw37)? zIo$?SrIL&rX_eth%zZ9+j=1lJys0DE0mgvPW|8wkah*tB{Z?^(jw#FdqfV71?nQ=F zHaru^3=}-BzWPB5WlP;J`QyfdR0TB~;fY5uw#&0l0L3p(nLgmRn(ow~`3M(VpTaVl1ZicG5D3cM%00|ymH+KkB?+KPRQ1-vJ=)?6`aTxJ4s5-$ zR27=|z8od&&#YIdhYpWNB5#;(1O7O%nJG^&0bWurFImz>Z zwqead@!)XXheB$|5dHz;BImY$txjwvsyZR?QJY)pKFGbrrlKEy91{jkT+Ng$ z0q^AH0Oz;2#E6nWqNbJ(D0ucie1eAH;72Gu9S$VJIv~pw%*zMDiDi(Ed!kX**9 zZpchPSM^P50a2gP#Q`%?c@Khu5&o58PStUw!iAII1`xHe$?YG0SVz4_iQBN)FjB!2K-QgMF>lsY@h(b`XHO7;VvrP5yuK^B>=uaSO9WqV~{pg-@slNyH~Oa6teL_Ru^ta4jd@;KVTo5 zX&n^B8Vh6rW2wSmWYrpfB-7)w|M6%vl;$Vs(MLVZ$Z`(wh1c*Pn+|`j9Tqt?n)-*CFLnG%W`mc722Iw1pR%R$Bm)Z=W*%5f5u7l8qyuNXS9clvi+7O) zEN{aoHc@Dz&WtQRXCh=?6@Wxhr^7!Gb6xXH7jOMIr#1dBPJ(4~4HEwMYKvD^JoHe_ z0+5VuVYECA@sjib{qT@KzxijW#3&Hqm=$()j65t}b;0mxYi%^sVe6eXc1C-n3HWk-es24Gi z$q1>-IW{sKA;@sZgOwN)xhZ;nmH1RO&;I96a2jLD^D(7L-nGym2P8z0itmhN!=cJih!r7BzCnb}r19(fhi~5YyEo6@e*N`&eO`389=xk6tmdS` z`WY@dHe(9p88}jqyf#A@8I!Dve5mNw*fcnQhnTUgEoZ58tIaGcG7&^bQ<5l$?30Cd z9r}-rDp(GXFB!lGw(yeJy_JW0Wb}YdurO6moLL-SwwnZ^)GLsufzc8C8R5}YTc{d~ z#j4C@HkD$zJf|m%jwBcHC;?p%e3p~5yvdW)c$rVo0%V(7@~Z?uy3Rs> za845GvGj92`0I60xEJ%g3$5uJ58Ran=T8gnaYQRDIND~{*%Yv*RhLTCYn7Td+oFI3 zjCvAebY3OBI*sm<)J_3vuiINEs6zJ9+4=-G#ar^{ocN2ofYsZhnc(1|YXqV*N*MN?q#BV2>s(5iplVJoq(&1z|q>U%&bUH|{Gn51WyKMVV_B zKyInY^UQ~pVlYs85NT?nxoUVM7{|^U&N{*HQM#sU6Jo1meeztMe3(`{9Aemi7SPxZ z0L{X=KmrqWtC_Nc_A?RZOHZ|j5-l0guzl^RkX~n#lfw# zn3mZAi@dI9@4HPkUa(%XYOwO|mK|r+p4oJtmK(oCip1<+SH|>J;PKZLz^u~s-NUb{ z_uu?ts3GI+cX#deixlp@e);x);?DiX!+6pvOazWs}11o-pw`#%2SYyJC^=Z9s74%QeCkm6BK$8?4N3(n4B%z+8Og`PqLt&J#6HW^lsLIM6@&@E*s_D*HhNwfZHhY9K4P>D*eCGvu>p{DMfIsxw^N-=R_X!r8y4GD+ zlaTrZVd}Fksok>=Gx4D6<<{Ph$cA&lRhA@Dw`f?PQIhqjO?JVj867!g3?g%k3=53m{e_Dxpqg=k^Dj*x*}K~;r;cqKIjE3uP7-YQ8YZ6GkY z&PO0l15js>S0sd~kpb!=9R<~Mq+C;OH=PLy!%GB7 zO6%o(_VA}a+@>6xKnv>b>;2;Hp?$sYpFdpk!CQ~#m7_#AS)QCBu54c^PC;?3&V~R6~+f1>}vuXpmG= z2;c!i+12Z}$B#0ia8n~qjF;Qe06~p$C``8ujeCMP}tuSfMbq{u$|HIA!nn-P*(1nWP>4ujHvuA^**@%jh&Yg8)k8CvJq+R< zNvImZrZI@+WEXKnSrYHnTT0^GsqlmnbUd2DEzG49pX^jcCa8!>>zSYBYtx-5lp_&s z(ggT_Yv~PtSnQk@%RfBo5njAm?e(~DUb*$qeW~73EfDgn47k+S05=CsgQtT!-CdOY z_)6rAqDqnAC-JD+b7D8{|MqC!Lqv{hPaQpSSy$cdz@*bk9`Ueuj8Nf?3onj1uysw9P`wSxg9wMZp@ z6mscxdR$3Y%waIj3NEvKVOvGF%!GRrK-WxBs5KmtTOD$j2vT42lDqNHU1hH3#9Tka zCAWjl4zf(OXCyaS3H=bv9o(r%zJC;$JITwL<^re~lsKVZKpg3<%`ORBJNT?L&j8S6 zO%PP^MSWw{%;1^Ltp>!A#&PO2THaZIHP*|`Gjoj~6PYw;m`st2v`SI~@gS%srpR(y z#q=TQhFX4(qeDVBpa9Xe?nYE5WHNbC*SGGu z_pr8{k4eUO_4egOqxP)_?MrpegOp46Wb`><;S#`h(W{EBn54F3_G!%46Jer%v^6(K zyeJfu&X;WKt&Wj;JzAC4N&sCDt2C{`ah0sJQKD;hGN)`)yMqYu=;>U!lWHG; zboTm)ZZ?>AT%!V)JM=HhM+6wWhl4^wkXB?xRT;N3smIw$#>te9x_vsGKjMQkejsD`;>@L+Nor_umpI#imZ1&EYhF6@XN)EJ2DAdoyi@{j^?qxf-l9cOYu@eJu1-xmX$~vy;Oo#Ds zo#a|#`)A#WJGBpx@ofly%)!)VaDGa9%ea(vxKc?m6H;_uA1kZP0G7m*+BkK6nA%pc zh>D=tqbg&S4fL8iVgQ}wY4k%gyJ`rYWaz*5F1MmGSIGy;ClxFL7hlE$Q;zFa>4u7t59UODv03IM zK?=1B@NO((1>eU`md=mg=l+IUKhA0O{Lv4qXSc!f_~qT2pe%5zaBZxZotNPa( zxy;q%#�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 Jef6XR5CE%$C_exI diff --git a/docs/app/[[...mdxPath]]/page.tsx b/docs/app/[[...mdxPath]]/page.tsx new file mode 100644 index 0000000000..e4c12507c4 --- /dev/null +++ b/docs/app/[[...mdxPath]]/page.tsx @@ -0,0 +1,28 @@ +import { generateStaticParamsFor, importPage } from "nextra/pages"; +import { useMDXComponents as getMDXComponents } from "../../mdx-components"; + +export const generateStaticParams = generateStaticParamsFor("mdxPath"); + +export async function generateMetadata(props: { + params: Promise<{ mdxPath?: string[] }>; +}) { + const params = await props.params; + const { metadata } = await importPage(params.mdxPath); + return metadata; +} + +const Wrapper = getMDXComponents().wrapper; + +export default async function Page(props: { + params: Promise<{ mdxPath?: string[] }>; +}) { + const params = await props.params; + const { default: MDXContent, toc, metadata, sourceCode } = await importPage( + params.mdxPath + ); + return ( + + + + ); +} diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx new file mode 100644 index 0000000000..43d53055b5 --- /dev/null +++ b/docs/app/layout.tsx @@ -0,0 +1,46 @@ +import { Footer, Layout, Navbar } from "nextra-theme-docs"; +import { Head } from "nextra/components"; +import { getPageMap } from "nextra/page-map"; +import Logo from "../components/Logo"; +import "nextra-theme-docs/style.css"; + +export const metadata = { + title: "eigenwallet Docs", + description: "eigenwallet Docs", + icons: { + icon: [ + { url: "/favicon.ico", sizes: "any" }, + { url: "/icon.svg", type: "image/svg+xml" }, + ], + apple: "/apple-touch-icon.png", + }, + manifest: "/manifest.webmanifest", +}; + +export default async function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + } + projectLink="https://github.com/eigenwallet/core" + /> + } + footer={
    } + > + {children} + + + + ); +} diff --git a/docs/components/SwapProviderTable.tsx b/docs/components/SwapProviderTable.tsx index 3e0fb1544e..5492d15498 100644 --- a/docs/components/SwapProviderTable.tsx +++ b/docs/components/SwapProviderTable.tsx @@ -1,5 +1,6 @@ +"use client"; + import { useState, useEffect } from "react"; -import { Table, Td, Th, Tr } from "nextra/components"; export default function SwapMakerTable() { function satsToBtc(sats) { @@ -26,30 +27,30 @@ export default function SwapMakerTable() { overflowX: "scroll", }} > - +
    - - - - - - - - + + + + + + + + {makers.map((maker) => ( - - - - - - - - + + + + + + + + ))} -
    NetworkMultiaddressPeer IDMinimum AmountMaximum AmountExchange Rate
    NetworkMultiaddressPeer IDMinimum AmountMaximum AmountExchange Rate
    {maker.testnet ? "Testnet" : "Mainnet"}{maker.multiAddr}{maker.peerId}{satsToBtc(maker.minSwapAmount)} BTC{satsToBtc(maker.maxSwapAmount)} BTC{satsToBtc(maker.price)} XMR/BTC
    {maker.testnet ? "Testnet" : "Mainnet"}{maker.multiAddr}{maker.peerId}{satsToBtc(maker.minSwapAmount)} BTC{satsToBtc(maker.maxSwapAmount)} BTC{satsToBtc(maker.price)} XMR/BTC
    +

    IDd$L%UQm1>`a@uf+n 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 delta 329532 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 z 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

); } diff --git a/docs/content/_meta.ts b/docs/content/_meta.ts new file mode 100644 index 0000000000..aea9b7eb40 --- /dev/null +++ b/docs/content/_meta.ts @@ -0,0 +1,9 @@ +export default { + index: "Introduction", + getting_started: "Getting Started", + usage: "Usage", + advanced: "Advanced", + becoming_a_maker: "Becoming a Maker", + send_feedback: "Support / Feedback", + donate: "Donate", +}; diff --git a/docs/content/advanced/_meta.ts b/docs/content/advanced/_meta.ts new file mode 100644 index 0000000000..a0f529dae5 --- /dev/null +++ b/docs/content/advanced/_meta.ts @@ -0,0 +1,3 @@ +export default { + swap_on_testnet: "How to swap on Testnet", +}; diff --git a/docs/pages/advanced/swap_on_testnet.mdx b/docs/content/advanced/swap_on_testnet.mdx similarity index 91% rename from docs/pages/advanced/swap_on_testnet.mdx rename to docs/content/advanced/swap_on_testnet.mdx index c0a9fc7b57..40003e2dc7 100644 --- a/docs/pages/advanced/swap_on_testnet.mdx +++ b/docs/content/advanced/swap_on_testnet.mdx @@ -12,22 +12,22 @@ Here are the steps to set up the wallets using Electrum and Monero GUI. Download Electrum from the official [site](https://electrum.org/#download) and then start the wallet in testnet mode. -import { Tabs, Tab } from 'nextra/components' +import { Tabs } from 'nextra/components' - + ```bash ./electrum --testnet ``` - - + + ```bash open -n /Applications/Electrum.app --args --testnet ``` - - + + Open the `Electrum Testnet` program from your start menu. - + To get some free Testnet coins visit a faucet like [this](https://testnet-faucet.mempool.co) one. @@ -44,16 +44,16 @@ View the [Installation Instructions](../getting_started/install_instructions) if Then start the GUI in testnet mode. - + ```bash ./UnstoppableSwap_*_amd64.AppImage --testnet ``` - - + + ```bash open -n /Applications/UnstoppableSwap.app --args --testnet ``` - + From here on you can follow the [Complete your first swap](../usage/first_swap) guide. diff --git a/docs/content/becoming_a_maker/_meta.ts b/docs/content/becoming_a_maker/_meta.ts new file mode 100644 index 0000000000..0768c96512 --- /dev/null +++ b/docs/content/becoming_a_maker/_meta.ts @@ -0,0 +1,3 @@ +export default { + overview: "Overview", +}; diff --git a/docs/pages/becoming_a_maker/overview.mdx b/docs/content/becoming_a_maker/overview.mdx similarity index 100% rename from docs/pages/becoming_a_maker/overview.mdx rename to docs/content/becoming_a_maker/overview.mdx diff --git a/docs/pages/donate.mdx b/docs/content/donate.mdx similarity index 100% rename from docs/pages/donate.mdx rename to docs/content/donate.mdx diff --git a/docs/content/getting_started/_meta.ts b/docs/content/getting_started/_meta.ts new file mode 100644 index 0000000000..9ec71749d6 --- /dev/null +++ b/docs/content/getting_started/_meta.ts @@ -0,0 +1,4 @@ +export default { + install_instructions: "Installation", + verify_tauri_signature: "Verify Signatures", +}; diff --git a/docs/pages/getting_started/install_instructions.mdx b/docs/content/getting_started/install_instructions.mdx similarity index 79% rename from docs/pages/getting_started/install_instructions.mdx rename to docs/content/getting_started/install_instructions.mdx index 553c90e8cc..5aedab99e1 100644 --- a/docs/pages/getting_started/install_instructions.mdx +++ b/docs/content/getting_started/install_instructions.mdx @@ -9,22 +9,22 @@ Unless you know what you're doing, you probably want to use the precompiled bina Precompiled binaries of the _GUI_ are available for most platforms. Simply download the appropriate binary for your system and follow the instructions. - + 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `.exe` installer + 2. Open the downloaded `eigenwallet_.exe` installer 3. Follow the installation wizard 4. Open the `eigenwallet` application from your Start menu 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `.dmg` file + 2. Open the downloaded `eigenwallet_.dmg` file 3. Drag the `eigenwallet` icon to your Applications folder 4. Open the `eigenwallet` application from your Applications folder 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `.dmg` file + 2. Open the downloaded `eigenwallet_.dmg` file 3. Drag the `eigenwallet` icon to your Applications folder 4. Open the `eigenwallet` application from your Applications folder @@ -55,7 +55,7 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl - For Linux systems with Flatpak support (version 1.0 or newer), you can install eigenwallet directly from our Flatpak repository: + For **x86-64** Linux systems with Flatpak support (version 1.0 or newer), you can install eigenwallet directly from our Flatpak repository: ```bash filename="install.sh" copy # Add eigenwallet repo @@ -79,8 +79,26 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl ``` + + + + The AUR package is **community maintained**. + We cannot take responsibility for it being up to date, working or secure. + Check the build script yourself. + + + For Arch based systems you can install the **community maintained** `eigenwallet-bin` AUR package: + + ```bash filename="install.sh" copy + yay -S eigenwallet-bin + ``` + + +Incase the website malfunctions you can also find the binaries on our latest [Github release](https://github.com/eigenwallet/core/releases/latest). +Search for the `eigenwallet__.` file that fits to your system. + ## Building from source If you want to build the application from source you'll need to have the following tools installed: diff --git a/docs/pages/getting_started/verify_tauri_signature.mdx b/docs/content/getting_started/verify_tauri_signature.mdx similarity index 100% rename from docs/pages/getting_started/verify_tauri_signature.mdx rename to docs/content/getting_started/verify_tauri_signature.mdx diff --git a/docs/pages/index.mdx b/docs/content/index.mdx similarity index 100% rename from docs/pages/index.mdx rename to docs/content/index.mdx diff --git a/docs/pages/send_feedback.mdx b/docs/content/send_feedback.mdx similarity index 100% rename from docs/pages/send_feedback.mdx rename to docs/content/send_feedback.mdx diff --git a/docs/content/usage/_meta.ts b/docs/content/usage/_meta.ts new file mode 100644 index 0000000000..218167b44e --- /dev/null +++ b/docs/content/usage/_meta.ts @@ -0,0 +1,5 @@ +export default { + first_swap: "Complete your first swap", + market_maker_discovery: "Maker discovery", + refund_punish: "Cancel, Refund and Punish explained", +}; diff --git a/docs/pages/usage/first_swap.mdx b/docs/content/usage/first_swap.mdx similarity index 100% rename from docs/pages/usage/first_swap.mdx rename to docs/content/usage/first_swap.mdx diff --git a/docs/pages/usage/market_maker_discovery.mdx b/docs/content/usage/market_maker_discovery.mdx similarity index 100% rename from docs/pages/usage/market_maker_discovery.mdx rename to docs/content/usage/market_maker_discovery.mdx diff --git a/docs/pages/usage/refund_punish.mdx b/docs/content/usage/refund_punish.mdx similarity index 100% rename from docs/pages/usage/refund_punish.mdx rename to docs/content/usage/refund_punish.mdx diff --git a/docs/mdx-components.tsx b/docs/mdx-components.tsx new file mode 100644 index 0000000000..3d87b6b66e --- /dev/null +++ b/docs/mdx-components.tsx @@ -0,0 +1,8 @@ +import { useMDXComponents as getDocsMDXComponents } from "nextra-theme-docs"; + +const docsComponents = getDocsMDXComponents(); + +export const useMDXComponents = (components?: Record) => ({ + ...docsComponents, + ...components, +}); diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts index a4a7b3f5cf..40c3d68096 100644 --- a/docs/next-env.d.ts +++ b/docs/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/docs/next.config.js b/docs/next.config.js deleted file mode 100644 index 15124fcfe9..0000000000 --- a/docs/next.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const withNextra = require("nextra")({ - theme: "nextra-theme-docs", - themeConfig: "./theme.config.jsx", -}); - -module.exports = withNextra({ - output: "standalone", -}); - -// If you have other Next.js configurations, you can pass them as the parameter: -// module.exports = withNextra({ /* other next.js config */ }) diff --git a/docs/next.config.mjs b/docs/next.config.mjs new file mode 100644 index 0000000000..1653272583 --- /dev/null +++ b/docs/next.config.mjs @@ -0,0 +1,7 @@ +import nextra from "nextra"; + +const withNextra = nextra({}); + +export default withNextra({ + output: "standalone", +}); diff --git a/docs/package.json b/docs/package.json index 033cca2aff..3b109ee9ce 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,13 +11,14 @@ }, "dependencies": { "next": "^15.0.3", - "nextra": "^2.13.4", - "nextra-theme-docs": "^2.13.4", - "react": "^18.3.1", - "react-dom": "^18.3.1" + "nextra": "^4", + "nextra-theme-docs": "^4", + "react": "^19", + "react-dom": "^19" }, "devDependencies": { "@types/node": "20.14.5", + "@types/react": "^19", "typescript": "5.4.5" }, "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8" diff --git a/docs/pages/_meta.json b/docs/pages/_meta.json deleted file mode 100644 index 521a18e107..0000000000 --- a/docs/pages/_meta.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "index": "Introduction", - "getting_started": "Getting Started", - "usage": "Usage", - "advanced": "Advanced", - "becoming_a_maker": "Becoming a Maker", - "send_feedback": "Support / Feedback", - "donate": "Donate" -} diff --git a/docs/pages/advanced/_meta.json b/docs/pages/advanced/_meta.json deleted file mode 100644 index e0fd5d46e8..0000000000 --- a/docs/pages/advanced/_meta.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "swap_on_testnet": "How to swap on Testnet" -} diff --git a/docs/pages/becoming_a_maker/_meta.json b/docs/pages/becoming_a_maker/_meta.json deleted file mode 100644 index 6875e2c4ea..0000000000 --- a/docs/pages/becoming_a_maker/_meta.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "overview": "Overview" -} diff --git a/docs/pages/getting_started/_meta.json b/docs/pages/getting_started/_meta.json deleted file mode 100644 index 555a344eeb..0000000000 --- a/docs/pages/getting_started/_meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "install_instructions": "Installation", - "verify_tauri_signature": "Verify Signatures" -} diff --git a/docs/pages/usage/_meta.json b/docs/pages/usage/_meta.json deleted file mode 100644 index 15f76b6246..0000000000 --- a/docs/pages/usage/_meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "first_swap": "Complete your first swap", - "market_maker_discovery": "Maker discovery", - "refund_punish": "Cancel, Refund and Punish explained" -} diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx deleted file mode 100644 index 0e0c0821f4..0000000000 --- a/docs/theme.config.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import Logo from "./components/Logo"; - -export default { - logo: , - project: { - link: "https://github.com/eigenwallet/core", - }, - head: ( - <> - eigenwallet Docs - - - - - - - - ), - primaryHue: 38, - primarySaturation: 100, - feedback: { - content: null, - }, - editLink: { - component: null, - }, -}; diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 1ed394a99a..b497137a23 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -8,12 +12,24 @@ "incremental": true, "module": "esnext", "esModuleInterop": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", - "target": "ES2017" + "target": "ES2017", + "plugins": [ + { + "name": "next" + } + ] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "include": [ + "**/*.ts", + "**/*.tsx", + "next-env.d.ts", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/docs/yarn.lock b/docs/yarn.lock index 20265d415d..70a3b61150 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -5,19 +5,62 @@ __metadata: version: 8 cacheKey: 10c0 -"@babel/runtime@npm:^7.23.8": - version: 7.24.7 - resolution: "@babel/runtime@npm:7.24.7" +"@antfu/install-pkg@npm:^1.1.0": + version: 1.1.0 + resolution: "@antfu/install-pkg@npm:1.1.0" dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + package-manager-detector: "npm:^1.3.0" + tinyexec: "npm:^1.0.1" + checksum: 10c0/140d5994c76fd3d0e824c88f1ce91b3370e8066a8bc2f5729ae133bf768caa239f7915e29c78f239b7ead253113ace51293e95127fafe2b786b88eb615b3be47 languageName: node linkType: hard -"@braintree/sanitize-url@npm:^6.0.1": - version: 6.0.4 - resolution: "@braintree/sanitize-url@npm:6.0.4" - checksum: 10c0/5d7bac57f3e49931db83f65aaa4fd22f96caa323bf0c7fcf6851fdbed179a8cf29eaa5dd372d340fc51ca5f44345ea5bc0196b36c8b16179888a7c9044313420 +"@braintree/sanitize-url@npm:^7.1.1": + version: 7.1.2 + resolution: "@braintree/sanitize-url@npm:7.1.2" + checksum: 10c0/62f2aa0cf58626e3880b2dc1025c42064b4639abd157ae4e1c35f4c2f5031e9273772046a423979845069c814e27ff818e8e669280dc53585e6f033d5b7a59cb + languageName: node + linkType: hard + +"@chevrotain/cst-dts-gen@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/cst-dts-gen@npm:11.1.2" + dependencies: + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/372a9573a404a1d717c92875024588a53d1eb078f12d2cd1d79d9c2c888c9b429eb62bbc85501b8ff168c14b22a675da99d97bb39b0a774e9fee000dc60fd8ff + languageName: node + linkType: hard + +"@chevrotain/gast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/gast@npm:11.1.2" + dependencies: + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/540bfc9270d752f398b29efe9c89bb907d2984a47db4308a943e50c1cbd261ee13ecbef15c0e07808cf476d835bc36e65854db0bd214c277296cc14013eca8f4 + languageName: node + linkType: hard + +"@chevrotain/regexp-to-ast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/regexp-to-ast@npm:11.1.2" + checksum: 10c0/645f02ac94cb33e04c10547b197762c6936c7b7668966240684795ce131cb515a76b63e0cc500e787d669f1a36bd2f902ec518f27843ec857ecf9043c717527e + languageName: node + linkType: hard + +"@chevrotain/types@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/types@npm:11.1.2" + checksum: 10c0/c0c4679a3d407df34e18d5adfa7ac599b4a2bfddbf68da6e43678b9b3e16ab911de7766b37b9fc466261c3dead3db1b620e2e344f800fa9f0f381720475eda8f + languageName: node + linkType: hard + +"@chevrotain/utils@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/utils@npm:11.1.2" + checksum: 10c0/72989e7051781b9084252486712844c55e3b454318c7da4a5f6ded28dcd3947ba2882773a6bf09b7e744599e8c8025df8d3de0d487121734e6edb66999450438 languageName: node linkType: hard @@ -30,16 +73,98 @@ __metadata: languageName: node linkType: hard -"@headlessui/react@npm:^1.7.17": - version: 1.7.19 - resolution: "@headlessui/react@npm:1.7.19" +"@floating-ui/core@npm:^1.7.5": + version: 1.7.5 + resolution: "@floating-ui/core@npm:1.7.5" + dependencies: + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10c0/f9c52205e198b231d63a387b09c659aab08c46a1899e0b0bbe147b8b4f048b546f15ba17cb5d2a471da9534f1883d979425e13e5c4ceee67be63e4b0abd4db5d + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.7.6": + version: 1.7.6 + resolution: "@floating-ui/dom@npm:1.7.6" + dependencies: + "@floating-ui/core": "npm:^1.7.5" + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10c0/5c098e0d7b58c9bc769f276cca1766994c2c9c70c92d091a61bba8b3e9be53c011e0a79a8457fc2fb2f3d91697a26eb52e0a4962ef936dc963b45f58613c212f + languageName: node + linkType: hard + +"@floating-ui/react-dom@npm:^2.1.2": + version: 2.1.8 + resolution: "@floating-ui/react-dom@npm:2.1.8" + dependencies: + "@floating-ui/dom": "npm:^1.7.6" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/26260ca4bb23b57c73b824062505abf977a008ce6e0463bdacca74f7e49853c4cd1d2bbf1a77c6caa17fa37dfffda2c6c4cd07a8737ebd7474aaff7818401d75 + languageName: node + linkType: hard + +"@floating-ui/react@npm:^0.26.16": + version: 0.26.28 + resolution: "@floating-ui/react@npm:0.26.28" + dependencies: + "@floating-ui/react-dom": "npm:^2.1.2" + "@floating-ui/utils": "npm:^0.2.8" + tabbable: "npm:^6.0.0" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/a42df129e1e976fe8ba3f4c8efdda265a0196c1b66b83f2b9b27423d08dcc765406f893aeff9d830e70e3f14a9d4c490867eb4c32983317cbaa33863b0fae6f6 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.11, @floating-ui/utils@npm:^0.2.8": + version: 0.2.11 + resolution: "@floating-ui/utils@npm:0.2.11" + checksum: 10c0/f4bcea1559bdbb721ecc8e8ead423ac58d6a5b6e70b602cf0810ba6ad4ed1c77211b207faa88b278a9042f0c743133de08a203ed6741c1b6443423332884d5b3 + languageName: node + linkType: hard + +"@formatjs/intl-localematcher@npm:^0.6.0": + version: 0.6.2 + resolution: "@formatjs/intl-localematcher@npm:0.6.2" + dependencies: + tslib: "npm:^2.8.0" + checksum: 10c0/22a17a4c67160b6c9f52667914acfb7b79cd6d80630d4ac6d4599ce447cb89d2a64f7d58fa35c3145ddb37fef893f0a45b9a55e663a4eb1f2ae8b10a89fac235 + languageName: node + linkType: hard + +"@headlessui/react@npm:^2.1.2": + version: 2.2.9 + resolution: "@headlessui/react@npm:2.2.9" dependencies: - "@tanstack/react-virtual": "npm:^3.0.0-beta.60" - client-only: "npm:^0.0.1" + "@floating-ui/react": "npm:^0.26.16" + "@react-aria/focus": "npm:^3.20.2" + "@react-aria/interactions": "npm:^3.25.0" + "@tanstack/react-virtual": "npm:^3.13.9" + use-sync-external-store: "npm:^1.5.0" peerDependencies: - react: ^16 || ^17 || ^18 - react-dom: ^16 || ^17 || ^18 - checksum: 10c0/c0ece0db6ca15092439177a5322de50b60fa5fd90354ae0f999b3e56abab0065ed54fa7b4b69994ec1bdc23adc6ae9919d7dd57f97922d0b9bb6515d27e3a7e5 + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + checksum: 10c0/a1bc4c473d4f58757e2bbc3b4302704030d9d56427a101bbe698b33b6b379885dd0177e5c0862d801117afa3b0a0b858be7685f1cfda5fb3ed3ede53eb24e987 + languageName: node + linkType: hard + +"@iconify/types@npm:^2.0.0": + version: 2.0.0 + resolution: "@iconify/types@npm:2.0.0" + checksum: 10c0/65a3be43500c7ccacf360e136d00e1717f050b7b91da644e94370256ac66f582d59212bdb30d00788aab4fc078262e91c95b805d1808d654b72f6d2072a7e4b2 + languageName: node + linkType: hard + +"@iconify/utils@npm:^3.0.1": + version: 3.1.0 + resolution: "@iconify/utils@npm:3.1.0" + dependencies: + "@antfu/install-pkg": "npm:^1.1.0" + "@iconify/types": "npm:^2.0.0" + mlly: "npm:^1.8.0" + checksum: 10c0/a39445e892b248486c186306e1ccba4b07ed1d5b21b143ddf279b33062063173feb84954b9a82e05713b927872787d6c0081073d23f55c44294de37615d4a1f7 languageName: node linkType: hard @@ -218,40 +343,45 @@ __metadata: languageName: node linkType: hard -"@mdx-js/mdx@npm:^2.2.1, @mdx-js/mdx@npm:^2.3.0": - version: 2.3.0 - resolution: "@mdx-js/mdx@npm:2.3.0" +"@mdx-js/mdx@npm:^3.0.0": + version: 3.1.1 + resolution: "@mdx-js/mdx@npm:3.1.1" dependencies: + "@types/estree": "npm:^1.0.0" "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" "@types/mdx": "npm:^2.0.0" - estree-util-build-jsx: "npm:^2.0.0" - estree-util-is-identifier-name: "npm:^2.0.0" - estree-util-to-js: "npm:^1.1.0" + acorn: "npm:^8.0.0" + collapse-white-space: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + estree-util-scope: "npm:^1.0.0" estree-walker: "npm:^3.0.0" - hast-util-to-estree: "npm:^2.0.0" - markdown-extensions: "npm:^1.0.0" - periscopic: "npm:^3.0.0" - remark-mdx: "npm:^2.0.0" - remark-parse: "npm:^10.0.0" - remark-rehype: "npm:^10.0.0" - unified: "npm:^10.0.0" - unist-util-position-from-estree: "npm:^1.0.0" - unist-util-stringify-position: "npm:^3.0.0" - unist-util-visit: "npm:^4.0.0" - vfile: "npm:^5.0.0" - checksum: 10c0/719384d8e72abd3e83aa2fd3010394636e32cc0e5e286b6414427ef03121397586ce97ec816afcc4d2b22ba65939c3801a8198e04cf921dd597c0aa9fd75dbb4 - languageName: node - linkType: hard - -"@mdx-js/react@npm:^2.2.1, @mdx-js/react@npm:^2.3.0": - version: 2.3.0 - resolution: "@mdx-js/react@npm:2.3.0" + hast-util-to-jsx-runtime: "npm:^2.0.0" + markdown-extensions: "npm:^2.0.0" + recma-build-jsx: "npm:^1.0.0" + recma-jsx: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + rehype-recma: "npm:^1.0.0" + remark-mdx: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-rehype: "npm:^11.0.0" + source-map: "npm:^0.7.0" + unified: "npm:^11.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/371ed95e2bee7731f30a7ce57db66383a0b7470e66c38139427174cb456d6a40bf7d259f3652716370c1de64acfba50a1ba27eb8c556e7a431dc7940b04cb1a1 + languageName: node + linkType: hard + +"@mermaid-js/parser@npm:^1.0.0": + version: 1.0.0 + resolution: "@mermaid-js/parser@npm:1.0.0" dependencies: - "@types/mdx": "npm:^2.0.0" - "@types/react": "npm:>=16" - peerDependencies: - react: ">=16" - checksum: 10c0/6d647115703dbe258f7fe372499fa8c6fe17a053ff0f2a208111c9973a71ae738a0ed376770445d39194d217e00e1a015644b24f32c2f7cb4f57988de0649b15 + langium: "npm:^4.0.0" + checksum: 10c0/e311a0981d31984614eee25101c695e950cb1197befc51296d8735390433de59dc6e4a48c3cce1e23a1279b6baf60f9f724d529b741c0c86cdcb09afe3e5e046 languageName: node linkType: hard @@ -437,410 +567,908 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.11.8": - version: 2.11.8 - resolution: "@popperjs/core@npm:2.11.8" - checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb languageName: node linkType: hard -"@swc/counter@npm:0.1.3": - version: 0.1.3 - resolution: "@swc/counter@npm:0.1.3" - checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d languageName: node linkType: hard -"@swc/helpers@npm:0.5.13": - version: 0.5.13 - resolution: "@swc/helpers@npm:0.5.13" +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/b9df578401fc62405da9a6c31e79e447a2fd90f68b25b1daee12f2caf2821991bb89106f0397bc1acb4c4d84a8ce079d04b60b65f534496952e3bf8c9a52f40f + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 languageName: node linkType: hard -"@tanstack/react-virtual@npm:^3.0.0-beta.60": - version: 3.5.1 - resolution: "@tanstack/react-virtual@npm:3.5.1" +"@react-aria/focus@npm:^3.20.2": + version: 3.21.4 + resolution: "@react-aria/focus@npm:3.21.4" dependencies: - "@tanstack/virtual-core": "npm:3.5.1" + "@react-aria/interactions": "npm:^3.27.0" + "@react-aria/utils": "npm:^3.33.0" + "@react-types/shared": "npm:^3.33.0" + "@swc/helpers": "npm:^0.5.0" + clsx: "npm:^2.0.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 10c0/165992ca01d124be2289f61cc51d1c26d12cd4af11f658167f512d86a89795903478ce3ded1799072cc20feffd1d17bbcb8843269736145769cfc00b113349bd + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/6b10ddcd1298a6177f6136e943c1a41b56c56bf53f2182c7437e31cdf5367c9449591eaa0c3f89080bbdb84b97abc1b620de4e6e4ea98c82aad7496c461ca663 languageName: node linkType: hard -"@tanstack/virtual-core@npm:3.5.1": - version: 3.5.1 - resolution: "@tanstack/virtual-core@npm:3.5.1" - checksum: 10c0/3ed6c82d168c8a7f240f7882c4386f1136ccc727a4db7ca8051505dab6175c43aa4c8d5a0eaca861d1503f4f98ad2f8e46b876e02002d8218a9f344fc944708b +"@react-aria/interactions@npm:^3.25.0, @react-aria/interactions@npm:^3.27.0": + version: 3.27.0 + resolution: "@react-aria/interactions@npm:3.27.0" + dependencies: + "@react-aria/ssr": "npm:^3.9.10" + "@react-aria/utils": "npm:^3.33.0" + "@react-stately/flags": "npm:^3.1.2" + "@react-types/shared": "npm:^3.33.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/52148c240e57e74fd5c78ad82f1924ebd457e9464b3b39508762672f9a1c73d789f3a5b0fec77cc48a7c27cb918f9c0aec3ba3962366818d01fd42735eff835c languageName: node linkType: hard -"@theguild/remark-mermaid@npm:^0.0.5": - version: 0.0.5 - resolution: "@theguild/remark-mermaid@npm:0.0.5" +"@react-aria/ssr@npm:^3.9.10": + version: 3.9.10 + resolution: "@react-aria/ssr@npm:3.9.10" dependencies: - mermaid: "npm:^10.2.2" - unist-util-visit: "npm:^5.0.0" + "@swc/helpers": "npm:^0.5.0" peerDependencies: - react: ^18.2.0 - checksum: 10c0/3471a32a87d50f7eb699f15ff181f9a3698209951ef0fab1e928ea391275105286b0391e46cca4dd22d30dcab934e5c7eb6573c341f5d8543ca5bcb2f60cc916 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/44acb4c441d9c5d65aab94aa81fd8368413cf2958ab458582296dd78f6ba4783583f2311fa986120060e5c26b54b1f01e8910ffd17e4f41ccc5fc8c357d84089 languageName: node linkType: hard -"@theguild/remark-npm2yarn@npm:^0.2.0": - version: 0.2.1 - resolution: "@theguild/remark-npm2yarn@npm:0.2.1" +"@react-aria/utils@npm:^3.33.0": + version: 3.33.0 + resolution: "@react-aria/utils@npm:3.33.0" dependencies: - npm-to-yarn: "npm:^2.1.0" - unist-util-visit: "npm:^5.0.0" - checksum: 10c0/69380ac3814bcf2f9c00c8e375d97e55220adea04d9c887df1b6ac888b726a8a7aaf391ed80ceca1756cfa39d572221d12f681bc1a5f3fdf49a0ed59f7c3addc + "@react-aria/ssr": "npm:^3.9.10" + "@react-stately/flags": "npm:^3.1.2" + "@react-stately/utils": "npm:^3.11.0" + "@react-types/shared": "npm:^3.33.0" + "@swc/helpers": "npm:^0.5.0" + clsx: "npm:^2.0.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/15e9c79102632f96c611ca10ce5a3436617f1b3979ca7b4be192cf4c65c74871edb66c72bdbcedaeeaa6498d04947184d5bccf29a2a36a28eff89c3d55d9d1ca languageName: node linkType: hard -"@types/acorn@npm:^4.0.0": - version: 4.0.6 - resolution: "@types/acorn@npm:4.0.6" +"@react-stately/flags@npm:^3.1.2": + version: 3.1.2 + resolution: "@react-stately/flags@npm:3.1.2" dependencies: - "@types/estree": "npm:*" - checksum: 10c0/5a65a1d7e91fc95703f0a717897be60fa7ccd34b17f5462056274a246e6690259fe0a1baabc86fd3260354f87245cb3dc483346d7faad2b78fc199763978ede9 + "@swc/helpers": "npm:^0.5.0" + checksum: 10c0/d86890ce662f04c7d8984e9560527f46c9779b97757abded9e1bf7e230a6900a0ea7a3e7c22534de8d2ff278abae194e4e4ad962d710f3b04c52a4e1011c2e5b languageName: node linkType: hard -"@types/d3-scale-chromatic@npm:^3.0.0": - version: 3.0.3 - resolution: "@types/d3-scale-chromatic@npm:3.0.3" - checksum: 10c0/2f48c6f370edba485b57b73573884ded71914222a4580140ff87ee96e1d55ccd05b1d457f726e234a31269b803270ac95d5554229ab6c43c7e4a9894e20dd490 +"@react-stately/utils@npm:^3.11.0": + version: 3.11.0 + resolution: "@react-stately/utils@npm:3.11.0" + dependencies: + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/09b38438df19fd8ff14d3147b2f9e5d42869b3ee637b0e33d6f2ab5cba93612e640c6de339b766b8c825d7bef828851fd551d5a197a037eb1331913546b8516c languageName: node linkType: hard -"@types/d3-scale@npm:^4.0.3": - version: 4.0.8 - resolution: "@types/d3-scale@npm:4.0.8" - dependencies: - "@types/d3-time": "npm:*" - checksum: 10c0/57de90e4016f640b83cb960b7e3a0ab3ed02e720898840ddc5105264ffcfea73336161442fdc91895377c2d2f91904d637282f16852b8535b77e15a761c8e99e +"@react-types/shared@npm:^3.33.0": + version: 3.33.0 + resolution: "@react-types/shared@npm:3.33.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10c0/159758a91b5ecbf028651b07c54972f557716f52f6d31e03a581c5a6b694453a7ceb1272f4b82e03b99cb00780e6f0829624d57ac9b83189f296436dc768b956 languageName: node linkType: hard -"@types/d3-time@npm:*": - version: 3.0.3 - resolution: "@types/d3-time@npm:3.0.3" - checksum: 10c0/245a8aadca504df27edf730de502e47a68f16ae795c86b5ca35e7afa91c133aa9ef4d08778f8cf1ed2be732f89a4105ba4b437ce2afbdfd17d3d937b6ba5f568 +"@shikijs/core@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/core@npm:3.23.0" + dependencies: + "@shikijs/types": "npm:3.23.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + hast-util-to-html: "npm:^9.0.5" + checksum: 10c0/c595f1f2ec09cab102d2b3e03a3c64bfaace5fe52760cfbcced961d3e16571aa646c7e6f85b3d2d0242efd2c832ce4d150b5f1b7332982c17cfbe72f32bd0850 languageName: node linkType: hard -"@types/debug@npm:^4.0.0": - version: 4.1.12 - resolution: "@types/debug@npm:4.1.12" +"@shikijs/engine-javascript@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/engine-javascript@npm:3.23.0" dependencies: - "@types/ms": "npm:*" - checksum: 10c0/5dcd465edbb5a7f226e9a5efd1f399c6172407ef5840686b73e3608ce135eeca54ae8037dcd9f16bdb2768ac74925b820a8b9ecc588a58ca09eca6acabe33e2f + "@shikijs/types": "npm:3.23.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + oniguruma-to-es: "npm:^4.3.4" + checksum: 10c0/884ebb7f66312c9f43e71fb33a3ac0e52f925fc6932de9f68f1bf171019c011c988a4bc0217212589985b1e1bc49452ed67eacbf3d74200b4a3725f11fd8ad98 languageName: node linkType: hard -"@types/estree-jsx@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/estree-jsx@npm:1.0.5" +"@shikijs/engine-oniguruma@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/engine-oniguruma@npm:3.23.0" dependencies: - "@types/estree": "npm:*" - checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + "@shikijs/types": "npm:3.23.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + checksum: 10c0/40dbda7aef55d5946c45b8cfe56f484eadb611f9f7c9eb77ff21f0dfce2bcc775686a61eda9e06401ddd71195945a522293f51d6522fce49244b1a6b9c0f61f7 languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/estree@npm:1.0.5" - checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d +"@shikijs/langs@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/langs@npm:3.23.0" + dependencies: + "@shikijs/types": "npm:3.23.0" + checksum: 10c0/513b90cfee0fa167d2063b7fbc2318b303a604f2e1fa156aa8b4659b49792401531a74acf68de622ecfff15738e1947a46cfe92a32fcd6a4ee5e70bcf1d06c66 languageName: node linkType: hard -"@types/hast@npm:^2.0.0": - version: 2.3.10 - resolution: "@types/hast@npm:2.3.10" +"@shikijs/themes@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/themes@npm:3.23.0" dependencies: - "@types/unist": "npm:^2" - checksum: 10c0/16daac35d032e656defe1f103f9c09c341a6dc553c7ec17b388274076fa26e904a71ea5ea41fd368a6d5f1e9e53be275c80af7942b9c466d8511d261c9529c7e + "@shikijs/types": "npm:3.23.0" + checksum: 10c0/5c99036d4a765765018f9106a354ebe5ccac204c69f00e3cda265828d493f005412659213f6574fa0e187c7d4437b3327bd6dad2e2146b2c472d2bf493d790dd languageName: node linkType: hard -"@types/hast@npm:^3.0.0": - version: 3.0.4 - resolution: "@types/hast@npm:3.0.4" +"@shikijs/twoslash@npm:^3.2.1": + version: 3.23.0 + resolution: "@shikijs/twoslash@npm:3.23.0" dependencies: - "@types/unist": "npm:*" - checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + "@shikijs/core": "npm:3.23.0" + "@shikijs/types": "npm:3.23.0" + twoslash: "npm:^0.3.6" + peerDependencies: + typescript: ">=5.5.0" + checksum: 10c0/a2d65e414691092fef57ef01c467e341f4519dd707416f8b5222d8850ae1a9fcd2e93660fd61288273b3e9b2fcd3291aec38b0a11a3f0785f8f21e5f239a2d83 languageName: node linkType: hard -"@types/js-yaml@npm:^4.0.0": - version: 4.0.9 - resolution: "@types/js-yaml@npm:4.0.9" - checksum: 10c0/24de857aa8d61526bbfbbaa383aa538283ad17363fcd5bb5148e2c7f604547db36646440e739d78241ed008702a8920665d1add5618687b6743858fae00da211 +"@shikijs/types@npm:3.23.0": + version: 3.23.0 + resolution: "@shikijs/types@npm:3.23.0" + dependencies: + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/bd0d1593f830a6b4e55c77871ec1b95cc44855d6e0e26282a948a3c58827237826e4110af27eb4d3231361f1e182c4410434a1dc15ec40aea988dc92dc97e9d6 languageName: node linkType: hard -"@types/katex@npm:^0.16.0": - version: 0.16.7 - resolution: "@types/katex@npm:0.16.7" - checksum: 10c0/68dcb9f68a90513ec78ca0196a142e15c2a2c270b1520d752bafd47a99207115085a64087b50140359017d7e9c870b3c68e7e4d36668c9e348a9ef0c48919b5a +"@shikijs/vscode-textmate@npm:^10.0.2": + version: 10.0.2 + resolution: "@shikijs/vscode-textmate@npm:10.0.2" + checksum: 10c0/36b682d691088ec244de292dc8f91b808f95c89466af421cf84cbab92230f03c8348649c14b3251991b10ce632b0c715e416e992dd5f28ff3221dc2693fd9462 languageName: node linkType: hard -"@types/mdast@npm:^3.0.0": - version: 3.0.15 - resolution: "@types/mdast@npm:3.0.15" - dependencies: - "@types/unist": "npm:^2" - checksum: 10c0/fcbf716c03d1ed5465deca60862e9691414f9c43597c288c7d2aefbe274552e1bbd7aeee91b88a02597e88a28c139c57863d0126fcf8416a95fdc681d054ee3d +"@swc/counter@npm:0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 languageName: node linkType: hard -"@types/mdast@npm:^4.0.0": - version: 4.0.4 - resolution: "@types/mdast@npm:4.0.4" +"@swc/helpers@npm:0.5.13": + version: 0.5.13 + resolution: "@swc/helpers@npm:0.5.13" dependencies: - "@types/unist": "npm:*" - checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + tslib: "npm:^2.4.0" + checksum: 10c0/b9df578401fc62405da9a6c31e79e447a2fd90f68b25b1daee12f2caf2821991bb89106f0397bc1acb4c4d84a8ce079d04b60b65f534496952e3bf8c9a52f40f languageName: node linkType: hard -"@types/mdx@npm:^2.0.0": - version: 2.0.13 - resolution: "@types/mdx@npm:2.0.13" - checksum: 10c0/5edf1099505ac568da55f9ae8a93e7e314e8cbc13d3445d0be61b75941226b005e1390d9b95caecf5dcb00c9d1bab2f1f60f6ff9876dc091a48b547495007720 +"@swc/helpers@npm:^0.5.0": + version: 0.5.19 + resolution: "@swc/helpers@npm:0.5.19" + dependencies: + tslib: "npm:^2.8.0" + checksum: 10c0/30317ee644d390c88dd975b11b5260f7c70602bfb81ec386b3807d97a763215df7f501e43b0246e0773150fcfd835349bcdcb3b220d121e485ee528a72b5fd79 languageName: node linkType: hard -"@types/ms@npm:*": - version: 0.7.34 - resolution: "@types/ms@npm:0.7.34" - checksum: 10c0/ac80bd90012116ceb2d188fde62d96830ca847823e8ca71255616bc73991aa7d9f057b8bfab79e8ee44ffefb031ddd1bcce63ea82f9e66f7c31ec02d2d823ccc +"@tanstack/react-virtual@npm:^3.13.9": + version: 3.13.19 + resolution: "@tanstack/react-virtual@npm:3.13.19" + dependencies: + "@tanstack/virtual-core": "npm:3.13.19" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/3b3d512590980ac609b1b319948c0a3f75f4ffa28677329d3dca6bd1fa3b15a88ea4229e45e4f3803cfd97a3c587ab4a7d9f016ddf7ea8f02be3c76f86fcf993 languageName: node linkType: hard -"@types/node@npm:20.14.5": - version: 20.14.5 - resolution: "@types/node@npm:20.14.5" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10c0/06a8c304b5f7f190d4497807dc67ad09ee7b14ea2996bfdc823553c624698d8cab1ef9d16f8b764f20cb9eb11caa0e832787741e9ef70e1c89d620797ab28436 +"@tanstack/virtual-core@npm:3.13.19": + version: 3.13.19 + resolution: "@tanstack/virtual-core@npm:3.13.19" + checksum: 10c0/7bcff6560902e157bec2753d009288bc3be0251a9762532cb2f43f9e9fb9b5d9a2d441eba87e0463c7a891e5966b9cfda88555d428149f6a7a54a65e66ba6726 languageName: node linkType: hard -"@types/prop-types@npm:*": - version: 15.7.12 - resolution: "@types/prop-types@npm:15.7.12" - checksum: 10c0/1babcc7db6a1177779f8fde0ccc78d64d459906e6ef69a4ed4dd6339c920c2e05b074ee5a92120fe4e9d9f1a01c952f843ebd550bee2332fc2ef81d1706878f8 +"@theguild/remark-mermaid@npm:^0.3.0": + version: 0.3.0 + resolution: "@theguild/remark-mermaid@npm:0.3.0" + dependencies: + mermaid: "npm:^11.0.0" + unist-util-visit: "npm:^5.0.0" + peerDependencies: + react: ^18.2.0 || ^19.0.0 + checksum: 10c0/c2f2953ca5cb17fe49382dcd50054ebae2f74c71201c1543559f44e6c648eefd2bae9fc147ae916dc2b440dc02ebe93472205f11636227e3a3e79e9e3bfc459d languageName: node linkType: hard -"@types/react@npm:>=16": - version: 18.3.3 - resolution: "@types/react@npm:18.3.3" +"@theguild/remark-npm2yarn@npm:^0.3.2": + version: 0.3.3 + resolution: "@theguild/remark-npm2yarn@npm:0.3.3" dependencies: - "@types/prop-types": "npm:*" - csstype: "npm:^3.0.2" - checksum: 10c0/fe455f805c5da13b89964c3d68060cebd43e73ec15001a68b34634604a78140e6fc202f3f61679b9d809dde6d7a7c2cb3ed51e0fd1462557911db09879b55114 + npm-to-yarn: "npm:^3.0.0" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/913cb9be9ba7288eef1dc781f3539921c87b1684ca35f197108cc0a485ed0a5cbbddce745859f7e29016b36bd005e5f7d981a6b022f1256de2f5f0d7ef27ba66 languageName: node linkType: hard -"@types/unist@npm:*, @types/unist@npm:^3.0.0": - version: 3.0.2 - resolution: "@types/unist@npm:3.0.2" - checksum: 10c0/39f220ce184a773c55c18a127062bfc4d0d30c987250cd59bab544d97be6cfec93717a49ef96e81f024b575718f798d4d329eb81c452fc57d6d051af8b043ebf +"@ts-morph/common@npm:~0.28.1": + version: 0.28.1 + resolution: "@ts-morph/common@npm:0.28.1" + dependencies: + minimatch: "npm:^10.0.1" + path-browserify: "npm:^1.0.1" + tinyglobby: "npm:^0.2.14" + checksum: 10c0/d51276d840997e0f8f83e04f8b1689135bb12588a7ddbed575f87848d5737eeae31e242685d6449de27573e8ed30892157fea643393cb875e175f2711200bc50 languageName: node linkType: hard -"@types/unist@npm:^2, @types/unist@npm:^2.0.0": - version: 2.0.10 - resolution: "@types/unist@npm:2.0.10" - checksum: 10c0/5f247dc2229944355209ad5c8e83cfe29419fa7f0a6d557421b1985a1500444719cc9efcc42c652b55aab63c931813c88033e0202c1ac684bcd4829d66e44731 +"@types/d3-array@npm:*": + version: 3.2.2 + resolution: "@types/d3-array@npm:3.2.2" + checksum: 10c0/6137cb97302f8a4f18ca22c0560c585cfcb823f276b23d89f2c0c005d72697ec13bca671c08e68b4b0cabd622e3f0e91782ee221580d6774074050be96dd7028 languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.0.0": - version: 1.2.0 - resolution: "@ungap/structured-clone@npm:1.2.0" - checksum: 10c0/8209c937cb39119f44eb63cf90c0b73e7c754209a6411c707be08e50e29ee81356dca1a848a405c8bdeebfe2f5e4f831ad310ae1689eeef65e7445c090c6657d +"@types/d3-axis@npm:*": + version: 3.0.6 + resolution: "@types/d3-axis@npm:3.0.6" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/d756d42360261f44d8eefd0950c5bb0a4f67a46dd92069da3f723ac36a1e8cb2b9ce6347d836ef19d5b8aef725dbcf8fdbbd6cfbff676ca4b0642df2f78b599a languageName: node linkType: hard -"acorn-jsx@npm:^5.0.0": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 +"@types/d3-brush@npm:*": + version: 3.0.6 + resolution: "@types/d3-brush@npm:3.0.6" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/fd6e2ac7657a354f269f6b9c58451ffae9d01b89ccb1eb6367fd36d635d2f1990967215ab498e0c0679ff269429c57fad6a2958b68f4d45bc9f81d81672edc01 languageName: node linkType: hard -"acorn@npm:^8.0.0": - version: 8.12.0 - resolution: "acorn@npm:8.12.0" - bin: - acorn: bin/acorn - checksum: 10c0/a19f9dead009d3b430fa3c253710b47778cdaace15b316de6de93a68c355507bc1072a9956372b6c990cbeeb167d4a929249d0faeb8ae4bb6911d68d53299549 +"@types/d3-chord@npm:*": + version: 3.0.6 + resolution: "@types/d3-chord@npm:3.0.6" + checksum: 10c0/c5a25eb5389db01e63faec0c5c2ec7cc41c494e9b3201630b494c4e862a60f1aa83fabbc33a829e7e1403941e3c30d206c741559b14406ac2a4239cfdf4b4c17 languageName: node linkType: hard -"ansi-sequence-parser@npm:^1.1.0": - version: 1.1.1 - resolution: "ansi-sequence-parser@npm:1.1.1" - checksum: 10c0/ab2259ccf69f145ecf1418d4e71524158828f44afdf37c7536677871f4cebaa8b176fcb95de8f94a68129357dddc59586597da25f9d4ebf9968f6ef022bf0b31 +"@types/d3-color@npm:*": + version: 3.1.3 + resolution: "@types/d3-color@npm:3.1.3" + checksum: 10c0/65eb0487de606eb5ad81735a9a5b3142d30bc5ea801ed9b14b77cb14c9b909f718c059f13af341264ee189acf171508053342142bdf99338667cea26a2d8d6ae languageName: node linkType: hard -"ansi-styles@npm:^3.1.0": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" +"@types/d3-contour@npm:*": + version: 3.0.6 + resolution: "@types/d3-contour@npm:3.0.6" dependencies: - color-convert: "npm:^1.9.0" - checksum: 10c0/ece5a8ef069fcc5298f67e3f4771a663129abd174ea2dfa87923a2be2abf6cd367ef72ac87942da00ce85bd1d651d4cd8595aebdb1b385889b89b205860e977b + "@types/d3-array": "npm:*" + "@types/geojson": "npm:*" + checksum: 10c0/e7d83e94719af4576ceb5ac7f277c5806f83ba6c3631744ae391cffc3641f09dfa279470b83053cd0b2acd6784e8749c71141d05bdffa63ca58ffb5b31a0f27c languageName: node linkType: hard -"arch@npm:^2.1.0": - version: 2.2.0 - resolution: "arch@npm:2.2.0" - checksum: 10c0/4ceaf8d8207817c216ebc4469742052cb0a097bc45d9b7fcd60b7507220da545a28562ab5bdd4dfe87921bb56371a0805da4e10d704e01f93a15f83240f1284c +"@types/d3-delaunay@npm:*": + version: 6.0.4 + resolution: "@types/d3-delaunay@npm:6.0.4" + checksum: 10c0/d154a8864f08c4ea23ecb9bdabcef1c406a25baa8895f0cb08a0ed2799de0d360e597552532ce7086ff0cdffa8f3563f9109d18f0191459d32bb620a36939123 languageName: node linkType: hard -"arg@npm:1.0.0": - version: 1.0.0 - resolution: "arg@npm:1.0.0" - checksum: 10c0/10bbbda299b1a5d5f1cc6492bdea9413f148c36b58e7abc49e8b8337047eec5db154c1d2f99e942c4b777ae28215fc28506d303d7e30bcd80ca1ad7baeb6ce28 +"@types/d3-dispatch@npm:*": + version: 3.0.7 + resolution: "@types/d3-dispatch@npm:3.0.7" + checksum: 10c0/38c6605ebf0bf0099dfb70eafe0dd4ae8213368b40b8f930b72a909ff2e7259d2bd8a54d100bb5a44eb4b36f4f2a62dcb37f8be59613ca6b507c7a2f910b3145 languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" +"@types/d3-drag@npm:*": + version: 3.0.7 + resolution: "@types/d3-drag@npm:3.0.7" dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de + "@types/d3-selection": "npm:*" + checksum: 10c0/65e29fa32a87c72d26c44b5e2df3bf15af21cd128386bcc05bcacca255927c0397d0cd7e6062aed5f0abd623490544a9d061c195f5ed9f018fe0b698d99c079d languageName: node linkType: hard -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e - languageName: node - linkType: hard - -"astring@npm:^1.8.0": - version: 1.8.6 - resolution: "astring@npm:1.8.6" - bin: - astring: bin/astring - checksum: 10c0/31f09144597048c11072417959a412f208f8f95ba8dce408dfbc3367acb929f31fbcc00ed5eb61ccbf7c2f1173b9ac8bfcaaa37134a9455050c669b2b036ed88 +"@types/d3-dsv@npm:*": + version: 3.0.7 + resolution: "@types/d3-dsv@npm:3.0.7" + checksum: 10c0/c0f01da862465594c8a28278b51c850af3b4239cc22b14fd1a19d7a98f93d94efa477bf59d8071beb285dca45bf614630811451e18e7c52add3a0abfee0a1871 languageName: node linkType: hard -"bail@npm:^2.0.0": - version: 2.0.2 - resolution: "bail@npm:2.0.2" - checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b +"@types/d3-ease@npm:*": + version: 3.0.2 + resolution: "@types/d3-ease@npm:3.0.2" + checksum: 10c0/aff5a1e572a937ee9bff6465225d7ba27d5e0c976bd9eacdac2e6f10700a7cb0c9ea2597aff6b43a6ed850a3210030870238894a77ec73e309b4a9d0333f099c languageName: node linkType: hard -"busboy@npm:1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" +"@types/d3-fetch@npm:*": + version: 3.0.7 + resolution: "@types/d3-fetch@npm:3.0.7" dependencies: - streamsearch: "npm:^1.1.0" - checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f + "@types/d3-dsv": "npm:*" + checksum: 10c0/3d147efa52a26da1a5d40d4d73e6cebaaa964463c378068062999b93ea3731b27cc429104c21ecbba98c6090e58ef13429db6399238c5e3500162fb3015697a0 languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001636 - resolution: "caniuse-lite@npm:1.0.30001636" - checksum: 10c0/e5f965b4da7bae1531fd9f93477d015729ff9e3fa12670ead39a9e6cdc4c43e62c272d47857c5cc332e7b02d697cb3f2f965a1030870ac7476da60c2fc81ee94 +"@types/d3-force@npm:*": + version: 3.0.10 + resolution: "@types/d3-force@npm:3.0.10" + checksum: 10c0/c82b459079a106b50e346c9b79b141f599f2fc4f598985a5211e72c7a2e20d35bd5dc6e91f306b323c8bfa325c02c629b1645f5243f1c6a55bd51bc85cccfa92 languageName: node linkType: hard -"ccount@npm:^2.0.0": - version: 2.0.1 - resolution: "ccount@npm:2.0.1" - checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 +"@types/d3-format@npm:*": + version: 3.0.4 + resolution: "@types/d3-format@npm:3.0.4" + checksum: 10c0/3ac1600bf9061a59a228998f7cd3f29e85cbf522997671ba18d4d84d10a2a1aff4f95aceb143fa9960501c3ec351e113fc75884e6a504ace44dc1744083035ee languageName: node linkType: hard -"chalk@npm:2.3.0": - version: 2.3.0 - resolution: "chalk@npm:2.3.0" +"@types/d3-geo@npm:*": + version: 3.1.0 + resolution: "@types/d3-geo@npm:3.1.0" dependencies: - ansi-styles: "npm:^3.1.0" - escape-string-regexp: "npm:^1.0.5" - supports-color: "npm:^4.0.0" - checksum: 10c0/ff3d14e7b31b1acdcd06b0c3b8d00e08748d76a0f2a6cc86baa1fe2456ebd4dd45037315a58df7f3c1886153c5d0a35da8183d2757f7fad28eaef6dedd33b437 + "@types/geojson": "npm:*" + checksum: 10c0/3745a93439038bb5b0b38facf435f7079812921d46406f5d38deaee59e90084ff742443c7ea0a8446df81a0d81eaf622fe7068cf4117a544bd4aa3b2dc182f88 languageName: node linkType: hard -"character-entities-html4@npm:^2.0.0": - version: 2.1.0 - resolution: "character-entities-html4@npm:2.1.0" - checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 +"@types/d3-hierarchy@npm:*": + version: 3.1.7 + resolution: "@types/d3-hierarchy@npm:3.1.7" + checksum: 10c0/873711737d6b8e7b6f1dda0bcd21294a48f75024909ae510c5d2c21fad2e72032e0958def4d9f68319d3aaac298ad09c49807f8bfc87a145a82693b5208613c7 languageName: node linkType: hard -"character-entities-legacy@npm:^3.0.0": - version: 3.0.0 - resolution: "character-entities-legacy@npm:3.0.0" - checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 +"@types/d3-interpolate@npm:*": + version: 3.0.4 + resolution: "@types/d3-interpolate@npm:3.0.4" + dependencies: + "@types/d3-color": "npm:*" + checksum: 10c0/066ebb8da570b518dd332df6b12ae3b1eaa0a7f4f0c702e3c57f812cf529cc3500ec2aac8dc094f31897790346c6b1ebd8cd7a077176727f4860c2b181a65ca4 languageName: node linkType: hard -"character-entities@npm:^2.0.0": - version: 2.0.2 - resolution: "character-entities@npm:2.0.2" - checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 +"@types/d3-path@npm:*": + version: 3.1.1 + resolution: "@types/d3-path@npm:3.1.1" + checksum: 10c0/2c36eb31ebaf2ce4712e793fd88087117976f7c4ed69cc2431825f999c8c77cca5cea286f3326432b770739ac6ccd5d04d851eb65e7a4dbcc10c982b49ad2c02 languageName: node linkType: hard -"character-reference-invalid@npm:^2.0.0": - version: 2.0.1 - resolution: "character-reference-invalid@npm:2.0.1" - checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 +"@types/d3-polygon@npm:*": + version: 3.0.2 + resolution: "@types/d3-polygon@npm:3.0.2" + checksum: 10c0/f46307bb32b6c2aef8c7624500e0f9b518de8f227ccc10170b869dc43e4c542560f6c8d62e9f087fac45e198d6e4b623e579c0422e34c85baf56717456d3f439 languageName: node linkType: hard -"client-only@npm:0.0.1, client-only@npm:^0.0.1": - version: 0.0.1 - resolution: "client-only@npm:0.0.1" - checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 +"@types/d3-quadtree@npm:*": + version: 3.0.6 + resolution: "@types/d3-quadtree@npm:3.0.6" + checksum: 10c0/7eaa0a4d404adc856971c9285e1c4ab17e9135ea669d847d6db7e0066126a28ac751864e7ce99c65d526e130f56754a2e437a1617877098b3bdcc3ef23a23616 languageName: node linkType: hard -"clipboardy@npm:1.2.2": - version: 1.2.2 - resolution: "clipboardy@npm:1.2.2" +"@types/d3-random@npm:*": + version: 3.0.3 + resolution: "@types/d3-random@npm:3.0.3" + checksum: 10c0/5f4fea40080cd6d4adfee05183d00374e73a10c530276a6455348983dda341003a251def28565a27c25d9cf5296a33e870e397c9d91ff83fb7495a21c96b6882 + languageName: node + linkType: hard + +"@types/d3-scale-chromatic@npm:*": + version: 3.1.0 + resolution: "@types/d3-scale-chromatic@npm:3.1.0" + checksum: 10c0/93c564e02d2e97a048e18fe8054e4a935335da6ab75a56c3df197beaa87e69122eef0dfbeb7794d4a444a00e52e3123514ee27cec084bd21f6425b7037828cc2 + languageName: node + linkType: hard + +"@types/d3-scale@npm:*": + version: 4.0.9 + resolution: "@types/d3-scale@npm:4.0.9" + dependencies: + "@types/d3-time": "npm:*" + checksum: 10c0/4ac44233c05cd50b65b33ecb35d99fdf07566bcdbc55bc1306b2f27d1c5134d8c560d356f2c8e76b096e9125ffb8d26d95f78d56e210d1c542cb255bdf31d6c8 + languageName: node + linkType: hard + +"@types/d3-selection@npm:*": + version: 3.0.11 + resolution: "@types/d3-selection@npm:3.0.11" + checksum: 10c0/0c512956c7503ff5def4bb32e0c568cc757b9a2cc400a104fc0f4cfe5e56d83ebde2a97821b6f2cb26a7148079d3b86a2f28e11d68324ed311cf35c2ed980d1d + languageName: node + linkType: hard + +"@types/d3-shape@npm:*": + version: 3.1.8 + resolution: "@types/d3-shape@npm:3.1.8" + dependencies: + "@types/d3-path": "npm:*" + checksum: 10c0/49ec2172b9eb66fc1d036e2a23966216bb972e9af51ddbed134df24bd71aedf207bb1ef81903a119eb4e1f5e927cf44beacaf64c9af86474e5548594b102b574 + languageName: node + linkType: hard + +"@types/d3-time-format@npm:*": + version: 4.0.3 + resolution: "@types/d3-time-format@npm:4.0.3" + checksum: 10c0/9ef5e8e2b96b94799b821eed5d61a3d432c7903247966d8ad951b8ce5797fe46554b425cb7888fa5bf604b4663c369d7628c0328ffe80892156671c58d1a7f90 + languageName: node + linkType: hard + +"@types/d3-time@npm:*": + version: 3.0.3 + resolution: "@types/d3-time@npm:3.0.3" + checksum: 10c0/245a8aadca504df27edf730de502e47a68f16ae795c86b5ca35e7afa91c133aa9ef4d08778f8cf1ed2be732f89a4105ba4b437ce2afbdfd17d3d937b6ba5f568 + languageName: node + linkType: hard + +"@types/d3-timer@npm:*": + version: 3.0.2 + resolution: "@types/d3-timer@npm:3.0.2" + checksum: 10c0/c644dd9571fcc62b1aa12c03bcad40571553020feeb5811f1d8a937ac1e65b8a04b759b4873aef610e28b8714ac71c9885a4d6c127a048d95118f7e5b506d9e1 + languageName: node + linkType: hard + +"@types/d3-transition@npm:*": + version: 3.0.9 + resolution: "@types/d3-transition@npm:3.0.9" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/4f68b9df7ac745b3491216c54203cbbfa0f117ae4c60e2609cdef2db963582152035407fdff995b10ee383bae2f05b7743493f48e1b8e46df54faa836a8fb7b5 + languageName: node + linkType: hard + +"@types/d3-zoom@npm:*": + version: 3.0.8 + resolution: "@types/d3-zoom@npm:3.0.8" + dependencies: + "@types/d3-interpolate": "npm:*" + "@types/d3-selection": "npm:*" + checksum: 10c0/1dbdbcafddcae12efb5beb6948546963f29599e18bc7f2a91fb69cc617c2299a65354f2d47e282dfb86fec0968406cd4fb7f76ba2d2fb67baa8e8d146eb4a547 + languageName: node + linkType: hard + +"@types/d3@npm:^7.4.3": + version: 7.4.3 + resolution: "@types/d3@npm:7.4.3" + dependencies: + "@types/d3-array": "npm:*" + "@types/d3-axis": "npm:*" + "@types/d3-brush": "npm:*" + "@types/d3-chord": "npm:*" + "@types/d3-color": "npm:*" + "@types/d3-contour": "npm:*" + "@types/d3-delaunay": "npm:*" + "@types/d3-dispatch": "npm:*" + "@types/d3-drag": "npm:*" + "@types/d3-dsv": "npm:*" + "@types/d3-ease": "npm:*" + "@types/d3-fetch": "npm:*" + "@types/d3-force": "npm:*" + "@types/d3-format": "npm:*" + "@types/d3-geo": "npm:*" + "@types/d3-hierarchy": "npm:*" + "@types/d3-interpolate": "npm:*" + "@types/d3-path": "npm:*" + "@types/d3-polygon": "npm:*" + "@types/d3-quadtree": "npm:*" + "@types/d3-random": "npm:*" + "@types/d3-scale": "npm:*" + "@types/d3-scale-chromatic": "npm:*" + "@types/d3-selection": "npm:*" + "@types/d3-shape": "npm:*" + "@types/d3-time": "npm:*" + "@types/d3-time-format": "npm:*" + "@types/d3-timer": "npm:*" + "@types/d3-transition": "npm:*" + "@types/d3-zoom": "npm:*" + checksum: 10c0/a9c6d65b13ef3b42c87f2a89ea63a6d5640221869f97d0657b0cb2f1dac96a0f164bf5605643c0794e0de3aa2bf05df198519aaf15d24ca135eb0e8bd8a9d879 + languageName: node + linkType: hard + +"@types/debug@npm:^4.0.0": + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" + dependencies: + "@types/ms": "npm:*" + checksum: 10c0/5dcd465edbb5a7f226e9a5efd1f399c6172407ef5840686b73e3608ce135eeca54ae8037dcd9f16bdb2768ac74925b820a8b9ecc588a58ca09eca6acabe33e2f + languageName: node + linkType: hard + +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree-jsx@npm:1.0.5" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d + languageName: node + linkType: hard + +"@types/geojson@npm:*": + version: 7946.0.16 + resolution: "@types/geojson@npm:7946.0.16" + checksum: 10c0/1ff24a288bd5860b766b073ead337d31d73bdc715e5b50a2cee5cb0af57a1ed02cc04ef295f5fa68dc40fe3e4f104dd31282b2b818a5ba3231bc1001ba084e3c + languageName: node + linkType: hard + +"@types/hast@npm:^3.0.0, @types/hast@npm:^3.0.4": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + +"@types/katex@npm:^0.16.0": + version: 0.16.7 + resolution: "@types/katex@npm:0.16.7" + checksum: 10c0/68dcb9f68a90513ec78ca0196a142e15c2a2c270b1520d752bafd47a99207115085a64087b50140359017d7e9c870b3c68e7e4d36668c9e348a9ef0c48919b5a + languageName: node + linkType: hard + +"@types/mdast@npm:^4.0.0": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + languageName: node + linkType: hard + +"@types/mdx@npm:^2.0.0": + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 10c0/5edf1099505ac568da55f9ae8a93e7e314e8cbc13d3445d0be61b75941226b005e1390d9b95caecf5dcb00c9d1bab2f1f60f6ff9876dc091a48b547495007720 + languageName: node + linkType: hard + +"@types/ms@npm:*": + version: 0.7.34 + resolution: "@types/ms@npm:0.7.34" + checksum: 10c0/ac80bd90012116ceb2d188fde62d96830ca847823e8ca71255616bc73991aa7d9f057b8bfab79e8ee44ffefb031ddd1bcce63ea82f9e66f7c31ec02d2d823ccc + languageName: node + linkType: hard + +"@types/nlcst@npm:^2.0.0": + version: 2.0.3 + resolution: "@types/nlcst@npm:2.0.3" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/d83549aaee59681ae8fa2a78d8a1b968a41eb7c0422773dff12acbf3661e4b2b2859740c3effdad9d0cd12ea14a0ec33ca302da12106476b627e09d2a029d3c1 + languageName: node + linkType: hard + +"@types/node@npm:20.14.5": + version: 20.14.5 + resolution: "@types/node@npm:20.14.5" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/06a8c304b5f7f190d4497807dc67ad09ee7b14ea2996bfdc823553c624698d8cab1ef9d16f8b764f20cb9eb11caa0e832787741e9ef70e1c89d620797ab28436 + languageName: node + linkType: hard + +"@types/react@npm:^19": + version: 19.2.14 + resolution: "@types/react@npm:19.2.14" + dependencies: + csstype: "npm:^3.2.2" + checksum: 10c0/7d25bf41b57719452d86d2ac0570b659210402707313a36ee612666bf11275a1c69824f8c3ee1fdca077ccfe15452f6da8f1224529b917050eb2d861e52b59b7 + languageName: node + linkType: hard + +"@types/trusted-types@npm:^2.0.7": + version: 2.0.7 + resolution: "@types/trusted-types@npm:2.0.7" + checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c + languageName: node + linkType: hard + +"@types/unist@npm:*, @types/unist@npm:^3.0.0": + version: 3.0.2 + resolution: "@types/unist@npm:3.0.2" + checksum: 10c0/39f220ce184a773c55c18a127062bfc4d0d30c987250cd59bab544d97be6cfec93717a49ef96e81f024b575718f798d4d329eb81c452fc57d6d051af8b043ebf + languageName: node + linkType: hard + +"@types/unist@npm:^2.0.0": + version: 2.0.10 + resolution: "@types/unist@npm:2.0.10" + checksum: 10c0/5f247dc2229944355209ad5c8e83cfe29419fa7f0a6d557421b1985a1500444719cc9efcc42c652b55aab63c931813c88033e0202c1ac684bcd4829d66e44731 + languageName: node + linkType: hard + +"@typescript/vfs@npm:^1.6.2": + version: 1.6.4 + resolution: "@typescript/vfs@npm:1.6.4" + dependencies: + debug: "npm:^4.4.3" + peerDependencies: + typescript: "*" + checksum: 10c0/acb9de42f23fda3f75e3d7900ba106ef323a2f4e7cf0e4a94dbb457e26d353ca63bb35193ed1a32fc8733f3ae59099612b290b06bd6221694861beb9bfb62f62 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.0.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 10c0/8209c937cb39119f44eb63cf90c0b73e7c754209a6411c707be08e50e29ee81356dca1a848a405c8bdeebfe2f5e4f831ad310ae1689eeef65e7445c090c6657d + languageName: node + linkType: hard + +"@xmldom/xmldom@npm:0.9.8": + version: 0.9.8 + resolution: "@xmldom/xmldom@npm:0.9.8" + checksum: 10c0/2ea984270832de2843ab0bbb6df71bde9aa02126b69e5fd56b5512b98ace48e94aff7186e77d0b22fe4b6780483862be752bcf8577436638a9210109029a0503 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.0.0": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.0.0": + version: 8.12.0 + resolution: "acorn@npm:8.12.0" + bin: + acorn: bin/acorn + checksum: 10c0/a19f9dead009d3b430fa3c253710b47778cdaace15b316de6de93a68c355507bc1072a9956372b6c990cbeeb167d4a929249d0faeb8ae4bb6911d68d53299549 + languageName: node + linkType: hard + +"acorn@npm:^8.15.0": + version: 8.16.0 + resolution: "acorn@npm:8.16.0" + bin: + acorn: bin/acorn + checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e + languageName: node + linkType: hard + +"arg@npm:^5.0.0": + version: 5.0.2 + resolution: "arg@npm:5.0.2" + checksum: 10c0/ccaf86f4e05d342af6666c569f844bec426595c567d32a8289715087825c2ca7edd8a3d204e4d2fb2aa4602e09a57d0c13ea8c9eea75aac3dbb4af5514e6800e + languageName: node + linkType: hard + +"array-iterate@npm:^2.0.0": + version: 2.0.1 + resolution: "array-iterate@npm:2.0.1" + checksum: 10c0/756c08334f95e290f03ab2141b034514af1311ef7b62f15b0f5ea6f8f3033ee9cc6a8f1c3e9ff4803d4d723cf992aa61460acf5fce884936972db966b1da287d + languageName: node + linkType: hard + +"astring@npm:^1.8.0": + version: 1.8.6 + resolution: "astring@npm:1.8.6" + bin: + astring: bin/astring + checksum: 10c0/31f09144597048c11072417959a412f208f8f95ba8dce408dfbc3367acb929f31fbcc00ed5eb61ccbf7c2f1173b9ac8bfcaaa37134a9455050c669b2b036ed88 + languageName: node + linkType: hard + +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b + languageName: node + linkType: hard + +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + +"better-react-mathjax@npm:^2.3.0": + version: 2.3.0 + resolution: "better-react-mathjax@npm:2.3.0" + dependencies: + mathjax-full: "npm:^3.2.2" + peerDependencies: + react: ">=16.8" + checksum: 10c0/ed529432224879b6acfc301af03df2548dba0af4805da5d03b8d5ba9eca6b1fdb16e24b272d48a76cf4233b62d58e5a9d1241b51e7281d1153044a46b1f01dc2 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.2": + version: 5.0.4 + resolution: "brace-expansion@npm:5.0.4" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/359cbcfa80b2eb914ca1f3440e92313fbfe7919ee6b274c35db55bec555aded69dac5ee78f102cec90c35f98c20fa43d10936d0cd9978158823c249257e1643a + languageName: node + linkType: hard + +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 + languageName: node + linkType: hard + +"busboy@npm:1.6.0": + version: 1.6.0 + resolution: "busboy@npm:1.6.0" + dependencies: + streamsearch: "npm:^1.1.0" + checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001636 + resolution: "caniuse-lite@npm:1.0.30001636" + checksum: 10c0/e5f965b4da7bae1531fd9f93477d015729ff9e3fa12670ead39a9e6cdc4c43e62c272d47857c5cc332e7b02d697cb3f2f965a1030870ac7476da60c2fc81ee94 + languageName: node + linkType: hard + +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 + languageName: node + linkType: hard + +"chalk@npm:^5.0.0": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976 + languageName: node + linkType: hard + +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 + languageName: node + linkType: hard + +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 + languageName: node + linkType: hard + +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 + languageName: node + linkType: hard + +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 + languageName: node + linkType: hard + +"chevrotain-allstar@npm:~0.3.1": + version: 0.3.1 + resolution: "chevrotain-allstar@npm:0.3.1" dependencies: - arch: "npm:^2.1.0" - execa: "npm:^0.8.0" - checksum: 10c0/c343ee1ff74fd7202b8e549575e0e09d36d122cd06b078b171cf9ee37f03479d53547a5792ee879145841122c11ee4419078ffec07daf3eda4fa800758c8f1d9 + lodash-es: "npm:^4.17.21" + peerDependencies: + chevrotain: ^11.0.0 + checksum: 10c0/5cadedffd3114eb06b15fd3939bb1aa6c75412dbd737fe302b52c5c24334f9cb01cee8edc1d1067d98ba80dddf971f1d0e94b387de51423fc6cf3c5d8b7ef27a languageName: node linkType: hard -"clsx@npm:^2.0.0": +"chevrotain@npm:~11.1.1": + version: 11.1.2 + resolution: "chevrotain@npm:11.1.2" + dependencies: + "@chevrotain/cst-dts-gen": "npm:11.1.2" + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/regexp-to-ast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + "@chevrotain/utils": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/7f0b5780035c582d4c620c81e1fbb58c9f41a69f1c7efdae96819c7bc0928ddb4f046bb8239e71539f383b3b8ce460bd11f44b5fb5107e1d45a0cc91bd6a4198 + languageName: node + linkType: hard + +"client-only@npm:0.0.1": + version: 0.0.1 + resolution: "client-only@npm:0.0.1" + checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 + languageName: node + linkType: hard + +"clipboardy@npm:^4.0.0": + version: 4.0.0 + resolution: "clipboardy@npm:4.0.0" + dependencies: + execa: "npm:^8.0.1" + is-wsl: "npm:^3.1.0" + is64bit: "npm:^2.0.0" + checksum: 10c0/02bb5f3d0a772bd84ec26a3566c72c2319a9f3b4cb8338370c3bffcf0073c80b834abe1a6945bea4f2cbea28e1627a975aaac577e3f61a868d924ce79138b041 + languageName: node + linkType: hard + +"clsx@npm:^2.0.0, clsx@npm:^2.1.0": version: 2.1.1 resolution: "clsx@npm:2.1.1" checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 languageName: node linkType: hard -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: "npm:1.1.3" - checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c +"code-block-writer@npm:^13.0.3": + version: 13.0.3 + resolution: "code-block-writer@npm:13.0.3" + checksum: 10c0/87db97b37583f71cfd7eced8bf3f0a0a0ca53af912751a734372b36c08cd27f3e8a4878ec05591c0cd9ae11bea8add1423e132d660edd86aab952656dd41fd66 + languageName: node + linkType: hard + +"collapse-white-space@npm:^2.0.0": + version: 2.1.0 + resolution: "collapse-white-space@npm:2.1.0" + checksum: 10c0/b2e2800f4ab261e62eb27a1fbe853378296e3a726d6695117ed033e82d61fb6abeae4ffc1465d5454499e237005de9cfc52c9562dc7ca4ac759b9a222ef14453 languageName: node linkType: hard @@ -853,13 +1481,6 @@ __metadata: languageName: node linkType: hard -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 - languageName: node - linkType: hard - "color-name@npm:^1.0.0, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" @@ -894,6 +1515,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:13.1.0": + version: 13.1.0 + resolution: "commander@npm:13.1.0" + checksum: 10c0/7b8c5544bba704fbe84b7cab2e043df8586d5c114a4c5b607f83ae5060708940ed0b5bd5838cf8ce27539cde265c1cbd59ce3c8c6b017ed3eec8943e3a415164 + languageName: node + linkType: hard + "commander@npm:7": version: 7.2.0 resolution: "commander@npm:7.2.0" @@ -915,6 +1543,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.8": + version: 0.1.8 + resolution: "confbox@npm:0.1.8" + checksum: 10c0/fc2c68d97cb54d885b10b63e45bd8da83a8a71459d3ecf1825143dd4c7f9f1b696b3283e07d9d12a144c1301c2ebc7842380bdf0014e55acc4ae1c9550102418 + languageName: node + linkType: hard + "cose-base@npm:^1.0.0": version: 1.0.3 resolution: "cose-base@npm:1.0.3" @@ -924,21 +1559,30 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^5.0.1": - version: 5.1.0 - resolution: "cross-spawn@npm:5.1.0" +"cose-base@npm:^2.2.0": + version: 2.2.0 + resolution: "cose-base@npm:2.2.0" dependencies: - lru-cache: "npm:^4.0.1" - shebang-command: "npm:^1.2.0" - which: "npm:^1.2.9" - checksum: 10c0/1918621fddb9f8c61e02118b2dbf81f611ccd1544ceaca0d026525341832b8511ce2504c60f935dbc06b35e5ef156fe8c1e72708c27dd486f034e9c0e1e07201 + layout-base: "npm:^2.0.0" + checksum: 10c0/14b9f8100ac322a00777ffb1daeb3321af368bbc9cabe3103943361273baee2003202ffe38e4ab770960b600214224e9c196195a78d589521540aa694df7cdec languageName: node linkType: hard -"csstype@npm:^3.0.2": - version: 3.1.3 - resolution: "csstype@npm:3.1.3" - checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 +"cross-spawn@npm:^7.0.3": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + +"csstype@npm:^3.2.2": + version: 3.2.3 + resolution: "csstype@npm:3.2.3" + checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce languageName: node linkType: hard @@ -953,10 +1597,21 @@ __metadata: languageName: node linkType: hard -"cytoscape@npm:^3.28.1": - version: 3.29.2 - resolution: "cytoscape@npm:3.29.2" - checksum: 10c0/fbd2b32496cc866429f2851200653dc1788c809bcb4da85e17054a0d4cd5a531cdebcf20d404c289b6ef7d0f914c107645372d958deb693458de15665b8fdf8b +"cytoscape-fcose@npm:^2.2.0": + version: 2.2.0 + resolution: "cytoscape-fcose@npm:2.2.0" + dependencies: + cose-base: "npm:^2.2.0" + peerDependencies: + cytoscape: ^3.2.0 + checksum: 10c0/ce472c9f85b9057e75c5685396f8e1f2468895e71b184913e05ad56dcf3092618fe59a1054f29cb0995051ba8ebe566ad0dd49a58d62845145624bd60cd44917 + languageName: node + linkType: hard + +"cytoscape@npm:^3.29.3": + version: 3.33.1 + resolution: "cytoscape@npm:3.33.1" + checksum: 10c0/dffcf5f74df4d91517c4faf394df880d8283ce76edef19edba0c762941cf4f18daf7c4c955ec50c794f476ace39ad4394f8c98483222bd2682e1fd206e976411 languageName: node linkType: hard @@ -1275,7 +1930,7 @@ __metadata: languageName: node linkType: hard -"d3@npm:^7.4.0, d3@npm:^7.8.2": +"d3@npm:^7.9.0": version: 7.9.0 resolution: "d3@npm:7.9.0" dependencies: @@ -1313,20 +1968,20 @@ __metadata: languageName: node linkType: hard -"dagre-d3-es@npm:7.0.10": - version: 7.0.10 - resolution: "dagre-d3-es@npm:7.0.10" +"dagre-d3-es@npm:7.0.13": + version: 7.0.13 + resolution: "dagre-d3-es@npm:7.0.13" dependencies: - d3: "npm:^7.8.2" + d3: "npm:^7.9.0" lodash-es: "npm:^4.17.21" - checksum: 10c0/3e1bb6efe9a78cea3fe6ff265eb330692f057bf84c99d6a1d67db379231c37a1a1ca2e1ccc25a732ddf924cd5566062c033d88defd230debec324dc9256c6775 + checksum: 10c0/4eca80dbbad4075311e3853930f99486024785b54210541796d4216140d91744738ee51125e2692c3532af148fbc2e690171750583916ed2ad553150abb198c7 languageName: node linkType: hard -"dayjs@npm:^1.11.7": - version: 1.11.11 - resolution: "dayjs@npm:1.11.11" - checksum: 10c0/0131d10516b9945f05a57e13f4af49a6814de5573a494824e103131a3bbe4cc470b1aefe8e17e51f9a478a22cd116084be1ee5725cedb66ec4c3f9091202dc4b +"dayjs@npm:^1.11.18": + version: 1.11.19 + resolution: "dayjs@npm:1.11.19" + checksum: 10c0/7d8a6074a343f821f81ea284d700bd34ea6c7abbe8d93bce7aba818948957c1b7f56131702e5e890a5622cdfc05dcebe8aed0b8313bdc6838a594d7846b0b000 languageName: node linkType: hard @@ -1342,6 +1997,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.4.3": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + "decode-named-character-reference@npm:^1.0.0": version: 1.0.2 resolution: "decode-named-character-reference@npm:1.0.2" @@ -1383,24 +2050,15 @@ __metadata: languageName: node linkType: hard -"diff@npm:^5.0.0": - version: 5.2.0 - resolution: "diff@npm:5.2.0" - checksum: 10c0/aed0941f206fe261ecb258dc8d0ceea8abbde3ace5827518ff8d302f0fc9cc81ce116c4d8f379151171336caf0516b79e01abdc1ed1201b6440d895a66689eb4 - languageName: node - linkType: hard - -"dompurify@npm:^3.0.5": - version: 3.1.5 - resolution: "dompurify@npm:3.1.5" - checksum: 10c0/8227fb1328c02d94f823de8cd499fca5ee07051e03e6b52bce06b592348aeb6e56ea8e2a4b0a9cfaeac7d623e4b5a52e4326aedf72596a6c2510b88dfcf2a2b6 - languageName: node - linkType: hard - -"elkjs@npm:^0.9.0": - version: 0.9.3 - resolution: "elkjs@npm:0.9.3" - checksum: 10c0/caf544ff4fce8442d1d3dd6dface176c9b2fe26fc1e34f56122828e6eef7d2d7fe70d3202f9f3ecf0feb6287d4c8430949f483e63e450a7454bb39ccffab3808 +"dompurify@npm:^3.2.5": + version: 3.3.1 + resolution: "dompurify@npm:3.3.1" + dependencies: + "@types/trusted-types": "npm:^2.0.7" + dependenciesMeta: + "@types/trusted-types": + optional: true + checksum: 10c0/fa0a8c55a436ba0d54389195e3d2337e311f56de709a2fc9efc98dbbc7746fa53bb4b74b6ac043b77a279a8f2ebd8685f0ebaa6e58c9e32e92051d529bc0baf8 languageName: node linkType: hard @@ -1411,10 +2069,27 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 +"esast-util-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "esast-util-from-estree@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + checksum: 10c0/6c619bc6963314f8f64b32e3b101b321bf121f659e62b11e70f425619c2db6f1d25f4c594a57fd00908da96c67d9bfbf876eb5172abf9e13f47a71796f6630ff + languageName: node + linkType: hard + +"esast-util-from-js@npm:^2.0.0": + version: 2.0.1 + resolution: "esast-util-from-js@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + acorn: "npm:^8.0.0" + esast-util-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3a446fb0b0d7bcd7e0157aa44b3b692802a08c93edbea81cc0f7fe4437bfdfb4b72e4563fe63b4e36d390086b71185dba4ac921f4180cc6349985c263cc74421 languageName: node linkType: hard @@ -1425,33 +2100,31 @@ __metadata: languageName: node linkType: hard -"esprima@npm:^4.0.0": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 +"esm@npm:^3.2.25": + version: 3.2.25 + resolution: "esm@npm:3.2.25" + checksum: 10c0/8e60e8075506a7ce28681c30c8f54623fe18a251c364cd481d86719fc77f58aa055b293d80632d9686d5408aaf865ffa434897dc9fd9153c8b3f469fad23f094 languageName: node linkType: hard -"estree-util-attach-comments@npm:^2.0.0": - version: 2.1.1 - resolution: "estree-util-attach-comments@npm:2.1.1" +"estree-util-attach-comments@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-attach-comments@npm:3.0.0" dependencies: "@types/estree": "npm:^1.0.0" - checksum: 10c0/cdb5fdb5809b376ca4a96afbcd916c3570b4bbf5d0115b8a9e1e8a10885d8d9fb549df0a16c077abb42ee35fa33192b69714bac25d4f3c43a36092288c9a64fd + checksum: 10c0/ee69bb5c45e2ad074725b90ed181c1c934b29d81bce4b0c7761431e83c4c6ab1b223a6a3d6a4fbeb92128bc5d5ee201d5dd36cf1770aa5e16a40b0cf36e8a1f1 languageName: node linkType: hard -"estree-util-build-jsx@npm:^2.0.0": - version: 2.2.2 - resolution: "estree-util-build-jsx@npm:2.2.2" +"estree-util-build-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "estree-util-build-jsx@npm:3.0.1" dependencies: "@types/estree-jsx": "npm:^1.0.0" - estree-util-is-identifier-name: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" estree-walker: "npm:^3.0.0" - checksum: 10c0/2cef6ad6747f51934eba0601c3477ba08c98331cfe616635e08dfc89d06b9bbd370c4d80e87fe7d42d82776fa7840868201f48491b0ef9c808039f15fe4667e1 + checksum: 10c0/274c119817b8e7caa14a9778f1e497fea56cdd2b01df1a1ed037f843178992d3afe85e0d364d485e1e2e239255763553d1b647b15e4a7ba50851bcb43dc6bf80 languageName: node linkType: hard @@ -1462,33 +2135,50 @@ __metadata: languageName: node linkType: hard -"estree-util-to-js@npm:^1.1.0": - version: 1.2.0 - resolution: "estree-util-to-js@npm:1.2.0" +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: 10c0/d1881c6ed14bd588ebd508fc90bf2a541811dbb9ca04dec2f39d27dcaa635f85b5ed9bbbe7fc6fb1ddfca68744a5f7c70456b4b7108b6c4c52780631cc787c5b + languageName: node + linkType: hard + +"estree-util-scope@npm:^1.0.0": + version: 1.0.0 + resolution: "estree-util-scope@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + checksum: 10c0/ef8a573cc899277c613623a1722f630e2163abbc6e9e2f49e758c59b81b484e248b585df6df09a38c00fbfb6390117997cc80c1347b7a86bc1525d9e462b60d5 + languageName: node + linkType: hard + +"estree-util-to-js@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-to-js@npm:2.0.0" dependencies: "@types/estree-jsx": "npm:^1.0.0" astring: "npm:^1.8.0" source-map: "npm:^0.7.0" - checksum: 10c0/ad9c99dc34b0510ab813b485251acbf0abd06361c07b13c08da5d1611c279bee02ec09f2c269ae30b8d2da587115fc1fad4fa9f2f5ba69e094e758a3a4de7069 + checksum: 10c0/ac88cb831401ef99e365f92f4af903755d56ae1ce0e0f0fb8ff66e678141f3d529194f0fb15f6c78cd7554c16fda36854df851d58f9e05cfab15bddf7a97cea0 languageName: node linkType: hard -"estree-util-value-to-estree@npm:^1.3.0": - version: 1.3.0 - resolution: "estree-util-value-to-estree@npm:1.3.0" +"estree-util-value-to-estree@npm:^3.3.3": + version: 3.5.0 + resolution: "estree-util-value-to-estree@npm:3.5.0" dependencies: - is-plain-obj: "npm:^3.0.0" - checksum: 10c0/8bf46c4629f55a6ad3a6c523277cd34591cf57dfcab01cf4f218a8780cd23d21901c393693484c449a46bad7b9cb6fbf24c3dd1c1b057e10fd6a076f24fd5f3f + "@types/estree": "npm:^1.0.0" + checksum: 10c0/05c8d4b3338598929122cbfd6b127b22de4600dda8178b789b0d139e5b296e57a2343e487d6e108d8c39b18550dae2af3a110093698684db810954f353e9099b languageName: node linkType: hard -"estree-util-visit@npm:^1.0.0": - version: 1.2.1 - resolution: "estree-util-visit@npm:1.2.1" +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" dependencies: "@types/estree-jsx": "npm:^1.0.0" - "@types/unist": "npm:^2.0.0" - checksum: 10c0/3c47086ab25947a889fca9f58a842e0d27edadcad24dc393fdd7c9ad3419fe05b3c63b6fc9d6c9d8f50d32bca615cd0a3fe8d0e6b300fb94f74c91210b55ea5d + "@types/unist": "npm:^3.0.0" + checksum: 10c0/acda8b03cc8f890d79c7c7361f6c95331ba84b7ccc0c32b49f447fc30206b20002b37ffdfc97b6ad16e6fe065c63ecbae1622492e2b6b4775c15966606217f39 languageName: node linkType: hard @@ -1501,27 +2191,20 @@ __metadata: languageName: node linkType: hard -"execa@npm:^0.8.0": - version: 0.8.0 - resolution: "execa@npm:0.8.0" - dependencies: - cross-spawn: "npm:^5.0.1" - get-stream: "npm:^3.0.0" - is-stream: "npm:^1.1.0" - npm-run-path: "npm:^2.0.0" - p-finally: "npm:^1.0.0" - signal-exit: "npm:^3.0.0" - strip-eof: "npm:^1.0.0" - checksum: 10c0/e6c085687024cd5d348cad98a12213f6ebad2e962c7f3298ea8608fd5ed2daad8d1e27e79bfe7104bf60d8d80b56dd60267a0667006c29019e4297c96ecfe99d - languageName: node - linkType: hard - -"extend-shallow@npm:^2.0.1": - version: 2.0.1 - resolution: "extend-shallow@npm:2.0.1" +"execa@npm:^8.0.1": + version: 8.0.1 + resolution: "execa@npm:8.0.1" dependencies: - is-extendable: "npm:^0.1.0" - checksum: 10c0/ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^8.0.1" + human-signals: "npm:^5.0.0" + is-stream: "npm:^3.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^5.1.0" + onetime: "npm:^6.0.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^3.0.0" + checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af languageName: node linkType: hard @@ -1532,87 +2215,92 @@ __metadata: languageName: node linkType: hard -"flexsearch@npm:^0.7.31": - version: 0.7.43 - resolution: "flexsearch@npm:0.7.43" - checksum: 10c0/797dc474ed97750b8e85c118b1af63eb2709da5fc05defcb13e96515774f28743ccb2448b63f3b703cf1ca571928c006069503dacf7d177bc07b9ee15e1f85d0 +"fast-glob@npm:^3.3.2": + version: 3.3.3 + resolution: "fast-glob@npm:3.3.3" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.8" + checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe languageName: node linkType: hard -"focus-visible@npm:^5.2.0": - version: 5.2.0 - resolution: "focus-visible@npm:5.2.0" - checksum: 10c0/bc746775e4c17d05faf7219a91fd5ae6fec320b87f20cde5402eff17fab148b6253f25748f0235b3110528a1335ee0c6d4dc3692cc6b6174d0ebd253dd28a50d +"fastq@npm:^1.6.0": + version: 1.20.1 + resolution: "fastq@npm:1.20.1" + dependencies: + reusify: "npm:^1.0.4" + checksum: 10c0/e5dd725884decb1f11e5c822221d76136f239d0236f176fab80b7b8f9e7619ae57e6b4e5b73defc21e6b9ef99437ee7b545cff8e6c2c337819633712fa9d352e languageName: node linkType: hard -"get-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "get-stream@npm:3.0.0" - checksum: 10c0/003f5f3b8870da59c6aafdf6ed7e7b07b48c2f8629cd461bd3900726548b6b8cfa2e14d6b7814fbb08f07a42f4f738407fa70b989928b2783a76b278505bba22 +"fault@npm:^2.0.0": + version: 2.0.1 + resolution: "fault@npm:2.0.1" + dependencies: + format: "npm:^0.2.0" + checksum: 10c0/b80fbf1019b9ce8b08ee09ce86e02b028563e13a32ac3be34e42bfac00a97b96d8dee6d31e26578ffc16224eb6729e01ff1f97ddfeee00494f4f56c0aeed4bdd languageName: node linkType: hard -"git-up@npm:^7.0.0": - version: 7.0.0 - resolution: "git-up@npm:7.0.0" - dependencies: - is-ssh: "npm:^1.4.0" - parse-url: "npm:^8.1.0" - checksum: 10c0/a3fa02e1a63c7c824b5ebbf23f4a9a6b34dd80031114c5dd8adb7ef53493642e39d3d80dfef4025a452128400c35c2c138d20a0f6ae5d7d7ef70d9ba13083d34 +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f languageName: node linkType: hard -"git-url-parse@npm:^13.1.0": - version: 13.1.1 - resolution: "git-url-parse@npm:13.1.1" +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" dependencies: - git-up: "npm:^7.0.0" - checksum: 10c0/9304e6fbc1a6acf5e351e84ad87574fa6b840ccbe531afbbce9ba38e01fcacf6adf386ef7593daa037da59d9fd43b5d7c5232d5648638f8301cc2f18d00ad386 + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 languageName: node linkType: hard -"github-slugger@npm:^2.0.0": - version: 2.0.0 - resolution: "github-slugger@npm:2.0.0" - checksum: 10c0/21b912b6b1e48f1e5a50b2292b48df0ff6abeeb0691b161b3d93d84f4ae6b1acd6ae23702e914af7ea5d441c096453cf0f621b72d57893946618d21dd1a1c486 +"format@npm:^0.2.0": + version: 0.2.2 + resolution: "format@npm:0.2.2" + checksum: 10c0/6032ba747541a43abf3e37b402b2f72ee08ebcb58bf84d816443dd228959837f1cddf1e8775b29fa27ff133f4bd146d041bfca5f9cf27f048edf3d493cf8fee6 languageName: node linkType: hard -"graceful-fs@npm:^4.2.11": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 +"get-stream@npm:^8.0.1": + version: 8.0.1 + resolution: "get-stream@npm:8.0.1" + checksum: 10c0/5c2181e98202b9dae0bb4a849979291043e5892eb40312b47f0c22b9414fc9b28a3b6063d2375705eb24abc41ecf97894d9a51f64ff021511b504477b27b4290 languageName: node linkType: hard -"gray-matter@npm:^4.0.3": - version: 4.0.3 - resolution: "gray-matter@npm:4.0.3" - dependencies: - js-yaml: "npm:^3.13.1" - kind-of: "npm:^6.0.2" - section-matter: "npm:^1.0.0" - strip-bom-string: "npm:^1.0.0" - checksum: 10c0/e38489906dad4f162ca01e0dcbdbed96d1a53740cef446b9bf76d80bec66fa799af07776a18077aee642346c5e1365ed95e4c91854a12bf40ba0d4fb43a625a6 +"github-slugger@npm:^2.0.0": + version: 2.0.0 + resolution: "github-slugger@npm:2.0.0" + checksum: 10c0/21b912b6b1e48f1e5a50b2292b48df0ff6abeeb0691b161b3d93d84f4ae6b1acd6ae23702e914af7ea5d441c096453cf0f621b72d57893946618d21dd1a1c486 languageName: node linkType: hard -"has-flag@npm:^2.0.0": - version: 2.0.0 - resolution: "has-flag@npm:2.0.0" - checksum: 10c0/5e1f136c7f801c2719048bedfabcf834a1ed46276cd4c98c6fcddb89a482f5d6a16df0771a38805cfc2d9010b4de157909e1a71b708e1d339b6e311041bde9b4 +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee languageName: node linkType: hard -"hash-obj@npm:^4.0.0": - version: 4.0.0 - resolution: "hash-obj@npm:4.0.0" - dependencies: - is-obj: "npm:^3.0.0" - sort-keys: "npm:^5.0.0" - type-fest: "npm:^1.0.2" - checksum: 10c0/af0a8bd3905afa2b9bd05ec75e37d904c66f6621ae185d53699fc7e5baf8157aeff6f4b9ae3c579da08aae6a5b2536c445c4dd1eecb94070c8717b63eeca97de +"hachure-fill@npm:^0.5.2": + version: 0.5.2 + resolution: "hachure-fill@npm:0.5.2" + checksum: 10c0/307e3b6f9f2d3c11a82099c3f71eecbb9c440c00c1f896ac1732c23e6dbff16a92bb893d222b8b721b89cf11e58649ca60b4c24e5663f705f877cefd40153429 languageName: node linkType: hard @@ -1708,26 +2396,69 @@ __metadata: languageName: node linkType: hard -"hast-util-to-estree@npm:^2.0.0": - version: 2.3.3 - resolution: "hast-util-to-estree@npm:2.3.3" +"hast-util-to-estree@npm:^3.0.0, hast-util-to-estree@npm:^3.1.0": + version: 3.1.3 + resolution: "hast-util-to-estree@npm:3.1.3" dependencies: "@types/estree": "npm:^1.0.0" "@types/estree-jsx": "npm:^1.0.0" - "@types/hast": "npm:^2.0.0" - "@types/unist": "npm:^2.0.0" + "@types/hast": "npm:^3.0.0" comma-separated-tokens: "npm:^2.0.0" - estree-util-attach-comments: "npm:^2.0.0" - estree-util-is-identifier-name: "npm:^2.0.0" - hast-util-whitespace: "npm:^2.0.0" - mdast-util-mdx-expression: "npm:^1.0.0" - mdast-util-mdxjs-esm: "npm:^1.0.0" - property-information: "npm:^6.0.0" + devlop: "npm:^1.0.0" + estree-util-attach-comments: "npm:^3.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" space-separated-tokens: "npm:^2.0.0" - style-to-object: "npm:^0.4.1" - unist-util-position: "npm:^4.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" zwitch: "npm:^2.0.0" - checksum: 10c0/5947b5030a6d20c193f5ea576cc751507e0b30d00f91e40a5208ca3a7add03a3862795a83600c0fdadf19c8b051917c7904715fa7dd358f04603d67a36341c38 + checksum: 10c0/8e86c075319082c8a6304c5bcdf24ec02466074571e993f58bfa2cfd70850ef46d33b5c402208597a87fe0f02f1e620bda5958217efb1b7396c81c486373b75f + languageName: node + linkType: hard + +"hast-util-to-html@npm:^9.0.5": + version: 9.0.5 + resolution: "hast-util-to-html@npm:9.0.5" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-whitespace: "npm:^3.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + stringify-entities: "npm:^4.0.0" + zwitch: "npm:^2.0.4" + checksum: 10c0/b7a08c30bab4371fc9b4a620965c40b270e5ae7a8e94cf885f43b21705179e28c8e43b39c72885d1647965fb3738654e6962eb8b58b0c2a84271655b4d748836 + languageName: node + linkType: hard + +"hast-util-to-jsx-runtime@npm:^2.0.0": + version: 2.3.6 + resolution: "hast-util-to-jsx-runtime@npm:2.3.6" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/27297e02848fe37ef219be04a26ce708d17278a175a807689e94a821dcffc88aa506d62c3a85beed1f9a8544f7211bdcbcde0528b7b456a57c2e342c3fd11056 languageName: node linkType: hard @@ -1746,6 +2477,15 @@ __metadata: languageName: node linkType: hard +"hast-util-to-string@npm:^3.0.0": + version: 3.0.1 + resolution: "hast-util-to-string@npm:3.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b5fa1912a6ba6131affae52a0f4394406c4c0d23c2b0307f1d69988f1030c7bb830289303e67c5ad8f674f5f23a454c1dcd492c39e45a22c1f46d3c9bce5bd0c + languageName: node + linkType: hard + "hast-util-to-text@npm:^4.0.0": version: 4.0.2 resolution: "hast-util-to-text@npm:4.0.2" @@ -1758,10 +2498,12 @@ __metadata: languageName: node linkType: hard -"hast-util-whitespace@npm:^2.0.0": - version: 2.0.1 - resolution: "hast-util-whitespace@npm:2.0.1" - checksum: 10c0/dcf6ebab091c802ffa7bb3112305c7631c15adb6c07a258f5528aefbddf82b4e162c8310ef426c48dc1dc623982cc33920e6dde5a50015d307f2778dcf6c2487 +"hast-util-whitespace@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-whitespace@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b898bc9fe27884b272580d15260b6bbdabe239973a147e97fa98c45fa0ffec967a481aaa42291ec34fb56530dc2d484d473d7e2bae79f39c83f3762307edfea8 languageName: node linkType: hard @@ -1785,6 +2527,13 @@ __metadata: languageName: node linkType: hard +"human-signals@npm:^5.0.0": + version: 5.0.0 + resolution: "human-signals@npm:5.0.0" + checksum: 10c0/5a9359073fe17a8b58e5a085e9a39a950366d9f00217c4ff5878bd312e09d80f460536ea6a3f260b5943a01fe55c158d1cea3fc7bee3d0520aeef04f6d915c82 + languageName: node + linkType: hard + "iconv-lite@npm:0.6": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -1794,10 +2543,10 @@ __metadata: languageName: node linkType: hard -"inline-style-parser@npm:0.1.1": - version: 0.1.1 - resolution: "inline-style-parser@npm:0.1.1" - checksum: 10c0/08832a533f51a1e17619f2eabf2f5ec5e956d6dcba1896351285c65df022c9420de61d73256e1dca8015a52abf96cc84ddc3b73b898b22de6589d3962b5e501b +"inline-style-parser@npm:0.2.7": + version: 0.2.7 + resolution: "inline-style-parser@npm:0.2.7" + checksum: 10c0/d884d76f84959517430ae6c22f0bda59bb3f58f539f99aac75a8d786199ec594ed648c6ab4640531f9fc244b0ed5cd8c458078e592d016ef06de793beb1debff languageName: node linkType: hard @@ -1815,13 +2564,6 @@ __metadata: languageName: node linkType: hard -"intersection-observer@npm:^0.12.2": - version: 0.12.2 - resolution: "intersection-observer@npm:0.12.2" - checksum: 10c0/9591f46b2b742f5801ed69dbc8860f487771b4af8361e7a5dcb28a377beff2ba56336a2b090af261825430d225dae9417121496d2e6925e000e4a469958843ff - languageName: node - linkType: hard - "is-alphabetical@npm:^2.0.0": version: 2.0.1 resolution: "is-alphabetical@npm:2.0.1" @@ -1846,13 +2588,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^2.0.0": - version: 2.0.5 - resolution: "is-buffer@npm:2.0.5" - checksum: 10c0/e603f6fced83cf94c53399cff3bda1a9f08e391b872b64a73793b0928be3e5f047f2bcece230edb7632eaea2acdbfcb56c23b33d8a20c820023b230f1485679a - languageName: node - linkType: hard - "is-decimal@npm:^2.0.0": version: 2.0.1 resolution: "is-decimal@npm:2.0.1" @@ -1860,10 +2595,28 @@ __metadata: languageName: node linkType: hard -"is-extendable@npm:^0.1.0": - version: 0.1.1 - resolution: "is-extendable@npm:0.1.1" - checksum: 10c0/dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a languageName: node linkType: hard @@ -1874,17 +2627,21 @@ __metadata: languageName: node linkType: hard -"is-obj@npm:^3.0.0": - version: 3.0.0 - resolution: "is-obj@npm:3.0.0" - checksum: 10c0/48d678fa15c56fd38353634ae2106a538827af9050211b18df13540dba0b38aa25c5cb498648a01311bf493a99ac3ce416576649b8cace10bcce7344611fa56a +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: "npm:^3.0.0" + bin: + is-inside-container: cli.js + checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd languageName: node linkType: hard -"is-plain-obj@npm:^3.0.0": - version: 3.0.0 - resolution: "is-plain-obj@npm:3.0.0" - checksum: 10c0/8e6483bfb051d42ec9c704c0ede051a821c6b6f9a6c7a3e3b55aa855e00981b0580c8f3b1f5e2e62649b39179b1abfee35d6f8086d999bfaa32c1908d29b07bc +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 languageName: node linkType: hard @@ -1895,28 +2652,28 @@ __metadata: languageName: node linkType: hard -"is-reference@npm:^3.0.0": - version: 3.0.2 - resolution: "is-reference@npm:3.0.2" - dependencies: - "@types/estree": "npm:*" - checksum: 10c0/652d31b405e8e8269071cee78fe874b072745012eba202c6dc86880fd603a65ae043e3160990ab4a0a4b33567cbf662eecf3bc6b3c2c1550e6c2b6cf885ce5aa +"is-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "is-stream@npm:3.0.0" + checksum: 10c0/eb2f7127af02ee9aa2a0237b730e47ac2de0d4e76a4a905a50a11557f2339df5765eaea4ceb8029f1efa978586abe776908720bfcb1900c20c6ec5145f6f29d8 languageName: node linkType: hard -"is-ssh@npm:^1.4.0": - version: 1.4.0 - resolution: "is-ssh@npm:1.4.0" +"is-wsl@npm:^3.1.0": + version: 3.1.1 + resolution: "is-wsl@npm:3.1.1" dependencies: - protocols: "npm:^2.0.1" - checksum: 10c0/3eb30d1bcb4507cd25562e7ac61a1c0aa31772134c67cec9c3afe6f4d57ec17e8c2892600a608e8e583f32f53f36465b8968c0305f2855cfbff95acfd049e113 + is-inside-container: "npm:^1.0.0" + checksum: 10c0/7e5023522bfb8f27de4de960b0d82c4a8146c0bddb186529a3616d78b5bbbfc19ef0c5fc60d0b3a3cc0bf95a415fbdedc18454310ea3049587c879b07ace5107 languageName: node linkType: hard -"is-stream@npm:^1.1.0": - version: 1.1.0 - resolution: "is-stream@npm:1.1.0" - checksum: 10c0/b8ae7971e78d2e8488d15f804229c6eed7ed36a28f8807a1815938771f4adff0e705218b7dab968270433f67103e4fef98062a0beea55d64835f705ee72c7002 +"is64bit@npm:^2.0.0": + version: 2.0.0 + resolution: "is64bit@npm:2.0.0" + dependencies: + system-architecture: "npm:^0.1.0" + checksum: 10c0/9f3741d4b7560e2a30b9ce0c79bb30c7bdcc5df77c897bd59bb68f0fd882ae698015e8da81d48331def66c778d430c1ae3cb8c1fcc34e96c576b66198395faa7 languageName: node linkType: hard @@ -1927,72 +2684,45 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^3.0.0 || ^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed - languageName: node - linkType: hard - -"js-yaml@npm:^3.13.1": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" - dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b - languageName: node - linkType: hard - -"js-yaml@npm:^4.0.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" +"katex@npm:^0.16.0": + version: 0.16.10 + resolution: "katex@npm:0.16.10" dependencies: - argparse: "npm:^2.0.1" + commander: "npm:^8.3.0" bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f - languageName: node - linkType: hard - -"jsonc-parser@npm:^3.2.0": - version: 3.2.1 - resolution: "jsonc-parser@npm:3.2.1" - checksum: 10c0/ada66dec143d7f9cb0e2d0d29c69e9ce40d20f3a4cb96b0c6efb745025ac7f9ba647d7ac0990d0adfc37a2d2ae084a12009a9c833dbdbeadf648879a99b9df89 + katex: cli.js + checksum: 10c0/b465213157e5245bbb31ff6563c33ae81807c06d6f2246325b3a2397497e8929a34eebbb262f5e0991ec00fbc0cc85f388246e6dfc38ec86c28d3e481cb70afa languageName: node linkType: hard -"katex@npm:^0.16.0, katex@npm:^0.16.9": - version: 0.16.10 - resolution: "katex@npm:0.16.10" +"katex@npm:^0.16.21, katex@npm:^0.16.22": + version: 0.16.33 + resolution: "katex@npm:0.16.33" dependencies: commander: "npm:^8.3.0" bin: katex: cli.js - checksum: 10c0/b465213157e5245bbb31ff6563c33ae81807c06d6f2246325b3a2397497e8929a34eebbb262f5e0991ec00fbc0cc85f388246e6dfc38ec86c28d3e481cb70afa + checksum: 10c0/b2b655e4a3592ee0db45fea87856542383109ed598504a1c67b8eb957b9ba4dab752d5865f6354579d2a260d71e3e3594278a66c184b70c574a52481abee8caa languageName: node linkType: hard -"khroma@npm:^2.0.0": +"khroma@npm:^2.1.0": version: 2.1.0 resolution: "khroma@npm:2.1.0" checksum: 10c0/634d98753ff5d2540491cafeb708fc98de0d43f4e6795256d5c8f6e3ad77de93049ea41433928fda3697adf7bbe6fe27351858f6d23b78f8b5775ef314c59891 languageName: node linkType: hard -"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 - languageName: node - linkType: hard - -"kleur@npm:^4.0.3": - version: 4.1.5 - resolution: "kleur@npm:4.1.5" - checksum: 10c0/e9de6cb49657b6fa70ba2d1448fd3d691a5c4370d8f7bbf1c2f64c24d461270f2117e1b0afe8cb3114f13bbd8e51de158c2a224953960331904e636a5e4c0f2a +"langium@npm:^4.0.0": + version: 4.2.1 + resolution: "langium@npm:4.2.1" + dependencies: + chevrotain: "npm:~11.1.1" + chevrotain-allstar: "npm:~0.3.1" + vscode-languageserver: "npm:~9.0.1" + vscode-languageserver-textdocument: "npm:~1.0.11" + vscode-uri: "npm:~3.1.0" + checksum: 10c0/19ddf79cc3c435ec70f8eb50de255571711db7cea89d171cf80bc97e7ed73d4d0bb6b4215899df8369fa6d0e17f442f30af4ec2e9657041bf2f93be1310ba50a languageName: node linkType: hard @@ -2003,6 +2733,20 @@ __metadata: languageName: node linkType: hard +"layout-base@npm:^2.0.0": + version: 2.0.1 + resolution: "layout-base@npm:2.0.1" + checksum: 10c0/a44df9ef3cbff9916a10f616635e22b5787c89fa62b2fec6f99e8e6ee512c7cebd22668ce32dab5a83c934ba0a309c51a678aa0b40d70853de6c357893c0a88b + languageName: node + linkType: hard + +"lodash-es@npm:4.17.23, lodash-es@npm:^4.17.23": + version: 4.17.23 + resolution: "lodash-es@npm:4.17.23" + checksum: 10c0/3150fb6660c14c7a6b5f23bd11597d884b140c0e862a17fdb415aaa5ef7741523182904a6b7929f04e5f60a11edb5a79499eb448734381c99ffb3c4734beeddd + languageName: node + linkType: hard + "lodash-es@npm:^4.17.21": version: 4.17.21 resolution: "lodash-es@npm:4.17.21" @@ -2010,13 +2754,6 @@ __metadata: languageName: node linkType: hard -"lodash.get@npm:^4.4.2": - version: 4.4.2 - resolution: "lodash.get@npm:4.4.2" - checksum: 10c0/48f40d471a1654397ed41685495acb31498d5ed696185ac8973daef424a749ca0c7871bf7b665d5c14f5cc479394479e0307e781f61d5573831769593411be6e - languageName: node - linkType: hard - "longest-streak@npm:^3.0.0": version: 3.1.0 resolution: "longest-streak@npm:3.1.0" @@ -2024,31 +2761,10 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.1.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e - languageName: node - linkType: hard - -"lru-cache@npm:^4.0.1": - version: 4.1.5 - resolution: "lru-cache@npm:4.1.5" - dependencies: - pseudomap: "npm:^1.0.2" - yallist: "npm:^2.1.2" - checksum: 10c0/1ca5306814e5add9ec63556d6fd9b24a4ecdeaef8e9cea52cbf30301e6b88c8d8ddc7cab45b59b56eb763e6c45af911585dc89925a074ab65e1502e3fe8103cf - languageName: node - linkType: hard - -"markdown-extensions@npm:^1.0.0": - version: 1.1.1 - resolution: "markdown-extensions@npm:1.1.1" - checksum: 10c0/eb9154016502ad1fb4477683ddb5cae8ba3ca06451b381b04dc4c34e91d8d168129d50d404b717d6bf7d458e13088c109303fc72d57cee7151a6082b0e7bba71 +"markdown-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-extensions@npm:2.0.0" + checksum: 10c0/406139da2aa0d5ebad86195c8e8c02412f873c452b4c087ae7bc767af37956141be449998223bb379eea179b5fd38dfa610602b6f29c22ddab5d51e627a7e41d languageName: node linkType: hard @@ -2059,228 +2775,256 @@ __metadata: languageName: node linkType: hard -"match-sorter@npm:^6.3.1": - version: 6.3.4 - resolution: "match-sorter@npm:6.3.4" - dependencies: - "@babel/runtime": "npm:^7.23.8" - remove-accents: "npm:0.5.0" - checksum: 10c0/35d2a6b6df003c677d9ec87ecd4683657638f5bce856f43f9cf90b03e357ed2f09813ebbac759defa7e7438706936dd34dc2bfe1a18771f7d2541f14d639b4ad +"marked@npm:^16.2.1": + version: 16.4.2 + resolution: "marked@npm:16.4.2" + bin: + marked: bin/marked.js + checksum: 10c0/fc6051142172454f2023f3d6b31cca92879ec8e1b96457086a54c70354c74b00e1b6543a76a1fad6d399366f52b90a848f6ffb8e1d65a5baff87f3ba9b8f1847 languageName: node linkType: hard -"mdast-util-definitions@npm:^5.0.0": - version: 5.1.2 - resolution: "mdast-util-definitions@npm:5.1.2" +"mathjax-full@npm:^3.2.2": + version: 3.2.2 + resolution: "mathjax-full@npm:3.2.2" dependencies: - "@types/mdast": "npm:^3.0.0" - "@types/unist": "npm:^2.0.0" - unist-util-visit: "npm:^4.0.0" - checksum: 10c0/da9049c15562e44ee4ea4a36113d98c6c9eaa3d8a17d6da2aef6a0626376dcd01d9ec007d77a8dfcad6d0cbd5c32a4abbad72a3f48c3172a55934c7d9a916480 + esm: "npm:^3.2.25" + mhchemparser: "npm:^4.1.0" + mj-context-menu: "npm:^0.6.1" + speech-rule-engine: "npm:^4.0.6" + checksum: 10c0/48f55747bd91aa6bba905bab8654045e4d654a0a65869b1d446e25a89284ef37dc722c6c4a585e7fc14c5f87bb6954291f066e08e5a8245bb5ff0c4f4c54c8d4 languageName: node linkType: hard -"mdast-util-find-and-replace@npm:^2.0.0": - version: 2.2.2 - resolution: "mdast-util-find-and-replace@npm:2.2.2" +"mdast-util-find-and-replace@npm:^3.0.0": + version: 3.0.2 + resolution: "mdast-util-find-and-replace@npm:3.0.2" dependencies: - "@types/mdast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" escape-string-regexp: "npm:^5.0.0" - unist-util-is: "npm:^5.0.0" - unist-util-visit-parents: "npm:^5.0.0" - checksum: 10c0/ce935f4bd4aeab47f91531a7f09dfab89aaeea62ad31029b43185c5b626921357703d8e5093c13073c097fdabfc57cb2f884d7dfad83dbe7239e351375d6797c + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/c8417a35605d567772ff5c1aa08363ff3010b0d60c8ea68c53cba09bf25492e3dd261560425c1756535f3b7107f62e7ff3857cdd8fb1e62d1b2cc2ea6e074ca2 languageName: node linkType: hard -"mdast-util-from-markdown@npm:^1.0.0, mdast-util-from-markdown@npm:^1.1.0, mdast-util-from-markdown@npm:^1.3.0": - version: 1.3.1 - resolution: "mdast-util-from-markdown@npm:1.3.1" +"mdast-util-from-markdown@npm:^2.0.0, mdast-util-from-markdown@npm:^2.0.1": + version: 2.0.3 + resolution: "mdast-util-from-markdown@npm:2.0.3" dependencies: - "@types/mdast": "npm:^3.0.0" - "@types/unist": "npm:^2.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" decode-named-character-reference: "npm:^1.0.0" - mdast-util-to-string: "npm:^3.1.0" - micromark: "npm:^3.0.0" - micromark-util-decode-numeric-character-reference: "npm:^1.0.0" - micromark-util-decode-string: "npm:^1.0.0" - micromark-util-normalize-identifier: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - unist-util-stringify-position: "npm:^3.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/f4e901bf2a2e93fe35a339e0cff581efacce2f7117cd5652e9a270847bd7e2508b3e717b7b4156af54d4f896d63033e06ff9fafbf59a1d46fe17dd5e2a3f7846 + devlop: "npm:^1.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark: "npm:^4.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/d3eac9ac2b88e3b41fb85aa81c7bfd1f4f8a2fde497ad805e66fea7b2abfe486ffd94d2a20f9fd2951dcdebe4916f3bdcf851319891dd62d343e26c2f02583ba languageName: node linkType: hard -"mdast-util-gfm-autolink-literal@npm:^1.0.0": - version: 1.0.3 - resolution: "mdast-util-gfm-autolink-literal@npm:1.0.3" +"mdast-util-frontmatter@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-frontmatter@npm:2.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + escape-string-regexp: "npm:^5.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-extension-frontmatter: "npm:^2.0.0" + checksum: 10c0/d9b0b70dd9c574cc0220d4e05dd8e9d86ac972a6a5af9e0c49c839b31cb750d4313445cfbbdf9264a7fbe3f8c8d920b45358b8500f4286e6b9dc830095b25b9a + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" dependencies: - "@types/mdast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" ccount: "npm:^2.0.0" - mdast-util-find-and-replace: "npm:^2.0.0" - micromark-util-character: "npm:^1.0.0" - checksum: 10c0/750e312eae73c3f2e8aa0e8c5232cb1b905357ff37ac236927f1af50cdbee7c2cfe2379b148ac32fa4137eeb3b24601e1bb6135084af926c7cd808867804193f + devlop: "npm:^1.0.0" + mdast-util-find-and-replace: "npm:^3.0.0" + micromark-util-character: "npm:^2.0.0" + checksum: 10c0/963cd22bd42aebdec7bdd0a527c9494d024d1ad0739c43dc040fee35bdfb5e29c22564330a7418a72b5eab51d47a6eff32bc0255ef3ccb5cebfe8970e91b81b6 languageName: node linkType: hard -"mdast-util-gfm-footnote@npm:^1.0.0": - version: 1.0.2 - resolution: "mdast-util-gfm-footnote@npm:1.0.2" +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "mdast-util-gfm-footnote@npm:2.1.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-to-markdown: "npm:^1.3.0" - micromark-util-normalize-identifier: "npm:^1.0.0" - checksum: 10c0/767973e46b9e2ae44e80e51a5e38ad0b032fc7f06a1a3095aa96c2886ba333941c764474a56b82e7db05efc56242a4789bc7fbbcc753d61512750e86a4192fe8 + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + checksum: 10c0/8ab965ee6be3670d76ec0e95b2ba3101fc7444eec47564943ab483d96ac17d29da2a4e6146a2a288be30c21b48c4f3938a1e54b9a46fbdd321d49a5bc0077ed0 languageName: node linkType: hard -"mdast-util-gfm-strikethrough@npm:^1.0.0": - version: 1.0.3 - resolution: "mdast-util-gfm-strikethrough@npm:1.0.3" +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-to-markdown: "npm:^1.3.0" - checksum: 10c0/29616b3dfdd33d3cd13f9b3181a8562fa2fbacfcb04a37dba3c690ba6829f0231b145444de984726d9277b2bc90dd7d96fb9df9f6292d5e77d65a8659ee2f52b + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/b053e93d62c7545019bd914271ea9e5667ad3b3b57d16dbf68e56fea39a7e19b4a345e781312714eb3d43fdd069ff7ee22a3ca7f6149dfa774554f19ce3ac056 languageName: node linkType: hard -"mdast-util-gfm-table@npm:^1.0.0": - version: 1.0.7 - resolution: "mdast-util-gfm-table@npm:1.0.7" +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" markdown-table: "npm:^3.0.0" - mdast-util-from-markdown: "npm:^1.0.0" - mdast-util-to-markdown: "npm:^1.3.0" - checksum: 10c0/a37a05a936292c4f48394123332d3c034a6e1b15bb3e7f3b94e6bce3260c9184fd388abbc4100827edd5485a6563098306994d15a729bde3c96de7a62ed5720b + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/128af47c503a53bd1c79f20642561e54a510ad5e2db1e418d28fefaf1294ab839e6c838e341aef5d7e404f9170b9ca3d1d89605f234efafde93ee51174a6e31e languageName: node linkType: hard -"mdast-util-gfm-task-list-item@npm:^1.0.0": - version: 1.0.2 - resolution: "mdast-util-gfm-task-list-item@npm:1.0.2" +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-to-markdown: "npm:^1.3.0" - checksum: 10c0/91fa91f7d1a8797bf129008dab12d23917015ad12df00044e275b4459e8b383fbec6234338953a0089ef9c3a114d0a360c3e652eb0ebf6ece7e7a8fd3b5977c6 + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/258d725288482b636c0a376c296431390c14b4f29588675297cb6580a8598ed311fc73ebc312acfca12cc8546f07a3a285a53a3b082712e2cbf5c190d677d834 languageName: node linkType: hard -"mdast-util-gfm@npm:^2.0.0": - version: 2.0.2 - resolution: "mdast-util-gfm@npm:2.0.2" +"mdast-util-gfm@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-gfm@npm:3.1.0" dependencies: - mdast-util-from-markdown: "npm:^1.0.0" - mdast-util-gfm-autolink-literal: "npm:^1.0.0" - mdast-util-gfm-footnote: "npm:^1.0.0" - mdast-util-gfm-strikethrough: "npm:^1.0.0" - mdast-util-gfm-table: "npm:^1.0.0" - mdast-util-gfm-task-list-item: "npm:^1.0.0" - mdast-util-to-markdown: "npm:^1.0.0" - checksum: 10c0/5b7f7f98a90a2962d7e0787e080c4e55b70119100c7685bbdb772d8d7865524aeffd1757edba5afba434250e0246b987c0617c2c635baaf51c26dbbb3b72dbec + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-gfm-autolink-literal: "npm:^2.0.0" + mdast-util-gfm-footnote: "npm:^2.0.0" + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-gfm-table: "npm:^2.0.0" + mdast-util-gfm-task-list-item: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4bedcfb6a20e39901c8772f0d2bb2d7a64ae87a54c13cbd92eec062cf470fbb68c2ad754e149af5b30794e2de61c978ab1de1ace03c0c40f443ca9b9b8044f81 languageName: node linkType: hard -"mdast-util-math@npm:^2.0.0": - version: 2.0.2 - resolution: "mdast-util-math@npm:2.0.2" +"mdast-util-math@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-math@npm:3.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" longest-streak: "npm:^3.0.0" - mdast-util-to-markdown: "npm:^1.3.0" - checksum: 10c0/2270b6f8d7f0eb7dd5c27bee8ad43f29a8e76a7092742945fd115480ddd8bf72ae53ba1f8f63697cec82016e0c169f0a201503862dfe6bc7ac2286662de3fe8e + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.1.0" + unist-util-remove-position: "npm:^5.0.0" + checksum: 10c0/d4e839e38719f26872ed78aac18339805a892f1b56585a9cb8668f34e221b4f0660b9dfe49ec96dbbe79fd1b63b648608a64046d8286bcd2f9d576e80b48a0a1 languageName: node linkType: hard -"mdast-util-mdx-expression@npm:^1.0.0": - version: 1.3.2 - resolution: "mdast-util-mdx-expression@npm:1.3.2" +"mdast-util-mdx-expression@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdx-expression@npm:2.0.1" dependencies: "@types/estree-jsx": "npm:^1.0.0" - "@types/hast": "npm:^2.0.0" - "@types/mdast": "npm:^3.0.0" - mdast-util-from-markdown: "npm:^1.0.0" - mdast-util-to-markdown: "npm:^1.0.0" - checksum: 10c0/01f306ee809d28825cbec23b3c80376a0fbe69601b6b2843d23beb5662a31ec7560995f52b96b13093cc03de1130404a47f139d16f58c3f54e91e88f4bdd82d2 + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/9a1e57940f66431f10312fa239096efa7627f375e7933b5d3162c0b5c1712a72ac87447aff2b6838d2bbd5c1311b188718cc90b33b67dc67a88550e0a6ef6183 languageName: node linkType: hard -"mdast-util-mdx-jsx@npm:^2.0.0": - version: 2.1.4 - resolution: "mdast-util-mdx-jsx@npm:2.1.4" +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" dependencies: "@types/estree-jsx": "npm:^1.0.0" - "@types/hast": "npm:^2.0.0" - "@types/mdast": "npm:^3.0.0" - "@types/unist": "npm:^2.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" ccount: "npm:^2.0.0" - mdast-util-from-markdown: "npm:^1.1.0" - mdast-util-to-markdown: "npm:^1.3.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" parse-entities: "npm:^4.0.0" stringify-entities: "npm:^4.0.0" - unist-util-remove-position: "npm:^4.0.0" - unist-util-stringify-position: "npm:^3.0.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/b0c16e56a99c5167e60c98dbdbe82645549630fb529688642c4664ca5557ff0b3029c75146f5657cadb7908d5fa99810eacc5dcc51676d0877c8b4dcebb11cbe + unist-util-stringify-position: "npm:^4.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3acadaf3b962254f7ad2990fed4729961dc0217ca31fde9917986e880843f3ecf3392b1f22d569235cacd180d50894ad266db7af598aedca69d330d33c7ac613 languageName: node linkType: hard -"mdast-util-mdx@npm:^2.0.0": - version: 2.0.1 - resolution: "mdast-util-mdx@npm:2.0.1" +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" dependencies: - mdast-util-from-markdown: "npm:^1.0.0" - mdast-util-mdx-expression: "npm:^1.0.0" - mdast-util-mdx-jsx: "npm:^2.0.0" - mdast-util-mdxjs-esm: "npm:^1.0.0" - mdast-util-to-markdown: "npm:^1.0.0" - checksum: 10c0/3b5e55781a7b7b4b7e71728a84afbec63516f251b3556efec52dbb4824c0733f5ebaa907d21211d008e5cb1a8265e6704bc062ee605f4c09e90fbfa2c6fbba3b + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4faea13f77d6bc9aa64ee41a5e4779110b73444a17fda363df6ebe880ecfa58b321155b71f8801c3faa6d70d6222a32a00cbd6dbf5fad8db417f4688bc9c74e1 languageName: node linkType: hard -"mdast-util-mdxjs-esm@npm:^1.0.0": - version: 1.3.1 - resolution: "mdast-util-mdxjs-esm@npm:1.3.1" +"mdast-util-mdxjs-esm@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" dependencies: "@types/estree-jsx": "npm:^1.0.0" - "@types/hast": "npm:^2.0.0" - "@types/mdast": "npm:^3.0.0" - mdast-util-from-markdown: "npm:^1.0.0" - mdast-util-to-markdown: "npm:^1.0.0" - checksum: 10c0/2ff0af34ea62004d39f15bd45b79e3008e68cae7e2510c9281e24a17e2c3f55d004524796166ef5aa3378798ca7f6c5f88883238f413577619bbaf41026b7e62 + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/5bda92fc154141705af2b804a534d891f28dac6273186edf1a4c5e3f045d5b01dbcac7400d27aaf91b7e76e8dce007c7b2fdf136c11ea78206ad00bdf9db46bc languageName: node linkType: hard -"mdast-util-phrasing@npm:^3.0.0": - version: 3.0.1 - resolution: "mdast-util-phrasing@npm:3.0.1" +"mdast-util-phrasing@npm:^4.0.0": + version: 4.1.0 + resolution: "mdast-util-phrasing@npm:4.1.0" dependencies: - "@types/mdast": "npm:^3.0.0" - unist-util-is: "npm:^5.0.0" - checksum: 10c0/5e00e303652a7581593549dbce20dfb69d687d79a972f7928f6ca1920ef5385bceb737a3d5292ab6d937ed8c67bb59771e80e88f530b78734fe7d155f833e32b + "@types/mdast": "npm:^4.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/bf6c31d51349aa3d74603d5e5a312f59f3f65662ed16c58017169a5fb0f84ca98578f626c5ee9e4aa3e0a81c996db8717096705521bddb4a0185f98c12c9b42f languageName: node linkType: hard -"mdast-util-to-hast@npm:^12.1.0": - version: 12.3.0 - resolution: "mdast-util-to-hast@npm:12.3.0" +"mdast-util-to-hast@npm:^13.0.0": + version: 13.2.0 + resolution: "mdast-util-to-hast@npm:13.2.0" dependencies: - "@types/hast": "npm:^2.0.0" - "@types/mdast": "npm:^3.0.0" - mdast-util-definitions: "npm:^5.0.0" - micromark-util-sanitize-uri: "npm:^1.1.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" trim-lines: "npm:^3.0.0" - unist-util-generated: "npm:^2.0.0" - unist-util-position: "npm:^4.0.0" - unist-util-visit: "npm:^4.0.0" - checksum: 10c0/0753e45bfcce423f7a13979ac720a23ed8d6bafed174c387f43bbe8baf3838f3a043cd8006975b71e5c4068b7948f83f1348acea79801101af31eaec4e7a499a + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/9ee58def9287df8350cbb6f83ced90f9c088d72d4153780ad37854f87144cadc6f27b20347073b285173b1649b0723ddf0b9c78158608a804dcacb6bda6e1816 languageName: node linkType: hard -"mdast-util-to-hast@npm:^13.0.0": - version: 13.2.0 - resolution: "mdast-util-to-hast@npm:13.2.0" +"mdast-util-to-hast@npm:^13.2.0": + version: 13.2.1 + resolution: "mdast-util-to-hast@npm:13.2.1" dependencies: "@types/hast": "npm:^3.0.0" "@types/mdast": "npm:^4.0.0" @@ -2291,351 +3035,376 @@ __metadata: unist-util-position: "npm:^5.0.0" unist-util-visit: "npm:^5.0.0" vfile: "npm:^6.0.0" - checksum: 10c0/9ee58def9287df8350cbb6f83ced90f9c088d72d4153780ad37854f87144cadc6f27b20347073b285173b1649b0723ddf0b9c78158608a804dcacb6bda6e1816 + checksum: 10c0/3eeaf28a5e84e1e08e6d54a1a8a06c0fca88cb5d36f4cf8086f0177248d1ce6e4e751f4ad0da19a3dea1c6ea61bd80784acc3ae021e44ceeb21aa5413a375e43 languageName: node linkType: hard -"mdast-util-to-markdown@npm:^1.0.0, mdast-util-to-markdown@npm:^1.3.0": - version: 1.5.0 - resolution: "mdast-util-to-markdown@npm:1.5.0" +"mdast-util-to-markdown@npm:^2.0.0, mdast-util-to-markdown@npm:^2.1.0": + version: 2.1.2 + resolution: "mdast-util-to-markdown@npm:2.1.2" dependencies: - "@types/mdast": "npm:^3.0.0" - "@types/unist": "npm:^2.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" longest-streak: "npm:^3.0.0" - mdast-util-phrasing: "npm:^3.0.0" - mdast-util-to-string: "npm:^3.0.0" - micromark-util-decode-string: "npm:^1.0.0" - unist-util-visit: "npm:^4.0.0" + mdast-util-phrasing: "npm:^4.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + unist-util-visit: "npm:^5.0.0" zwitch: "npm:^2.0.0" - checksum: 10c0/9831d14aa6c097750a90c7b87b4e814b040731c30606a794c9b136dc746633dd9ec07154ca97d4fec4eaf732cf89d14643424e2581732d6ee18c9b0e51ff7664 + checksum: 10c0/4649722a6099f12e797bd8d6469b2b43b44e526b5182862d9c7766a3431caad2c0112929c538a972f214e63c015395e5d3f54bd81d9ac1b16e6d8baaf582f749 languageName: node linkType: hard -"mdast-util-to-string@npm:^3.0.0, mdast-util-to-string@npm:^3.1.0": - version: 3.2.0 - resolution: "mdast-util-to-string@npm:3.2.0" +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - checksum: 10c0/112f4bf0f6758dcb95deffdcf37afba7eaecdfe2ee13252de031723094d4d55220e147326690a8b91244758e2d678e7aeb1fdd0fa6ef3317c979bc42effd9a21 + "@types/mdast": "npm:^4.0.0" + checksum: 10c0/2d3c1af29bf3fe9c20f552ee9685af308002488f3b04b12fa66652c9718f66f41a32f8362aa2d770c3ff464c034860b41715902ada2306bb0a055146cef064d7 + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + languageName: node + linkType: hard + +"merge2@npm:^1.3.0": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb languageName: node linkType: hard -"mermaid@npm:^10.2.2": - version: 10.9.1 - resolution: "mermaid@npm:10.9.1" +"mermaid@npm:^11.0.0": + version: 11.12.3 + resolution: "mermaid@npm:11.12.3" dependencies: - "@braintree/sanitize-url": "npm:^6.0.1" - "@types/d3-scale": "npm:^4.0.3" - "@types/d3-scale-chromatic": "npm:^3.0.0" - cytoscape: "npm:^3.28.1" + "@braintree/sanitize-url": "npm:^7.1.1" + "@iconify/utils": "npm:^3.0.1" + "@mermaid-js/parser": "npm:^1.0.0" + "@types/d3": "npm:^7.4.3" + cytoscape: "npm:^3.29.3" cytoscape-cose-bilkent: "npm:^4.1.0" - d3: "npm:^7.4.0" + cytoscape-fcose: "npm:^2.2.0" + d3: "npm:^7.9.0" d3-sankey: "npm:^0.12.3" - dagre-d3-es: "npm:7.0.10" - dayjs: "npm:^1.11.7" - dompurify: "npm:^3.0.5" - elkjs: "npm:^0.9.0" - katex: "npm:^0.16.9" - khroma: "npm:^2.0.0" - lodash-es: "npm:^4.17.21" - mdast-util-from-markdown: "npm:^1.3.0" - non-layered-tidy-tree-layout: "npm:^2.0.2" - stylis: "npm:^4.1.3" + dagre-d3-es: "npm:7.0.13" + dayjs: "npm:^1.11.18" + dompurify: "npm:^3.2.5" + katex: "npm:^0.16.22" + khroma: "npm:^2.1.0" + lodash-es: "npm:^4.17.23" + marked: "npm:^16.2.1" + roughjs: "npm:^4.6.6" + stylis: "npm:^4.3.6" ts-dedent: "npm:^2.2.0" - uuid: "npm:^9.0.0" - web-worker: "npm:^1.2.0" - checksum: 10c0/034f326682e3e478e4bd85e418cfef00773db4432301b858247c8d4bf813e67fa1901e8548fc490eafe4c9c215c9fb96dead73007ff317ee99973cf4f63c8791 + uuid: "npm:^11.1.0" + checksum: 10c0/a50e0e79fa913d8d0c88a8927d14b07c8236ebb595aade815152b2668ed4e3e5204884c776739ee0b473df2277a4431cf21ed98cc2a7d81995d0f5a94af93058 languageName: node linkType: hard -"micromark-core-commonmark@npm:^1.0.0, micromark-core-commonmark@npm:^1.0.1": - version: 1.1.0 - resolution: "micromark-core-commonmark@npm:1.1.0" +"mhchemparser@npm:^4.1.0": + version: 4.2.1 + resolution: "mhchemparser@npm:4.2.1" + checksum: 10c0/5afe8b5ed918fda71a17875227050fd7e8e706305df28bd0beb5a7cd07886a393d041317e3c4b9105fc518ab75065b65886b2574cbd8dec49520de04d119e64a + languageName: node + linkType: hard + +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" dependencies: decode-named-character-reference: "npm:^1.0.0" - micromark-factory-destination: "npm:^1.0.0" - micromark-factory-label: "npm:^1.0.0" - micromark-factory-space: "npm:^1.0.0" - micromark-factory-title: "npm:^1.0.0" - micromark-factory-whitespace: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-chunked: "npm:^1.0.0" - micromark-util-classify-character: "npm:^1.0.0" - micromark-util-html-tag-name: "npm:^1.0.0" - micromark-util-normalize-identifier: "npm:^1.0.0" - micromark-util-resolve-all: "npm:^1.0.0" - micromark-util-subtokenize: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.1" - uvu: "npm:^0.5.0" - checksum: 10c0/b3bf7b7004ce7dbb3ae151dcca4db1d12546f1b943affb2418da4b90b9ce59357373c433ee2eea4c868aee0791dafa355aeed19f5ef2b0acaf271f32f1ecbe6a - languageName: node - linkType: hard - -"micromark-extension-gfm-autolink-literal@npm:^1.0.0": - version: 1.0.5 - resolution: "micromark-extension-gfm-autolink-literal@npm:1.0.5" + devlop: "npm:^1.0.0" + micromark-factory-destination: "npm:^2.0.0" + micromark-factory-label: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-factory-title: "npm:^2.0.0" + micromark-factory-whitespace: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-html-tag-name: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bd4a794fdc9e88dbdf59eaf1c507ddf26e5f7ddf4e52566c72239c0f1b66adbcd219ba2cd42350debbe24471434d5f5e50099d2b3f4e5762ca222ba8e5b549ee + languageName: node + linkType: hard + +"micromark-extension-frontmatter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-frontmatter@npm:2.0.0" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-sanitize-uri: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/4964a52605ac36d24501d427e2d173fa39b5e0402275cb45068eba4898f4cb9cc57f7007b21b7514f0ab5f7b371b1701a5156a10b6ac8e77a7f36e830cf481d4 + fault: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/7d0d876e598917a67146d29f536d6fbbf9d1b2401a77e2f64a3f80f934a63ff26fa94b01759c9185c24b2a91e4e6abf908fa7aa246f00a7778a6b37a17464300 languageName: node linkType: hard -"micromark-extension-gfm-footnote@npm:^1.0.0": - version: 1.1.2 - resolution: "micromark-extension-gfm-footnote@npm:1.1.2" +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0" dependencies: - micromark-core-commonmark: "npm:^1.0.0" - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-normalize-identifier: "npm:^1.0.0" - micromark-util-sanitize-uri: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/b8090876cc3da5436c6253b0b40e39ceaa470c2429f699c19ee4163cef3102c4cd16c4ac2ec8caf916037fad310cfb52a9ef182c75d50fca7419ba08faad9b39 + micromark-util-character: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/84e6fbb84ea7c161dfa179665dc90d51116de4c28f3e958260c0423e5a745372b7dcbc87d3cde98213b532e6812f847eef5ae561c9397d7f7da1e59872ef3efe languageName: node linkType: hard -"micromark-extension-gfm-strikethrough@npm:^1.0.0": - version: 1.0.7 - resolution: "micromark-extension-gfm-strikethrough@npm:1.0.7" +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-footnote@npm:2.1.0" dependencies: - micromark-util-chunked: "npm:^1.0.0" - micromark-util-classify-character: "npm:^1.0.0" - micromark-util-resolve-all: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/b45fe93a7a412fc44bae7a183b92a988e17b49ed9d683bd80ee4dde96d462e1ca6b316dd64bda7759e4086d6d8686790a711e53c244f1f4d2b37e1cfe852884d + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d172e4218968b7371b9321af5cde8c77423f73b233b2b0fcf3ff6fd6f61d2e0d52c49123a9b7910612478bf1f0d5e88c75a3990dd68f70f3933fe812b9f77edc languageName: node linkType: hard -"micromark-extension-gfm-table@npm:^1.0.0": - version: 1.0.7 - resolution: "micromark-extension-gfm-table@npm:1.0.7" +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0" dependencies: - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/38b5af80ecab8206845a057338235bee6f47fb6cb904208be4b76e87906765821683e25bef85dfa485809f931eaf8cd55f16cd2f4d6e33b84f56edfaf1dfb129 + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/ef4f248b865bdda71303b494671b7487808a340b25552b11ca6814dff3fcfaab9be8d294643060bbdb50f79313e4a686ab18b99cbe4d3ee8a4170fcd134234fb languageName: node linkType: hard -"micromark-extension-gfm-tagfilter@npm:^1.0.0": - version: 1.0.2 - resolution: "micromark-extension-gfm-tagfilter@npm:1.0.2" +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-extension-gfm-table@npm:2.1.1" dependencies: - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/7e1bf278255cf2a8d2dda9de84bc238b39c53100e25ba8d7168220d5b00dc74869a6cb038fbf2e76b8ae89efc66906762311797a906d7d9cdd71e07bfe1ed505 + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/04bc00e19b435fa0add62cd029d8b7eb6137522f77832186b1d5ef34544a9bd030c9cf85e92ddfcc5c31f6f0a58a43d4b96dba4fc21316037c734630ee12c912 languageName: node linkType: hard -"micromark-extension-gfm-task-list-item@npm:^1.0.0": - version: 1.0.5 - resolution: "micromark-extension-gfm-task-list-item@npm:1.0.5" +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" dependencies: - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/2179742fa2cbb243cc06bd9e43fbb94cd98e4814c9d368ddf8b4b5afa0348023f335626ae955e89d679e2c2662a7f82c315117a3b060c87bdb4420fee5a219d1 + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/995558843fff137ae4e46aecb878d8a4691cdf23527dcf1e2f0157d66786be9f7bea0109c52a8ef70e68e3f930af811828ba912239438e31a9cfb9981f44d34d languageName: node linkType: hard -"micromark-extension-gfm@npm:^2.0.0": - version: 2.0.3 - resolution: "micromark-extension-gfm@npm:2.0.3" +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0" dependencies: - micromark-extension-gfm-autolink-literal: "npm:^1.0.0" - micromark-extension-gfm-footnote: "npm:^1.0.0" - micromark-extension-gfm-strikethrough: "npm:^1.0.0" - micromark-extension-gfm-table: "npm:^1.0.0" - micromark-extension-gfm-tagfilter: "npm:^1.0.0" - micromark-extension-gfm-task-list-item: "npm:^1.0.0" - micromark-util-combine-extensions: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/53056376d14caf3fab2cc44881c1ad49d975776cc2267bca74abda2cb31f2a77ec0fb2bdb2dd97565f0d9943ad915ff192b89c1cee5d9d727569a5e38505799b + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/78aa537d929e9309f076ba41e5edc99f78d6decd754b6734519ccbbfca8abd52e1c62df68d41a6ae64d2a3fc1646cea955893c79680b0b4385ced4c52296181f languageName: node linkType: hard -"micromark-extension-math@npm:^2.0.0": - version: 2.1.2 - resolution: "micromark-extension-math@npm:2.1.2" +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: "npm:^2.0.0" + micromark-extension-gfm-footnote: "npm:^2.0.0" + micromark-extension-gfm-strikethrough: "npm:^2.0.0" + micromark-extension-gfm-table: "npm:^2.0.0" + micromark-extension-gfm-tagfilter: "npm:^2.0.0" + micromark-extension-gfm-task-list-item: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/970e28df6ebdd7c7249f52a0dda56e0566fbfa9ae56c8eeeb2445d77b6b89d44096880cd57a1c01e7821b1f4e31009109fbaca4e89731bff7b83b8519690e5d9 + languageName: node + linkType: hard + +"micromark-extension-math@npm:^3.0.0": + version: 3.1.0 + resolution: "micromark-extension-math@npm:3.1.0" dependencies: "@types/katex": "npm:^0.16.0" + devlop: "npm:^1.0.0" katex: "npm:^0.16.0" - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/5d40ffc93862498cbcbc9c96a40a05150b878c3d86ab25bc771dec005d286f4381578ccee3f421ecfd9db259298a89a37a5b6b48529842240d34f8acd8edffb5 + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/56e6f2185a4613f9d47e7e98cf8605851c990957d9229c942b005e286c8087b61dc9149448d38b2f8be6d42cc6a64aad7e1f2778ddd86fbbb1a2f48a3ca1872f languageName: node linkType: hard -"micromark-extension-mdx-expression@npm:^1.0.0": - version: 1.0.8 - resolution: "micromark-extension-mdx-expression@npm:1.0.8" +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.1 + resolution: "micromark-extension-mdx-expression@npm:3.0.1" dependencies: "@types/estree": "npm:^1.0.0" - micromark-factory-mdx-expression: "npm:^1.0.0" - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-events-to-acorn: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/99e2997a54caafc4258979c0591b3fe8e31018079df833d559768092fec41e57a71225d423f4179cea4e8bc1af2f52f5c9ae640673619d8fe142ded875240da3 + devlop: "npm:^1.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/4d8cc5353b083b06bd51c98389de9c198261a5b2b440b75e85000a18d10511f21ba77538d6dfde0e0589df9de3fba9a1d14c2448d30c92d6b461c26d86e397f4 languageName: node linkType: hard -"micromark-extension-mdx-jsx@npm:^1.0.0": - version: 1.0.5 - resolution: "micromark-extension-mdx-jsx@npm:1.0.5" +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-mdx-jsx@npm:3.0.2" dependencies: - "@types/acorn": "npm:^4.0.0" "@types/estree": "npm:^1.0.0" - estree-util-is-identifier-name: "npm:^2.0.0" - micromark-factory-mdx-expression: "npm:^1.0.0" - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/1b4bfbe60b9cabfabfb870f70ded8da0caacbaa3be6bdf07f6db25cc5a14c6bc970c34c60e5c80da1e97766064a117feb8160b6d661d69e530a4cc7ec97305de + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/5693b2e51934ac29a6aab521eaa2151f891d1fe092550bbd4ce24e4dd7567c1421a54f5e585a57dfa1769a79570f6df57ddd7a98bf0889dd11d495847a266dd7 languageName: node linkType: hard -"micromark-extension-mdx-md@npm:^1.0.0": - version: 1.0.1 - resolution: "micromark-extension-mdx-md@npm:1.0.1" +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" dependencies: - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/9ad70b3a5e842fd7ebd93c8c48a32fd3d05fe77be06a08ef32462ea53e97d8f297e2c1c4b30a6929dbd05125279fe98bb04e9cc0bb686c691bdcf7d36c6e51b0 + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bae91c61273de0e5ba80a980c03470e6cd9d7924aa936f46fbda15d780704d9386e945b99eda200e087b96254fbb4271a9545d5ce02676cd6ae67886a8bf82df languageName: node linkType: hard -"micromark-extension-mdxjs-esm@npm:^1.0.0": - version: 1.0.5 - resolution: "micromark-extension-mdxjs-esm@npm:1.0.5" +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" dependencies: "@types/estree": "npm:^1.0.0" - micromark-core-commonmark: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-events-to-acorn: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - unist-util-position-from-estree: "npm:^1.1.0" - uvu: "npm:^0.5.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/612028bced78e882641a43c78fc4813a573b383dc0a7b90db75ed88b37bf5b5997dc7ead4a1011315b34f17bc76b7f4419de6ad9532a088102ab1eea0245d380 - languageName: node - linkType: hard - -"micromark-extension-mdxjs@npm:^1.0.0": - version: 1.0.1 - resolution: "micromark-extension-mdxjs@npm:1.0.1" - dependencies: - acorn: "npm:^8.0.0" - acorn-jsx: "npm:^5.0.0" - micromark-extension-mdx-expression: "npm:^1.0.0" - micromark-extension-mdx-jsx: "npm:^1.0.0" - micromark-extension-mdx-md: "npm:^1.0.0" - micromark-extension-mdxjs-esm: "npm:^1.0.0" - micromark-util-combine-extensions: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/3f123e4afea9674c96934c9ea6a057ec9e5584992c50c36c173a2e331d272b1f4e2a8552364a0e2cb50703d0218831fdae1a17b563f0009aac6a35350e6a7b77 + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/13e3f726495a960650cdedcba39198ace5bdc953ccb12c14d71fc9ed9bb88e40cc3ba9231e973f6984da3b3573e7ddb23ce409f7c16f52a8d57b608bf46c748d languageName: node linkType: hard -"micromark-factory-destination@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-factory-destination@npm:1.1.0" +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/71ebd9089bf0c9689b98ef42215c04032ae2701ae08c3546b663628553255dca18e5310dbdacddad3acd8de4f12a789835fff30dadc4da3c4e30387a75e6b488 + acorn: "npm:^8.0.0" + acorn-jsx: "npm:^5.0.0" + micromark-extension-mdx-expression: "npm:^3.0.0" + micromark-extension-mdx-jsx: "npm:^3.0.0" + micromark-extension-mdx-md: "npm:^2.0.0" + micromark-extension-mdxjs-esm: "npm:^3.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/fd84f036ddad0aabbc12e7f1b3e9dcfe31573bbc413c5ae903779ef0366d7a4c08193547e7ba75718c9f45654e45f52e575cfc2f23a5f89205a8a70d9a506aea languageName: node linkType: hard -"micromark-factory-label@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-factory-label@npm:1.1.0" +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-destination@npm:2.0.1" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/5e2cd2d8214bb92a34dfcedf9c7aecf565e3648650a3a6a0495ededf15f2318dd214dc069e3026402792cd5839d395313f8ef9c2e86ca34a8facaa0f75a77753 + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bbafcf869cee5bf511161354cb87d61c142592fbecea051000ff116068dc85216e6d48519d147890b9ea5d7e2864a6341c0c09d9948c203bff624a80a476023c languageName: node linkType: hard -"micromark-factory-mdx-expression@npm:^1.0.0": - version: 1.0.9 - resolution: "micromark-factory-mdx-expression@npm:1.0.9" +"micromark-factory-label@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-label@npm:2.0.1" dependencies: - "@types/estree": "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-events-to-acorn: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - unist-util-position-from-estree: "npm:^1.0.0" - uvu: "npm:^0.5.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/b28bd8e072f37ca91446fe8d113e4ae64baaef013b0cde4aa224add0ee40963ce3584b9709f7662d30491f875ae7104b897d37efa26cdaecf25082ed5bac7b8c + devlop: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/0137716b4ecb428114165505e94a2f18855c8bbea21b07a8b5ce514b32a595ed789d2b967125718fc44c4197ceaa48f6609d58807a68e778138d2e6b91b824e8 languageName: node linkType: hard -"micromark-factory-space@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-factory-space@npm:1.1.0" +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-factory-mdx-expression@npm:2.0.3" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/3da81187ce003dd4178c7adc4674052fb8befc8f1a700ae4c8227755f38581a4ae963866dc4857488d62d1dc9837606c9f2f435fa1332f62a0f1c49b83c6a822 + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/a6004ef6272dd01a5d718f2affd7bfb5e08f0849340f5fd96ac823fbc5e9d3b3343acedda50805873ccda5e3b8af4d5fbb302abc874544044ac90c217345cf97 languageName: node linkType: hard -"micromark-factory-title@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-factory-title@npm:1.1.0" +"micromark-factory-space@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-space@npm:2.0.1" dependencies: - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/cf8c687d1d5c3928846a4791d4a7e2f1d7bdd2397051e20d60f06b7565a48bf85198ab6f85735e997ab3f0cbb80b8b6391f4f7ebc0aae2f2f8c3a08541257bf6 + micromark-util-character: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f9ed43f1c0652d8d898de0ac2be3f77f776fffe7dd96bdbba1e02d7ce33d3853c6ff5daa52568fc4fa32cdf3a62d86b85ead9b9189f7211e1d69ff2163c450fb languageName: node linkType: hard -"micromark-factory-whitespace@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-factory-whitespace@npm:1.1.0" +"micromark-factory-title@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-title@npm:2.0.1" dependencies: - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/7248cc4534f9befb38c6f398b6e38efd3199f1428fc214c9cb7ed5b6e9fa7a82c0d8cdfa9bcacde62887c9a7c8c46baf5c318b2ae8f701afbccc8ad702e92dce + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/e72fad8d6e88823514916890099a5af20b6a9178ccf78e7e5e05f4de99bb8797acb756257d7a3a57a53854cb0086bf8aab15b1a9e9db8982500dd2c9ff5948b6 languageName: node linkType: hard -"micromark-util-character@npm:^1.0.0": - version: 1.2.0 - resolution: "micromark-util-character@npm:1.2.0" +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-whitespace@npm:2.0.1" dependencies: - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/3390a675a50731b58a8e5493cd802e190427f10fa782079b455b00f6b54e406e36882df7d4a3bd32b709f7a2c3735b4912597ebc1c0a99566a8d8d0b816e2cd4 + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/20a1ec58698f24b766510a309b23a10175034fcf1551eaa9da3adcbed3e00cd53d1ebe5f030cf873f76a1cec3c34eb8c50cc227be3344caa9ed25d56cf611224 languageName: node linkType: hard @@ -2649,61 +3418,54 @@ __metadata: languageName: node linkType: hard -"micromark-util-chunked@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-chunked@npm:1.1.0" +"micromark-util-chunked@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-chunked@npm:2.0.1" dependencies: - micromark-util-symbol: "npm:^1.0.0" - checksum: 10c0/59534cf4aaf481ed58d65478d00eae0080df9b5816673f79b5ddb0cea263e5a9ee9cbb6cc565daf1eb3c8c4ff86fc4e25d38a0577539655cda823a4249efd358 + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/b68c0c16fe8106949537bdcfe1be9cf36c0ccd3bc54c4007003cb0984c3750b6cdd0fd77d03f269a3382b85b0de58bde4f6eedbe7ecdf7244759112289b1ab56 languageName: node linkType: hard -"micromark-util-classify-character@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-classify-character@npm:1.1.0" +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-classify-character@npm:2.0.1" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/3266453dc0fdaf584e24c9b3c91d1ed180f76b5856699c51fd2549305814fcab7ec52afb4d3e83d002a9115cd2d2b2ffdc9c0b38ed85120822bf515cc00636ec + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/8a02e59304005c475c332f581697e92e8c585bcd45d5d225a66c1c1b14ab5a8062705188c2ccec33cc998d33502514121478b2091feddbc751887fc9c290ed08 languageName: node linkType: hard -"micromark-util-combine-extensions@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-combine-extensions@npm:1.1.0" +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-combine-extensions@npm:2.0.1" dependencies: - micromark-util-chunked: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/0bc572fab3fe77f533c29aa1b75cb847b9fc9455f67a98623ef9740b925c0b0426ad9f09bbb56f1e844ea9ebada7873d1f06d27f7c979a917692b273c4b69e31 + micromark-util-chunked: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f15e282af24c8372cbb10b9b0b3e2c0aa681fea0ca323a44d6bc537dc1d9382c819c3689f14eaa000118f5a163245358ce6276b2cda9a84439cdb221f5d86ae7 languageName: node linkType: hard -"micromark-util-decode-numeric-character-reference@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-decode-numeric-character-reference@npm:1.1.0" +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2" dependencies: - micromark-util-symbol: "npm:^1.0.0" - checksum: 10c0/64ef2575e3fc2426976c19e16973348f20b59ddd5543f1467ac2e251f29e0a91f12089703d29ae985b0b9a408ee0d72f06d04ed3920811aa2402aabca3bdf9e4 + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/9c8a9f2c790e5593ffe513901c3a110e9ec8882a08f466da014112a25e5059b51551ca0aeb7ff494657d86eceb2f02ee556c6558b8d66aadc61eae4a240da0df languageName: node linkType: hard -"micromark-util-decode-string@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-decode-string@npm:1.1.0" +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-string@npm:2.0.1" dependencies: decode-named-character-reference: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-decode-numeric-character-reference: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - checksum: 10c0/757a0aaa5ad6c50c7480bd75371d407ac75f5022cd4404aba07adadf1448189502aea9bb7b2d09d25e18745e0abf72b95506b6beb184bcccabe919e48e3a5df7 - languageName: node - linkType: hard - -"micromark-util-encode@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-encode@npm:1.1.0" - checksum: 10c0/9878c9bc96999d45626a7597fffac85348ea842dce75d2417345cbf070a9941c62477bd0963bef37d4f0fd29f2982be6ddf416d62806f00ccb334af9d6ee87e7 + micromark-util-character: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/f24d75b2e5310be6e7b6dee532e0d17d3bf46996841d6295f2a9c87a2046fff4ab603c52ab9d7a7a6430a8b787b1574ae895849c603d262d1b22eef71736b5cb languageName: node linkType: hard @@ -2714,55 +3476,43 @@ __metadata: languageName: node linkType: hard -"micromark-util-events-to-acorn@npm:^1.0.0": - version: 1.2.3 - resolution: "micromark-util-events-to-acorn@npm:1.2.3" +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-util-events-to-acorn@npm:2.0.3" dependencies: - "@types/acorn": "npm:^4.0.0" "@types/estree": "npm:^1.0.0" - "@types/unist": "npm:^2.0.0" - estree-util-visit: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/cd3af7365806a0b22efb83cb7726cb835725c0bc22e04f7ea83f2f38a09e7132413eff6ab6d53652b969a7ec30e442731c3abbbe8a74dc2081c51fd10223c269 - languageName: node - linkType: hard - -"micromark-util-html-tag-name@npm:^1.0.0": - version: 1.2.0 - resolution: "micromark-util-html-tag-name@npm:1.2.0" - checksum: 10c0/15421869678d36b4fe51df453921e8186bff514a14e9f79f32b7e1cdd67874e22a66ad34a7f048dd132cbbbfc7c382ae2f777a2bfd1f245a47705dc1c6d4f199 + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/a4e0716e943ffdd16a918edf51d4f8291ec2692f5c4d04693dbef3358716fba891f288197afd102c14f4d98dac09d52351046ab7aad1d50b74677bdd5fa683c0 languageName: node linkType: hard -"micromark-util-normalize-identifier@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-normalize-identifier@npm:1.1.0" - dependencies: - micromark-util-symbol: "npm:^1.0.0" - checksum: 10c0/a9657321a2392584e4d978061882117a84db7d2c2c1c052c0f5d25da089d463edb9f956d5beaf7f5768984b6f72d046d59b5972951ec7bf25397687a62b8278a +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-html-tag-name@npm:2.0.1" + checksum: 10c0/ae80444db786fde908e9295f19a27a4aa304171852c77414516418650097b8afb401961c9edb09d677b06e97e8370cfa65638dde8438ebd41d60c0a8678b85b9 languageName: node linkType: hard -"micromark-util-resolve-all@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-resolve-all@npm:1.1.0" +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-normalize-identifier@npm:2.0.1" dependencies: - micromark-util-types: "npm:^1.0.0" - checksum: 10c0/b5c95484c06e87bbbb60d8430eb030a458733a5270409f4c67892d1274737087ca6a7ca888987430e57cf1dcd44bb16390d3b3936a2bf07f7534ec8f52ce43c9 + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/5299265fa360769fc499a89f40142f10a9d4a5c3dd8e6eac8a8ef3c2e4a6570e4c009cf75ea46dce5ee31c01f25587bde2f4a5cc0a935584ae86dd857f2babbd languageName: node linkType: hard -"micromark-util-sanitize-uri@npm:^1.0.0, micromark-util-sanitize-uri@npm:^1.1.0": - version: 1.2.0 - resolution: "micromark-util-sanitize-uri@npm:1.2.0" +"micromark-util-resolve-all@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-resolve-all@npm:2.0.1" dependencies: - micromark-util-character: "npm:^1.0.0" - micromark-util-encode: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - checksum: 10c0/dbdb98248e9f0408c7a00f1c1cd805775b41d213defd659533835f34b38da38e8f990bf7b3f782e96bffbc549aec9c3ecdab197d4ad5adbfe08f814a70327b6e + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bb6ca28764696bb479dc44a2d5b5fe003e7177aeae1d6b0d43f24cc223bab90234092d9c3ce4a4d2b8df095ccfd820537b10eb96bb7044d635f385d65a4c984a languageName: node linkType: hard @@ -2777,22 +3527,15 @@ __metadata: languageName: node linkType: hard -"micromark-util-subtokenize@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-subtokenize@npm:1.1.0" +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" dependencies: - micromark-util-chunked: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.0" - uvu: "npm:^0.5.0" - checksum: 10c0/f292b1b162845db50d36255c9d4c4c6d47931fbca3ac98a80c7e536d2163233fd662f8ca0479ee2b80f145c66a1394c7ed17dfce801439741211015e77e3901e - languageName: node - linkType: hard - -"micromark-util-symbol@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-symbol@npm:1.1.0" - checksum: 10c0/10ceaed33a90e6bfd3a5d57053dbb53f437d4809cc11430b5a09479c0ba601577059be9286df4a7eae6e350a60a2575dc9fa9d9872b5b8d058c875e075c33803 + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bee69eece4393308e657c293ba80d92ebcb637e5f55e21dcf9c3fa732b91a8eda8ac248d76ff375e675175bfadeae4712e5158ef97eef1111789da1ce7ab5067 languageName: node linkType: hard @@ -2803,13 +3546,6 @@ __metadata: languageName: node linkType: hard -"micromark-util-types@npm:^1.0.0, micromark-util-types@npm:^1.0.1": - version: 1.1.0 - resolution: "micromark-util-types@npm:1.1.0" - checksum: 10c0/a9749cb0a12a252ff536baabcb7012421b6fad4d91a5fdd80d7b33dc7b4c22e2d0c4637dfe5b902d00247fe6c9b01f4a24fce6b572b16ccaa4da90e6ce2a11e4 - languageName: node - linkType: hard - "micromark-util-types@npm:^2.0.0": version: 2.0.0 resolution: "micromark-util-types@npm:2.0.0" @@ -2817,35 +3553,73 @@ __metadata: languageName: node linkType: hard -"micromark@npm:^3.0.0": - version: 3.2.0 - resolution: "micromark@npm:3.2.0" +"micromark@npm:^4.0.0": + version: 4.0.2 + resolution: "micromark@npm:4.0.2" dependencies: "@types/debug": "npm:^4.0.0" debug: "npm:^4.0.0" decode-named-character-reference: "npm:^1.0.0" - micromark-core-commonmark: "npm:^1.0.1" - micromark-factory-space: "npm:^1.0.0" - micromark-util-character: "npm:^1.0.0" - micromark-util-chunked: "npm:^1.0.0" - micromark-util-combine-extensions: "npm:^1.0.0" - micromark-util-decode-numeric-character-reference: "npm:^1.0.0" - micromark-util-encode: "npm:^1.0.0" - micromark-util-normalize-identifier: "npm:^1.0.0" - micromark-util-resolve-all: "npm:^1.0.0" - micromark-util-sanitize-uri: "npm:^1.0.0" - micromark-util-subtokenize: "npm:^1.0.0" - micromark-util-symbol: "npm:^1.0.0" - micromark-util-types: "npm:^1.0.1" - uvu: "npm:^0.5.0" - checksum: 10c0/f243e805d1b3cc699fddae2de0b1492bc82462f1a709d7ae5c82039f88b1e009c959100184717e748be057b5f88603289d5681679a4e6fbabcd037beb34bc744 - languageName: node - linkType: hard - -"mri@npm:^1.1.0": - version: 1.2.0 - resolution: "mri@npm:1.2.0" - checksum: 10c0/a3d32379c2554cf7351db6237ddc18dc9e54e4214953f3da105b97dc3babe0deb3ffe99cf409b38ea47cc29f9430561ba6b53b24ab8f9ce97a4b50409e4a50e7 + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/07462287254219d6eda6eac8a3cebaff2994e0575499e7088027b825105e096e4f51e466b14b2a81b71933a3b6c48ee069049d87bc2c2127eee50d9cc69e8af6 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + +"mimic-fn@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-fn@npm:4.0.0" + checksum: 10c0/de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf + languageName: node + linkType: hard + +"minimatch@npm:^10.0.1": + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" + dependencies: + brace-expansion: "npm:^5.0.2" + checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945 + languageName: node + linkType: hard + +"mj-context-menu@npm:^0.6.1": + version: 0.6.1 + resolution: "mj-context-menu@npm:0.6.1" + checksum: 10c0/2bf3564bb5cbd3915e14417e8df4a4e3013f1e281d431ee1e88976ae6529cc88e6eea7d9b3e217d1d79666f89070c3e1a193383ba9c7bf82d63075e616664ce9 + languageName: node + linkType: hard + +"mlly@npm:^1.7.4, mlly@npm:^1.8.0": + version: 1.8.0 + resolution: "mlly@npm:1.8.0" + dependencies: + acorn: "npm:^8.15.0" + pathe: "npm:^2.0.3" + pkg-types: "npm:^1.3.1" + ufo: "npm:^1.6.1" + checksum: 10c0/f174b844ae066c71e9b128046677868e2e28694f0bbeeffbe760b2a9d8ff24de0748d0fde6fabe706700c1d2e11d3c0d7a53071b5ea99671592fac03364604ab languageName: node linkType: hard @@ -2856,6 +3630,13 @@ __metadata: languageName: node linkType: hard +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + "nanoid@npm:^3.3.6": version: 3.3.7 resolution: "nanoid@npm:3.3.7" @@ -2865,40 +3646,20 @@ __metadata: languageName: node linkType: hard -"next-mdx-remote@npm:^4.2.1": - version: 4.4.1 - resolution: "next-mdx-remote@npm:4.4.1" - dependencies: - "@mdx-js/mdx": "npm:^2.2.1" - "@mdx-js/react": "npm:^2.2.1" - vfile: "npm:^5.3.0" - vfile-matter: "npm:^3.0.1" - peerDependencies: - react: ">=16.x <=18.x" - react-dom: ">=16.x <=18.x" - checksum: 10c0/d48ad271f58312d11f392b0fbd7b2dbc5990cc82fcb6d28f687875a52b28b695c0700b93f197c72910a4c73da0a1fe4867db95315bc2ee7f0fc1743279f41b80 - languageName: node - linkType: hard - -"next-seo@npm:^6.0.0": - version: 6.5.0 - resolution: "next-seo@npm:6.5.0" - peerDependencies: - next: ^8.1.1-canary.54 || >=9.0.0 - react: ">=16.0.0" - react-dom: ">=16.0.0" - checksum: 10c0/f2403356aa7fa91314fb91f9b1f7a3436ff76307e2345faec67132e8c0546312f4c6262bc10db28339612c1777dc07ba566bd407262d662f2e417932563837a6 +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b languageName: node linkType: hard -"next-themes@npm:^0.2.1": - version: 0.2.1 - resolution: "next-themes@npm:0.2.1" +"next-themes@npm:^0.4.0": + version: 0.4.6 + resolution: "next-themes@npm:0.4.6" peerDependencies: - next: "*" - react: "*" - react-dom: "*" - checksum: 10c0/979dec0a2de049ce7d1b5da835e7f7dc3b7ec83ba9e464348f497a52a6a6e5b5c395c97f071f66a63f50f22cce89fb6d19061ec7e75643b0eab215b21794bde7 + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + checksum: 10c0/83590c11d359ce7e4ced14f6ea9dd7a691d5ce6843fe2dc520fc27e29ae1c535118478d03e7f172609c41b1ef1b8da6b8dd2d2acd6cd79cac1abbdbd5b99f2c4 languageName: node linkType: hard @@ -2963,106 +3724,133 @@ __metadata: languageName: node linkType: hard -"nextra-theme-docs@npm:^2.13.4": - version: 2.13.4 - resolution: "nextra-theme-docs@npm:2.13.4" +"nextra-theme-docs@npm:^4": + version: 4.6.1 + resolution: "nextra-theme-docs@npm:4.6.1" dependencies: - "@headlessui/react": "npm:^1.7.17" - "@popperjs/core": "npm:^2.11.8" - clsx: "npm:^2.0.0" - escape-string-regexp: "npm:^5.0.0" - flexsearch: "npm:^0.7.31" - focus-visible: "npm:^5.2.0" - git-url-parse: "npm:^13.1.0" - intersection-observer: "npm:^0.12.2" - match-sorter: "npm:^6.3.1" - next-seo: "npm:^6.0.0" - next-themes: "npm:^0.2.1" + "@headlessui/react": "npm:^2.1.2" + clsx: "npm:^2.1.0" + next-themes: "npm:^0.4.0" + react-compiler-runtime: "npm:^19.1.0-rc.2" scroll-into-view-if-needed: "npm:^3.1.0" - zod: "npm:^3.22.3" + zod: "npm:^4.1.12" + zustand: "npm:^5.0.1" peerDependencies: - next: ">=9.5.3" - nextra: 2.13.4 - react: ">=16.13.1" - react-dom: ">=16.13.1" - checksum: 10c0/3c8711391a771878370db9e71296d700f30fdcc31a1c739eac1f586b12b0d7960326f5e4a75e1b7c3ffc16734bc2c98347b001734e6e607f0f89efa2ac0e84d2 + next: ">=14" + nextra: 4.6.1 + react: ">=18" + react-dom: ">=18" + checksum: 10c0/53b217fdf3207493461be660a4ab3c807b5149f2019abd00d1a0436d2edd06c426e6fde2bee0912b3f0c5b5f949ddbc2bc78fcf15c96e2cf53e2f0e3fba24a62 languageName: node linkType: hard -"nextra@npm:^2.13.4": - version: 2.13.4 - resolution: "nextra@npm:2.13.4" +"nextra@npm:^4": + version: 4.6.1 + resolution: "nextra@npm:4.6.1" dependencies: - "@headlessui/react": "npm:^1.7.17" - "@mdx-js/mdx": "npm:^2.3.0" - "@mdx-js/react": "npm:^2.3.0" + "@formatjs/intl-localematcher": "npm:^0.6.0" + "@headlessui/react": "npm:^2.1.2" + "@mdx-js/mdx": "npm:^3.0.0" "@napi-rs/simple-git": "npm:^0.1.9" - "@theguild/remark-mermaid": "npm:^0.0.5" - "@theguild/remark-npm2yarn": "npm:^0.2.0" - clsx: "npm:^2.0.0" + "@shikijs/twoslash": "npm:^3.2.1" + "@theguild/remark-mermaid": "npm:^0.3.0" + "@theguild/remark-npm2yarn": "npm:^0.3.2" + better-react-mathjax: "npm:^2.3.0" + clsx: "npm:^2.1.0" + estree-util-to-js: "npm:^2.0.0" + estree-util-value-to-estree: "npm:^3.3.3" + fast-glob: "npm:^3.3.2" github-slugger: "npm:^2.0.0" - graceful-fs: "npm:^4.2.11" - gray-matter: "npm:^4.0.3" - katex: "npm:^0.16.9" - lodash.get: "npm:^4.4.2" - next-mdx-remote: "npm:^4.2.1" - p-limit: "npm:^3.1.0" + hast-util-to-estree: "npm:^3.1.0" + katex: "npm:^0.16.21" + mdast-util-from-markdown: "npm:^2.0.1" + mdast-util-gfm: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.2.0" + negotiator: "npm:^1.0.0" + react-compiler-runtime: "npm:^19.1.0-rc.2" + react-medium-image-zoom: "npm:^5.2.12" rehype-katex: "npm:^7.0.0" - rehype-pretty-code: "npm:0.9.11" + rehype-pretty-code: "npm:0.14.1" rehype-raw: "npm:^7.0.0" - remark-gfm: "npm:^3.0.1" - remark-math: "npm:^5.1.1" - remark-reading-time: "npm:^2.0.1" - shiki: "npm:^0.14.3" - slash: "npm:^3.0.0" - title: "npm:^3.5.3" + remark-frontmatter: "npm:^5.0.0" + remark-gfm: "npm:^4.0.0" + remark-math: "npm:^6.0.0" + remark-reading-time: "npm:^2.0.2" + remark-smartypants: "npm:^3.0.0" + server-only: "npm:^0.0.1" + shiki: "npm:^3.2.1" + slash: "npm:^5.1.0" + title: "npm:^4.0.1" + ts-morph: "npm:^27.0.0" unist-util-remove: "npm:^4.0.0" unist-util-visit: "npm:^5.0.0" - zod: "npm:^3.22.3" + unist-util-visit-children: "npm:^3.0.0" + yaml: "npm:^2.3.2" + zod: "npm:^4.1.12" peerDependencies: - next: ">=9.5.3" - react: ">=16.13.1" - react-dom: ">=16.13.1" - checksum: 10c0/68941552f83639ae818e27b1cfbfef4031362c95bb5c80188cabe29ccd700e0889e20d90cde621d79e151fdf02713b096cfaa42b9304946133b82c223d2e01e3 + next: ">=14" + react: ">=18" + react-dom: ">=18" + checksum: 10c0/67b39c8c153afd83043b4edf54ef98472c37d37fcf06614b14e10e712cebdc02f4ca9d0f231b75a5ebc64db124a2794fc911068bccf591cdaf0941cd07deb5b9 languageName: node linkType: hard -"non-layered-tidy-tree-layout@npm:^2.0.2": - version: 2.0.2 - resolution: "non-layered-tidy-tree-layout@npm:2.0.2" - checksum: 10c0/73856e9959667193e733a7ef2b06a69421f4d9d7428a3982ce39763cd979a04eed0007f2afb3414afa3f6dc4dc6b5c850c2af9aa71a974475236a465093ec9c7 +"nlcst-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "nlcst-to-string@npm:4.0.0" + dependencies: + "@types/nlcst": "npm:^2.0.0" + checksum: 10c0/a192c8b3365a7c076812004e72ae5b4a1734e582be2a6f3c062f3beecf18868a9fe2d1bad870bfead320fb39830f2c4f3752e5ae6574c4e59157126fd1ddba70 languageName: node linkType: hard -"npm-run-path@npm:^2.0.0": - version: 2.0.2 - resolution: "npm-run-path@npm:2.0.2" +"npm-run-path@npm:^5.1.0": + version: 5.3.0 + resolution: "npm-run-path@npm:5.3.0" dependencies: - path-key: "npm:^2.0.0" - checksum: 10c0/95549a477886f48346568c97b08c4fda9cdbf7ce8a4fbc2213f36896d0d19249e32d68d7451bdcbca8041b5fba04a6b2c4a618beaf19849505c05b700740f1de + path-key: "npm:^4.0.0" + checksum: 10c0/124df74820c40c2eb9a8612a254ea1d557ddfab1581c3e751f825e3e366d9f00b0d76a3c94ecd8398e7f3eee193018622677e95816e8491f0797b21e30b2deba languageName: node linkType: hard -"npm-to-yarn@npm:^2.1.0": - version: 2.2.1 - resolution: "npm-to-yarn@npm:2.2.1" - checksum: 10c0/65c696a3e595facad802b6b13c04e504806ea88fd4f87ab758f8042c19f65b4c4822815a47095df944b0809a95e574c27323c33cca5533f8454515eaa6e14fac +"npm-to-yarn@npm:^3.0.0": + version: 3.0.1 + resolution: "npm-to-yarn@npm:3.0.1" + checksum: 10c0/f0a72bfc0ed2ad50c5995511ff6442520d259aee5a58e1b0914572a33d29c07090a684a1d8ce95d2399dfe9bc51e649e8d029b0118ecf941f40212053693caca languageName: node linkType: hard -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 +"onetime@npm:^6.0.0": + version: 6.0.0 + resolution: "onetime@npm:6.0.0" + dependencies: + mimic-fn: "npm:^4.0.0" + checksum: 10c0/4eef7c6abfef697dd4479345a4100c382d73c149d2d56170a54a07418c50816937ad09500e1ed1e79d235989d073a9bade8557122aee24f0576ecde0f392bb6c languageName: node linkType: hard -"p-limit@npm:^3.1.0": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" +"oniguruma-parser@npm:^0.12.1": + version: 0.12.1 + resolution: "oniguruma-parser@npm:0.12.1" + checksum: 10c0/b843ea54cda833efb19f856314afcbd43e903ece3de489ab78c527ddec84859208052557daa9fad4bdba89ebdd15b0cc250de86b3daf8c7cbe37bac5a6a185d3 + languageName: node + linkType: hard + +"oniguruma-to-es@npm:^4.3.4": + version: 4.3.4 + resolution: "oniguruma-to-es@npm:4.3.4" dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + oniguruma-parser: "npm:^0.12.1" + regex: "npm:^6.0.1" + regex-recursion: "npm:^6.0.2" + checksum: 10c0/fb58459f50db71c2c4785205636186bfbb125b094c4275512a8f41f123ed3fbf61f37c455f4360ef14a56c693981aecd7da3ae2c05614a222e872c4643b463fc + languageName: node + linkType: hard + +"package-manager-detector@npm:^1.3.0": + version: 1.6.0 + resolution: "package-manager-detector@npm:1.6.0" + checksum: 10c0/6419d0b840be64fd45bcdcb7a19f09b81b65456d5e7f7a3daac305a4c90643052122f6ac0308afe548ffee75e36148532a2002ea9d292754f1e385aa2e1ea03b languageName: node linkType: hard @@ -3082,28 +3870,24 @@ __metadata: languageName: node linkType: hard -"parse-numeric-range@npm:^1.3.0": - version: 1.3.0 - resolution: "parse-numeric-range@npm:1.3.0" - checksum: 10c0/53465afaa92111e86697281b684aa4574427360889cc23a1c215488c06b72441febdbf09f47ab0bef9a0c701e059629f3eebd2fe6fb241a254ad7a7a642aebe8 - languageName: node - linkType: hard - -"parse-path@npm:^7.0.0": +"parse-latin@npm:^7.0.0": version: 7.0.0 - resolution: "parse-path@npm:7.0.0" + resolution: "parse-latin@npm:7.0.0" dependencies: - protocols: "npm:^2.0.0" - checksum: 10c0/e7646f6b998b083bbd40102643d803557ce4ae18ae1704e6cc7ae2525ea7c5400f4a3635aca3244cfe65ce4dd0ff77db1142dde4d080e8a80c364c4b3e8fe8d2 + "@types/nlcst": "npm:^2.0.0" + "@types/unist": "npm:^3.0.0" + nlcst-to-string: "npm:^4.0.0" + unist-util-modify-children: "npm:^4.0.0" + unist-util-visit-children: "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/4232a464f98c41c6680575c54bc2c9b21ac4b82a1f796a871bfef5efa6eddaab9bccf734b08cde6b0a5504ef46a0a14041ddd0bc5d9cc70f73a507f93f610596 languageName: node linkType: hard -"parse-url@npm:^8.1.0": - version: 8.1.0 - resolution: "parse-url@npm:8.1.0" - dependencies: - parse-path: "npm:^7.0.0" - checksum: 10c0/68b95afdf4bbf72e57c7ab66f8757c935fff888f7e2b0f1e06098b4faa19e06b6b743bddaed5bc8df4f0c2de6fc475355d787373b2fdd40092be9e4e4b996648 +"parse-numeric-range@npm:^1.3.0": + version: 1.3.0 + resolution: "parse-numeric-range@npm:1.3.0" + checksum: 10c0/53465afaa92111e86697281b684aa4574427360889cc23a1c215488c06b72441febdbf09f47ab0bef9a0c701e059629f3eebd2fe6fb241a254ad7a7a642aebe8 languageName: node linkType: hard @@ -3116,21 +3900,38 @@ __metadata: languageName: node linkType: hard -"path-key@npm:^2.0.0": - version: 2.0.1 - resolution: "path-key@npm:2.0.1" - checksum: 10c0/dd2044f029a8e58ac31d2bf34c34b93c3095c1481942960e84dd2faa95bbb71b9b762a106aead0646695330936414b31ca0bd862bf488a937ad17c8c5d73b32b +"path-browserify@npm:^1.0.1": + version: 1.0.1 + resolution: "path-browserify@npm:1.0.1" + checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66 languageName: node linkType: hard -"periscopic@npm:^3.0.0": - version: 3.1.0 - resolution: "periscopic@npm:3.1.0" - dependencies: - "@types/estree": "npm:^1.0.0" - estree-walker: "npm:^3.0.0" - is-reference: "npm:^3.0.0" - checksum: 10c0/fb5ce7cd810c49254cdf1cd3892811e6dd1a1dfbdf5f10a0a33fb7141baac36443c4cad4f0e2b30abd4eac613f6ab845c2bc1b7ce66ae9694c7321e6ada5bd96 +"path-data-parser@npm:0.1.0, path-data-parser@npm:^0.1.0": + version: 0.1.0 + resolution: "path-data-parser@npm:0.1.0" + checksum: 10c0/ba22d54669a8bc4a3df27431fe667900685585d1196085b803d0aa4066b83e709bbf2be7c1d2b56e706b49cc698231d55947c22abbfc4843ca424bbf8c985745 + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 + languageName: node + linkType: hard + +"pathe@npm:^2.0.1, pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 languageName: node linkType: hard @@ -3141,6 +3942,48 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + languageName: node + linkType: hard + +"picomatch@npm:^4.0.3": + version: 4.0.3 + resolution: "picomatch@npm:4.0.3" + checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2 + languageName: node + linkType: hard + +"pkg-types@npm:^1.3.1": + version: 1.3.1 + resolution: "pkg-types@npm:1.3.1" + dependencies: + confbox: "npm:^0.1.8" + mlly: "npm:^1.7.4" + pathe: "npm:^2.0.1" + checksum: 10c0/19e6cb8b66dcc66c89f2344aecfa47f2431c988cfa3366bdfdcfb1dd6695f87dcce37fbd90fe9d1605e2f4440b77f391e83c23255347c35cf84e7fd774d7fcea + languageName: node + linkType: hard + +"points-on-curve@npm:0.2.0, points-on-curve@npm:^0.2.0": + version: 0.2.0 + resolution: "points-on-curve@npm:0.2.0" + checksum: 10c0/f0d92343fcc2ad1f48334633e580574c1e0e28038a756133e171e537f270d6d64203feada5ee556e36f448a1b46e0306dee07b30f589f4e3ad720f6ee38ef48c + languageName: node + linkType: hard + +"points-on-path@npm:^0.2.1": + version: 0.2.1 + resolution: "points-on-path@npm:0.2.1" + dependencies: + path-data-parser: "npm:0.1.0" + points-on-curve: "npm:0.2.0" + checksum: 10c0/a7010340f9f196976f61838e767bb7b0b7f6273ab4fb9eb37c61001fe26fbfc3fcd63c96d5e85b9a4ab579213ab366f2ddaaf60e2a9253e2b91a62db33f395ba + languageName: node + linkType: hard + "postcss@npm:8.4.31": version: 8.4.31 resolution: "postcss@npm:8.4.31" @@ -3159,52 +4002,136 @@ __metadata: languageName: node linkType: hard -"protocols@npm:^2.0.0, protocols@npm:^2.0.1": - version: 2.0.1 - resolution: "protocols@npm:2.0.1" - checksum: 10c0/016cc58a596e401004a028a2f7005e3444bf89ee8f606409c411719374d1e8bba0464fc142a065cce0d19f41669b2f7ffe25a8bde4f16ce3b6eb01fabc51f2e7 +"property-information@npm:^7.0.0": + version: 7.1.0 + resolution: "property-information@npm:7.1.0" + checksum: 10c0/e0fe22cff26103260ad0e82959229106563fa115a54c4d6c183f49d88054e489cc9f23452d3ad584179dc13a8b7b37411a5df873746b5e4086c865874bfa968e languageName: node linkType: hard -"pseudomap@npm:^1.0.2": - version: 1.0.2 - resolution: "pseudomap@npm:1.0.2" - checksum: 10c0/5a91ce114c64ed3a6a553aa7d2943868811377388bb31447f9d8028271bae9b05b340fe0b6961a64e45b9c72946aeb0a4ab635e8f7cb3715ffd0ff2beeb6a679 +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 + languageName: node + linkType: hard + +"react-compiler-runtime@npm:^19.1.0-rc.2": + version: 19.1.0-rc.3 + resolution: "react-compiler-runtime@npm:19.1.0-rc.3" + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental + checksum: 10c0/a3f58880bbbda22ef47a4d0d45bd210f2e506bad5d30ca5aa0a8758b71c226d8abb89b3db9b0c1850d5d7c0891763551d2910d16a37da10a8477552b93f40019 + languageName: node + linkType: hard + +"react-dom@npm:^19": + version: 19.2.4 + resolution: "react-dom@npm:19.2.4" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.4 + checksum: 10c0/f0c63f1794dedb154136d4d0f59af00b41907f4859571c155940296808f4b94bf9c0c20633db75b5b2112ec13d8d7dd4f9bf57362ed48782f317b11d05a44f35 + languageName: node + linkType: hard + +"react-medium-image-zoom@npm:^5.2.12": + version: 5.4.1 + resolution: "react-medium-image-zoom@npm:5.4.1" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/513cd9126cd0d54500e6022847e9f8bf70140bf6983fa44fcd1608b264eb30d09d1047abce114173647ebe9a278843b2f76c1b05bf2410c0dc29919ac38c7b45 + languageName: node + linkType: hard + +"react@npm:^19": + version: 19.2.4 + resolution: "react@npm:19.2.4" + checksum: 10c0/cd2c9ff67a720799cc3b38a516009986f7fc4cb8d3e15716c6211cf098d1357ee3e348ab05ad0600042bbb0fd888530ba92e329198c92eafa0994f5213396596 + languageName: node + linkType: hard + +"reading-time@npm:^1.3.0": + version: 1.5.0 + resolution: "reading-time@npm:1.5.0" + checksum: 10c0/0f730852fd4fb99e5f78c5b0cf36ab8c3fa15db96f87d9563843f6fd07a47864273ade539ebb184b785b728cde81a70283aa2d9b80cba5ca03b81868be03cabc languageName: node linkType: hard -"react-dom@npm:^18.3.1": - version: 18.3.1 - resolution: "react-dom@npm:18.3.1" +"recma-build-jsx@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-build-jsx@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-build-jsx: "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/ca30f5163887b44c74682355da2625f7b49f33267699d22247913e513e043650cbdd6a7497cf13c60f09ad9e7bc2bd35bd20853672773c19188569814b56bb04 + languageName: node + linkType: hard + +"recma-jsx@npm:^1.0.0": + version: 1.0.1 + resolution: "recma-jsx@npm:1.0.1" dependencies: - loose-envify: "npm:^1.1.0" - scheduler: "npm:^0.23.2" + acorn-jsx: "npm:^5.0.0" + estree-util-to-js: "npm:^2.0.0" + recma-parse: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + unified: "npm:^11.0.0" peerDependencies: - react: ^18.3.1 - checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/9921b1270581ff133b94678868e665ba0fb6285ee60a6936106bac4899196c2ffb02dde894d9bc088fbf3deacb3e2426a3452e72066bf1203cbefebd7809d93f + languageName: node + linkType: hard + +"recma-parse@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-parse@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + esast-util-from-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/37c0990859a562d082e02d475ca5f4c8ef0840d285270f6699fe888cbb06260f97eb098585eda4aae416182c207fd19cf05e4f0b2dcf55cbf81dde4406d95545 + languageName: node + linkType: hard + +"recma-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-stringify@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-to-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/c2ed4c0e8cf8a09aedcd47c5d016d47f6e1ff6c2d4b220e2abaf1b77713bf404756af2ea3ea7999aec5862e8825aff035edceb370c7fd8603a7e9da03bd6987e languageName: node linkType: hard -"react@npm:^18.3.1": - version: 18.3.1 - resolution: "react@npm:18.3.1" +"regex-recursion@npm:^6.0.2": + version: 6.0.2 + resolution: "regex-recursion@npm:6.0.2" dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 + regex-utilities: "npm:^2.3.0" + checksum: 10c0/68e8b6889680e904b75d7f26edaf70a1a4dc1087406bff53face4c2929d918fd77c72223843fe816ac8ed9964f96b4160650e8d5909e26a998c6e9de324dadb1 languageName: node linkType: hard -"reading-time@npm:^1.3.0": - version: 1.5.0 - resolution: "reading-time@npm:1.5.0" - checksum: 10c0/0f730852fd4fb99e5f78c5b0cf36ab8c3fa15db96f87d9563843f6fd07a47864273ade539ebb184b785b728cde81a70283aa2d9b80cba5ca03b81868be03cabc +"regex-utilities@npm:^2.3.0": + version: 2.3.0 + resolution: "regex-utilities@npm:2.3.0" + checksum: 10c0/78c550a80a0af75223244fff006743922591bd8f61d91fef7c86b9b56cf9bbf8ee5d7adb6d8991b5e304c57c90103fc4818cf1e357b11c6c669b782839bd7893 languageName: node linkType: hard -"regenerator-runtime@npm:^0.14.0": - version: 0.14.1 - resolution: "regenerator-runtime@npm:0.14.1" - checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 +"regex@npm:^6.0.1": + version: 6.1.0 + resolution: "regex@npm:6.1.0" + dependencies: + regex-utilities: "npm:^2.3.0" + checksum: 10c0/6e0ee2a1c17d5a66dc1120dfc51899dedf6677857e83a0df4d5a822ebb8645a54a079772efc1ade382b67aad35e4e22b5bd2d33c05ed28b0e000f8f57eb0aec1 languageName: node linkType: hard @@ -3223,16 +4150,30 @@ __metadata: languageName: node linkType: hard -"rehype-pretty-code@npm:0.9.11": - version: 0.9.11 - resolution: "rehype-pretty-code@npm:0.9.11" +"rehype-parse@npm:^9.0.0": + version: 9.0.1 + resolution: "rehype-parse@npm:9.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-from-html: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/efa9ca17673fe70e2d322a1d262796bbed5f6a89382f8f8393352bbd6f6bbf1d4d1d050984b86ff9cb6c0fa2535175ab0829e53c94b1e38fc3c158e6c0ad90bc + languageName: node + linkType: hard + +"rehype-pretty-code@npm:0.14.1": + version: 0.14.1 + resolution: "rehype-pretty-code@npm:0.14.1" dependencies: - "@types/hast": "npm:^2.0.0" - hash-obj: "npm:^4.0.0" + "@types/hast": "npm:^3.0.4" + hast-util-to-string: "npm:^3.0.0" parse-numeric-range: "npm:^1.3.0" + rehype-parse: "npm:^9.0.0" + unified: "npm:^11.0.5" + unist-util-visit: "npm:^5.0.0" peerDependencies: - shiki: "*" - checksum: 10c0/10d9b87df6b9a963f6e650b90908347e6cce8f521bbc220ee3a101e82025d7721e2c108d90922f1a16f9d08a1b18f898ec241a12a12f5e931548e3fb528039d9 + shiki: ^1.0.0 || ^2.0.0 || ^3.0.0 + checksum: 10c0/9f51a965edfd49d086f6421d13fa4725e59c891187fcb82aba0fe471425058af3b98210cedf2a9790e85575d1bd6d817ee88bf007628123e7878636c2c00bb1a languageName: node linkType: hard @@ -3247,79 +4188,174 @@ __metadata: languageName: node linkType: hard -"remark-gfm@npm:^3.0.1": - version: 3.0.1 - resolution: "remark-gfm@npm:3.0.1" +"rehype-recma@npm:^1.0.0": + version: 1.0.0 + resolution: "rehype-recma@npm:1.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-gfm: "npm:^2.0.0" - micromark-extension-gfm: "npm:^2.0.0" - unified: "npm:^10.0.0" - checksum: 10c0/53c4e82204f82f81949a170efdeb49d3c45137b7bca06a7ff857a483aac1a44b55ef0de8fb1bbe4f1292f2a378058e2e42e644f2c61f3e0cdc3e56afa4ec2a2c + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + hast-util-to-estree: "npm:^3.0.0" + checksum: 10c0/be60d7433a7f788a14f41da3e93ba9d9272c908ddef47757026cc4bbcc912f6301d56810349adf876d294a8d048626a0dbf6988aaa574afbfc29eac1ddc1eb74 languageName: node linkType: hard -"remark-math@npm:^5.1.1": - version: 5.1.1 - resolution: "remark-math@npm:5.1.1" +"remark-frontmatter@npm:^5.0.0": + version: 5.0.0 + resolution: "remark-frontmatter@npm:5.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-math: "npm:^2.0.0" - micromark-extension-math: "npm:^2.0.0" - unified: "npm:^10.0.0" - checksum: 10c0/e61e314398e65d1ef9343cce37bdb8e94697772d53f1b9e48f815cece35033b4d41db81766696135558c6de40f2ad86877b49891daec6c7b1453dba0e034a9dc + "@types/mdast": "npm:^4.0.0" + mdast-util-frontmatter: "npm:^2.0.0" + micromark-extension-frontmatter: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/102325d5edbcf30eaf74de8a0a6e03096cc2370dfef19080fd2dd208f368fbb2323388751ac9931a1aa38a4f2828fa4bad6c52dc5249dcadcd34861693b52bf9 languageName: node linkType: hard -"remark-mdx@npm:^2.0.0": - version: 2.3.0 - resolution: "remark-mdx@npm:2.3.0" +"remark-gfm@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-gfm@npm:4.0.1" dependencies: - mdast-util-mdx: "npm:^2.0.0" - micromark-extension-mdxjs: "npm:^1.0.0" - checksum: 10c0/2688bbf03094a9cd17cc86afb6cf0270e86ffc696a2fe25ccb1befb84eb0864d281388dc560b585e05e20f94a994c9fa88492430d2ba703a2fef6918bca4c36b + "@types/mdast": "npm:^4.0.0" + mdast-util-gfm: "npm:^3.0.0" + micromark-extension-gfm: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/427ecc6af3e76222662061a5f670a3e4e33ec5fffe2cabf04034da6a3f9a1bda1fc023e838a636385ba314e66e2bebbf017ca61ebea357eb0f5200fe0625a4b7 languageName: node linkType: hard -"remark-parse@npm:^10.0.0": - version: 10.0.2 - resolution: "remark-parse@npm:10.0.2" +"remark-math@npm:^6.0.0": + version: 6.0.0 + resolution: "remark-math@npm:6.0.0" dependencies: - "@types/mdast": "npm:^3.0.0" - mdast-util-from-markdown: "npm:^1.0.0" - unified: "npm:^10.0.0" - checksum: 10c0/30cb8f2790380b1c7370a1c66cda41f33a7dc196b9e440a00e2675037bca55aea868165a8204e0cdbacc27ef4a3bdb7d45879826bd6efa07d9fdf328cb67a332 + "@types/mdast": "npm:^4.0.0" + mdast-util-math: "npm:^3.0.0" + micromark-extension-math: "npm:^3.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/859613c4db194bb6b3c9c063661dc52b8ceda9c5cf3256b42f73d93eb8f38a6d634eb5f976fe094425f6f1035aaf329eb49ada314feb3b2b1073326b6d3aaa02 languageName: node linkType: hard -"remark-reading-time@npm:^2.0.1": - version: 2.0.1 - resolution: "remark-reading-time@npm:2.0.1" +"remark-mdx@npm:^3.0.0": + version: 3.1.1 + resolution: "remark-mdx@npm:3.1.1" + dependencies: + mdast-util-mdx: "npm:^3.0.0" + micromark-extension-mdxjs: "npm:^3.0.0" + checksum: 10c0/3e5585d4c2448d8ac7548b1d148f04b89251ff47fbfc80be1428cecec2fc2530abe30a5da53bb031283f8a78933259df6120c1cd4cc7cc1d43978d508798ba88 + languageName: node + linkType: hard + +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/6eed15ddb8680eca93e04fcb2d1b8db65a743dcc0023f5007265dda558b09db595a087f622062ccad2630953cd5cddc1055ce491d25a81f3317c858348a8dd38 + languageName: node + linkType: hard + +"remark-reading-time@npm:^2.0.2": + version: 2.0.2 + resolution: "remark-reading-time@npm:2.0.2" dependencies: estree-util-is-identifier-name: "npm:^2.0.0" - estree-util-value-to-estree: "npm:^1.3.0" + estree-util-value-to-estree: "npm:^3.3.3" reading-time: "npm:^1.3.0" unist-util-visit: "npm:^3.1.0" - checksum: 10c0/9efab1883a326964822442af234c3e7776596267431edae42ac3717887af60a1cd145d07cb8a0329fb5e4cab92ae4b3ca9dc058ee453139aa2978dc4c56c4527 + checksum: 10c0/d0b1c393e70625bba407887b5df8d1b1a8147069188ffe098e19985fd02bd7422e015a3b9e3b1b5d5a1a79de6b3a68d2c90158b7568226773fea979ac96c8c9c + languageName: node + linkType: hard + +"remark-rehype@npm:^11.0.0": + version: 11.1.2 + resolution: "remark-rehype@npm:11.1.2" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + mdast-util-to-hast: "npm:^13.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/f9eccacfb596d9605581dc05bfad28635d6ded5dd0a18e88af5fd4df0d3fcf9612e1501d4513bc2164d833cfe9636dab20400080b09e53f155c6e1442a1231fb + languageName: node + linkType: hard + +"remark-smartypants@npm:^3.0.0": + version: 3.0.2 + resolution: "remark-smartypants@npm:3.0.2" + dependencies: + retext: "npm:^9.0.0" + retext-smartypants: "npm:^6.0.0" + unified: "npm:^11.0.4" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/661129f6258feb4531c896d0d7013d0cd7835599f7d9c46947ff0cda19c717e2d5a7da28fc72a9d454dd5a5b6308403f0d7a7ec58338865a28c9242a77739b40 + languageName: node + linkType: hard + +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/0cdb37ce1217578f6f847c7ec9f50cbab35df5b9e3903d543e74b405404e67c07defcb23cd260a567b41b769400f6de03c2c3d9cd6ae7a6707d5c8d89ead489f + languageName: node + linkType: hard + +"retext-latin@npm:^4.0.0": + version: 4.0.0 + resolution: "retext-latin@npm:4.0.0" + dependencies: + "@types/nlcst": "npm:^2.0.0" + parse-latin: "npm:^7.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/51530be66db9ef6ab8e9cda5dd0598377ff4321481d6a941bf70dac16fa6e9123ff7d8ff093a05c30a3e00e282e37094b845b6130a8005a3cb7186a961ab99cb + languageName: node + linkType: hard + +"retext-smartypants@npm:^6.0.0": + version: 6.2.0 + resolution: "retext-smartypants@npm:6.2.0" + dependencies: + "@types/nlcst": "npm:^2.0.0" + nlcst-to-string: "npm:^4.0.0" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/36f925353dd7f31df642bca2493524a8daee15f9b0e0dfe7fb8982462d23ccb12a99864989db22f0bacb6d7fea1f696ba96e031d3fbac4f013e1c95ef3fed881 + languageName: node + linkType: hard + +"retext-stringify@npm:^4.0.0": + version: 4.0.0 + resolution: "retext-stringify@npm:4.0.0" + dependencies: + "@types/nlcst": "npm:^2.0.0" + nlcst-to-string: "npm:^4.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/eb2930356c85999a8978092a5d6ba3695fea859c71f221dcdc485704552922641bc17e50fea2ae0599d665192eaad002e98bb4236ecac94a570b73581b99004d languageName: node linkType: hard -"remark-rehype@npm:^10.0.0": - version: 10.1.0 - resolution: "remark-rehype@npm:10.1.0" +"retext@npm:^9.0.0": + version: 9.0.0 + resolution: "retext@npm:9.0.0" dependencies: - "@types/hast": "npm:^2.0.0" - "@types/mdast": "npm:^3.0.0" - mdast-util-to-hast: "npm:^12.1.0" - unified: "npm:^10.0.0" - checksum: 10c0/803e658c9b51a9b53ee2ada42ff82e8e570444bb97c873e0d602c2d8dcb69a774fd22bd6f26643dfd5ab4c181059ea6c9fb9a99a2d7f9665f3f11bef1a1489bd + "@types/nlcst": "npm:^2.0.0" + retext-latin: "npm:^4.0.0" + retext-stringify: "npm:^4.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/eee9f66ff6fae5670a5eeccc0b5e2639112f868475273ce307d3079cfe7deb9d1b0f2b8fa28b4ab30abaf8538345185a44908f461a27bbf43c4f94feda90ecac languageName: node linkType: hard -"remove-accents@npm:0.5.0": - version: 0.5.0 - resolution: "remove-accents@npm:0.5.0" - checksum: 10c0/a75321aa1b53d9abe82637115a492770bfe42bb38ed258be748bf6795871202bc8b4badff22013494a7029f5a241057ad8d3f72adf67884dbe15a9e37e87adc4 +"reusify@npm:^1.0.4": + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa languageName: node linkType: hard @@ -3330,19 +4366,31 @@ __metadata: languageName: node linkType: hard -"rw@npm:1": - version: 1.3.3 - resolution: "rw@npm:1.3.3" - checksum: 10c0/b1e1ef37d1e79d9dc7050787866e30b6ddcb2625149276045c262c6b4d53075ddc35f387a856a8e76f0d0df59f4cd58fe24707e40797ebee66e542b840ed6a53 +"roughjs@npm:^4.6.6": + version: 4.6.6 + resolution: "roughjs@npm:4.6.6" + dependencies: + hachure-fill: "npm:^0.5.2" + path-data-parser: "npm:^0.1.0" + points-on-curve: "npm:^0.2.0" + points-on-path: "npm:^0.2.1" + checksum: 10c0/68c11bf4516aa014cef2fe52426a9bab237c2f500d13e1a4f13b523cb5723667bf2d92b9619325efdc5bc2a193588ff5af8d51683df17cfb8720e96fe2b92b0c languageName: node linkType: hard -"sade@npm:^1.7.3": - version: 1.8.1 - resolution: "sade@npm:1.8.1" +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" dependencies: - mri: "npm:^1.1.0" - checksum: 10c0/da8a3a5d667ad5ce3bf6d4f054bbb9f711103e5df21003c5a5c1a8a77ce12b640ed4017dd423b13c2307ea7e645adee7c2ae3afe8051b9db16a6f6d3da3f90b1 + queue-microtask: "npm:^1.2.2" + checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 + languageName: node + linkType: hard + +"rw@npm:1": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: 10c0/b1e1ef37d1e79d9dc7050787866e30b6ddcb2625149276045c262c6b4d53075ddc35f387a856a8e76f0d0df59f4cd58fe24707e40797ebee66e542b840ed6a53 languageName: node linkType: hard @@ -3353,12 +4401,10 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.2": - version: 0.23.2 - resolution: "scheduler@npm:0.23.2" - dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 languageName: node linkType: hard @@ -3371,16 +4417,6 @@ __metadata: languageName: node linkType: hard -"section-matter@npm:^1.0.0": - version: 1.0.0 - resolution: "section-matter@npm:1.0.0" - dependencies: - extend-shallow: "npm:^2.0.1" - kind-of: "npm:^6.0.0" - checksum: 10c0/8007f91780adc5aaa781a848eaae50b0f680bbf4043b90cf8a96778195b8fab690c87fe7a989e02394ce69890e330811ec8dab22397d384673ce59f7d750641d - languageName: node - linkType: hard - "semver@npm:^7.6.3": version: 7.6.3 resolution: "semver@npm:7.6.3" @@ -3390,6 +4426,13 @@ __metadata: languageName: node linkType: hard +"server-only@npm:^0.0.1": + version: 0.0.1 + resolution: "server-only@npm:0.0.1" + checksum: 10c0/4704f0ef85da0be981af6d4ed8e739d39bcfd265b9c246a684060acda5642d0fdc6daffc2308e71e2682c5f508090978802eae0a77623c9b90a49f9ae68048d6 + languageName: node + linkType: hard + "sharp@npm:^0.33.5": version: 0.33.5 resolution: "sharp@npm:0.33.5" @@ -3459,38 +4502,42 @@ __metadata: languageName: node linkType: hard -"shebang-command@npm:^1.2.0": - version: 1.2.0 - resolution: "shebang-command@npm:1.2.0" +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" dependencies: - shebang-regex: "npm:^1.0.0" - checksum: 10c0/7b20dbf04112c456b7fc258622dafd566553184ac9b6938dd30b943b065b21dabd3776460df534cc02480db5e1b6aec44700d985153a3da46e7db7f9bd21326d + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e languageName: node linkType: hard -"shebang-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "shebang-regex@npm:1.0.0" - checksum: 10c0/9abc45dee35f554ae9453098a13fdc2f1730e525a5eb33c51f096cc31f6f10a4b38074c1ebf354ae7bffa7229506083844008dfc3bb7818228568c0b2dc1fff2 +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 languageName: node linkType: hard -"shiki@npm:^0.14.3": - version: 0.14.7 - resolution: "shiki@npm:0.14.7" +"shiki@npm:^3.2.1": + version: 3.23.0 + resolution: "shiki@npm:3.23.0" dependencies: - ansi-sequence-parser: "npm:^1.1.0" - jsonc-parser: "npm:^3.2.0" - vscode-oniguruma: "npm:^1.7.0" - vscode-textmate: "npm:^8.0.0" - checksum: 10c0/5c7fcbb870d0facccc7ae2f3410a28121f8e0b3f298e4e956de817ad6ab60a4c7e20a9184edfe50a93447addbb88b95b69e6ef88ac16ac6ca3e94c50771a6459 + "@shikijs/core": "npm:3.23.0" + "@shikijs/engine-javascript": "npm:3.23.0" + "@shikijs/engine-oniguruma": "npm:3.23.0" + "@shikijs/langs": "npm:3.23.0" + "@shikijs/themes": "npm:3.23.0" + "@shikijs/types": "npm:3.23.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/b06a3eddac4bd0a838f9bd79bea70b0a01195570cb11d70fd2ff7ab0a42c33a8c4980ee52174173aae0476cc152b4c1a68c081a82d94ee340cb3ef9d772ae4ba languageName: node linkType: hard -"signal-exit@npm:^3.0.0": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 +"signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 languageName: node linkType: hard @@ -3503,19 +4550,10 @@ __metadata: languageName: node linkType: hard -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b - languageName: node - linkType: hard - -"sort-keys@npm:^5.0.0": - version: 5.0.0 - resolution: "sort-keys@npm:5.0.0" - dependencies: - is-plain-obj: "npm:^4.0.0" - checksum: 10c0/9f7abc51e184ef27327cb2e6da729c84d1c0223bdfc714b5065df3ff167f8e1bbdfaec6bbd41d87a308d9e79eba93c90534d034f5790b305dfbecf0701f3ee55 +"slash@npm:^5.1.0": + version: 5.1.0 + resolution: "slash@npm:5.1.0" + checksum: 10c0/eb48b815caf0bdc390d0519d41b9e0556a14380f6799c72ba35caf03544d501d18befdeeef074bc9c052acf69654bc9e0d79d7f1de0866284137a40805299eb3 languageName: node linkType: hard @@ -3540,10 +4578,16 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb +"speech-rule-engine@npm:^4.0.6": + version: 4.1.2 + resolution: "speech-rule-engine@npm:4.1.2" + dependencies: + "@xmldom/xmldom": "npm:0.9.8" + commander: "npm:13.1.0" + wicked-good-xpath: "npm:1.3.0" + bin: + sre: bin/sre + checksum: 10c0/bf3de3a009751f72442bb6ba85a82ecf9f32b2764a46d9a83aa28a7da89a05ba173ee2b8018d6f556d7a8ff18358f04da8133f3aa7eaefcb66c43997ae75fa20 languageName: node linkType: hard @@ -3564,26 +4608,28 @@ __metadata: languageName: node linkType: hard -"strip-bom-string@npm:^1.0.0": - version: 1.0.0 - resolution: "strip-bom-string@npm:1.0.0" - checksum: 10c0/5c5717e2643225aa6a6d659d34176ab2657037f1fe2423ac6fcdb488f135e14fef1022030e426d8b4d0989e09adbd5c3288d5d3b9c632abeefd2358dfc512bca +"strip-final-newline@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-final-newline@npm:3.0.0" + checksum: 10c0/a771a17901427bac6293fd416db7577e2bc1c34a19d38351e9d5478c3c415f523f391003b42ed475f27e33a78233035df183525395f731d3bfb8cdcbd4da08ce languageName: node linkType: hard -"strip-eof@npm:^1.0.0": - version: 1.0.0 - resolution: "strip-eof@npm:1.0.0" - checksum: 10c0/f336beed8622f7c1dd02f2cbd8422da9208fae81daf184f73656332899978919d5c0ca84dc6cfc49ad1fc4dd7badcde5412a063cf4e0d7f8ed95a13a63f68f45 +"style-to-js@npm:^1.0.0": + version: 1.1.21 + resolution: "style-to-js@npm:1.1.21" + dependencies: + style-to-object: "npm:1.0.14" + checksum: 10c0/94231aa80f58f442c3a5ae01a21d10701e5d62f96b4b3e52eab3499077ee52df203cc0df4a1a870707f5e99470859136ea8657b782a5f4ca7934e0ffe662a588 languageName: node linkType: hard -"style-to-object@npm:^0.4.1": - version: 0.4.4 - resolution: "style-to-object@npm:0.4.4" +"style-to-object@npm:1.0.14": + version: 1.0.14 + resolution: "style-to-object@npm:1.0.14" dependencies: - inline-style-parser: "npm:0.1.1" - checksum: 10c0/3a733080da66952881175b17d65f92985cf94c1ca358a92cf21b114b1260d49b94a404ed79476047fb95698d64c7e366ca7443f0225939e2fb34c38bbc9c7639 + inline-style-parser: "npm:0.2.7" + checksum: 10c0/854d9e9b77afc336e6d7b09348e7939f2617b34eb0895824b066d8cd1790284cb6d8b2ba36be88025b2595d715dba14b299ae76e4628a366541106f639e13679 languageName: node linkType: hard @@ -3603,40 +4649,63 @@ __metadata: languageName: node linkType: hard -"stylis@npm:^4.1.3": - version: 4.3.2 - resolution: "stylis@npm:4.3.2" - checksum: 10c0/0410e1404cbeee3388a9e17587875211ce2f014c8379af0d1e24ca55878867c9f1ccc7b0ce9a156ca53f5d6e301391a82b0645522a604674a378b3189a4a1994 +"stylis@npm:^4.3.6": + version: 4.3.6 + resolution: "stylis@npm:4.3.6" + checksum: 10c0/e736d484983a34f7c65d362c67dc79b7bce388054b261c2b7b23d02eaaf280617033f65d44b1ea341854f4331a5074b885668ac8741f98c13a6cfd6443ae85d0 languageName: node linkType: hard -"supports-color@npm:^4.0.0": - version: 4.5.0 - resolution: "supports-color@npm:4.5.0" +"system-architecture@npm:^0.1.0": + version: 0.1.0 + resolution: "system-architecture@npm:0.1.0" + checksum: 10c0/1969974ea5d31a9ac7c38f2657cfe8255b36f9e1d5ba3c58cb84c24fbeedf562778b8511f18a0abe6d70ae90148cfcaf145ecf26e37c0a53a3829076f3238cbb + languageName: node + linkType: hard + +"tabbable@npm:^6.0.0": + version: 6.4.0 + resolution: "tabbable@npm:6.4.0" + checksum: 10c0/d931427f4a96b801fd8801ba296a702119e06f70ad262fed8abc5271225c9f1ca51b89fdec4fb2f22e1d35acb3d2881db0a17cedc758272e9ecb540d00299d76 + languageName: node + linkType: hard + +"tinyexec@npm:^1.0.1": + version: 1.0.2 + resolution: "tinyexec@npm:1.0.2" + checksum: 10c0/1261a8e34c9b539a9aae3b7f0bb5372045ff28ee1eba035a2a059e532198fe1a182ec61ac60fa0b4a4129f0c4c4b1d2d57355b5cb9aa2d17ac9454ecace502ee + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.14": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" dependencies: - has-flag: "npm:^2.0.0" - checksum: 10c0/2dc369eeac73954e87037dea1ebae0238b2abc0a39d7e35aa60eb8a84cc8d1dcade8b62e010597f5859f94c937e992abe6a6195460855fcc5e51f8cfc7fcc72a + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 languageName: node linkType: hard -"title@npm:^3.5.3": - version: 3.5.3 - resolution: "title@npm:3.5.3" +"title@npm:^4.0.1": + version: 4.0.1 + resolution: "title@npm:4.0.1" dependencies: - arg: "npm:1.0.0" - chalk: "npm:2.3.0" - clipboardy: "npm:1.2.2" - titleize: "npm:1.0.0" + arg: "npm:^5.0.0" + chalk: "npm:^5.0.0" + clipboardy: "npm:^4.0.0" bin: - title: bin/title.js - checksum: 10c0/9334ff46f49c215a108adbb3ab39bd946dfd1a669b999ad173ff61aa7598a17718f954462d8ebf8fb3ea643b5c37f2f7a163310d186acb18a101c028248d3b15 + title: dist/esm/bin.js + checksum: 10c0/992fbe55f2bbf6189e478dbca48a3d67eff1cf5cbe13228399c4ef9951f5ede752818efe1f841ab1f113d3b88106dd30a61ea616ce96b894daf048be6da24257 languageName: node linkType: hard -"titleize@npm:1.0.0": - version: 1.0.0 - resolution: "titleize@npm:1.0.0" - checksum: 10c0/7c542bdc5754406839fc61e1a43803cb460cb0b5472f7cecf267bd9498e72d549d7f5cdfadd72ec20c3bb0783d52f4c72fe68e104cecd84195b29a5ffe836510 +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 languageName: node linkType: hard @@ -3661,6 +4730,16 @@ __metadata: languageName: node linkType: hard +"ts-morph@npm:^27.0.0": + version: 27.0.2 + resolution: "ts-morph@npm:27.0.2" + dependencies: + "@ts-morph/common": "npm:~0.28.1" + code-block-writer: "npm:^13.0.3" + checksum: 10c0/224715cc6d97b8ff5afd3986f9629f912a0ebd83eaecbdca91c35cf10a98f607c663f666e7ea5e6afab00563d00dc80fa7a13552cc7f1cef735261c3217d0863 + languageName: node + linkType: hard + "tslib@npm:^2.4.0": version: 2.6.3 resolution: "tslib@npm:2.6.3" @@ -3668,10 +4747,29 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^1.0.2": - version: 1.4.0 - resolution: "type-fest@npm:1.4.0" - checksum: 10c0/a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 +"tslib@npm:^2.8.0": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + +"twoslash-protocol@npm:0.3.6": + version: 0.3.6 + resolution: "twoslash-protocol@npm:0.3.6" + checksum: 10c0/3316ad1eb0ccd83c8664582f9718c9fa0fb034ae44c68f374a49e91911585769b8994fda9532c16719d5a3c7407bf8e24fdab11a59d3f41ba41217ef67a1ffcf + languageName: node + linkType: hard + +"twoslash@npm:^0.3.6": + version: 0.3.6 + resolution: "twoslash@npm:0.3.6" + dependencies: + "@typescript/vfs": "npm:^1.6.2" + twoslash-protocol: "npm:0.3.6" + peerDependencies: + typescript: ^5.5.0 + checksum: 10c0/b0c95590e3e87a05f35c4d613087934e16074098fabb9c9096c01a02522ab3be29301bc04007e5803c2586ec33ed5212f955280af7cd0acafccdb7d32a2a2088 languageName: node linkType: hard @@ -3695,6 +4793,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.6.1": + version: 1.6.3 + resolution: "ufo@npm:1.6.3" + checksum: 10c0/bf0e4ebff99e54da1b9c7182ac2f40475988b41faa881d579bc97bc2a0509672107b0a0e94c4b8d31a0ab8c4bf07f4aa0b469ac6da8536d56bda5b085ea2e953 + languageName: node + linkType: hard + "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" @@ -3702,18 +4807,18 @@ __metadata: languageName: node linkType: hard -"unified@npm:^10.0.0": - version: 10.1.2 - resolution: "unified@npm:10.1.2" +"unified@npm:^11.0.0, unified@npm:^11.0.4, unified@npm:^11.0.5": + version: 11.0.5 + resolution: "unified@npm:11.0.5" dependencies: - "@types/unist": "npm:^2.0.0" + "@types/unist": "npm:^3.0.0" bail: "npm:^2.0.0" + devlop: "npm:^1.0.0" extend: "npm:^3.0.0" - is-buffer: "npm:^2.0.0" is-plain-obj: "npm:^4.0.0" trough: "npm:^2.0.0" - vfile: "npm:^5.0.0" - checksum: 10c0/da9195e3375a74ab861a65e1d7b0454225d17a61646697911eb6b3e97de41091930ed3d167eb11881d4097c51deac407091d39ddd1ee8bf1fde3f946844a17a7 + vfile: "npm:^6.0.0" + checksum: 10c0/53c8e685f56d11d9d458a43e0e74328a4d6386af51c8ac37a3dcabec74ce5026da21250590d4aff6733ccd7dc203116aae2b0769abc18cdf9639a54ae528dfc9 languageName: node linkType: hard @@ -3727,13 +4832,6 @@ __metadata: languageName: node linkType: hard -"unist-util-generated@npm:^2.0.0": - version: 2.0.1 - resolution: "unist-util-generated@npm:2.0.1" - checksum: 10c0/6f052dd47a7280785f3787f52cdfe8819e1de50317a1bcf7c9346c63268cf2cebc61a5980e7ca734a54735e27dbb73091aa0361a98504ab7f9409fb75f1b16bb - languageName: node - linkType: hard - "unist-util-is@npm:^5.0.0": version: 5.2.1 resolution: "unist-util-is@npm:5.2.1" @@ -3752,21 +4850,22 @@ __metadata: languageName: node linkType: hard -"unist-util-position-from-estree@npm:^1.0.0, unist-util-position-from-estree@npm:^1.1.0": - version: 1.1.2 - resolution: "unist-util-position-from-estree@npm:1.1.2" +"unist-util-modify-children@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-modify-children@npm:4.0.0" dependencies: - "@types/unist": "npm:^2.0.0" - checksum: 10c0/1d95d0b2b05efcec07a4e6745a6950cd498f6100fb900615b252937baed5140df1c6319b9a67364c8a6bd891c58b3c9a52a22e8e1d3422c50bb785d7e3ad7484 + "@types/unist": "npm:^3.0.0" + array-iterate: "npm:^2.0.0" + checksum: 10c0/63d44b09a2e4c674c72816d4328d668972e68cc965ea719fef1c642b66a3ebe3b102e284a3213b4920ebccff05e0f689b4eaae8a0e5c3dafcad117d1577496da languageName: node linkType: hard -"unist-util-position@npm:^4.0.0": - version: 4.0.4 - resolution: "unist-util-position@npm:4.0.4" +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" dependencies: - "@types/unist": "npm:^2.0.0" - checksum: 10c0/e506d702e25a0fb47a64502054f709a6ff5db98993bf139eec868cd11eb7de34392b781c6c2002e2c24d97aa398c14b32a47076129f36e4b894a2c1351200888 + "@types/unist": "npm:^3.0.0" + checksum: 10c0/39127bf5f0594e0a76d9241dec4f7aa26323517120ce1edd5ed91c8c1b9df7d6fb18af556e4b6250f1c7368825720ed892e2b6923be5cdc08a9bb16536dc37b3 languageName: node linkType: hard @@ -3779,16 +4878,6 @@ __metadata: languageName: node linkType: hard -"unist-util-remove-position@npm:^4.0.0": - version: 4.0.2 - resolution: "unist-util-remove-position@npm:4.0.2" - dependencies: - "@types/unist": "npm:^2.0.0" - unist-util-visit: "npm:^4.0.0" - checksum: 10c0/17371b1e53c52d1b00656c9c6fe1bb044846e7067022195823ed3d1a8d8b965d4f9a79b286b8a841e68731b4ec93afd563b81ae92151f80c28534ba51e9dc18f - languageName: node - linkType: hard - "unist-util-remove-position@npm:^5.0.0": version: 5.0.0 resolution: "unist-util-remove-position@npm:5.0.0" @@ -3810,15 +4899,6 @@ __metadata: languageName: node linkType: hard -"unist-util-stringify-position@npm:^3.0.0": - version: 3.0.3 - resolution: "unist-util-stringify-position@npm:3.0.3" - dependencies: - "@types/unist": "npm:^2.0.0" - checksum: 10c0/14550027825230528f6437dad7f2579a841780318569851291be6c8a970bae6f65a7feb24dabbcfce0e5e68cacae85bf12cbda3f360f7c873b4db602bdf7bb21 - languageName: node - linkType: hard - "unist-util-stringify-position@npm:^4.0.0": version: 4.0.0 resolution: "unist-util-stringify-position@npm:4.0.0" @@ -3828,23 +4908,22 @@ __metadata: languageName: node linkType: hard -"unist-util-visit-parents@npm:^4.0.0": - version: 4.1.1 - resolution: "unist-util-visit-parents@npm:4.1.1" +"unist-util-visit-children@npm:^3.0.0": + version: 3.0.0 + resolution: "unist-util-visit-children@npm:3.0.0" dependencies: - "@types/unist": "npm:^2.0.0" - unist-util-is: "npm:^5.0.0" - checksum: 10c0/f84b544a111af5a17f2b80c462da9f7fdcb46a69f85ab317d2d9ddca766c00e2ceea6c76c0960e58ef4607aad89661c99eccf290973b453e15dd1621c57079d4 + "@types/unist": "npm:^3.0.0" + checksum: 10c0/51e95f54fbf11d414952c011c761c3960864948ad3fd2abe3989eb18b18d96b8f48e7ea5ab6f23264d1a3f4f5a1ff76312dd8f2196c78b762098403505c3abb9 languageName: node linkType: hard -"unist-util-visit-parents@npm:^5.0.0, unist-util-visit-parents@npm:^5.1.1": - version: 5.1.3 - resolution: "unist-util-visit-parents@npm:5.1.3" +"unist-util-visit-parents@npm:^4.0.0": + version: 4.1.1 + resolution: "unist-util-visit-parents@npm:4.1.1" dependencies: "@types/unist": "npm:^2.0.0" unist-util-is: "npm:^5.0.0" - checksum: 10c0/f6829bfd8f2eddf63a32e2c302cd50978ef0c194b792c6fe60c2b71dfd7232415a3c5941903972543e9d34e6a8ea69dee9ccd95811f4a795495ed2ae855d28d0 + checksum: 10c0/f84b544a111af5a17f2b80c462da9f7fdcb46a69f85ab317d2d9ddca766c00e2ceea6c76c0960e58ef4607aad89661c99eccf290973b453e15dd1621c57079d4 languageName: node linkType: hard @@ -3869,17 +4948,6 @@ __metadata: languageName: node linkType: hard -"unist-util-visit@npm:^4.0.0": - version: 4.1.2 - resolution: "unist-util-visit@npm:4.1.2" - dependencies: - "@types/unist": "npm:^2.0.0" - unist-util-is: "npm:^5.0.0" - unist-util-visit-parents: "npm:^5.1.1" - checksum: 10c0/56a1f49a4d8e321e75b3c7821d540a45165a031dd06324bb0e8c75e7737bc8d73bdddbf0b0ca82000f9708a4c36861c6ebe88d01f7cf00e925f5d75f13a3a017 - languageName: node - linkType: hard - "unist-util-visit@npm:^5.0.0": version: 5.0.0 resolution: "unist-util-visit@npm:5.0.0" @@ -3896,35 +4964,31 @@ __metadata: resolution: "unstoppableswap-docs@workspace:." dependencies: "@types/node": "npm:20.14.5" + "@types/react": "npm:^19" next: "npm:^15.0.3" - nextra: "npm:^2.13.4" - nextra-theme-docs: "npm:^2.13.4" - react: "npm:^18.3.1" - react-dom: "npm:^18.3.1" + nextra: "npm:^4" + nextra-theme-docs: "npm:^4" + react: "npm:^19" + react-dom: "npm:^19" typescript: "npm:5.4.5" languageName: unknown linkType: soft -"uuid@npm:^9.0.0": - version: 9.0.1 - resolution: "uuid@npm:9.0.1" - bin: - uuid: dist/bin/uuid - checksum: 10c0/1607dd32ac7fc22f2d8f77051e6a64845c9bce5cd3dd8aa0070c074ec73e666a1f63c7b4e0f4bf2bc8b9d59dc85a15e17807446d9d2b17c8485fbc2147b27f9b +"use-sync-external-store@npm:^1.5.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/35e1179f872a53227bdf8a827f7911da4c37c0f4091c29b76b1e32473d1670ebe7bcd880b808b7549ba9a5605c233350f800ffab963ee4a4ee346ee983b6019b languageName: node linkType: hard -"uvu@npm:^0.5.0": - version: 0.5.6 - resolution: "uvu@npm:0.5.6" - dependencies: - dequal: "npm:^2.0.0" - diff: "npm:^5.0.0" - kleur: "npm:^4.0.3" - sade: "npm:^1.7.3" +"uuid@npm:^11.1.0": + version: 11.1.0 + resolution: "uuid@npm:11.1.0" bin: - uvu: bin.js - checksum: 10c0/ad32eb5f7d94bdeb71f80d073003f0138e24f61ed68cecc8e15d2f30838f44c9670577bb1775c8fac894bf93d1bc1583d470a9195e49bfa6efa14cc6f4942bff + uuid: dist/esm/bin/uuid + checksum: 10c0/34aa51b9874ae398c2b799c88a127701408cd581ee89ec3baa53509dd8728cbb25826f2a038f9465f8b7be446f0fbf11558862965b18d21c993684297628d4d3 languageName: node linkType: hard @@ -3938,27 +5002,6 @@ __metadata: languageName: node linkType: hard -"vfile-matter@npm:^3.0.1": - version: 3.0.1 - resolution: "vfile-matter@npm:3.0.1" - dependencies: - "@types/js-yaml": "npm:^4.0.0" - is-buffer: "npm:^2.0.0" - js-yaml: "npm:^4.0.0" - checksum: 10c0/45ff9b49e7a5817b646d76f14d2486e12a93a16951bd8cfa6c64f0c78c4e56e48d30a0542a980bc9c7aae1bb430d457f9dfc2677e514d66cc2976ab31f10403a - languageName: node - linkType: hard - -"vfile-message@npm:^3.0.0": - version: 3.1.4 - resolution: "vfile-message@npm:3.1.4" - dependencies: - "@types/unist": "npm:^2.0.0" - unist-util-stringify-position: "npm:^3.0.0" - checksum: 10c0/c4ccf9c0ced92d657846fd067fefcf91c5832cdbe2ecc431bb67886e8c959bf7fc05a9dbbca5551bc34c9c87a0a73854b4249f65c64ddfebc4d59ea24a18b996 - languageName: node - linkType: hard - "vfile-message@npm:^4.0.0": version: 4.0.2 resolution: "vfile-message@npm:4.0.2" @@ -3969,18 +5012,6 @@ __metadata: languageName: node linkType: hard -"vfile@npm:^5.0.0, vfile@npm:^5.3.0": - version: 5.3.7 - resolution: "vfile@npm:5.3.7" - dependencies: - "@types/unist": "npm:^2.0.0" - is-buffer: "npm:^2.0.0" - unist-util-stringify-position: "npm:^3.0.0" - vfile-message: "npm:^3.0.0" - checksum: 10c0/c36bd4c3f16ec0c6cbad0711ca99200316bbf849d6b07aa4cb5d9062cc18ae89249fe62af9521926e9659c0e6bc5c2c1da0fe26b41fb71e757438297e1a41da4 - languageName: node - linkType: hard - "vfile@npm:^6.0.0": version: 6.0.1 resolution: "vfile@npm:6.0.1" @@ -3992,17 +5023,52 @@ __metadata: languageName: node linkType: hard -"vscode-oniguruma@npm:^1.7.0": - version: 1.7.0 - resolution: "vscode-oniguruma@npm:1.7.0" - checksum: 10c0/bef0073c665ddf8c86e51da94529c905856559e9aba97a9882f951acd572da560384775941ab6e7e8db94d9c578b25fefb951e4b73c37e8712e16b0231de2689 +"vscode-jsonrpc@npm:8.2.0": + version: 8.2.0 + resolution: "vscode-jsonrpc@npm:8.2.0" + checksum: 10c0/0789c227057a844f5ead55c84679206227a639b9fb76e881185053abc4e9848aa487245966cc2393fcb342c4541241b015a1a2559fddd20ac1e68945c95344e6 languageName: node linkType: hard -"vscode-textmate@npm:^8.0.0": - version: 8.0.0 - resolution: "vscode-textmate@npm:8.0.0" - checksum: 10c0/836f7fe73fc94998a38ca193df48173a2b6eab08b4943d83c8cac9a2a0c3546cfdab4cf1b10b890ec4a4374c5bee03a885ef0e83e7fd2bd618cf00781c017c04 +"vscode-languageserver-protocol@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-protocol@npm:3.17.5" + dependencies: + vscode-jsonrpc: "npm:8.2.0" + vscode-languageserver-types: "npm:3.17.5" + checksum: 10c0/5f38fd80da9868d706eaa4a025f4aff9c3faad34646bcde1426f915cbd8d7e8b6c3755ce3fef6eebd256ba3145426af1085305f8a76e34276d2e95aaf339a90b + languageName: node + linkType: hard + +"vscode-languageserver-textdocument@npm:~1.0.11": + version: 1.0.12 + resolution: "vscode-languageserver-textdocument@npm:1.0.12" + checksum: 10c0/534349894b059602c4d97615a1147b6c4c031141c2093e59657f54e38570f5989c21b376836f13b9375419869242e9efb4066643208b21ab1e1dee111a0f00fb + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-types@npm:3.17.5" + checksum: 10c0/1e1260de79a2cc8de3e46f2e0182cdc94a7eddab487db5a3bd4ee716f67728e685852707d72c059721ce500447be9a46764a04f0611e94e4321ffa088eef36f8 + languageName: node + linkType: hard + +"vscode-languageserver@npm:~9.0.1": + version: 9.0.1 + resolution: "vscode-languageserver@npm:9.0.1" + dependencies: + vscode-languageserver-protocol: "npm:3.17.5" + bin: + installServerIntoExtension: bin/installServerIntoExtension + checksum: 10c0/8a0838d77c98a211c76e54bd3a6249fc877e4e1a73322673fb0e921168d8e91de4f170f1d4ff7e8b6289d0698207afc6aba6662d4c1cd8e4bd7cae96afd6b0c2 + languageName: node + linkType: hard + +"vscode-uri@npm:~3.1.0": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10c0/5f6c9c10fd9b1664d71fab4e9fbbae6be93c7f75bb3a1d9d74399a88ab8649e99691223fd7cef4644376cac6e94fa2c086d802521b9a8e31c5af3e60f0f35624 languageName: node linkType: hard @@ -4013,46 +5079,62 @@ __metadata: languageName: node linkType: hard -"web-worker@npm:^1.2.0": - version: 1.3.0 - resolution: "web-worker@npm:1.3.0" - checksum: 10c0/bca341b421f07c2d33aa205d463e6a2d3d376fb0628a01052dc343fd88a1d688df58d1c7fe36f631d0d860bbd3060f5014cca67d6f8781634b6c2fae25d1fc70 - languageName: node - linkType: hard - -"which@npm:^1.2.9": - version: 1.3.1 - resolution: "which@npm:1.3.1" +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" dependencies: isexe: "npm:^2.0.0" bin: - which: ./bin/which - checksum: 10c0/e945a8b6bbf6821aaaef7f6e0c309d4b615ef35699576d5489b4261da9539f70393c6b2ce700ee4321c18f914ebe5644bc4631b15466ffbaad37d83151f6af59 + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f languageName: node linkType: hard -"yallist@npm:^2.1.2": - version: 2.1.2 - resolution: "yallist@npm:2.1.2" - checksum: 10c0/0b9e25aa00adf19e01d2bcd4b208aee2b0db643d9927131797b7af5ff69480fc80f1c3db738cbf3946f0bddf39d8f2d0a5709c644fd42d4aa3a4e6e786c087b5 +"wicked-good-xpath@npm:1.3.0": + version: 1.3.0 + resolution: "wicked-good-xpath@npm:1.3.0" + checksum: 10c0/6837e1027e75e2ad7fe0620d11def4c42235cbe6c649727258973d7d77c2c5066a5376595e0283d3ba8e2fa22deb3cfe7358db5a02a938bde273b55b9ac57832 languageName: node linkType: hard -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f +"yaml@npm:^2.3.2": + version: 2.8.2 + resolution: "yaml@npm:2.8.2" + bin: + yaml: bin.mjs + checksum: 10c0/703e4dc1e34b324aa66876d63618dcacb9ed49f7e7fe9b70f1e703645be8d640f68ab84f12b86df8ac960bac37acf5513e115de7c970940617ce0343c8c9cd96 + languageName: node + linkType: hard + +"zod@npm:^4.1.12": + version: 4.3.6 + resolution: "zod@npm:4.3.6" + checksum: 10c0/860d25a81ab41d33aa25f8d0d07b091a04acb426e605f396227a796e9e800c44723ed96d0f53a512b57be3d1520f45bf69c0cb3b378a232a00787a2609625307 languageName: node linkType: hard -"zod@npm:^3.22.3": - version: 3.23.8 - resolution: "zod@npm:3.23.8" - checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 +"zustand@npm:^5.0.1": + version: 5.0.11 + resolution: "zustand@npm:5.0.11" + peerDependencies: + "@types/react": ">=18.0.0" + immer: ">=9.0.6" + react: ">=18.0.0" + use-sync-external-store: ">=1.2.0" + peerDependenciesMeta: + "@types/react": + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + checksum: 10c0/61836b48dac5978c9d1b8289d5162a151bee77828371b9aba6431a079b77faca0635ba53da3f7b331295fbc4e78318a109a4527f7a051cb63abfe79b69ccbecf languageName: node linkType: hard -"zwitch@npm:^2.0.0": +"zwitch@npm:^2.0.0, zwitch@npm:^2.0.4": version: 2.0.4 resolution: "zwitch@npm:2.0.4" checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e From 0e2d5af5a97e1bf006eed461d2a25025f73333b0 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Wed, 4 Mar 2026 19:24:48 +0100 Subject: [PATCH 137/146] docs: fix primary color issue after migration to nextra v4 --- docs/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx index 43d53055b5..7c59c1c8bc 100644 --- a/docs/app/layout.tsx +++ b/docs/app/layout.tsx @@ -24,7 +24,7 @@ export default async function RootLayout({ }) { return ( - + Date: Thu, 5 Mar 2026 16:14:44 +0100 Subject: [PATCH 138/146] docs: make installation instructions step based --- docs/app/layout.tsx | 1 + docs/content/_meta.ts | 1 + docs/content/contributing/_meta.ts | 3 + .../contributing/building_from_source.mdx | 4 + .../getting_started/install_instructions.mdx | 87 ++++++++++--------- docs/content/index.mdx | 27 ++++-- 6 files changed, 77 insertions(+), 46 deletions(-) create mode 100644 docs/content/contributing/_meta.ts create mode 100644 docs/content/contributing/building_from_source.mdx diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx index 7c59c1c8bc..4e84e86589 100644 --- a/docs/app/layout.tsx +++ b/docs/app/layout.tsx @@ -30,6 +30,7 @@ export default async function RootLayout({ pageMap={await getPageMap()} editLink={null} feedback={{ content: null }} + sidebar={{ defaultMenuCollapseLevel: 1 }} navbar={ } diff --git a/docs/content/_meta.ts b/docs/content/_meta.ts index aea9b7eb40..248c830ab5 100644 --- a/docs/content/_meta.ts +++ b/docs/content/_meta.ts @@ -4,6 +4,7 @@ export default { usage: "Usage", advanced: "Advanced", becoming_a_maker: "Becoming a Maker", + contributing: "Contributing", send_feedback: "Support / Feedback", donate: "Donate", }; diff --git a/docs/content/contributing/_meta.ts b/docs/content/contributing/_meta.ts new file mode 100644 index 0000000000..22eee26272 --- /dev/null +++ b/docs/content/contributing/_meta.ts @@ -0,0 +1,3 @@ +export default { + building_from_source: "Building from Source", +}; diff --git a/docs/content/contributing/building_from_source.mdx b/docs/content/contributing/building_from_source.mdx new file mode 100644 index 0000000000..aca64215e6 --- /dev/null +++ b/docs/content/contributing/building_from_source.mdx @@ -0,0 +1,4 @@ +# Building from Source + + + diff --git a/docs/content/getting_started/install_instructions.mdx b/docs/content/getting_started/install_instructions.mdx index 5aedab99e1..0bd4215b80 100644 --- a/docs/content/getting_started/install_instructions.mdx +++ b/docs/content/getting_started/install_instructions.mdx @@ -1,32 +1,48 @@ -import { Tabs, Callout } from 'nextra/components' +import { Tabs, Callout, Steps } from 'nextra/components' # Installation -To install the app you can either download ready-to-use binaries or build it from source. -Unless you know what you're doing, you probably want to use the precompiled binaries. +## Download -## Precompiled binaries - -Precompiled binaries of the _GUI_ are available for most platforms. Simply download the appropriate binary for your system and follow the instructions. +Ready-to-use binaries of the app are available for all desktop platforms. +Choose your platform and follow the instructions. - 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `eigenwallet_.exe` installer - 3. Follow the installation wizard - 4. Open the `eigenwallet` application from your Start menu + + ### Download + Download the latest release from our [download page](https://eigenwallet.org/download/) + ### Install + Open the downloaded `eigenwallet_.exe` installer + ### Setup + Follow the installation wizard + ### Launch + Open the `eigenwallet` application from your Start menu + - 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `eigenwallet_.dmg` file - 3. Drag the `eigenwallet` icon to your Applications folder - 4. Open the `eigenwallet` application from your Applications folder + + ### Download + Download the latest release from our [download page](https://eigenwallet.org/download/) + ### Open + Open the downloaded `eigenwallet_.dmg` file + ### Install + Drag the `eigenwallet` icon to your Applications folder + ### Launch + Open the `eigenwallet` application from your Applications folder + - 1. Download the latest release from our [download page](https://eigenwallet.org/download/) - 2. Open the downloaded `eigenwallet_.dmg` file - 3. Drag the `eigenwallet` icon to your Applications folder - 4. Open the `eigenwallet` application from your Applications folder + + ### Download + Download the latest release from our [download page](https://eigenwallet.org/download/) + ### Open + Open the downloaded `eigenwallet_.dmg` file + ### Install + Drag the `eigenwallet` icon to your Applications folder + ### Launch + Open the `eigenwallet` application from your Applications folder + @@ -57,6 +73,9 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl For **x86-64** Linux systems with Flatpak support (version 1.0 or newer), you can install eigenwallet directly from our Flatpak repository: + + ### Install + ```bash filename="install.sh" copy # Add eigenwallet repo flatpak remote-add --if-not-exists eigenwallet https://eigenwallet.github.io/core/eigenwallet.flatpakrepo @@ -66,18 +85,18 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl flatpak install eigenwallet org.eigenwallet.app ``` - ## Run + ### Run ```bash filename="run.sh" copy flatpak run org.eigenwallet.app ``` - ## Update + ### Update ```bash filename="update.sh" copy flatpak update org.eigenwallet.app ``` - + @@ -96,26 +115,14 @@ Precompiled binaries of the _GUI_ are available for most platforms. Simply downl -Incase the website malfunctions you can also find the binaries on our latest [Github release](https://github.com/eigenwallet/core/releases/latest). -Search for the `eigenwallet__.` file that fits to your system. - -## Building from source - -If you want to build the application from source you'll need to have the following tools installed: -- `cargo` ([installation](https://www.rust-lang.org/tools/install)) and `cargo tauri` ([installation](https://v2.tauri.app/reference/cli/) and [prerequisites](https://v2.tauri.app/start/prerequisites/)) -- `node` ([installation](https://nodejs.org/en/download/)) and `yarn` (version 1.22, not 4.x) -- `dprint` (`cargo install dprint@0.50.0`) -- `typeshare` (`cargo install typeshare-cli`) +------- -After that you only need to clone the repository and run the following commands: +Sometimes the website does not display the latest release. +In that case you can also find the binaries on our latest [Github release](https://github.com/eigenwallet/core/releases/latest). +Search for the `eigenwallet__.` file that fits to your system. -```bash -git clone https://github.com/eigenwallet/core.git -cd core/src-tauri -cargo tauri build # may take a while -``` +## Building from source -This will create the `core/target/release/bundle` folder which contains the executable in a platform specific folder. -By default this will compile the binary the platform you are currently on. -You can configure this using options for the `cargo tauri build` command ([docs](https://v2.tauri.app/reference/cli/#build)). +You can build `eigenwallet` from source. +Read the [Contributing](/contributing/building_from_source) guide for instructions. diff --git a/docs/content/index.mdx b/docs/content/index.mdx index 005b7de226..411a0af29d 100644 --- a/docs/content/index.mdx +++ b/docs/content/index.mdx @@ -1,14 +1,29 @@ -import { Cards } from 'nextra/components' +import { Cards, Steps } from 'nextra/components' -# Introduction +# eigenwallet -**eigenwallet** is a protocol _and_ desktop application for swapping Monero and Bitcoin. -It uses atomic swaps to make trustless and private trades possible without the need for a centralized exchange. +eigenwallet is a Monero and Bitcoin wallet and a decentalized exchange (DEX) which can be used to safely swap your Bitcoin for Monero: + + + +### Peer to Peer + +Trustless swaps between two peers -- without any third party involved. + +### Open Source + +Built by the community for the community. + +### Battle tested + +eigenwallet (formerly UnstoppableSwap) has been live for more than 3 years. + + ## Quick Start -To start using eigenwallet, you need to install the application. Then you can do your first swap. +To start using eigenwallet, you need to install the application first. @@ -30,4 +45,4 @@ _Makers_ are users who run the eigenwallet protocol on their own computer or ser They buy your Bitcoin and in return give you Monero. Each maker can set their own prices and fees. -[^1]: The guarantee only holds when the protocol is followed. \ No newline at end of file +[^1]: The guarantee only holds when the protocol is followed. From 76383b81242bec9cb65521d05c8a714beb66763d Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 5 Mar 2026 16:14:58 +0100 Subject: [PATCH 139/146] bob: extend manual refund to complete partial refund path --- swap/src/cli/cancel_and_refund.rs | 189 ++++++++++++++++++------------ 1 file changed, 111 insertions(+), 78 deletions(-) diff --git a/swap/src/cli/cancel_and_refund.rs b/swap/src/cli/cancel_and_refund.rs index c9f549ff1c..5c3857465a 100644 --- a/swap/src/cli/cancel_and_refund.rs +++ b/swap/src/cli/cancel_and_refund.rs @@ -1,12 +1,12 @@ use crate::monero::BlockHeight; use crate::protocol::bob::BobState; use crate::protocol::Database; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use bitcoin::Txid; use bitcoin_wallet::BitcoinWallet; use std::sync::Arc; use swap_core::bitcoin::ExpiredTimelocks; -use swap_machine::bob::RefundType; +use swap_machine::bob::{RefundType, State6}; use uuid::Uuid; pub async fn cancel_and_refund( @@ -235,91 +235,124 @@ pub async fn refund( ), }; - tracing::info!(%swap_id, "Attempting to manually refund swap"); + tracing::info!(%swap_id, "Checking timelocks before attempting to manually refund swap"); + + match state6.expired_timelock(bitcoin_wallet.as_ref()).await? { + ExpiredTimelocks::None { blocks_left } => { + // Cancel timelock isn't even expired -> no refund possible + bail!( + "Cannot refund swap because the cancel timelock has not expired yet. Blocks left: {}", + blocks_left + ); + } + ExpiredTimelocks::Cancel { .. } => { + // Refund possible + } + ExpiredTimelocks::Punish { .. } => { + // We have been punished -> can't refund Bitcoin. + // Only option left is cooperative redeem which is out of scope for this function + let state = BobState::BtcPunished { + state: state6.clone(), + tx_lock_id: state6.tx_lock_id(), + }; + db.insert_latest_state(swap_id, state.into()).await?; + bail!("Cannot refund swap because we have already been punished. Resume the swap to attempt cooperative redeem."); + } + ExpiredTimelocks::WaitingForRemainingRefund { .. } | ExpiredTimelocks::RemainingRefund => { + // This means we already published TxPartialRefund, so we try to reclaim the + // deposit + tracing::info!("TxPartialRefund was already published, attempting to reclaim the remaining Bitcoin (anti-spam deposit)"); + return reclaim(swap_id, state6, bitcoin_wallet, db) + .await + .context("Couldn't reclaim anti-spam deposit"); + } + } let (refund_tx, refund_type) = state6.construct_best_bitcoin_refund_tx().await?; - tracing::info!("Attempting to publish Bitcoin refund transaction. Refund type: {refund_type}"); + tracing::info!("Best possible refund available: {refund_type}"); + tracing::info!("Attempting to publish Bitcoin refund transaction"); - // Attempt to just publish the refund transaction - match bitcoin_wallet + let (_txid, subscription) = bitcoin_wallet .ensure_broadcasted(refund_tx, &refund_type.to_string()) - .await - { - Ok((_txid, subscription)) => { - // First save the "published" state - let published_state = match &refund_type { - RefundType::Full => BobState::BtcRefundPublished(state6.clone()), - RefundType::Partial { .. } => BobState::BtcPartialRefundPublished(state6.clone()), - }; + .await?; - db.insert_latest_state(swap_id, published_state.into()) - .await?; + // First save the "published" state + let published_state = match &refund_type { + RefundType::Full => BobState::BtcRefundPublished(state6.clone()), + RefundType::Partial { .. } => BobState::BtcPartialRefundPublished(state6.clone()), + }; - // Wait for the transaction to be confirmed - tracing::info!("Waiting for refund transaction to be confirmed..."); - subscription.wait_until_final().await?; + db.insert_latest_state(swap_id, published_state.into()) + .await?; - // Now save and return the confirmed state - let confirmed_state = match refund_type { - RefundType::Full => BobState::BtcRefunded(state6), - RefundType::Partial { .. } => BobState::BtcPartiallyRefunded(state6), - }; + // Wait for the transaction to be confirmed + tracing::info!("Waiting for refund transaction to be confirmed..."); + subscription.wait_until_final().await?; - db.insert_latest_state(swap_id, confirmed_state.clone().into()) - .await?; + // Now save and return the confirmed state + let confirmed_state = match refund_type { + RefundType::Full => BobState::BtcRefunded(state6), + RefundType::Partial { .. } => BobState::BtcPartiallyRefunded(state6), + }; - Ok(confirmed_state) - } + db.insert_latest_state(swap_id, confirmed_state.clone().into()) + .await?; - // If we fail to submit the refund transaction it can have one of two reasons: - // 1. The cancel transaction has not been published yet - // 2. The refund timelock has already expired and we have been punished - Err(bitcoin_publication_err) => { - match state6.expired_timelock(bitcoin_wallet.as_ref()).await { - // We have been punished - Ok(ExpiredTimelocks::Punish { .. }) => { - let state = BobState::BtcPunished { - state: state6.clone(), - tx_lock_id: state6.tx_lock_id(), - }; - db.insert_latest_state(swap_id, state.clone().into()) - .await?; - tracing::info!("You have been punished for not refunding in time"); - bail!(bitcoin_publication_err - .context("Cannot refund swap because we have already been punished")); - } - Ok(ExpiredTimelocks::None { blocks_left }) => { - bail!( - bitcoin_publication_err.context(format!( - "Cannot refund swap because the cancel timelock has not expired yet. Blocks left: {}", - blocks_left - )) - ); - } - Ok(ExpiredTimelocks::Cancel { .. }) => { - bail!(bitcoin_publication_err.context("Failed to refund swap even though cancel timelock has expired. This is unexpected.")); - } - Ok(ExpiredTimelocks::WaitingForRemainingRefund { blocks_left }) => { - bail!( - bitcoin_publication_err.context(format!( - "Cannot refund swap yet. Partial refund was published but waiting {} blocks for amnesty timelock to expire.", - blocks_left - )) - ); - } - Ok(ExpiredTimelocks::RemainingRefund) => { - // TODO: Try to publish TxReclaim here instead of just reporting the state - bail!(bitcoin_publication_err.context( - "Amnesty timelock has expired. TxReclaim can be published." - )); - } - Err(e) => { - bail!(bitcoin_publication_err - .context(e) - .context("Failed to refund swap and could not check timelock status")); - } - } - } - } + Ok(confirmed_state) +} + +/// On the partial refund path we need to attempt to reclaim the remaining +/// Bitcoin (anti-spam deposit) after completing the partial refund. +/// Waits for the remaining-refund timelock to expire, then publishes TxReclaim. +/// Races against Alice confirming TxWithhold — whichever confirms first wins. +async fn reclaim( + swap_id: Uuid, + state6: State6, + bitcoin_wallet: Arc, + db: Arc, +) -> Result { + let remaining_refund_timelock = state6 + .remaining_refund_timelock + .context("Can't reclaim because remaining_refund_timelock is missing")?; + + let tx_partial_refund = state6.construct_tx_partial_refund()?; + let tx_withhold = state6.construct_tx_withhold()?; + + let partial_refund_sub = bitcoin_wallet.subscribe_to(Box::new(tx_partial_refund)).await; + let withhold_sub = bitcoin_wallet.subscribe_to(Box::new(tx_withhold)).await; + + let state6_for_withhold = state6.clone(); + let db_for_reclaim = db.clone(); + + let reclaim_future = async { + partial_refund_sub + .wait_until_confirmed_with(remaining_refund_timelock) + .await + .context("Failed waiting for remaining refund timelock to expire")?; + + tracing::info!("Remaining refund timelock expired, publishing TxReclaim"); + + let tx_reclaim = state6.signed_amnesty_transaction().context("Couldn't construct signed TxReclaim")?; + let (_txid, sub) = bitcoin_wallet.ensure_broadcasted(tx_reclaim, "reclaim").await.context("Couldn't broadcast TxReclaim")?; + db_for_reclaim.insert_latest_state(swap_id, BobState::BtcReclaimPublished(state6.clone()).into()).await?; + + sub.wait_until_final().await.context("Failed waiting for TxReclaim confirmation")?; + tracing::info!("TxReclaim confirmed, anti-spam deposit reclaimed"); + anyhow::Ok(BobState::BtcReclaimConfirmed(state6)) + }; + + let withhold_future = async { + withhold_sub.wait_until_final().await.context("Failed waiting for TxWithhold confirmation")?; + tracing::info!("Alice confirmed TxWithhold, anti-spam deposit is burnt"); + anyhow::Ok(BobState::BtcWithheld(state6_for_withhold)) + }; + + let state = tokio::select! { + result = reclaim_future => result?, + result = withhold_future => result?, + }; + + db.insert_latest_state(swap_id, state.clone().into()).await?; + Ok(state) } From d1ee572d301303620b5b1b0bf15826c893b8e83a Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 5 Mar 2026 16:15:35 +0100 Subject: [PATCH 140/146] test(bob): add integration tests for bob manual refund on partial refund --- ...ancel_and_refund_command_partial_refund.rs | 87 ++++++++++++++++++ ..._refund_command_partial_refund_withheld.rs | 90 +++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs create mode 100644 swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs new file mode 100644 index 0000000000..4f16a30959 --- /dev/null +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs @@ -0,0 +1,87 @@ +pub mod harness; + +use harness::alice_run_until::is_xmr_lock_transaction_sent; +use harness::bob_run_until::is_btc_locked; +use harness::FastAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use swap::{asb, cli}; +use swap_env::config::RefundPolicy; + +/// Bob locks BTC, Alice locks XMR but stops cooperating. +/// Bob manually cancels and does a partial refund via CLI, then calls refund +/// again to reclaim the anti-spam deposit. Alice does NOT withhold, so Bob ends +/// up in BtcReclaimConfirmed. +#[tokio::test] +async fn given_partial_refund_bob_manually_reclaims_deposit_via_cli() { + let refund_policy = Some(RefundPolicy { + anti_spam_deposit_ratio: Decimal::new(5, 2), + always_withhold_deposit: false, + }); + + harness::setup_test(FastAmnestyConfig, None, refund_policy, |mut ctx| async move { + let (bob_swap, bob_join_handle) = ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + let bob_state = bob_swap.await??; + assert!(matches!(bob_state, BobState::BtcLocked { .. })); + + let alice_state = alice_swap.await??; + assert!(matches!(alice_state, AliceState::XmrLockTransactionSent { .. })); + + let (bob_swap, bob_join_handle) = ctx + .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) + .await; + + // Wait for cancel timelock to expire + if let BobState::BtcLocked { state3, .. } = bob_swap.state.clone() { + bob_swap + .bitcoin_wallet + .subscribe_to(Box::new(state3.tx_lock)) + .await + .wait_until_confirmed_with(state3.cancel_timelock) + .await?; + } else { + panic!("Bob in unexpected state {}", bob_swap.state); + } + + // Bob manually cancels + partial refunds + bob_join_handle.abort(); + let bob_state = + cli::cancel_and_refund(bob_swap.id, bob_swap.bitcoin_wallet.clone(), bob_swap.db.clone()).await?; + assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); + + // Bob calls refund again to reclaim the anti-spam deposit + let bob_state = + cli::refund(bob_swap.id, bob_swap.bitcoin_wallet, bob_swap.db).await?; + + ctx.assert_bob_amnesty_received(bob_state).await; + + // Manually refund Alice's XMR + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let alice_state = asb::refund( + alice_swap.swap_id, + alice_swap.bitcoin_wallet, + alice_swap.monero_wallet, + alice_swap.db, + ) + .await?; + + ctx.assert_alice_refunded(alice_state).await; + + Ok(()) + }) + .await +} diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs new file mode 100644 index 0000000000..de10b98905 --- /dev/null +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs @@ -0,0 +1,90 @@ +pub mod harness; + +use std::time::Duration; + +use harness::alice_run_until::is_xmr_lock_transaction_sent; +use harness::bob_run_until::is_btc_locked; +use harness::SlowAmnestyConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::alice::AliceState; +use swap::protocol::bob::BobState; +use swap::protocol::{alice, bob}; +use swap::cli; +use swap_env::config::RefundPolicy; + +/// Bob locks BTC, Alice locks XMR but stops cooperating. +/// Bob manually cancels and does a partial refund via CLI, then calls refund +/// again to reclaim the deposit. Alice withholds the deposit before Bob's +/// reclaim timelock expires, so Bob ends up in BtcWithheld. +#[tokio::test] +async fn given_partial_refund_alice_withholds_deposit_while_bob_reclaims_via_cli() { + let refund_policy = Some(RefundPolicy { + anti_spam_deposit_ratio: Decimal::new(5, 2), + always_withhold_deposit: true, + }); + + harness::setup_test(SlowAmnestyConfig, None, refund_policy, |mut ctx| async move { + let (bob_swap, bob_join_handle) = ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + )); + + let bob_state = bob_swap.await??; + assert!(matches!(bob_state, BobState::BtcLocked { .. })); + + let alice_state = alice_swap.await??; + assert!(matches!(alice_state, AliceState::XmrLockTransactionSent { .. })); + + let (bob_swap, bob_join_handle) = ctx + .stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id) + .await; + + // Wait for cancel timelock to expire + if let BobState::BtcLocked { state3, .. } = bob_swap.state.clone() { + bob_swap + .bitcoin_wallet + .subscribe_to(Box::new(state3.tx_lock)) + .await + .wait_until_confirmed_with(state3.cancel_timelock) + .await?; + } else { + panic!("Bob in unexpected state {}", bob_swap.state); + } + + // Bob manually cancels + partial refunds + bob_join_handle.abort(); + let bob_state = + cli::cancel_and_refund(bob_swap.id, bob_swap.bitcoin_wallet.clone(), bob_swap.db.clone()).await?; + assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); + + // Restart Alice so she can refund XMR and publish TxWithhold + ctx.restart_alice().await; + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Generate Monero blocks so Alice's XMR refund confirms in time + tokio::time::sleep(Duration::from_secs(15)).await; + ctx.monero.generate_blocks().await?; + + // Bob calls refund again — races reclaim against Alice's TxWithhold + // Alice's withhold should win because SlowAmnestyConfig has a long timelock + let bob_state = + cli::refund(bob_swap.id, bob_swap.bitcoin_wallet, bob_swap.db).await?; + + ctx.assert_bob_withheld(bob_state).await; + + // Alice should be in withhold confirmed state + let alice_state = alice_swap.await??; + ctx.assert_alice_withhold_confirmed(alice_state).await; + + Ok(()) + }) + .await +} From 1511b5626beab6f007c2b6884ca66aa1c8b15047 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 5 Mar 2026 17:02:06 +0100 Subject: [PATCH 141/146] asb: extend manual refund command to publish TxWithhold if appropriate --- swap/src/asb/recovery/refund.rs | 49 +++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/swap/src/asb/recovery/refund.rs b/swap/src/asb/recovery/refund.rs index 1c46c307e2..0214d57e34 100644 --- a/swap/src/asb/recovery/refund.rs +++ b/swap/src/asb/recovery/refund.rs @@ -3,7 +3,7 @@ use crate::monero; use crate::protocol::alice::swap::XmrRefundable; use crate::protocol::alice::AliceState; use crate::protocol::Database; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use bitcoin_wallet::BitcoinWallet; use libp2p::PeerId; use std::convert::TryInto; @@ -30,7 +30,7 @@ pub async fn refund( swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, - db: Arc, + db: Arc, ) -> Result { let state = db.get_state(swap_id).await?.try_into()?; @@ -74,11 +74,9 @@ pub async fn refund( tracing::info!(%swap_id, "Trying to manually refund swap"); - let spend_key = if let Some(published_refund_tx) = - state3.fetch_tx_refund(bitcoin_wallet.as_ref()).await? - { + let spend_key = if let Some(spend_key) = state3.refund_btc(bitcoin_wallet.as_ref()).await? { tracing::debug!(%swap_id, "Bitcoin refund transaction found, extracting key to refund Monero"); - state3.extract_monero_private_key_from_refund(published_refund_tx)? + spend_key } else { let bob_peer_id = db.get_peer_id(swap_id).await?; bail!(Error::RefundTransactionNotPublishedYet(bob_peer_id),); @@ -102,11 +100,46 @@ pub async fn refund( ) .await?; - let state = AliceState::XmrRefunded { - state3: Some(state3), + let mut state = AliceState::XmrRefunded { + state3: Some(state3.clone()), }; + db.insert_latest_state(swap_id, state.clone().into()) .await?; + if state3.should_publish_tx_withhold.unwrap_or(false) { + let timelocks = state3.expired_timelocks(bitcoin_wallet.as_ref()).await?; + + if matches!(timelocks, swap_core::bitcoin::ExpiredTimelocks::RemainingRefund) { + tracing::warn!(%swap_id, "Remaining refund timelock already expired, Bob may have already reclaimed. Attempting TxWithhold anyway"); + } + + tracing::info!(%swap_id, "Publishing TxWithhold to withhold anti-spam deposit"); + + let signed_tx = state3 + .signed_withhold_transaction() + .context("Failed to construct signed TxWithhold")?; + + let (_txid, subscription) = bitcoin_wallet + .ensure_broadcasted(signed_tx, "withhold") + .await + .context("Failed to broadcast TxWithhold")?; + + state = AliceState::BtcWithholdPublished { + state3: state3.clone(), + }; + db.insert_latest_state(swap_id, state.clone().into()) + .await?; + + subscription + .wait_until_final() + .await + .context("Failed to wait for TxWithhold confirmation")?; + + state = AliceState::BtcWithholdConfirmed { state3 }; + db.insert_latest_state(swap_id, state.clone().into()) + .await?; + } + Ok(state) } From 6f9d42a13e3fb92862528b79f868da61e05855c6 Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Thu, 5 Mar 2026 17:04:21 +0100 Subject: [PATCH 142/146] tests: use manual refund for alice as well in integration tests, add to ci --- .github/workflows/ci.yml | 4 +++ ...ancel_and_refund_command_partial_refund.rs | 27 +++++++++---------- ..._refund_command_partial_refund_withheld.rs | 15 ++++++++--- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e118ca01b8..a835ea765e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -192,6 +192,10 @@ jobs: test_name: swap_rejected_deposit_too_small - package: swap test_name: partial_refund_bob_restart_detects_withhold + - package: swap + test_name: alice_and_bob_refund_using_cancel_and_refund_command_partial_refund + - package: swap + test_name: alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld - package: monero-tests test_name: reserve_proof - package: monero-tests diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs index 4f16a30959..470ee9694c 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund.rs @@ -62,23 +62,22 @@ async fn given_partial_refund_bob_manually_reclaims_deposit_via_cli() { cli::cancel_and_refund(bob_swap.id, bob_swap.bitcoin_wallet.clone(), bob_swap.db.clone()).await?; assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); - // Bob calls refund again to reclaim the anti-spam deposit - let bob_state = - cli::refund(bob_swap.id, bob_swap.bitcoin_wallet, bob_swap.db).await?; - - ctx.assert_bob_amnesty_received(bob_state).await; - - // Manually refund Alice's XMR + // Restart Alice so she can refund XMR via manual command ctx.restart_alice().await; let alice_swap = ctx.alice_next_swap().await; - let alice_state = asb::refund( - alice_swap.swap_id, - alice_swap.bitcoin_wallet, - alice_swap.monero_wallet, - alice_swap.db, - ) - .await?; + // Run Bob's reclaim and Alice's manual refund in parallel + let (bob_state, alice_state) = tokio::try_join!( + cli::refund(bob_swap.id, bob_swap.bitcoin_wallet, bob_swap.db), + asb::refund( + alice_swap.swap_id, + alice_swap.bitcoin_wallet, + alice_swap.monero_wallet, + alice_swap.db, + ), + )?; + + ctx.assert_bob_amnesty_received(bob_state).await; ctx.assert_alice_refunded(alice_state).await; Ok(()) diff --git a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs index de10b98905..fbae7d0ed0 100644 --- a/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs +++ b/swap/tests/alice_and_bob_refund_using_cancel_and_refund_command_partial_refund_withheld.rs @@ -10,7 +10,7 @@ use swap::asb::FixedRate; use swap::protocol::alice::AliceState; use swap::protocol::bob::BobState; use swap::protocol::{alice, bob}; -use swap::cli; +use swap::{asb, cli}; use swap_env::config::RefundPolicy; /// Bob locks BTC, Alice locks XMR but stops cooperating. @@ -64,10 +64,17 @@ async fn given_partial_refund_alice_withholds_deposit_while_bob_reclaims_via_cli cli::cancel_and_refund(bob_swap.id, bob_swap.bitcoin_wallet.clone(), bob_swap.db.clone()).await?; assert!(matches!(bob_state, BobState::BtcPartiallyRefunded { .. })); - // Restart Alice so she can refund XMR and publish TxWithhold + // Restart Alice so she can refund XMR and publish TxWithhold via manual command ctx.restart_alice().await; let alice_swap = ctx.alice_next_swap().await; - let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + // Spawn Alice's manual refund (runs in background: refunds XMR, publishes TxWithhold) + let alice_refund = tokio::spawn(asb::refund( + alice_swap.swap_id, + alice_swap.bitcoin_wallet, + alice_swap.monero_wallet, + alice_swap.db, + )); // Generate Monero blocks so Alice's XMR refund confirms in time tokio::time::sleep(Duration::from_secs(15)).await; @@ -81,7 +88,7 @@ async fn given_partial_refund_alice_withholds_deposit_while_bob_reclaims_via_cli ctx.assert_bob_withheld(bob_state).await; // Alice should be in withhold confirmed state - let alice_state = alice_swap.await??; + let alice_state = alice_refund.await??; ctx.assert_alice_withhold_confirmed(alice_state).await; Ok(()) From 78b41db8bbaf923b9ead9276672ae2220c76d139 Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Mon, 9 Mar 2026 13:54:01 +0100 Subject: [PATCH 143/146] fix: properly center circular progress subtitle --- .../pages/swap/swap/components/CircularProgressWithSubtitle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle.tsx b/src-gui/src/renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle.tsx index 6c7965089b..7bc8595939 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle.tsx @@ -21,7 +21,7 @@ export default function CircularProgressWithSubtitle({ }} > - + {description}
From ca1d5e7939b3f0813623126e999f37a13cd4202c Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Mon, 9 Mar 2026 13:54:27 +0100 Subject: [PATCH 144/146] fix: expand explanation for anti spam deposit on offer acceptance page --- .../swap/in_progress/SwapSetupInflightPage.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx index 0a5eb4eb25..6ed84b5b3a 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/in_progress/SwapSetupInflightPage.tsx @@ -189,7 +189,21 @@ export default function SwapSetupInflightPage({ color="text.secondary" sx={{ display: "block", mt: 0.5 }} > - └ Usually returned; maker may lock for abuse + └ Never witheld for successful swaps + + + └ Almost always returned in case of a refund + + + └ Maker may freeze as an anti-spam measure in rare circumstances From 6708f4251c012796c718751eb0894c002b42ac3d Mon Sep 17 00:00:00 2001 From: Binarybaron Date: Mon, 9 Mar 2026 13:54:47 +0100 Subject: [PATCH 145/146] prune: remove redundant main message of BitcoinPartialRefundPage --- .../pages/swap/swap/done/BitcoinPartialRefundPage.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx index 7e6624e451..41c4e6186d 100644 --- a/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx +++ b/src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPartialRefundPage.tsx @@ -93,10 +93,6 @@ function PartialRefundPage({ const guaranteedPercent = Math.round(((btcLockAmount - btcAmnestyAmount) / btcLockAmount) * 100); const atRiskPercent = Math.round((btcAmnestyAmount / btcLockAmount) * 100); - const mainMessage = confirmed - ? `Refunded the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to withhold the earnest deposit of ${atRiskPercent}%. Unless they do that we will claim it shortly.` - : `Refunding the first ${guaranteedPercent}% of your Bitcoin. The maker has a short time window to withhold the earnest deposit of ${atRiskPercent}%. Unless they do that we will claim it shortly.`; - const additionalContent = swap ? ( <> {!confirmed && "Waiting for transaction to be confirmed..."} @@ -107,7 +103,6 @@ function PartialRefundPage({ return ( <> - {mainMessage} Patience: We are first refunding the guaranteed {guaranteedPercent}% of the Bitcoin refund. From 5fb8b25421aa7da22b102c8a3de9e36fc5858a5f Mon Sep 17 00:00:00 2001 From: einliterflasche Date: Mon, 9 Mar 2026 15:53:26 +0100 Subject: [PATCH 146/146] clean-up: we don't need RUST_MIN_STCK in commands anymore because we have it in .carg/config.toml --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index a561eee619..337875d749 100644 --- a/justfile +++ b/justfile @@ -30,7 +30,7 @@ test-ffi-address: # Start the Tauri app tauri: - cd src-tauri && RUST_MIN_STACK=41943040 RUST_BACKTRACE=1 cargo tauri dev --no-watch -- -vv -- --testnet + cd src-tauri && RUST_BACKTRACE=1 cargo tauri dev --no-watch -- -vv -- --testnet tauri-mainnet: cd src-tauri && RUST_BACKTRACE=1 cargo tauri dev --no-watch -- -vv