From d5fb00c9f5bcabed78ff301434903b405e4b155d Mon Sep 17 00:00:00 2001 From: Kayos Date: Mon, 4 May 2026 21:09:31 -0700 Subject: [PATCH] mainnet prep: tighten max_send_lovelace default + cost model docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit max_send_lovelace default is now network-aware: mainnet 10 ADA, preprod/preview 100 (t)ADA. Mainnet handles real value, so the cap should bite earlier — anything > 10 ADA needs explicit force=true. Test ada on preprod/preview is faucet-replaceable, no need to sand off the test surface. New regression mainnet_default_max_send_is_tighter locks the rule in. PLUTUS_V3_COST_MODEL_PREPROD docstring updated: confirmed identical to mainnet PV3 cost model (preprod epoch 286 = mainnet epoch 629, both 297 params, byte-identical). Cost models are protocol-version parameters, not network parameters; using the same constant on both is correct. Re-snapshot from mainnet Koios after any major hard fork. Naming kept as _PREPROD for git churn reasons. --- crates/aldabra-core/src/plutus_cost_models.rs | 16 ++++++++-- crates/aldabra-mcp/src/config.rs | 31 +++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/crates/aldabra-core/src/plutus_cost_models.rs b/crates/aldabra-core/src/plutus_cost_models.rs index 18bdc4b..36a5b17 100644 --- a/crates/aldabra-core/src/plutus_cost_models.rs +++ b/crates/aldabra-core/src/plutus_cost_models.rs @@ -1,5 +1,17 @@ -// Conway-era preprod Plutus V3 cost model, epoch 286 (2026-05). -// 297 params. Pull fresh via koios epoch_params after major hard forks. +// Conway-era Plutus V3 cost model, 297 params. Snapshot from preprod +// epoch 286 (2026-05) but **identical to mainnet epoch 629** — +// confirmed 2026-05-04 by parallel Koios `epoch_params` fetch from +// `api.koios.rest` and `preprod.koios.rest`. Cost models are +// protocol-version parameters, not network parameters; they only +// diverge if a network does an experimental hard fork off-cycle. +// +// Used by both preprod and mainnet Plutus paths today. Re-snapshot +// from mainnet Koios after any major hard fork. If preprod and +// mainnet ever diverge, split into two constants and select by +// `Network`. +// +// Naming kept as `_PREPROD` for git churn reasons; treat as +// "current Plutus V3 protocol parameters." pub const PLUTUS_V3_COST_MODEL_PREPROD: [i64; 297] = [ 100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, 4, 1, 11183, 32, 201305, 8356, diff --git a/crates/aldabra-mcp/src/config.rs b/crates/aldabra-mcp/src/config.rs index 76f10b6..2cb494c 100644 --- a/crates/aldabra-mcp/src/config.rs +++ b/crates/aldabra-mcp/src/config.rs @@ -25,11 +25,22 @@ pub struct Config { pub data_dir: PathBuf, /// Hard cap on outbound `wallet.send` lovelace. Tools must /// reject sends above this unless the caller passes `force=true`. - /// Default 100 ADA (100_000_000 lovelace). Override via TOML or + /// Default is network-aware: mainnet 10 ADA (real value, tighter + /// blast radius), preprod/preview 100 tADA (test ADA is + /// faucet-replaceable). Override via TOML or /// `ALDABRA_MAX_SEND_LOVELACE`. pub max_send_lovelace: u64, } +/// Network-aware default for `max_send_lovelace`. See the docstring on +/// `Config::max_send_lovelace`. +fn default_max_send_for(network: Network) -> u64 { + match network { + Network::Mainnet => 10_000_000, + Network::Preview | Network::Preprod => 100_000_000, + } +} + #[derive(Debug, Default, Deserialize)] struct FileConfig { #[serde(default)] @@ -146,7 +157,9 @@ impl Config { var: "ALDABRA_MAX_SEND_LOVELACE", value: s, })?, - Err(_) => file_cfg.max_send_lovelace.unwrap_or(100_000_000), + Err(_) => file_cfg + .max_send_lovelace + .unwrap_or_else(|| default_max_send_for(network)), }; Ok(Self { @@ -207,4 +220,18 @@ mod tests { assert!(default_koios_for(Network::Preprod).contains("preprod.koios.rest")); assert!(default_koios_for(Network::Preview).contains("preview.koios.rest")); } + + #[test] + fn mainnet_default_max_send_is_tighter() { + // Mainnet handles real value, so the default cap is 10 ADA. + // Preprod/preview are faucet-replaceable, so 100 (t)ADA is fine. + assert_eq!(default_max_send_for(Network::Mainnet), 10_000_000); + assert_eq!(default_max_send_for(Network::Preprod), 100_000_000); + assert_eq!(default_max_send_for(Network::Preview), 100_000_000); + assert!( + default_max_send_for(Network::Mainnet) + < default_max_send_for(Network::Preprod), + "mainnet default must be strictly tighter than preprod" + ); + } }