|
|
|
|
@ -3563,15 +3563,19 @@ impl WalletService {
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── escrow_wip — WIP/UNAUDITED two-party agreement-with-veto escrow ───
|
|
|
|
|
// ─── escrow — two-party agreement-with-veto escrow on Plutus V3 ───
|
|
|
|
|
//
|
|
|
|
|
// Feature-gated (`--features escrow_wip`) so the default release build
|
|
|
|
|
// doesn't surface tools whose validator hasn't been externally audited.
|
|
|
|
|
// Enable for preprod E2E only.
|
|
|
|
|
// Validator hash: a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d.
|
|
|
|
|
// Internal audit pass + 9-tx preprod E2E shipped 2026-05-09. Has NOT been
|
|
|
|
|
// through external third-party audit; the `escrow_open_unsigned` response
|
|
|
|
|
// carries a runtime "use at own risk" notice so the calling agent has it
|
|
|
|
|
// in-context for the conversation that opens an escrow. Subsequent escrow
|
|
|
|
|
// tools (deposit / agree / veto / settle / refund_timeout) don't repeat
|
|
|
|
|
// the notice — once acknowledged at open, the same caveat carries.
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_open_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build (but DO NOT submit) an unsigned escrow_open tx. Locks lovelace at the escrow validator script address with an inline EscrowDatum (state=Open, optional initial deposit). Two-party agreement-with-veto: party_a + party_b must both sign Agree to flip the state; either can fire Veto from Agreed; recipient is settled-to after the lock period. ⚠️ v1 WIP feature — the validator has NOT been externally audited. Do not route mainnet value through it. Args: escrow_script_address (bech32), party_a/b/recipient_pkh_hex (28-byte hex), open_deadline_ms (after which Refund-timeout becomes valid), lock_period_ms (veto window after Agree), initial_contributor_pkh_hex (optional — party_a or party_b — funds initial deposit), initial_lovelace (lovelace to lock at the script), fee_lovelace (~2.5 ADA reasonable). Returns CBOR-hex of the unsigned tx body. Caller signs via wallet_sign_partial then submits via wallet_submit_signed_tx."
|
|
|
|
|
description = "Build (but DO NOT submit) an unsigned escrow_open tx. Locks lovelace at the escrow validator script address with an inline EscrowDatum (state=Open, initial deposit). Two-party agreement-with-veto: party_a + party_b must both sign Agree to flip the state; either can fire Veto from Agreed; recipient is settled-to after the lock period. The response carries an `audit_notice` field — read it before proceeding; pass that text on to the user opening the escrow. Args: escrow_script_address (bech32), party_a/b/recipient_pkh_hex (28-byte hex), open_deadline_ms (after which Refund-timeout becomes valid), lock_period_ms (veto window after Agree), initial_contributor_pkh_hex (party_a or party_b — funds initial deposit), initial_lovelace (lovelace to lock at the script). Returns CBOR-hex of the unsigned tx body. Caller signs via wallet_sign_partial then submits via wallet_submit_signed_tx."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_open_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -3651,14 +3655,14 @@ impl WalletService {
|
|
|
|
|
"escrow_datum_cbor_hex": unsigned.escrow_datum_cbor_hex,
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "review tx_cbor_hex (decode + audit), sign via wallet_sign_partial, submit via wallet_submit_signed_tx. After submission, query the script address to discover the new escrow UTxO + its tx_hash#index for follow-up deposit/agree/veto/settle/refund tools.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
"audit_notice": "This escrow validator has had an internal review and a 9-tx preprod E2E pass, but has NOT been audited by an external third party. Use at your own risk. If the user is opening this with anything beyond test-net or low-value funds, pass this notice along and confirm they accept the risk. Validator hash: a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_deposit_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build (but DO NOT submit) an unsigned escrow_deposit tx. Plutus V3 spend with continuing-output state transition (only `deposits` field mutated). Validator runs `Deposit{contributor}` redeemer. v1 ADA-only deposits — multi-asset deferred until cbor-canonicality of Aiken Pairs is golden-tested. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path (V3 UPLC), escrow_in_tx_hash_hex + escrow_in_output_index (the existing escrow UTxO), escrow_in_lovelace, escrow_in_datum_cbor_hex (the current EscrowDatum encoded as Plutus Data CBOR — pull via chain_address_info), contributor_pkh_hex (must equal party_a or party_b), add_lovelace (>0), fee_lovelace, validity_window_seconds (optional, default 1800). Returns CBOR-hex of the unsigned tx body."
|
|
|
|
|
description = "Build (but DO NOT submit) an unsigned escrow_deposit tx. Plutus V3 spend with continuing-output state transition (only `deposits` field mutated). Validator runs `Deposit{contributor}` redeemer. v1 ADA-only deposits — multi-asset deferred until cbor-canonicality of Aiken Pairs is golden-tested. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path (V3 UPLC), escrow_in_tx_hash_hex + escrow_in_output_index (the existing escrow UTxO), escrow_in_lovelace, escrow_in_datum_cbor_hex (the current EscrowDatum encoded as Plutus Data CBOR — pull via chain_address_info), contributor_pkh_hex (must equal party_a or party_b), add_lovelace (>0), fee_lovelace, validity_window_seconds (optional, default 1800). Returns CBOR-hex of the unsigned tx body."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_deposit_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -3718,14 +3722,13 @@ impl WalletService {
|
|
|
|
|
"new_escrow_lovelace": unsigned.new_escrow_lovelace,
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "sign via wallet_sign_partial (contributor must sign), submit via wallet_submit_signed_tx. After submission, the new escrow UTxO at script address has tx_hash = tx_hash_hex above, output_index = 0; pass these to subsequent escrow tools.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_agree_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build an unsigned escrow_agree tx — flips state Open → Agreed{at=upper}. BOTH party_a + party_b must sign (this tool is run by the driver, who signs first; co-signer adds witness via wallet_sign_partial). Validator enforces validity_upper ≤ open_deadline_ms. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (party_a or party_b), fee_lovelace, validity_window_seconds (optional default 1800; clamps to open_deadline if needed). Returns CBOR-hex requiring co-signer's witness."
|
|
|
|
|
description = "Build an unsigned escrow_agree tx — flips state Open → Agreed{at=upper}. BOTH party_a + party_b must sign (this tool is run by the driver, who signs first; co-signer adds witness via wallet_sign_partial). Validator enforces validity_upper ≤ open_deadline_ms. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (party_a or party_b), fee_lovelace, validity_window_seconds (optional default 1800; clamps to open_deadline if needed). Returns CBOR-hex requiring co-signer's witness."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_agree_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -3803,14 +3806,13 @@ impl WalletService {
|
|
|
|
|
"co_signer_pkh_hex": unsigned.co_signer_pkh_hex,
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "this tx requires BOTH parties' signatures. Driver signs via wallet_sign_partial, then sends the partial-signed CBOR to the co-signer (pkh = co_signer_pkh_hex) who calls wallet_sign_partial again, then wallet_submit_signed_tx.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_veto_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build an unsigned escrow_veto tx — consumes an Agreed escrow and refunds every contributor to their enterprise (null-stake) address. Either party can fire (validator: signed_by(a) || signed_by(b)). Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (party_a or party_b), fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
description = "Build an unsigned escrow_veto tx — consumes an Agreed escrow and refunds every contributor to their enterprise (null-stake) address. Either party can fire (validator: signed_by(a) || signed_by(b)). Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (party_a or party_b), fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_veto_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -3865,14 +3867,13 @@ impl WalletService {
|
|
|
|
|
"refunds": unsigned.refunds.iter().map(|(p,l)| serde_json::json!({"contributor_pkh_hex": p, "lovelace": l})).collect::<Vec<_>>(),
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "driver signs via wallet_sign_partial then submits via wallet_submit_signed_tx.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_settle_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build an unsigned escrow_settle tx — consumes an Agreed escrow whose lock window has elapsed and pays the entire in_value to the recipient's enterprise address. Validator gate: state==Agreed AND lower > agreed_at_ms + lock_period_ms (strict gt). No party signer required by validator — anyone with funding + collateral can push it. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (whoever's paying fees), fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
description = "Build an unsigned escrow_settle tx — consumes an Agreed escrow whose lock window has elapsed and pays the entire in_value to the recipient's enterprise address. Validator gate: state==Agreed AND lower > agreed_at_ms + lock_period_ms (strict gt). No party signer required by validator — anyone with funding + collateral can push it. Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex (whoever's paying fees), fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_settle_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -3940,14 +3941,13 @@ impl WalletService {
|
|
|
|
|
"recipient_lovelace_paid": unsigned.recipient_lovelace_paid,
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "driver signs via wallet_sign_partial then submits via wallet_submit_signed_tx.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tool(
|
|
|
|
|
name = "escrow_refund_timeout_unsigned",
|
|
|
|
|
description = "WIP — UNAUDITED: Build an unsigned escrow_refund_timeout tx — consumes an Open escrow whose open_deadline has elapsed and refunds every contributor. No party signer required. Validator gate: state==Open AND lower > open_deadline_ms (strict gt). Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex, fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
description = "Build an unsigned escrow_refund_timeout tx — consumes an Open escrow whose open_deadline has elapsed and refunds every contributor. No party signer required. Validator gate: state==Open AND lower > open_deadline_ms (strict gt). Args: escrow_script_address, validator_script_cbor_hex OR validator_script_path, escrow_in_tx_hash_hex + escrow_in_output_index + escrow_in_lovelace + escrow_in_datum_cbor_hex, driver_pkh_hex, fee_lovelace, validity_window_seconds (optional)."
|
|
|
|
|
)]
|
|
|
|
|
async fn escrow_refund_timeout_unsigned(
|
|
|
|
|
&self,
|
|
|
|
|
@ -4006,7 +4006,6 @@ impl WalletService {
|
|
|
|
|
"refunds": unsigned.refunds.iter().map(|(p,l)| serde_json::json!({"contributor_pkh_hex": p, "lovelace": l})).collect::<Vec<_>>(),
|
|
|
|
|
"summary": unsigned.summary,
|
|
|
|
|
"next_step": "driver signs via wallet_sign_partial then submits via wallet_submit_signed_tx.",
|
|
|
|
|
"wip_warning": "⚠️ UNAUDITED escrow validator. Use preprod testnet only.",
|
|
|
|
|
})
|
|
|
|
|
.to_string())
|
|
|
|
|
}
|
|
|
|
|
@ -4300,7 +4299,7 @@ pub struct EscrowOpenUnsignedArgs {
|
|
|
|
|
pub initial_lovelace: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── escrow_wip spend-tool args (deposit / agree / veto / settle / refund) ──
|
|
|
|
|
// ─── escrow spend-tool args (deposit / agree / veto / settle / refund) ──
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, schemars::JsonSchema)]
|
|
|
|
|
pub struct EscrowDepositUnsignedArgs {
|
|
|
|
|
|