From e3baedbbe9e3e18b6cc3f42437465ff96b616f41 Mon Sep 17 00:00:00 2001 From: Elthelthetallgirl <331852652+Elthelthetallgirl@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:32:43 -0700 Subject: [PATCH 1/5] fix(stellar): limit the default workspace build to deployable members A plain `cargo build --target wasm32-unknown-unknown --release` in a virtual workspace selects every member. bench, bench-crossover and integration-tests enable soroban-sdk/testutils, which the SDK rejects for wasm with a compile_error, so the whole wasm build failed inside the SDK's transitive deps instead of in the crates that were actually wrong. default-members now selects only the ten deployable members, so the WASM, optimize and size-gate steps in CI can become blocking again. Host-only members remain reachable with --workspace or -p. --- stellar/Cargo.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/stellar/Cargo.toml b/stellar/Cargo.toml index 5719fb08..612e80b8 100644 --- a/stellar/Cargo.toml +++ b/stellar/Cargo.toml @@ -14,6 +14,24 @@ members = [ "integration-tests", "contracts/governance", ] +# A plain `cargo build` from this directory produces the deployable contract +# artifacts, so it must select only the contract crates. `bench`, +# `bench-crossover` and `integration-tests` are host-only: they enable +# soroban-sdk/testutils in [dependencies], and the SDK refuses to compile +# testutils for wasm32, so including them in the default set breaks every wasm +# build (see SUPPLY_CHAIN.md). Reach them with --workspace or -p. +default-members = [ + "stealth-announcer", + "stealth-registry", + "stealth-sender", + "stealth-splitter", + "stealth-batch-sender", + "stealth-vault", + "wraith-names", + "wraith-asset-policy", + "wraith-metrics", + "contracts/governance", +] resolver = "2" [workspace.dependencies] From f2ad0e9771e99fe82a76a9104981f9bf7fb81ff7 Mon Sep 17 00:00:00 2001 From: Elthelthetallgirl <331852652+Elthelthetallgirl@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:35:09 -0700 Subject: [PATCH 2/5] fix(stellar): decode the owner key from the strkey in wraith-names wraith-names converted the owner Address into an xdr::ScAddress, but soroban-sdk gates that conversion behind cfg(not(target_family = "wasm")), so the crate only built on the host and every wasm32 build of it failed. The previous documentation blamed soroban-sdk 22.0.11 and told CI to keep the old 9,755-byte baseline forever; the contract simply could not be deployed as written. owner_public_key now decodes the strkey on chain: unpadded base32, version byte 6 << 3, CRC16-XMODEM over the first 33 bytes compared little-endian. Contract, muxed and corrupt addresses still map to NamesError::InvalidSigner, exactly as the ScAddress match did. Also gate `extern crate alloc` behind cfg(test): linking alloc into the cdylib requires a global allocator the contract does not have, which was the second reason the wasm artifact never built. --- stellar/wraith-names/src/lib.rs | 133 +++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 12 deletions(-) diff --git a/stellar/wraith-names/src/lib.rs b/stellar/wraith-names/src/lib.rs index 75c69e50..bb7244f1 100644 --- a/stellar/wraith-names/src/lib.rs +++ b/stellar/wraith-names/src/lib.rs @@ -1,10 +1,12 @@ #![no_std] +// Only the test module allocates. Linking `alloc` into the crate unconditionally +// makes the wasm32 cdylib require a global allocator it does not have. +#[cfg(test)] extern crate alloc; use core::convert::TryInto; -use soroban_sdk::xdr::{AccountId, PublicKey, ScAddress}; use soroban_sdk::{ contract, contracterror, contractimpl, contracttype, symbol_short, Address, Bytes, BytesN, Env, String, Vec, @@ -141,6 +143,73 @@ pub enum NamesError { const TTL_THRESHOLD: u32 = 17280; // ~1 day const TTL_EXTEND_TO: u32 = 518400; // ~30 days +/// An ed25519 account strkey (`G…`) is 56 unpadded base32 characters over +/// `[version byte, 32-byte public key, 2-byte CRC16 checksum]`. +const ACCOUNT_STRKEY_CHARS: usize = 56; +const ACCOUNT_STRKEY_BYTES: usize = 35; +/// Version 6 left-shifted into the high five bits, which is what makes the +/// strkey start with `G`. +const ACCOUNT_VERSION_BYTE: u8 = 6 << 3; + +fn base32_quintet(byte: u8) -> Option { + match byte { + b'A'..=b'Z' => Some(byte - b'A'), + b'2'..=b'7' => Some(26 + byte - b'2'), + _ => None, + } +} + +fn crc16_xmodem(bytes: &[u8]) -> u16 { + let mut crc: u16 = 0; + for &byte in bytes { + crc ^= (byte as u16) << 8; + for _ in 0..8 { + let overflowed = crc & 0x8000 != 0; + crc = crc.wrapping_shl(1); + if overflowed { + crc ^= 0x1021; + } + } + } + crc +} + +/// Recovers the ed25519 public key from an account strkey. +/// +/// Returns `None` for a contract address (`C…`), a muxed account (`M…`), or a +/// corrupt checksum, which the caller maps to `NamesError::InvalidSigner`. +fn account_public_key(strkey: &[u8]) -> Option<[u8; 32]> { + if strkey.len() != ACCOUNT_STRKEY_CHARS { + return None; + } + + let mut decoded = [0u8; ACCOUNT_STRKEY_BYTES]; + let mut accumulator: u32 = 0; + let mut bits: u32 = 0; + let mut written: usize = 0; + for &byte in strkey { + let quintet = base32_quintet(byte)?; + accumulator = (accumulator << 5) | quintet as u32; + bits += 5; + if bits >= 8 { + bits -= 8; + decoded[written] = ((accumulator >> bits) & 0xff) as u8; + written += 1; + } + } + + if written != ACCOUNT_STRKEY_BYTES || decoded[0] != ACCOUNT_VERSION_BYTE { + return None; + } + if u16::from_le_bytes([decoded[33], decoded[34]]) != crc16_xmodem(&decoded[..33]) { + return None; + } + + let mut public_key = [0u8; 32]; + public_key.copy_from_slice(&decoded[1..33]); + Some(public_key) +} + #[contract] pub struct WraithNamesContract; @@ -456,18 +525,17 @@ impl WraithNamesContract { } fn owner_public_key(env: &Env, owner: &Address) -> Result, NamesError> { - let sc_address: ScAddress = owner.try_into().map_err(|_| NamesError::InvalidSigner)?; - - match sc_address { - ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(public_key))) => { - let public_key_bytes: [u8; 32] = public_key - .as_slice() - .try_into() - .map_err(|_| NamesError::InvalidSigner)?; - Ok(BytesN::from_array(env, &public_key_bytes)) - } - _ => Err(NamesError::InvalidSigner), + // soroban-sdk converts an `Address` to an `xdr::ScAddress` only on the + // host (`cfg(not(target_family = "wasm"))`), so the deployed wasm has to + // recover the owner's key from the strkey instead. + let strkey = owner.to_string(); + if strkey.len() as usize != ACCOUNT_STRKEY_CHARS { + return Err(NamesError::InvalidSigner); } + let mut strkey_bytes = [0u8; ACCOUNT_STRKEY_CHARS]; + strkey.copy_into_slice(&mut strkey_bytes); + let public_key = account_public_key(&strkey_bytes).ok_or(NamesError::InvalidSigner)?; + Ok(BytesN::from_array(env, &public_key)) } fn register_internal( @@ -1177,6 +1245,47 @@ mod test { (owner, signing_key) } + #[test] + fn strkey_decode_recovers_the_account_public_key() { + let env = Env::default(); + let seed = [7u8; 32]; + let (owner, signing_key) = signing_account(&env, seed); + let strkey = owner.to_string(); + let mut bytes = [0u8; ACCOUNT_STRKEY_CHARS]; + strkey.copy_into_slice(&mut bytes); + let decoded = account_public_key(&bytes).expect("account strkey decodes"); + assert_eq!(decoded, signing_key.verifying_key().to_bytes()); + } + + /// The all-zero ed25519 public key as encoded by the reference strkey + /// encoder: version byte `6 << 3`, 32 zero bytes, then the CRC16 checksum + /// in little-endian byte order. + const ZERO_ACCOUNT_STRKEY: &[u8; ACCOUNT_STRKEY_CHARS] = + b"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; + + #[test] + fn strkey_decode_matches_a_known_vector() { + let decoded = account_public_key(ZERO_ACCOUNT_STRKEY).expect("valid strkey"); + assert_eq!(decoded, [0u8; 32]); + } + + #[test] + fn strkey_decode_rejects_a_corrupt_checksum() { + let mut strkey = *ZERO_ACCOUNT_STRKEY; + strkey[ACCOUNT_STRKEY_CHARS - 1] = b'A'; + assert_eq!(account_public_key(&strkey), None); + } + + #[test] + fn strkey_decode_rejects_non_account_addresses() { + let env = Env::default(); + let contract = Address::generate(&env); + let strkey = contract.to_string(); + let mut bytes = [0u8; ACCOUNT_STRKEY_CHARS]; + strkey.copy_into_slice(&mut bytes); + assert_eq!(account_public_key(&bytes), None); + } + fn sign_authorization( env: &Env, signing_key: &SigningKey, From c7ef7c06e316dd1c75bc673bd36b12aca22e51f8 Mon Sep 17 00:00:00 2001 From: Elthelthetallgirl <331852652+Elthelthetallgirl@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:45:10 -0700 Subject: [PATCH 3/5] fix(stellar): regenerate the checked-in bindings and ABI snapshots The artifact steps have been non-blocking for so long that the checked-in output no longer described the contracts. Regenerating with stellar-cli 26.1.0, the new CI pin, shows what was invisible: - 47 of the 72 ABI-exported functions had no client method. wraith-names exposed 5 of 39, stealth-sender 3 of 15 and stealth-registry 2 of 3, so those three clients could not call most of their own contract. The regenerated clients are 711, 339 and 145 lines instead of 147, 123 and 106. - stealth-batch-sender's client had no package.json, tsconfig.json, README.md or .gitignore, so it was not installable outside this repository even though its methods were complete. - The ABI snapshots did not cover the current wraith-names and stealth-sender surfaces. Also drop the timestamp from the generated top-level index.ts. The bindings step now fails the PR on any diff, and a generation date changes on every run, which would make every CI run look like drift. Both generators are idempotent on the committed tree: re-running `pnpm bindings:stellar` and `stellar/abi/update.sh` produces no diff. --- stellar/abi/stealth_announcer.json | 2 +- stellar/abi/stealth_batch_sender.json | 647 +++++- stellar/abi/stealth_registry.json | 74 + stellar/abi/stealth_sender.json | 564 ++++- stellar/abi/wraith_names.json | 1827 ++++++++++++++++- stellar/bindings/typescript/index.ts | 1 - .../typescript/stealth-announcer/src/index.ts | 25 +- .../stealth-batch-sender/.gitignore | 2 + .../typescript/stealth-batch-sender/README.md | 54 + .../stealth-batch-sender/package.json | 17 + .../stealth-batch-sender/src/index.ts | 391 +++- .../stealth-batch-sender/tsconfig.json | 98 + .../typescript/stealth-registry/src/index.ts | 43 +- .../typescript/stealth-sender/src/index.ts | 232 ++- .../typescript/wraith-names/src/index.ts | 616 +++++- stellar/scripts/generate-bindings.ts | 7 +- 16 files changed, 4422 insertions(+), 178 deletions(-) create mode 100644 stellar/bindings/typescript/stealth-batch-sender/.gitignore create mode 100644 stellar/bindings/typescript/stealth-batch-sender/README.md create mode 100644 stellar/bindings/typescript/stealth-batch-sender/package.json create mode 100644 stellar/bindings/typescript/stealth-batch-sender/tsconfig.json diff --git a/stellar/abi/stealth_announcer.json b/stellar/abi/stealth_announcer.json index c997c9b3..3e5c2582 100644 --- a/stellar/abi/stealth_announcer.json +++ b/stellar/abi/stealth_announcer.json @@ -1,7 +1,7 @@ [ { "function_v0": { - "doc": "Emits a stealth address announcement event.\\n\\nThis is a pure event-emission function with no access control and no\\nstorage. Indexers watch for these events to let recipients detect\\nincoming payments.\\n\\n# Arguments\\n* `scheme_id` - Identifier for the stealth address scheme (e.g. 1 for the default DKSAP scheme).\\n* `stealth_address` - The one-time stealth address that received funds.\\n* `ephemeral_pub_key` - The ephemeral public key used to derive the stealth address.\\n* `metadata` - Arbitrary metadata (e.g. view tag) to speed up scanning.", + "doc": "Emits a Stellar v2 stealth address announcement event.\\n\\nThis is a pure event-emission function with no access control and no\\nstorage. Indexers watch for these events to let recipients detect\\nincoming payments.\\n\\nv2 event shape:\\n* topics: `(\"announce\", scheme_id, view_tag_bucket, metadata_kind)`\\n* data: `(stealth_address, ephemeral_pub_key, metadata)`\\n\\nThe stable `view_tag_bucket` derivation is `metadata[0] as u32`, where\\n`metadata_kind = 1` (`METADATA_KIND_VIEW_TAG`) means the first metadata\\nbyte is the view tag and the remaining bytes are scheme-specific. This\\nlets wallets and indexers filter Stellar RPC `getEvents` by scheme and\\nbucket before doing client-side cryptographic validation.\\n\\nMigration note: v1 announcements used the old Stellar layout\\n`(\"announce\", scheme_id, stealth_address)` with\\n`(caller, ephemeral_pub_key, metadata)`. Do not reinterpret historical v1\\nevents as v2. The compatibility path is a new announcer deployment using\\n`scheme_id = 2`.\\n\\n# Arguments\\n* `scheme_id` - Must be `2` for the v2 St", "name": "announce", "inputs": [ { diff --git a/stellar/abi/stealth_batch_sender.json b/stellar/abi/stealth_batch_sender.json index 7fe049ce..8c42a4e0 100644 --- a/stellar/abi/stealth_batch_sender.json +++ b/stellar/abi/stealth_batch_sender.json @@ -1,20 +1,631 @@ [ - {"udt_union_v0":{"doc":"Storage keys.","lib":"","name":"DataKey","cases":[{"void_v0":{"doc":"Pause admin address.","name":"Admin"}},{"void_v0":{"doc":"Address of the deployed StealthAnnouncer contract.","name":"Announcer"}},{"void_v0":{"doc":"Optional address of the asset policy contract.","name":"AssetPolicy"}},{"void_v0":{"doc":"Whether the contract is paused.","name":"Paused"}},{"void_v0":{"doc":"Governance multisig signer set.","name":"MultisigSigners"}},{"void_v0":{"doc":"Governance multisig quorum threshold.","name":"MultisigThreshold"}},{"void_v0":{"doc":"Pending signer-rotation proposal, if any.","name":"PendingRotation"}}]}}, - {"udt_struct_v0":{"doc":"A single stealth transfer within a batch.","lib":"","name":"Transfer","fields":[{"doc":"Pre-computed stealth address (recipient)","name":"stealth_address","type_":"address"},{"doc":"Ephemeral public key for the recipient to scan.","name":"ephemeral_pub_key","type_":"bytes"},{"doc":"Token amount (in the asset's base unit)","name":"amount","type_":"i128"},{"doc":"Announcement metadata whose first byte is the view tag","name":"metadata","type_":"bytes"}]}}, - {"udt_struct_v0":{"doc":"A pending signer-rotation proposal.","lib":"","name":"RotationProposal","fields":[{"doc":"","name":"new_signers","type_":{"vec":{"element_type":"address"}}},{"doc":"","name":"new_threshold","type_":"u32"},{"doc":"","name":"executable_at","type_":"u64"},{"doc":"","name":"approvals","type_":{"vec":{"element_type":"address"}}}]}}, - {"udt_error_enum_v0":{"doc":"Errors that the batch-sender contract can produce.","lib":"","name":"BatchSenderError","cases":[{"doc":"The contract has already been initialised.","name":"AlreadyInitialized","value":1300},{"doc":"The contract has not been initialised yet.","name":"NotInitialized","value":1301},{"doc":"The batch contains no transfers.","name":"EmptyBatch","value":1302},{"doc":"The batch exceeds `MAX_BATCH_SIZE`.","name":"BatchTooLarge","value":1303},{"doc":"A transfer amount was zero or negative.","name":"NonPositiveAmount","value":1304},{"doc":"A transfer's ephemeral public key was empty or not 32 bytes.","name":"EmptyEphemeralKey","value":1305},{"doc":"The contract is paused.","name":"Paused","value":1306},{"doc":"The asset is not allowed by the configured asset policy.","name":"AssetNotAllowed","value":1307},{"doc":"The governance multisig has not been initialised.","name":"MultisigNotInitialized","value":1308},{"doc":"The governance multisig has already been initialised.","name":"MultisigAlreadyInitialized","value":1309},{"doc":"The caller is not a current governance signer.","name":"NotSigner","value":1310},{"doc":"The requested threshold is invalid.","name":"InvalidThreshold","value":1311},{"doc":"A signer-rotation proposal is already pending.","name":"RotationAlreadyPending","value":1312},{"doc":"No signer-rotation proposal is pending.","name":"NoPendingRotation","value":1313},{"doc":"The caller has already approved the pending rotation.","name":"AlreadyApprovedRotation","value":1314},{"doc":"The pending rotation has not collected enough approvals yet.","name":"QuorumNotMet","value":1315},{"doc":"The rotation timelock has not elapsed yet.","name":"TimelockNotElapsed","value":1316}]}}, - {"function_v0":{"doc":"Initialise the contract by storing the pause admin, the announcer address, and an optional asset policy.","name":"init","inputs":[{"doc":"","name":"admin","type_":"address"},{"doc":"","name":"announcer","type_":"address"},{"doc":"","name":"asset_policy","type_":{"option":{"value_type":"address"}}}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Pause the contract — admin only.","name":"pause","inputs":[{"doc":"","name":"caller","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Unpause the contract — admin only.","name":"unpause","inputs":[{"doc":"","name":"caller","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Returns true if the contract is paused.","name":"is_paused","inputs":[],"outputs":["bool"]}}, - {"function_v0":{"doc":"Atomically send `asset` tokens from `from` to N pre-computed stealth addresses in a single transaction.","name":"batch_send","inputs":[{"doc":"","name":"from","type_":"address"},{"doc":"","name":"transfers","type_":{"vec":{"element_type":{"udt":{"name":"Transfer"}}}}},{"doc":"","name":"asset","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Query the maximum allowed batch size.","name":"max_batch_size","inputs":[],"outputs":["u32"]}}, - {"function_v0":{"doc":"One-time setup of the governance signer set used to authorise signer rotations.","name":"init_multisig","inputs":[{"doc":"","name":"signers","type_":{"vec":{"element_type":"address"}}},{"doc":"","name":"threshold","type_":"u32"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Current governance signer set.","name":"signers","inputs":[],"outputs":[{"vec":{"element_type":"address"}}]}}, - {"function_v0":{"doc":"Current governance quorum threshold.","name":"threshold","inputs":[],"outputs":["u32"]}}, - {"function_v0":{"doc":"The pending signer-rotation proposal, if any.","name":"pending_rotation","inputs":[],"outputs":[{"option":{"value_type":{"udt":{"name":"RotationProposal"}}}}]}}, - {"function_v0":{"doc":"Propose a new signer set + threshold behind the rotation timelock.","name":"propose_rotate_signers","inputs":[{"doc":"","name":"caller","type_":"address"},{"doc":"","name":"new_signers","type_":{"vec":{"element_type":"address"}}},{"doc":"","name":"new_threshold","type_":"u32"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Approve the pending signer-rotation proposal.","name":"approve_rotate_signers","inputs":[{"doc":"","name":"caller","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Execute the pending rotation once quorum is met and the timelock has elapsed.","name":"execute_rotate_signers","inputs":[{"doc":"","name":"caller","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}}, - {"function_v0":{"doc":"Cancel the pending rotation, clearing all of its state.","name":"cancel_rotate_signers","inputs":[{"doc":"","name":"caller","type_":"address"}],"outputs":[{"result":{"ok_type":{"tuple":{"value_types":[]}},"error_type":{"udt":{"name":"BatchSenderError"}}}}]}} + { + "function_v0": { + "doc": "Initialise the contract by storing the pause admin, the announcer\\naddress, and an optional asset policy. Idempotent: a second call\\nreturns `AlreadyInitialized` rather than overwriting the config.\\n\\nMust be called before `batch_send`.", + "name": "init", + "inputs": [ + { + "doc": "", + "name": "admin", + "type_": "address" + }, + { + "doc": "", + "name": "announcer", + "type_": "address" + }, + { + "doc": "", + "name": "asset_policy", + "type_": { + "option": { + "value_type": "address" + } + } + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Pause the contract \\xe2\\x80\\x94 admin only. Prevents `batch_send` while paused.", + "name": "pause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Current governance signer set.", + "name": "signers", + "inputs": [], + "outputs": [ + { + "vec": { + "element_type": "address" + } + } + ] + } + }, + { + "function_v0": { + "doc": "Unpause the contract \\xe2\\x80\\x94 admin only.", + "name": "unpause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Returns true if the contract is paused.", + "name": "is_paused", + "inputs": [], + "outputs": [ + "bool" + ] + } + }, + { + "function_v0": { + "doc": "Current governance quorum threshold.", + "name": "threshold", + "inputs": [], + "outputs": [ + "u32" + ] + } + }, + { + "udt_union_v0": { + "doc": "Storage keys.", + "lib": "", + "name": "DataKey", + "cases": [ + { + "void_v0": { + "doc": "Pause admin address.", + "name": "Admin" + } + }, + { + "void_v0": { + "doc": "Address of the deployed StealthAnnouncer contract, recorded at init\\ntime. Invoked by `batch_send` for each transfer so announcements use\\nthe v2 4-topic layout (`announce`, scheme_id, view_tag_bucket, metadata_kind).", + "name": "Announcer" + } + }, + { + "void_v0": { + "doc": "Optional address of the asset policy contract.", + "name": "AssetPolicy" + } + }, + { + "void_v0": { + "doc": "Whether the contract is paused.", + "name": "Paused" + } + }, + { + "void_v0": { + "doc": "Governance multisig signer set.", + "name": "MultisigSigners" + } + }, + { + "void_v0": { + "doc": "Governance multisig quorum threshold.", + "name": "MultisigThreshold" + } + }, + { + "void_v0": { + "doc": "Pending signer-rotation proposal, if any.", + "name": "PendingRotation" + } + } + ] + } + }, + { + "function_v0": { + "doc": "Atomically send `asset` tokens from `from` to N pre-computed stealth\\naddresses in a single transaction.\\n\\n# All-or-nothing semantics\\nSoroban reverts every state change made during a failed invocation \\xe2\\x80\\x94\\nwhether the failure is a panic or a returned contract error \\xe2\\x80\\x94 so a\\nrejected batch never leaves partial transfers behind.\\n\\n# Resource budget\\nCapped at MAX_BATCH_SIZE (100) transfers. This keeps instruction usage\\nwell under Soroban's per-transaction limit while still being ~100x more\\nefficient than N individual stealth-sender::send calls (one auth, one\\nledger round-trip vs N).", + "name": "batch_send", + "inputs": [ + { + "doc": "", + "name": "from", + "type_": "address" + }, + { + "doc": "", + "name": "transfers", + "type_": { + "vec": { + "element_type": { + "udt": { + "name": "Transfer" + } + } + } + } + }, + { + "doc": "", + "name": "asset", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A single stealth transfer within a batch.\\nMirrors the EVM WraithSender batchSendETH/batchSendERC20 structure.", + "lib": "", + "name": "Transfer", + "fields": [ + { + "doc": "Token amount (in the asset's base unit)", + "name": "amount", + "type_": "i128" + }, + { + "doc": "Ephemeral public key for the recipient to scan with.\\nMust be exactly 32 bytes so it can be forwarded to the announcer.", + "name": "ephemeral_pub_key", + "type_": "bytes" + }, + { + "doc": "Announcement metadata whose first byte is the view tag\\n(`view_tag_bucket = metadata[0] as u32` under metadata_kind = 1).", + "name": "metadata", + "type_": "bytes" + }, + { + "doc": "Pre-computed stealth address (recipient)", + "name": "stealth_address", + "type_": "address" + } + ] + } + }, + { + "function_v0": { + "doc": "One-time setup of the governance signer set used to authorise signer\\nrotations. Independent of `init` \\xe2\\x80\\x94 does not gate `batch_send`.", + "name": "init_multisig", + "inputs": [ + { + "doc": "", + "name": "signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Query the maximum allowed batch size.", + "name": "max_batch_size", + "inputs": [], + "outputs": [ + "u32" + ] + } + }, + { + "function_v0": { + "doc": "The pending signer-rotation proposal, if any.", + "name": "pending_rotation", + "inputs": [], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "RotationProposal" + } + } + } + } + ] + } + }, + { + "udt_error_enum_v0": { + "doc": "Errors that the batch-sender contract can produce.\\n\\nCodes are allocated from the `1300-1399` range reserved for\\n`stealth-batch-sender` in `ERRORS.md`'s code-allocation policy.", + "lib": "", + "name": "BatchSenderError", + "cases": [ + { + "doc": "The contract has already been initialised.", + "name": "AlreadyInitialized", + "value": 1300 + }, + { + "doc": "The contract has not been initialised yet.", + "name": "NotInitialized", + "value": 1301 + }, + { + "doc": "The batch contains no transfers.", + "name": "EmptyBatch", + "value": 1302 + }, + { + "doc": "The batch exceeds `MAX_BATCH_SIZE`.", + "name": "BatchTooLarge", + "value": 1303 + }, + { + "doc": "A transfer amount was zero or negative.", + "name": "NonPositiveAmount", + "value": 1304 + }, + { + "doc": "A transfer's ephemeral public key was empty or not 32 bytes.", + "name": "EmptyEphemeralKey", + "value": 1305 + }, + { + "doc": "The contract is paused.", + "name": "Paused", + "value": 1306 + }, + { + "doc": "The asset is not allowed by the configured asset policy.", + "name": "AssetNotAllowed", + "value": 1307 + }, + { + "doc": "The governance multisig has not been initialised.", + "name": "MultisigNotInitialized", + "value": 1308 + }, + { + "doc": "The governance multisig has already been initialised.", + "name": "MultisigAlreadyInitialized", + "value": 1309 + }, + { + "doc": "The caller is not a current governance signer.", + "name": "NotSigner", + "value": 1310 + }, + { + "doc": "The requested threshold is invalid (zero, or greater than signer count).", + "name": "InvalidThreshold", + "value": 1311 + }, + { + "doc": "A signer-rotation proposal is already pending.", + "name": "RotationAlreadyPending", + "value": 1312 + }, + { + "doc": "No signer-rotation proposal is pending.", + "name": "NoPendingRotation", + "value": 1313 + }, + { + "doc": "The caller has already approved the pending rotation.", + "name": "AlreadyApprovedRotation", + "value": 1314 + }, + { + "doc": "The pending rotation has not collected enough approvals yet.", + "name": "QuorumNotMet", + "value": 1315 + }, + { + "doc": "The rotation timelock has not elapsed yet.", + "name": "TimelockNotElapsed", + "value": 1316 + } + ] + } + }, + { + "function_v0": { + "doc": "Cancel the pending rotation, clearing all of its state.", + "name": "cancel_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Approve the pending signer-rotation proposal.", + "name": "approve_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Execute the pending rotation once quorum is met and the timelock has\\nelapsed. Emits `SignersRotated`.", + "name": "execute_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Propose a new signer set + threshold behind the rotation timelock.\\n`caller` must be a current signer; the proposal is auto-approved by\\n`caller`. Rejects thresholds that could never reach quorum.", + "name": "propose_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "BatchSenderError" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A pending signer-rotation proposal.", + "lib": "", + "name": "RotationProposal", + "fields": [ + { + "doc": "", + "name": "approvals", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "executable_at", + "type_": "u64" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "Wraith Protocol standard metric event schema.\\n\\nAll Wraith contracts emit metric events using this structure to enable\\nstandardized off-chain observability and monitoring.", + "lib": "", + "name": "WraithMetricEvent", + "fields": [ + { + "doc": "Contract identifier (e.g., \"stealth-registry\", \"stealth-sender\")", + "name": "contract", + "type_": "symbol" + }, + { + "doc": "Optional dimensions for filtering/grouping (e.g., token_address, scheme_id)", + "name": "dimensions", + "type_": { + "vec": { + "element_type": { + "tuple": { + "value_types": [ + "symbol", + "val" + ] + } + } + } + } + }, + { + "doc": "Metric name (e.g., \"register_count\", \"send_volume\")", + "name": "metric_name", + "type_": "symbol" + }, + { + "doc": "Numeric value of the metric", + "name": "value", + "type_": "i128" + } + ] + } + } ] diff --git a/stellar/abi/stealth_registry.json b/stellar/abi/stealth_registry.json index cfc16cff..6f1384ab 100644 --- a/stellar/abi/stealth_registry.json +++ b/stellar/abi/stealth_registry.json @@ -18,6 +18,40 @@ ] } }, + { + "function_v0": { + "doc": "Remove a previously registered stealth meta-address.\\n\\n# Arguments\\n* `registrant` - The address whose meta-address is being removed (must authorise).\\n* `scheme_id` - The stealth address scheme identifier.", + "name": "remove_keys", + "inputs": [ + { + "doc": "", + "name": "registrant", + "type_": "address" + }, + { + "doc": "", + "name": "scheme_id", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "RegistryError" + } + } + } + } + ] + } + }, { "function_v0": { "doc": "Register or update a stealth meta-address.\\n\\n# Arguments\\n* `registrant` - The address whose meta-address is being set (must authorise).\\n* `scheme_id` - The stealth address scheme identifier.\\n* `stealth_meta_address` - 64-byte value: `spending_pubkey || viewing_pubkey`.", @@ -105,5 +139,45 @@ } ] } + }, + { + "udt_struct_v0": { + "doc": "Wraith Protocol standard metric event schema.\\n\\nAll Wraith contracts emit metric events using this structure to enable\\nstandardized off-chain observability and monitoring.", + "lib": "", + "name": "WraithMetricEvent", + "fields": [ + { + "doc": "Contract identifier (e.g., \"stealth-registry\", \"stealth-sender\")", + "name": "contract", + "type_": "symbol" + }, + { + "doc": "Optional dimensions for filtering/grouping (e.g., token_address, scheme_id)", + "name": "dimensions", + "type_": { + "vec": { + "element_type": { + "tuple": { + "value_types": [ + "symbol", + "val" + ] + } + } + } + } + }, + { + "doc": "Metric name (e.g., \"register_count\", \"send_volume\")", + "name": "metric_name", + "type_": "symbol" + }, + { + "doc": "Numeric value of the metric", + "name": "value", + "type_": "i128" + } + ] + } } ] diff --git a/stellar/abi/stealth_sender.json b/stellar/abi/stealth_sender.json index 2149d2b9..3a98cb54 100644 --- a/stellar/abi/stealth_sender.json +++ b/stellar/abi/stealth_sender.json @@ -1,13 +1,41 @@ [ { "function_v0": { - "doc": "Initialise the contract by storing the announcer address.\\n\\nMust be called exactly once before any `send` or `batch_send`.", + "doc": "Initialise the contract by storing the announcer address, optional asset policy,\\nand optional protocol fee configuration.\\n\\nMust be called exactly once before any `send` or `batch_send`.", "name": "init", "inputs": [ { "doc": "", "name": "announcer", "type_": "address" + }, + { + "doc": "", + "name": "asset_policy", + "type_": { + "option": { + "value_type": "address" + } + } + }, + { + "doc": "", + "name": "fee_recipient", + "type_": { + "option": { + "value_type": "address" + } + } + }, + { + "doc": "", + "name": "fee_basis_points", + "type_": "u32" + }, + { + "doc": "", + "name": "admin", + "type_": "address" } ], "outputs": [ @@ -91,6 +119,98 @@ ] } }, + { + "function_v0": { + "doc": "Pause the contract \\xe2\\x80\\x94 admin only.\\nPrevents all sends and batch_sends while paused.", + "name": "pause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Current governance signer set.", + "name": "signers", + "inputs": [], + "outputs": [ + { + "vec": { + "element_type": "address" + } + } + ] + } + }, + { + "function_v0": { + "doc": "Unpause the contract \\xe2\\x80\\x94 admin only.", + "name": "unpause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Returns true if the contract is paused.", + "name": "is_paused", + "inputs": [], + "outputs": [ + "bool" + ] + } + }, + { + "function_v0": { + "doc": "Current governance quorum threshold.", + "name": "threshold", + "inputs": [], + "outputs": [ + "u32" + ] + } + }, { "udt_union_v0": { "doc": "Storage keys.", @@ -102,6 +222,54 @@ "doc": "The address of the deployed StealthAnnouncer contract.", "name": "Announcer" } + }, + { + "void_v0": { + "doc": "Optional address of the asset policy contract.", + "name": "AssetPolicy" + } + }, + { + "void_v0": { + "doc": "Optional address of the protocol fee recipient.", + "name": "FeeRecipient" + } + }, + { + "void_v0": { + "doc": "Protocol fee in basis points (max 50 bps, 0 = disabled).", + "name": "FeeBasisPoints" + } + }, + { + "void_v0": { + "doc": "Pause admin address.", + "name": "Admin" + } + }, + { + "void_v0": { + "doc": "Whether the contract is paused.", + "name": "Paused" + } + }, + { + "void_v0": { + "doc": "Governance multisig signer set.", + "name": "MultisigSigners" + } + }, + { + "void_v0": { + "doc": "Governance multisig quorum threshold.", + "name": "MultisigThreshold" + } + }, + { + "void_v0": { + "doc": "Pending signer-rotation proposal, if any.", + "name": "PendingRotation" + } } ] } @@ -185,6 +353,86 @@ ] } }, + { + "function_v0": { + "doc": "One-time setup of the governance signer set used to authorise signer\\nrotations. Independent of `init` \\xe2\\x80\\x94 does not gate `send`/`batch_send`.", + "name": "init_multisig", + "inputs": [ + { + "doc": "", + "name": "signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Withdraw assets to multiple destinations in a single atomic transaction.\\n\\nThe batch is capped at 30 entries. If any single entry cannot be\\nprocessed, the entire batch aborts and no state changes are retained.", + "name": "withdraw_many", + "inputs": [ + { + "doc": "", + "name": "withdrawer", + "type_": "address" + }, + { + "doc": "", + "name": "entries", + "type_": { + "vec": { + "element_type": { + "udt": { + "name": "WithdrawalEntry" + } + } + } + } + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, { "udt_error_enum_v0": { "doc": "Errors that the sender contract can produce.", @@ -205,6 +453,320 @@ "doc": "The batch input vectors have mismatched lengths.", "name": "LengthMismatch", "value": 3 + }, + { + "doc": "The token is not allowed by the asset policy.", + "name": "TokenNotAllowed", + "value": 4 + }, + { + "doc": "The fee configuration is invalid (e.g. fee > 50 bps, or fee > 0 with no recipient).", + "name": "InvalidFeeConfig", + "value": 5 + }, + { + "doc": "The contract is paused.", + "name": "Paused", + "value": 16 + }, + { + "doc": "The batch withdrawal exceeds the supported size cap.", + "name": "BatchTooLarge", + "value": 6 + }, + { + "doc": "The governance multisig has not been initialised.", + "name": "MultisigNotInitialized", + "value": 7 + }, + { + "doc": "The governance multisig has already been initialised.", + "name": "MultisigAlreadyInitialized", + "value": 8 + }, + { + "doc": "The caller is not a current governance signer.", + "name": "NotSigner", + "value": 9 + }, + { + "doc": "The requested threshold is invalid (zero, or greater than signer count).", + "name": "InvalidThreshold", + "value": 10 + }, + { + "doc": "A signer-rotation proposal is already pending.", + "name": "RotationAlreadyPending", + "value": 11 + }, + { + "doc": "No signer-rotation proposal is pending.", + "name": "NoPendingRotation", + "value": 12 + }, + { + "doc": "The caller has already approved the pending rotation.", + "name": "AlreadyApprovedRotation", + "value": 13 + }, + { + "doc": "The pending rotation has not collected enough approvals yet.", + "name": "QuorumNotMet", + "value": 14 + }, + { + "doc": "The rotation timelock has not elapsed yet.", + "name": "TimelockNotElapsed", + "value": 15 + } + ] + } + }, + { + "function_v0": { + "doc": "The pending signer-rotation proposal, if any.", + "name": "pending_rotation", + "inputs": [], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "RotationProposal" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A single withdrawal entry for batched asset exits.", + "lib": "", + "name": "WithdrawalEntry", + "fields": [ + { + "doc": "The amount to transfer in the token's base unit.", + "name": "amount", + "type_": "i128" + }, + { + "doc": "The destination address for the withdrawal.", + "name": "to", + "type_": "address" + }, + { + "doc": "The token contract to withdraw from or to transfer through.", + "name": "token", + "type_": "address" + } + ] + } + }, + { + "function_v0": { + "doc": "Cancel the pending rotation, clearing all of its state.", + "name": "cancel_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Approve the pending signer-rotation proposal.", + "name": "approve_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Execute the pending rotation once quorum is met and the timelock has\\nelapsed. Emits `SignersRotated`.", + "name": "execute_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Propose a new signer set + threshold behind the rotation timelock.\\n`caller` must be a current signer; the proposal is auto-approved by\\n`caller`. Rejects thresholds that could never reach quorum.", + "name": "propose_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "SenderError" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A pending signer-rotation proposal.", + "lib": "", + "name": "RotationProposal", + "fields": [ + { + "doc": "", + "name": "approvals", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "executable_at", + "type_": "u64" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "Wraith Protocol standard metric event schema.\\n\\nAll Wraith contracts emit metric events using this structure to enable\\nstandardized off-chain observability and monitoring.", + "lib": "", + "name": "WraithMetricEvent", + "fields": [ + { + "doc": "Contract identifier (e.g., \"stealth-registry\", \"stealth-sender\")", + "name": "contract", + "type_": "symbol" + }, + { + "doc": "Optional dimensions for filtering/grouping (e.g., token_address, scheme_id)", + "name": "dimensions", + "type_": { + "vec": { + "element_type": { + "tuple": { + "value_types": [ + "symbol", + "val" + ] + } + } + } + } + }, + { + "doc": "Metric name (e.g., \"register_count\", \"send_volume\")", + "name": "metric_name", + "type_": "symbol" + }, + { + "doc": "Numeric value of the metric", + "name": "value", + "type_": "i128" } ] } diff --git a/stellar/abi/wraith_names.json b/stellar/abi/wraith_names.json index 2be38bf2..a999e087 100644 --- a/stellar/abi/wraith_names.json +++ b/stellar/abi/wraith_names.json @@ -1,4 +1,62 @@ [ + { + "function_v0": { + "doc": "Initialise the contract by storing the pause admin.\\n\\nMust be called before `pause` / `unpause`. Idempotent: calling\\nmore than once is a no-op (the first admin sticks).", + "name": "init", + "inputs": [ + { + "doc": "", + "name": "admin", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Pause the contract \\xe2\\x80\\x94 admin only.\\nPrevents all registrations, updates, releases and TTL extensions\\nwhile paused. Lookups (`resolve`, `name_of`) remain available.", + "name": "pause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, { "function_v0": { "doc": "Update the meta-address for an existing name.\\nOnly the current owner can update.", @@ -99,7 +157,7 @@ }, { "function_v0": { - "doc": "Resolve a name to its stealth meta-address.", + "doc": "Resolve a name to its stealth meta-address.\\n\\nFor a subdomain (`payments.alice`) resolution walks to the parent\\n(`alice`): if the parent no longer exists the subdomain does not resolve.", "name": "resolve", "inputs": [ { @@ -124,7 +182,50 @@ }, { "function_v0": { - "doc": "Register a name mapped to a stealth meta-address.\\nThe caller (owner) must authorize. Ownership is tied to the caller's address.\\n\\n# Arguments\\n* `owner` - The address registering the name (must authorize).\\n* `name` - The human-readable name (lowercase alphanumeric, 3-32 chars).\\n* `stealth_meta_address` - 64-byte stealth meta-address.", + "doc": "Current protocol-level governance signer set.", + "name": "signers", + "inputs": [], + "outputs": [ + { + "vec": { + "element_type": "address" + } + } + ] + } + }, + { + "function_v0": { + "doc": "Unpause the contract \\xe2\\x80\\x94 admin only.", + "name": "unpause", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Register a name mapped to a stealth meta-address.", "name": "register", "inputs": [ { @@ -161,6 +262,26 @@ ] } }, + { + "function_v0": { + "doc": "Returns true if the contract is paused.", + "name": "is_paused", + "inputs": [], + "outputs": [ + "bool" + ] + } + }, + { + "function_v0": { + "doc": "Current protocol-level governance quorum threshold.", + "name": "threshold", + "inputs": [], + "outputs": [ + "u32" + ] + } + }, { "udt_union_v0": { "doc": "Storage keys.", @@ -182,7 +303,7 @@ }, { "tuple_v0": { - "doc": "Reverse lookup: meta-address hash (BytesN<32>) to name hash (BytesN<32>).", + "doc": "Reverse lookup: meta-address hash (BytesN<32>) to name string.", "name": "Reverse", "type_": [ { @@ -192,64 +313,383 @@ } ] } + }, + { + "tuple_v0": { + "doc": "Replay protection for signed on-behalf calls.", + "name": "Replay", + "type_": [ + { + "bytes_n": { + "n": 32 + } + } + ] + } + }, + { + "tuple_v0": { + "doc": "Guardian config for a name.", + "name": "Guardians", + "type_": [ + { + "bytes_n": { + "n": 32 + } + } + ] + } + }, + { + "tuple_v0": { + "doc": "Pending recovery proposal for a name.", + "name": "Recovery", + "type_": [ + { + "bytes_n": { + "n": 32 + } + } + ] + } + }, + { + "void_v0": { + "doc": "Pause admin address.", + "name": "Admin" + } + }, + { + "void_v0": { + "doc": "Whether the contract is paused.", + "name": "Paused" + } + }, + { + "void_v0": { + "doc": "Protocol-level governance multisig signer set.", + "name": "MultisigSigners" + } + }, + { + "void_v0": { + "doc": "Protocol-level governance multisig quorum threshold.", + "name": "MultisigThreshold" + } + }, + { + "void_v0": { + "doc": "Pending protocol-level signer-rotation proposal, if any.", + "name": "PendingRotation" + } + }, + { + "void_v0": { + "doc": "Pending auction-admin rotation proposal, if any.", + "name": "PendingAuctionAdminRotation" + } } ] } }, { - "udt_struct_v0": { - "doc": "A registered name entry.", - "lib": "", - "name": "NameEntry", - "fields": [ + "function_v0": { + "doc": "Renew (extend TTL for) multiple names in a single atomic transaction.\\n\\nAll names must exist. If any name is not found, the entire operation\\nreverts.", + "name": "bulk_renew", + "inputs": [ { - "doc": "The human-readable name.", - "name": "name", - "type_": "string" + "doc": "", + "name": "names", + "type_": { + "vec": { + "element_type": "string" + } + } }, { - "doc": "The registrant address (for auth).", - "name": "owner", + "doc": "", + "name": "extend_to_ledger", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Claim a won auction: registers the name to the winner with their\\nstealth meta-address.", + "name": "claim_name", + "inputs": [ + { + "doc": "", + "name": "winner", "type_": "address" }, { - "doc": "The 64-byte stealth meta-address (spending_pubkey || viewing_pubkey).", + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", "name": "stealth_meta_address", "type_": "bytes" } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } ] } }, { - "udt_error_enum_v0": { - "doc": "Errors.", - "lib": "", - "name": "NamesError", - "cases": [ + "function_v0": { + "doc": "Commit a sealed bid. `commitment` hides the bid amount; `deposit` is\\ntransferred to the contract and must cover the bid revealed later.", + "name": "commit_bid", + "inputs": [ { "doc": "", - "name": "NameTaken", - "value": 1 + "name": "bidder", + "type_": "address" }, { "doc": "", - "name": "NameTooShort", - "value": 2 + "name": "name", + "type_": "string" }, { "doc": "", - "name": "NameTooLong", - "value": 3 + "name": "commitment", + "type_": { + "bytes_n": { + "n": 32 + } + } }, { "doc": "", - "name": "InvalidNameCharacter", - "value": 4 - }, + "name": "deposit", + "type_": "i128" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Reveal a previously committed bid by disclosing the amount and salt.", + "name": "reveal_bid", + "inputs": [ { "doc": "", - "name": "InvalidMetaAddress", - "value": 5 + "name": "bidder", + "type_": "address" + }, + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "amount", + "type_": "i128" + }, + { + "doc": "", + "name": "salt", + "type_": { + "bytes_n": { + "n": 32 + } + } + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Read the auction state for a name, if any.", + "name": "get_auction", + "inputs": [ + { + "doc": "", + "name": "name", + "type_": "string" + } + ], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "Auction" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A registered name entry.", + "lib": "", + "name": "NameEntry", + "fields": [ + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "owner", + "type_": "address" + }, + { + "doc": "For a subdomain (`sub.parent`), the name hash of the parent label.\\n`None` for a flat top-level name. Existing flat names register with\\n`None`, so prior behaviour is preserved.", + "name": "parent", + "type_": { + "option": { + "value_type": { + "bytes_n": { + "n": 32 + } + } + } + } + }, + { + "doc": "", + "name": "stealth_meta_address", + "type_": "bytes" + } + ] + } + }, + { + "function_v0": { + "doc": "Withdraw a losing (or unrevealed) bid deposit in full.", + "name": "withdraw_bid", + "inputs": [ + { + "doc": "", + "name": "bidder", + "type_": "address" + }, + { + "doc": "", + "name": "name", + "type_": "string" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "udt_error_enum_v0": { + "doc": "Errors.", + "lib": "", + "name": "NamesError", + "cases": [ + { + "doc": "", + "name": "NameTaken", + "value": 1 + }, + { + "doc": "", + "name": "NameTooShort", + "value": 2 + }, + { + "doc": "", + "name": "NameTooLong", + "value": 3 + }, + { + "doc": "", + "name": "InvalidNameCharacter", + "value": 4 + }, + { + "doc": "", + "name": "InvalidMetaAddress", + "value": 5 }, { "doc": "", @@ -260,6 +700,1333 @@ "doc": "", "name": "NotOwner", "value": 7 + }, + { + "doc": "", + "name": "SignatureExpired", + "value": 8 + }, + { + "doc": "", + "name": "SignatureReplay", + "value": 9 + }, + { + "doc": "", + "name": "InvalidSigner", + "value": 10 + }, + { + "doc": "", + "name": "NotGuardian", + "value": 11 + }, + { + "doc": "", + "name": "NoProposal", + "value": 12 + }, + { + "doc": "", + "name": "ProposalAlreadyExists", + "value": 13 + }, + { + "doc": "", + "name": "AlreadyApproved", + "value": 14 + }, + { + "doc": "", + "name": "DelayNotElapsed", + "value": 15 + }, + { + "doc": "", + "name": "ThresholdNotMet", + "value": 16 + }, + { + "doc": "", + "name": "TooManyGuardians", + "value": 17 + }, + { + "doc": "", + "name": "InvalidThreshold", + "value": 18 + }, + { + "doc": "", + "name": "InvalidExtendLedger", + "value": 19 + }, + { + "doc": "", + "name": "ParentNotFound", + "value": 20 + }, + { + "doc": "The contract is paused.", + "name": "Paused", + "value": 32 + }, + { + "doc": "The protocol-level governance multisig has not been initialised.", + "name": "MultisigNotInitialized", + "value": 21 + }, + { + "doc": "The protocol-level governance multisig has already been initialised.", + "name": "MultisigAlreadyInitialized", + "value": 22 + }, + { + "doc": "The caller is not a current protocol-level governance signer.", + "name": "NotSigner", + "value": 23 + }, + { + "doc": "A signer-rotation proposal is already pending.", + "name": "RotationAlreadyPending", + "value": 24 + }, + { + "doc": "No signer-rotation proposal is pending.", + "name": "NoPendingRotation", + "value": 25 + }, + { + "doc": "The caller has already approved the pending rotation.", + "name": "AlreadyApprovedRotation", + "value": 26 + }, + { + "doc": "The pending rotation has not collected enough approvals yet.", + "name": "QuorumNotMet", + "value": 27 + }, + { + "doc": "The rotation timelock has not elapsed yet.", + "name": "TimelockNotElapsed", + "value": 28 + }, + { + "doc": "", + "name": "NameTooDeep", + "value": 29 + }, + { + "doc": "", + "name": "BulkLimitExceeded", + "value": 30 + }, + { + "doc": "The name is premium (<= 4 chars) and the auction window is active, so\\nit can only be obtained through the sealed-bid auction.", + "name": "PremiumAuctionRequired", + "value": 31 + }, + { + "doc": "The auction subsystem has not been initialised, so there is no auction\\nadmin to rotate.", + "name": "AuctionsNotInitialized", + "value": 1600 + }, + { + "doc": "An auction has a revealed winner and has not settled yet, so the\\nauction admin cannot be rotated out from under it.", + "name": "AuctionInProgress", + "value": 1601 + } + ] + } + }, + { + "function_v0": { + "doc": "Register multiple names in a single atomic transaction.\\n\\nAll names must be valid and not already taken. If any name fails,\\nthe entire operation reverts.", + "name": "bulk_register", + "inputs": [ + { + "doc": "", + "name": "owner", + "type_": "address" + }, + { + "doc": "", + "name": "names", + "type_": { + "vec": { + "element_type": "string" + } + } + }, + { + "doc": "", + "name": "meta_addresses", + "type_": { + "vec": { + "element_type": "bytes" + } + } + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "One-time initialization of the premium-name auction system.\\n\\n`admin` operates settlements per the runbook, `treasury` receives\\nwinning bids, `token` is the payment asset (native XLM SAC on mainnet),\\n`reserve_price` is the minimum bid, and `commit_secs` / `reveal_secs`\\nare the phase durations for each auction. The 90-day premium window\\nstarts at the ledger timestamp of this call.", + "name": "init_auctions", + "inputs": [ + { + "doc": "", + "name": "admin", + "type_": "address" + }, + { + "doc": "", + "name": "treasury", + "type_": "address" + }, + { + "doc": "", + "name": "token", + "type_": "address" + }, + { + "doc": "", + "name": "reserve_price", + "type_": "i128" + }, + { + "doc": "", + "name": "commit_secs", + "type_": "u64" + }, + { + "doc": "", + "name": "reveal_secs", + "type_": "u64" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "One-time setup of the protocol-level governance signer set used to\\nauthorise signer rotations.", + "name": "init_multisig", + "inputs": [ + { + "doc": "", + "name": "signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Start a sealed-bid auction for a premium name (<= 4 chars, top-level).\\nPermissionless: anyone may open the auction for an eligible name.", + "name": "start_auction", + "inputs": [ + { + "doc": "", + "name": "name", + "type_": "string" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Read the auction configuration, if initialized.", + "name": "auction_config", + "inputs": [], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "AuctionConfig" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Settle an auction after the reveal phase: pays the winning bid to the\\ntreasury and refunds the winner's excess deposit. Permissionless so\\nfunds can never be trapped, operated by the admin per the runbook.", + "name": "settle_auction", + "inputs": [ + { + "doc": "", + "name": "name", + "type_": "string" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "AuctionError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Extend TTL for persistent storage entries only.\\nExtend the TTL of a registered name to a future ledger.\\nThis is a permissionless function that anyone can call.\\nIdempotent: calling twice in the same ledger has no additional effect.", + "name": "extend_name_ttl", + "inputs": [ + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "extend_to_ledger", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "The pending signer-rotation proposal, if any.", + "name": "pending_rotation", + "inputs": [], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "RotationProposal" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Update a name on behalf of an owner using a signed authorization.", + "name": "update_on_behalf", + "inputs": [ + { + "doc": "", + "name": "owner", + "type_": "address" + }, + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "new_meta_address", + "type_": "bytes" + }, + { + "doc": "", + "name": "signature", + "type_": { + "bytes_n": { + "n": 64 + } + } + }, + { + "doc": "", + "name": "expiry", + "type_": "u64" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "Guardian configuration for a name.", + "lib": "", + "name": "GuardianConfig", + "fields": [ + { + "doc": "", + "name": "guardians", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "threshold", + "type_": "u32" + } + ] + } + }, + { + "function_v0": { + "doc": "Release a name on behalf of an owner using a signed authorization.", + "name": "release_on_behalf", + "inputs": [ + { + "doc": "", + "name": "owner", + "type_": "address" + }, + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "signature", + "type_": { + "bytes_n": { + "n": 64 + } + } + }, + { + "doc": "", + "name": "expiry", + "type_": "u64" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Compute the sealed-bid commitment for the given parameters.\\n\\nIntended for off-chain use (simulation only): calling this in a real\\ntransaction would leak the bid amount.", + "name": "compute_commitment", + "inputs": [ + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "bidder", + "type_": "address" + }, + { + "doc": "", + "name": "amount", + "type_": "i128" + }, + { + "doc": "", + "name": "salt", + "type_": { + "bytes_n": { + "n": 32 + } + } + } + ], + "outputs": [ + { + "bytes_n": { + "n": 32 + } + } + ] + } + }, + { + "function_v0": { + "doc": "Register a name on behalf of an owner using a signed authorization.", + "name": "register_on_behalf", + "inputs": [ + { + "doc": "", + "name": "owner", + "type_": "address" + }, + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "", + "name": "stealth_meta_address", + "type_": "bytes" + }, + { + "doc": "", + "name": "signature", + "type_": { + "bytes_n": { + "n": 64 + } + } + }, + { + "doc": "", + "name": "expiry", + "type_": "u64" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A pending recovery proposal.", + "lib": "", + "name": "RecoveryProposal", + "fields": [ + { + "doc": "", + "name": "approvals", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_meta_address", + "type_": "bytes" + }, + { + "doc": "", + "name": "new_owner", + "type_": "address" + }, + { + "doc": "", + "name": "proposed_at", + "type_": "u32" + } + ] + } + }, + { + "function_v0": { + "doc": "Cancel the pending rotation, clearing all of its state.", + "name": "cancel_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Approve the pending signer-rotation proposal.", + "name": "approve_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Execute the pending rotation once quorum is met and the timelock has\\nelapsed. Emits `SignersRotated`.", + "name": "execute_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Propose a new signer set + threshold behind the rotation timelock.\\n`caller` must be a current signer; the proposal is auto-approved by\\n`caller`. Rejects thresholds that could never reach quorum.", + "name": "propose_rotate_signers", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Auctions with a revealed winner that have not settled yet. While this\\nis non-zero, `execute_rotate_auction_admin` is blocked.", + "name": "auctions_pending_settlement", + "inputs": [], + "outputs": [ + "u32" + ] + } + }, + { + "function_v0": { + "doc": "Cancel the pending auction-admin rotation, clearing all of its state.", + "name": "cancel_rotate_auction_admin", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Approve the pending auction-admin rotation proposal.", + "name": "approve_rotate_auction_admin", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Execute the pending auction-admin rotation once quorum is met and the\\ntimelock has elapsed. Emits `AuctionAdminRotated(old, new)`.\\n\\nFails with `AuctionInProgress` while any auction is in its reveal or\\nsettle phase, leaving the proposal intact so it can be retried after\\nsettlement.", + "name": "execute_rotate_auction_admin", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "Propose a new premium-auction admin behind the 7-day rotation\\ntimelock, gated by the same governance signer set as\\n`propose_rotate_signers`. `caller` must be a current signer; the\\nproposal is auto-approved by `caller`.", + "name": "propose_rotate_auction_admin", + "inputs": [ + { + "doc": "", + "name": "caller", + "type_": "address" + }, + { + "doc": "", + "name": "new_admin", + "type_": "address" + } + ], + "outputs": [ + { + "result": { + "ok_type": { + "tuple": { + "value_types": [] + } + }, + "error_type": { + "udt": { + "name": "NamesError" + } + } + } + } + ] + } + }, + { + "function_v0": { + "doc": "The pending auction-admin rotation proposal, if any.", + "name": "pending_auction_admin_rotation", + "inputs": [], + "outputs": [ + { + "option": { + "value_type": { + "udt": { + "name": "AdminRotationProposal" + } + } + } + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "State of a single name auction.", + "lib": "", + "name": "Auction", + "fields": [ + { + "doc": "Timestamp at which the commit phase ends and the reveal phase begins.", + "name": "commit_end", + "type_": "u64" + }, + { + "doc": "Highest revealed bid amount so far.", + "name": "highest_amount", + "type_": "i128" + }, + { + "doc": "Highest revealed bidder so far. Ties go to the earliest reveal.", + "name": "highest_bidder", + "type_": { + "option": { + "value_type": "address" + } + } + }, + { + "doc": "", + "name": "name", + "type_": "string" + }, + { + "doc": "Timestamp at which the reveal phase ends and settlement is possible.", + "name": "reveal_end", + "type_": "u64" + }, + { + "doc": "", + "name": "settled", + "type_": "bool" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A sealed bid.", + "lib": "", + "name": "SealedBid", + "fields": [ + { + "doc": "sha256 commitment binding bidder, name, amount and salt.", + "name": "commitment", + "type_": { + "bytes_n": { + "n": 32 + } + } + }, + { + "doc": "Tokens locked in the contract; refunded in full to losers.", + "name": "deposit", + "type_": "i128" + }, + { + "doc": "", + "name": "revealed", + "type_": "bool" + } + ] + } + }, + { + "udt_union_v0": { + "doc": "Storage keys for the auction subsystem.", + "lib": "", + "name": "AuctionKey", + "cases": [ + { + "void_v0": { + "doc": "Auction configuration (instance storage).", + "name": "Config" + } + }, + { + "tuple_v0": { + "doc": "Auction state per name hash.", + "name": "Auction", + "type_": [ + { + "bytes_n": { + "n": 32 + } + } + ] + } + }, + { + "tuple_v0": { + "doc": "Sealed bid per (name hash, bidder).", + "name": "Bid", + "type_": [ + { + "bytes_n": { + "n": 32 + } + }, + "address" + ] + } + }, + { + "void_v0": { + "doc": "Count of auctions with a revealed winner that have not settled yet\\n(instance storage). Guards auction-admin rotation.", + "name": "PendingSettlements" + } + } + ] + } + }, + { + "udt_error_enum_v0": { + "doc": "Auction errors. Codes start at 100 to stay disjoint from `NamesError`.", + "lib": "", + "name": "AuctionError", + "cases": [ + { + "doc": "", + "name": "NotInitialized", + "value": 100 + }, + { + "doc": "", + "name": "AlreadyInitialized", + "value": 101 + }, + { + "doc": "", + "name": "InvalidConfig", + "value": 102 + }, + { + "doc": "", + "name": "WindowClosed", + "value": 103 + }, + { + "doc": "", + "name": "NotPremiumName", + "value": 104 + }, + { + "doc": "", + "name": "NameAlreadyRegistered", + "value": 105 + }, + { + "doc": "", + "name": "AuctionExists", + "value": 106 + }, + { + "doc": "", + "name": "NoAuction", + "value": 107 + }, + { + "doc": "", + "name": "CommitPhaseOver", + "value": 108 + }, + { + "doc": "", + "name": "AlreadyCommitted", + "value": 109 + }, + { + "doc": "", + "name": "DepositBelowReserve", + "value": 110 + }, + { + "doc": "", + "name": "RevealPhaseNotActive", + "value": 111 + }, + { + "doc": "", + "name": "NoBid", + "value": 112 + }, + { + "doc": "", + "name": "AlreadyRevealed", + "value": 113 + }, + { + "doc": "", + "name": "CommitmentMismatch", + "value": 114 + }, + { + "doc": "", + "name": "BidBelowReserve", + "value": 115 + }, + { + "doc": "", + "name": "BidExceedsDeposit", + "value": 116 + }, + { + "doc": "", + "name": "RevealPhaseNotOver", + "value": 117 + }, + { + "doc": "", + "name": "AlreadySettled", + "value": 118 + }, + { + "doc": "", + "name": "NotSettled", + "value": 119 + }, + { + "doc": "", + "name": "NotWinner", + "value": 120 + }, + { + "doc": "", + "name": "WinnerCannotWithdraw", + "value": 121 + }, + { + "doc": "", + "name": "InvalidMetaAddress", + "value": 122 + }, + { + "doc": "", + "name": "RegistrationFailed", + "value": 123 + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "Auction configuration, set once at initialization.", + "lib": "", + "name": "AuctionConfig", + "fields": [ + { + "doc": "Operator that runs settlements per the runbook.", + "name": "admin", + "type_": "address" + }, + { + "doc": "Duration of the commit phase of each auction, in seconds.", + "name": "commit_secs", + "type_": "u64" + }, + { + "doc": "Ledger timestamp at initialization; the premium window runs for\\n`PREMIUM_WINDOW_SECS` from this point.", + "name": "launch_time", + "type_": "u64" + }, + { + "doc": "Minimum bid; deposits must also be at least this amount.", + "name": "reserve_price", + "type_": "i128" + }, + { + "doc": "Duration of the reveal phase of each auction, in seconds.", + "name": "reveal_secs", + "type_": "u64" + }, + { + "doc": "Payment token (native XLM SAC on mainnet).", + "name": "token", + "type_": "address" + }, + { + "doc": "Receives winning bids.", + "name": "treasury", + "type_": "address" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A pending signer-rotation proposal.", + "lib": "", + "name": "RotationProposal", + "fields": [ + { + "doc": "", + "name": "approvals", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "executable_at", + "type_": "u64" + }, + { + "doc": "", + "name": "new_signers", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "new_threshold", + "type_": "u32" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "A pending auction-admin rotation proposal. Mirrors `RotationProposal` \\xe2\\x80\\x94\\nsame signer set, same quorum, same timelock \\xe2\\x80\\x94 but carries the incoming\\nauction operator address instead of a new signer set.", + "lib": "", + "name": "AdminRotationProposal", + "fields": [ + { + "doc": "", + "name": "approvals", + "type_": { + "vec": { + "element_type": "address" + } + } + }, + { + "doc": "", + "name": "executable_at", + "type_": "u64" + }, + { + "doc": "", + "name": "new_admin", + "type_": "address" + } + ] + } + }, + { + "udt_struct_v0": { + "doc": "Wraith Protocol standard metric event schema.\\n\\nAll Wraith contracts emit metric events using this structure to enable\\nstandardized off-chain observability and monitoring.", + "lib": "", + "name": "WraithMetricEvent", + "fields": [ + { + "doc": "Contract identifier (e.g., \"stealth-registry\", \"stealth-sender\")", + "name": "contract", + "type_": "symbol" + }, + { + "doc": "Optional dimensions for filtering/grouping (e.g., token_address, scheme_id)", + "name": "dimensions", + "type_": { + "vec": { + "element_type": { + "tuple": { + "value_types": [ + "symbol", + "val" + ] + } + } + } + } + }, + { + "doc": "Metric name (e.g., \"register_count\", \"send_volume\")", + "name": "metric_name", + "type_": "symbol" + }, + { + "doc": "Numeric value of the metric", + "name": "value", + "type_": "i128" } ] } diff --git a/stellar/bindings/typescript/index.ts b/stellar/bindings/typescript/index.ts index 5d02536d..2f5c093f 100644 --- a/stellar/bindings/typescript/index.ts +++ b/stellar/bindings/typescript/index.ts @@ -1,5 +1,4 @@ // Auto-generated Stellar TypeScript bindings re-exports -// Generated on 2026-05-28T02:32:58.942Z export * as StealthAnnouncer from './stealth-announcer/src/index'; export * as StealthRegistry from './stealth-registry/src/index'; diff --git a/stellar/bindings/typescript/stealth-announcer/src/index.ts b/stellar/bindings/typescript/stealth-announcer/src/index.ts index 4e3fefcf..99119ca8 100644 --- a/stellar/bindings/typescript/stealth-announcer/src/index.ts +++ b/stellar/bindings/typescript/stealth-announcer/src/index.ts @@ -37,17 +37,30 @@ if (typeof window !== "undefined") { export interface Client { /** * Construct and simulate a announce transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - * Emits a stealth address announcement event. + * Emits a Stellar v2 stealth address announcement event. * * This is a pure event-emission function with no access control and no * storage. Indexers watch for these events to let recipients detect * incoming payments. * + * v2 event shape: + * * topics: `("announce", scheme_id, view_tag_bucket, metadata_kind)` + * * data: `(stealth_address, ephemeral_pub_key, metadata)` + * + * The stable `view_tag_bucket` derivation is `metadata[0] as u32`, where + * `metadata_kind = 1` (`METADATA_KIND_VIEW_TAG`) means the first metadata + * byte is the view tag and the remaining bytes are scheme-specific. This + * lets wallets and indexers filter Stellar RPC `getEvents` by scheme and + * bucket before doing client-side cryptographic validation. + * + * Migration note: v1 announcements used the old Stellar layout + * `("announce", scheme_id, stealth_address)` with + * `(caller, ephemeral_pub_key, metadata)`. Do not reinterpret historical v1 + * events as v2. The compatibility path is a new announcer deployment using + * `scheme_id = 2`. + * * # Arguments - * * `scheme_id` - Identifier for the stealth address scheme (e.g. 1 for the default DKSAP scheme). - * * `stealth_address` - The one-time stealth address that received funds. - * * `ephemeral_pub_key` - The ephemeral public key used to derive the stealth address. - * * `metadata` - Arbitrary metadata (e.g. view tag) to speed up scanning. + * * `scheme_id` - Must be `2` for the v2 St */ announce: ({scheme_id, stealth_address, ephemeral_pub_key, metadata}: {scheme_id: u32, stealth_address: string, ephemeral_pub_key: Buffer, metadata: Buffer}, options?: MethodOptions) => Promise> @@ -69,7 +82,7 @@ export class Client extends ContractClient { } constructor(public readonly options: ContractClientOptions) { super( - new ContractSpec([ "AAAAAAAAAhlFbWl0cyBhIHN0ZWFsdGggYWRkcmVzcyBhbm5vdW5jZW1lbnQgZXZlbnQuCgpUaGlzIGlzIGEgcHVyZSBldmVudC1lbWlzc2lvbiBmdW5jdGlvbiB3aXRoIG5vIGFjY2VzcyBjb250cm9sIGFuZCBubwpzdG9yYWdlLiBJbmRleGVycyB3YXRjaCBmb3IgdGhlc2UgZXZlbnRzIHRvIGxldCByZWNpcGllbnRzIGRldGVjdAppbmNvbWluZyBwYXltZW50cy4KCiMgQXJndW1lbnRzCiogYHNjaGVtZV9pZGAgLSBJZGVudGlmaWVyIGZvciB0aGUgc3RlYWx0aCBhZGRyZXNzIHNjaGVtZSAoZS5nLiAxIGZvciB0aGUgZGVmYXVsdCBES1NBUCBzY2hlbWUpLgoqIGBzdGVhbHRoX2FkZHJlc3NgIC0gVGhlIG9uZS10aW1lIHN0ZWFsdGggYWRkcmVzcyB0aGF0IHJlY2VpdmVkIGZ1bmRzLgoqIGBlcGhlbWVyYWxfcHViX2tleWAgLSBUaGUgZXBoZW1lcmFsIHB1YmxpYyBrZXkgdXNlZCB0byBkZXJpdmUgdGhlIHN0ZWFsdGggYWRkcmVzcy4KKiBgbWV0YWRhdGFgIC0gQXJiaXRyYXJ5IG1ldGFkYXRhIChlLmcuIHZpZXcgdGFnKSB0byBzcGVlZCB1cCBzY2FubmluZy4AAAAAAAAIYW5ub3VuY2UAAAAEAAAAAAAAAAlzY2hlbWVfaWQAAAAAAAAEAAAAAAAAAA9zdGVhbHRoX2FkZHJlc3MAAAAAEwAAAAAAAAARZXBoZW1lcmFsX3B1Yl9rZXkAAAAAAAPuAAAAIAAAAAAAAAAIbWV0YWRhdGEAAAAOAAAAAA==" ]), + new ContractSpec([ "AAAAAAAABABFbWl0cyBhIFN0ZWxsYXIgdjIgc3RlYWx0aCBhZGRyZXNzIGFubm91bmNlbWVudCBldmVudC4KClRoaXMgaXMgYSBwdXJlIGV2ZW50LWVtaXNzaW9uIGZ1bmN0aW9uIHdpdGggbm8gYWNjZXNzIGNvbnRyb2wgYW5kIG5vCnN0b3JhZ2UuIEluZGV4ZXJzIHdhdGNoIGZvciB0aGVzZSBldmVudHMgdG8gbGV0IHJlY2lwaWVudHMgZGV0ZWN0CmluY29taW5nIHBheW1lbnRzLgoKdjIgZXZlbnQgc2hhcGU6CiogdG9waWNzOiBgKCJhbm5vdW5jZSIsIHNjaGVtZV9pZCwgdmlld190YWdfYnVja2V0LCBtZXRhZGF0YV9raW5kKWAKKiBkYXRhOiBgKHN0ZWFsdGhfYWRkcmVzcywgZXBoZW1lcmFsX3B1Yl9rZXksIG1ldGFkYXRhKWAKClRoZSBzdGFibGUgYHZpZXdfdGFnX2J1Y2tldGAgZGVyaXZhdGlvbiBpcyBgbWV0YWRhdGFbMF0gYXMgdTMyYCwgd2hlcmUKYG1ldGFkYXRhX2tpbmQgPSAxYCAoYE1FVEFEQVRBX0tJTkRfVklFV19UQUdgKSBtZWFucyB0aGUgZmlyc3QgbWV0YWRhdGEKYnl0ZSBpcyB0aGUgdmlldyB0YWcgYW5kIHRoZSByZW1haW5pbmcgYnl0ZXMgYXJlIHNjaGVtZS1zcGVjaWZpYy4gVGhpcwpsZXRzIHdhbGxldHMgYW5kIGluZGV4ZXJzIGZpbHRlciBTdGVsbGFyIFJQQyBgZ2V0RXZlbnRzYCBieSBzY2hlbWUgYW5kCmJ1Y2tldCBiZWZvcmUgZG9pbmcgY2xpZW50LXNpZGUgY3J5cHRvZ3JhcGhpYyB2YWxpZGF0aW9uLgoKTWlncmF0aW9uIG5vdGU6IHYxIGFubm91bmNlbWVudHMgdXNlZCB0aGUgb2xkIFN0ZWxsYXIgbGF5b3V0CmAoImFubm91bmNlIiwgc2NoZW1lX2lkLCBzdGVhbHRoX2FkZHJlc3MpYCB3aXRoCmAoY2FsbGVyLCBlcGhlbWVyYWxfcHViX2tleSwgbWV0YWRhdGEpYC4gRG8gbm90IHJlaW50ZXJwcmV0IGhpc3RvcmljYWwgdjEKZXZlbnRzIGFzIHYyLiBUaGUgY29tcGF0aWJpbGl0eSBwYXRoIGlzIGEgbmV3IGFubm91bmNlciBkZXBsb3ltZW50IHVzaW5nCmBzY2hlbWVfaWQgPSAyYC4KCiMgQXJndW1lbnRzCiogYHNjaGVtZV9pZGAgLSBNdXN0IGJlIGAyYCBmb3IgdGhlIHYyIFN0AAAACGFubm91bmNlAAAABAAAAAAAAAAJc2NoZW1lX2lkAAAAAAAABAAAAAAAAAAPc3RlYWx0aF9hZGRyZXNzAAAAABMAAAAAAAAAEWVwaGVtZXJhbF9wdWJfa2V5AAAAAAAD7gAAACAAAAAAAAAACG1ldGFkYXRhAAAADgAAAAA=" ]), options ) } diff --git a/stellar/bindings/typescript/stealth-batch-sender/.gitignore b/stellar/bindings/typescript/stealth-batch-sender/.gitignore new file mode 100644 index 00000000..72aae85f --- /dev/null +++ b/stellar/bindings/typescript/stealth-batch-sender/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +out/ diff --git a/stellar/bindings/typescript/stealth-batch-sender/README.md b/stellar/bindings/typescript/stealth-batch-sender/README.md new file mode 100644 index 00000000..b47afb19 --- /dev/null +++ b/stellar/bindings/typescript/stealth-batch-sender/README.md @@ -0,0 +1,54 @@ +# stealth-batch-sender JS + +JS library for interacting with [Soroban](https://soroban.stellar.org/) smart contract `stealth-batch-sender` via Soroban RPC. + +This library was automatically generated by Soroban CLI using a command similar to: + +```bash +soroban contract bindings ts \ + --rpc-url INSERT_RPC_URL_HERE \ + --network-passphrase "INSERT_NETWORK_PASSPHRASE_HERE" \ + --contract-id INSERT_CONTRACT_ID_HERE \ + --output-dir ./path/to/stealth-batch-sender +``` + +The network passphrase and contract ID are exported from [index.ts](./src/index.ts) in the `networks` constant. If you are the one who generated this library and you know that this contract is also deployed to other networks, feel free to update `networks` with other valid options. This will help your contract consumers use this library more easily. + +# To publish or not to publish + +This library is suitable for publishing to NPM. You can publish it to NPM using the `npm publish` command. + +But you don't need to publish this library to NPM to use it. You can add it to your project's `package.json` using a file path: + +```json +"dependencies": { + "stealth-batch-sender": "./path/to/this/folder" +} +``` + +However, we've actually encountered [frustration](https://github.com/stellar/soroban-example-dapp/pull/117#discussion_r1232873560) using local libraries with NPM in this way. Though it seems a bit messy, we suggest generating the library directly to your `node_modules` folder automatically after each install by using a `postinstall` script. We've had the least trouble with this approach. NPM will automatically remove what it sees as erroneous directories during the `install` step, and then regenerate them when it gets to your `postinstall` step, which will keep the library up-to-date with your contract. + +```json +"scripts": { + "postinstall": "soroban contract bindings ts --rpc-url INSERT_RPC_URL_HERE --network-passphrase \"INSERT_NETWORK_PASSPHRASE_HERE\" --id INSERT_CONTRACT_ID_HERE --name stealth-batch-sender" +} +``` + +Obviously you need to adjust the above command based on the actual command you used to generate the library. + +# Use it + +Now that you have your library up-to-date and added to your project, you can import it in a file and see inline documentation for all of its exported methods: + +```js +import { Contract, networks } from "stealth-batch-sender" + +const contract = new Contract({ + ...networks.futurenet, // for example; check which networks this library exports + rpcUrl: '...', // use your own, or find one for testing at https://soroban.stellar.org/docs/reference/rpc#public-rpc-providers +}) + +contract.| +``` + +As long as your editor is configured to show JavaScript/TypeScript documentation, you can pause your typing at that `|` to get a list of all exports and inline-documentation for each. It exports a separate [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) function for each method in the smart contract, with documentation for each generated from the comments the contract's author included in the original source code. diff --git a/stellar/bindings/typescript/stealth-batch-sender/package.json b/stellar/bindings/typescript/stealth-batch-sender/package.json new file mode 100644 index 00000000..b13e4eca --- /dev/null +++ b/stellar/bindings/typescript/stealth-batch-sender/package.json @@ -0,0 +1,17 @@ +{ + "version": "0.0.0", + "name": "stealth-batch-sender", + "type": "module", + "exports": "./dist/index.js", + "typings": "dist/index.d.ts", + "scripts": { + "build": "tsc" + }, + "dependencies": { + "@stellar/stellar-sdk": "^14.5.0", + "buffer": "6.0.3" + }, + "devDependencies": { + "typescript": "^5.6.2" + } +} diff --git a/stellar/bindings/typescript/stealth-batch-sender/src/index.ts b/stellar/bindings/typescript/stealth-batch-sender/src/index.ts index e192df47..0b31d5fd 100644 --- a/stellar/bindings/typescript/stealth-batch-sender/src/index.ts +++ b/stellar/bindings/typescript/stealth-batch-sender/src/index.ts @@ -1,5 +1,5 @@ -// Auto-generated from stealth-batch-sender's Soroban contract specification. import { Buffer } from "buffer"; +import { Address } from "@stellar/stellar-sdk"; import { AssembledTransaction, Client as ContractClient, @@ -8,110 +8,335 @@ import { Result, Spec as ContractSpec, } from "@stellar/stellar-sdk/contract"; -import type { i128, u32, u64, Option } from "@stellar/stellar-sdk/contract"; - +import type { + u32, + i32, + u64, + i64, + u128, + i128, + u256, + i256, + Option, + Timepoint, + Duration, +} from "@stellar/stellar-sdk/contract"; export * from "@stellar/stellar-sdk"; export * as contract from "@stellar/stellar-sdk/contract"; export * as rpc from "@stellar/stellar-sdk/rpc"; if (typeof window !== "undefined") { - // @ts-ignore Buffer exists + //@ts-ignore Buffer exists window.Buffer = window.Buffer || Buffer; } -export type DataKey = - | { tag: "Admin"; values: void } - | { tag: "Announcer"; values: void } - | { tag: "AssetPolicy"; values: void } - | { tag: "Paused"; values: void } - | { tag: "MultisigSigners"; values: void } - | { tag: "MultisigThreshold"; values: void } - | { tag: "PendingRotation"; values: void }; + + +/** + * Storage keys. + */ +export type DataKey = {tag: "Admin", values: void} | {tag: "Announcer", values: void} | {tag: "AssetPolicy", values: void} | {tag: "Paused", values: void} | {tag: "MultisigSigners", values: void} | {tag: "MultisigThreshold", values: void} | {tag: "PendingRotation", values: void}; + + +/** + * A single stealth transfer within a batch. + * Mirrors the EVM WraithSender batchSendETH/batchSendERC20 structure. + */ export interface Transfer { - stealth_address: string; - ephemeral_pub_key: Buffer; - amount: i128; - metadata: Buffer; + /** + * Token amount (in the asset's base unit) + */ +amount: i128; + /** + * Ephemeral public key for the recipient to scan with. + * Must be exactly 32 bytes so it can be forwarded to the announcer. + */ +ephemeral_pub_key: Buffer; + /** + * Announcement metadata whose first byte is the view tag + * (`view_tag_bucket = metadata[0] as u32` under metadata_kind = 1). + */ +metadata: Buffer; + /** + * Pre-computed stealth address (recipient) + */ +stealth_address: string; +} + +/** + * Errors that the batch-sender contract can produce. + * + * Codes are allocated from the `1300-1399` range reserved for + * `stealth-batch-sender` in `ERRORS.md`'s code-allocation policy. + */ +export const BatchSenderError = { + /** + * The contract has already been initialised. + */ + 1300: {message:"AlreadyInitialized"}, + /** + * The contract has not been initialised yet. + */ + 1301: {message:"NotInitialized"}, + /** + * The batch contains no transfers. + */ + 1302: {message:"EmptyBatch"}, + /** + * The batch exceeds `MAX_BATCH_SIZE`. + */ + 1303: {message:"BatchTooLarge"}, + /** + * A transfer amount was zero or negative. + */ + 1304: {message:"NonPositiveAmount"}, + /** + * A transfer's ephemeral public key was empty or not 32 bytes. + */ + 1305: {message:"EmptyEphemeralKey"}, + /** + * The contract is paused. + */ + 1306: {message:"Paused"}, + /** + * The asset is not allowed by the configured asset policy. + */ + 1307: {message:"AssetNotAllowed"}, + /** + * The governance multisig has not been initialised. + */ + 1308: {message:"MultisigNotInitialized"}, + /** + * The governance multisig has already been initialised. + */ + 1309: {message:"MultisigAlreadyInitialized"}, + /** + * The caller is not a current governance signer. + */ + 1310: {message:"NotSigner"}, + /** + * The requested threshold is invalid (zero, or greater than signer count). + */ + 1311: {message:"InvalidThreshold"}, + /** + * A signer-rotation proposal is already pending. + */ + 1312: {message:"RotationAlreadyPending"}, + /** + * No signer-rotation proposal is pending. + */ + 1313: {message:"NoPendingRotation"}, + /** + * The caller has already approved the pending rotation. + */ + 1314: {message:"AlreadyApprovedRotation"}, + /** + * The pending rotation has not collected enough approvals yet. + */ + 1315: {message:"QuorumNotMet"}, + /** + * The rotation timelock has not elapsed yet. + */ + 1316: {message:"TimelockNotElapsed"} } + +/** + * A pending signer-rotation proposal. + */ export interface RotationProposal { + approvals: Array; + executable_at: u64; new_signers: Array; new_threshold: u32; - executable_at: u64; - approvals: Array; } -export const BatchSenderError = { - 1300: { message: "AlreadyInitialized" }, - 1301: { message: "NotInitialized" }, - 1302: { message: "EmptyBatch" }, - 1303: { message: "BatchTooLarge" }, - 1304: { message: "NonPositiveAmount" }, - 1305: { message: "EmptyEphemeralKey" }, - 1306: { message: "Paused" }, - 1307: { message: "AssetNotAllowed" }, - 1308: { message: "MultisigNotInitialized" }, - 1309: { message: "MultisigAlreadyInitialized" }, - 1310: { message: "NotSigner" }, - 1311: { message: "InvalidThreshold" }, - 1312: { message: "RotationAlreadyPending" }, - 1313: { message: "NoPendingRotation" }, - 1314: { message: "AlreadyApprovedRotation" }, - 1315: { message: "QuorumNotMet" }, - 1316: { message: "TimelockNotElapsed" }, -} as const; -export interface Client { - init: ({ admin, announcer, asset_policy }: { admin: string; announcer: string; asset_policy: Option }, options?: MethodOptions) => Promise>>; - pause: ({ caller }: { caller: string }, options?: MethodOptions) => Promise>>; - unpause: ({ caller }: { caller: string }, options?: MethodOptions) => Promise>>; - is_paused: (options?: MethodOptions) => Promise>; - batch_send: ({ from, transfers, asset }: { from: string; transfers: Array; asset: string }, options?: MethodOptions) => Promise>>; - max_batch_size: (options?: MethodOptions) => Promise>; - init_multisig: ({ signers, threshold }: { signers: Array; threshold: u32 }, options?: MethodOptions) => Promise>>; - signers: (options?: MethodOptions) => Promise>>; - threshold: (options?: MethodOptions) => Promise>; - pending_rotation: (options?: MethodOptions) => Promise>>; - propose_rotate_signers: ({ caller, new_signers, new_threshold }: { caller: string; new_signers: Array; new_threshold: u32 }, options?: MethodOptions) => Promise>>; - approve_rotate_signers: ({ caller }: { caller: string }, options?: MethodOptions) => Promise>>; - execute_rotate_signers: ({ caller }: { caller: string }, options?: MethodOptions) => Promise>>; - cancel_rotate_signers: ({ caller }: { caller: string }, options?: MethodOptions) => Promise>>; +/** + * Wraith Protocol standard metric event schema. + * + * All Wraith contracts emit metric events using this structure to enable + * standardized off-chain observability and monitoring. + */ +export interface WraithMetricEvent { + /** + * Contract identifier (e.g., "stealth-registry", "stealth-sender") + */ +contract: string; + /** + * Optional dimensions for filtering/grouping (e.g., token_address, scheme_id) + */ +dimensions: Array; + /** + * Metric name (e.g., "register_count", "send_volume") + */ +metric_name: string; + /** + * Numeric value of the metric + */ +value: i128; } +export interface Client { + /** + * Construct and simulate a init transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Initialise the contract by storing the pause admin, the announcer + * address, and an optional asset policy. Idempotent: a second call + * returns `AlreadyInitialized` rather than overwriting the config. + * + * Must be called before `batch_send`. + */ + init: ({admin, announcer, asset_policy}: {admin: string, announcer: string, asset_policy: Option}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a pause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Pause the contract — admin only. Prevents `batch_send` while paused. + */ + pause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current governance signer set. + */ + signers: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a unpause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Unpause the contract — admin only. + */ + unpause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a is_paused transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns true if the contract is paused. + */ + is_paused: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a threshold transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current governance quorum threshold. + */ + threshold: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a batch_send transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Atomically send `asset` tokens from `from` to N pre-computed stealth + * addresses in a single transaction. + * + * # All-or-nothing semantics + * Soroban reverts every state change made during a failed invocation — + * whether the failure is a panic or a returned contract error — so a + * rejected batch never leaves partial transfers behind. + * + * # Resource budget + * Capped at MAX_BATCH_SIZE (100) transfers. This keeps instruction usage + * well under Soroban's per-transaction limit while still being ~100x more + * efficient than N individual stealth-sender::send calls (one auth, one + * ledger round-trip vs N). + */ + batch_send: ({from, transfers, asset}: {from: string, transfers: Array, asset: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a init_multisig transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * One-time setup of the governance signer set used to authorise signer + * rotations. Independent of `init` — does not gate `batch_send`. + */ + init_multisig: ({signers, threshold}: {signers: Array, threshold: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a max_batch_size transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Query the maximum allowed batch size. + */ + max_batch_size: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a pending_rotation transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * The pending signer-rotation proposal, if any. + */ + pending_rotation: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a cancel_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Cancel the pending rotation, clearing all of its state. + */ + cancel_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a approve_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Approve the pending signer-rotation proposal. + */ + approve_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a execute_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Execute the pending rotation once quorum is met and the timelock has + * elapsed. Emits `SignersRotated`. + */ + execute_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a propose_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Propose a new signer set + threshold behind the rotation timelock. + * `caller` must be a current signer; the proposal is auto-approved by + * `caller`. Rejects thresholds that could never reach quorum. + */ + propose_rotate_signers: ({caller, new_signers, new_threshold}: {caller: string, new_signers: Array, new_threshold: u32}, options?: MethodOptions) => Promise>> + +} export class Client extends ContractClient { - static async deploy(options: MethodOptions & Omit & { wasmHash: Buffer | string; salt?: Buffer | Uint8Array; format?: "hex" | "base64" }): Promise> { - return ContractClient.deploy(null, options); + static async deploy( + /** Options for initializing a Client as well as for calling a method, with extras specific to deploying. */ + options: MethodOptions & + Omit & { + /** The hash of the Wasm blob, which must already be installed on-chain. */ + wasmHash: Buffer | string; + /** Salt used to generate the contract's ID. Passed through to {@link Operation.createCustomContract}. Default: random. */ + salt?: Buffer | Uint8Array; + /** The format used to decode `wasmHash`, if it's provided as a string. */ + format?: "hex" | "base64"; + } + ): Promise> { + return ContractClient.deploy(null, options) } - constructor(public readonly options: ContractClientOptions) { - super(new ContractSpec([ - "AAAAAQAAAAAAAAAAAAAACFRyYW5zZmVyAAAABAAAAAAAAAAPc3RlYWx0aF9hZGRyZXNzAAAAABMAAAAAAAAAEWVwaGVtZXJhbF9wdWJfa2V5AAAAAAAADgAAAAAAAAAGYW1vdW50AAAAAAALAAAAAAAAAAhtZXRhZGF0YQAAAA4=", - "AAAAAQAAAAAAAAAAAAAAEFJvdGF0aW9uUHJvcG9zYWwAAAAEAAAAAAAAAAtuZXdfc2lnbmVycwAAAAPqAAAAEwAAAAAAAAANbmV3X3RocmVzaG9sZAAAAAAAAAQAAAAAAAAADWV4ZWN1dGFibGVfYXQAAAAAAAAGAAAAAAAAAAlhcHByb3ZhbHMAAAAAAAPqAAAAEw==", - "AAAABAAAAAAAAAAAAAAAEEJhdGNoU2VuZGVyRXJyb3IAAAARAAAAAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAABRQAAAAAAAAADk5vdEluaXRpYWxpemVkAAAAAAUVAAAAAAAAAApFbXB0eUJhdGNoAAAAAAUWAAAAAAAAAA1CYXRjaFRvb0xhcmdlAAAAAAAFFwAAAAAAAAARTm9uUG9zaXRpdmVBbW91bnQAAAAAAAUYAAAAAAAAABFFbXB0eUVwaGVtZXJhbEtleQAAAAAABRkAAAAAAAAABlBhdXNlZAAAAAAFGgAAAAAAAAAPQXNzZXROb3RBbGxvd2VkAAAABRsAAAAAAAAAFk11bHRpc2lnTm90SW5pdGlhbGl6ZWQAAAAABRwAAAAAAAAAGk11bHRpc2lnQWxyZWFkeUluaXRpYWxpemVkAAAAAAUdAAAAAAAAAAlOb3RTaWduZXIAAAAAAAUeAAAAAAAAABBJbnZhbGlkVGhyZXNob2xkAAAFHwAAAAAAAAAWUm90YXRpb25BbHJlYWR5UGVuZGluZwAAAAAFIAAAAAAAAAARTm9QZW5kaW5nUm90YXRpb24AAAAAAAUhAAAAAAAAABdBbHJlYWR5QXBwcm92ZWRSb3RhdGlvbgAAAAUiAAAAAAAAAAxRdW9ydW1Ob3RNZXQAAAUjAAAAAAAAABJUaW1lbG9ja05vdEVsYXBzZWQAAAAABSQ=", - "AAAAAAAAAAAAAAAEaW5pdAAAAAMAAAAAAAAABWFkbWluAAAAAAAAEwAAAAAAAAAJYW5ub3VuY2VyAAAAAAAAEwAAAAAAAAAMYXNzZXRfcG9saWN5AAAD6AAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAFcGF1c2UAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAHdW5wYXVzZQAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAJaXNfcGF1c2VkAAAAAAAAAAAAAAEAAAAB", - "AAAAAAAAAAAAAAAKYmF0Y2hfc2VuZAAAAAAAAwAAAAAAAAAEZnJvbQAAABMAAAAAAAAACXRyYW5zZmVycwAAAAAAA+oAAAfQAAAACFRyYW5zZmVyAAAAAAAAAAVhc3NldAAAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAObWF4X2JhdGNoX3NpemUAAAAAAAAAAAABAAAABA==", - "AAAAAAAAAAAAAAANaW5pdF9tdWx0aXNpZwAAAAAAAAIAAAAAAAAAB3NpZ25lcnMAAAAD6gAAABMAAAAAAAAACXRocmVzaG9sZAAAAAAAAAQAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAHc2lnbmVycwAAAAAAAAAAAQAAA+oAAAAT", - "AAAAAAAAAAAAAAAJdGhyZXNob2xkAAAAAAAAAAAAAAEAAAAE", - "AAAAAAAAAAAAAAAQcGVuZGluZ19yb3RhdGlvbgAAAAAAAAABAAAD6AAAB9AAAAAQUm90YXRpb25Qcm9wb3NhbA==", - "AAAAAAAAAAAAAAAWcHJvcG9zZV9yb3RhdGVfc2lnbmVycwAAAAAAAwAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAAAAAAtuZXdfc2lnbmVycwAAAAPqAAAAEwAAAAAAAAANbmV3X3RocmVzaG9sZAAAAAAAAAQAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", - "AAAAAAAAAAAAAAAWYXBwcm92ZV9yb3RhdGVfc2lnbmVycwAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", - "AAAAAAAAAAAAAAAWZXhlY3V0ZV9yb3RhdGVfc2lnbmVycwAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", - "AAAAAAAAAAAAAAAVY2FuY2VsX3JvdGF0ZV9zaWduZXJzAAAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", - ]), options); + super( + new ContractSpec([ "AAAAAAAAAOhJbml0aWFsaXNlIHRoZSBjb250cmFjdCBieSBzdG9yaW5nIHRoZSBwYXVzZSBhZG1pbiwgdGhlIGFubm91bmNlcgphZGRyZXNzLCBhbmQgYW4gb3B0aW9uYWwgYXNzZXQgcG9saWN5LiBJZGVtcG90ZW50OiBhIHNlY29uZCBjYWxsCnJldHVybnMgYEFscmVhZHlJbml0aWFsaXplZGAgcmF0aGVyIHRoYW4gb3ZlcndyaXRpbmcgdGhlIGNvbmZpZy4KCk11c3QgYmUgY2FsbGVkIGJlZm9yZSBgYmF0Y2hfc2VuZGAuAAAABGluaXQAAAADAAAAAAAAAAVhZG1pbgAAAAAAABMAAAAAAAAACWFubm91bmNlcgAAAAAAABMAAAAAAAAADGFzc2V0X3BvbGljeQAAA+gAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", + "AAAAAAAAAEZQYXVzZSB0aGUgY29udHJhY3Qg4oCUIGFkbWluIG9ubHkuIFByZXZlbnRzIGBiYXRjaF9zZW5kYCB3aGlsZSBwYXVzZWQuAAAAAAAFcGF1c2UAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", + "AAAAAAAAAB5DdXJyZW50IGdvdmVybmFuY2Ugc2lnbmVyIHNldC4AAAAAAAdzaWduZXJzAAAAAAAAAAABAAAD6gAAABM=", + "AAAAAAAAACRVbnBhdXNlIHRoZSBjb250cmFjdCDigJQgYWRtaW4gb25seS4AAAAHdW5wYXVzZQAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", + "AAAAAAAAACdSZXR1cm5zIHRydWUgaWYgdGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAACWlzX3BhdXNlZAAAAAAAAAAAAAABAAAAAQ==", + "AAAAAAAAACRDdXJyZW50IGdvdmVybmFuY2UgcXVvcnVtIHRocmVzaG9sZC4AAAAJdGhyZXNob2xkAAAAAAAAAAAAAAEAAAAE", + "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAcAAAAAAAAAFFBhdXNlIGFkbWluIGFkZHJlc3MuAAAABUFkbWluAAAAAAAAAAAAANdBZGRyZXNzIG9mIHRoZSBkZXBsb3llZCBTdGVhbHRoQW5ub3VuY2VyIGNvbnRyYWN0LCByZWNvcmRlZCBhdCBpbml0CnRpbWUuIEludm9rZWQgYnkgYGJhdGNoX3NlbmRgIGZvciBlYWNoIHRyYW5zZmVyIHNvIGFubm91bmNlbWVudHMgdXNlCnRoZSB2MiA0LXRvcGljIGxheW91dCAoYGFubm91bmNlYCwgc2NoZW1lX2lkLCB2aWV3X3RhZ19idWNrZXQsIG1ldGFkYXRhX2tpbmQpLgAAAAAJQW5ub3VuY2VyAAAAAAAAAAAAAC5PcHRpb25hbCBhZGRyZXNzIG9mIHRoZSBhc3NldCBwb2xpY3kgY29udHJhY3QuAAAAAAALQXNzZXRQb2xpY3kAAAAAAAAAAB9XaGV0aGVyIHRoZSBjb250cmFjdCBpcyBwYXVzZWQuAAAAAAZQYXVzZWQAAAAAAAAAAAAfR292ZXJuYW5jZSBtdWx0aXNpZyBzaWduZXIgc2V0LgAAAAAPTXVsdGlzaWdTaWduZXJzAAAAAAAAAAAlR292ZXJuYW5jZSBtdWx0aXNpZyBxdW9ydW0gdGhyZXNob2xkLgAAAAAAABFNdWx0aXNpZ1RocmVzaG9sZAAAAAAAAAAAAAApUGVuZGluZyBzaWduZXItcm90YXRpb24gcHJvcG9zYWwsIGlmIGFueS4AAAAAAAAPUGVuZGluZ1JvdGF0aW9uAA==", + "AAAAAAAAAkZBdG9taWNhbGx5IHNlbmQgYGFzc2V0YCB0b2tlbnMgZnJvbSBgZnJvbWAgdG8gTiBwcmUtY29tcHV0ZWQgc3RlYWx0aAphZGRyZXNzZXMgaW4gYSBzaW5nbGUgdHJhbnNhY3Rpb24uCgojIEFsbC1vci1ub3RoaW5nIHNlbWFudGljcwpTb3JvYmFuIHJldmVydHMgZXZlcnkgc3RhdGUgY2hhbmdlIG1hZGUgZHVyaW5nIGEgZmFpbGVkIGludm9jYXRpb24g4oCUCndoZXRoZXIgdGhlIGZhaWx1cmUgaXMgYSBwYW5pYyBvciBhIHJldHVybmVkIGNvbnRyYWN0IGVycm9yIOKAlCBzbyBhCnJlamVjdGVkIGJhdGNoIG5ldmVyIGxlYXZlcyBwYXJ0aWFsIHRyYW5zZmVycyBiZWhpbmQuCgojIFJlc291cmNlIGJ1ZGdldApDYXBwZWQgYXQgTUFYX0JBVENIX1NJWkUgKDEwMCkgdHJhbnNmZXJzLiBUaGlzIGtlZXBzIGluc3RydWN0aW9uIHVzYWdlCndlbGwgdW5kZXIgU29yb2JhbidzIHBlci10cmFuc2FjdGlvbiBsaW1pdCB3aGlsZSBzdGlsbCBiZWluZyB+MTAweCBtb3JlCmVmZmljaWVudCB0aGFuIE4gaW5kaXZpZHVhbCBzdGVhbHRoLXNlbmRlcjo6c2VuZCBjYWxscyAob25lIGF1dGgsIG9uZQpsZWRnZXIgcm91bmQtdHJpcCB2cyBOKS4AAAAAAApiYXRjaF9zZW5kAAAAAAADAAAAAAAAAARmcm9tAAAAEwAAAAAAAAAJdHJhbnNmZXJzAAAAAAAD6gAAB9AAAAAIVHJhbnNmZXIAAAAAAAAABWFzc2V0AAAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAEEJhdGNoU2VuZGVyRXJyb3I=", + "AAAAAQAAAG1BIHNpbmdsZSBzdGVhbHRoIHRyYW5zZmVyIHdpdGhpbiBhIGJhdGNoLgpNaXJyb3JzIHRoZSBFVk0gV3JhaXRoU2VuZGVyIGJhdGNoU2VuZEVUSC9iYXRjaFNlbmRFUkMyMCBzdHJ1Y3R1cmUuAAAAAAAAAAAAAAhUcmFuc2ZlcgAAAAQAAAAnVG9rZW4gYW1vdW50IChpbiB0aGUgYXNzZXQncyBiYXNlIHVuaXQpAAAAAAZhbW91bnQAAAAAAAsAAAB2RXBoZW1lcmFsIHB1YmxpYyBrZXkgZm9yIHRoZSByZWNpcGllbnQgdG8gc2NhbiB3aXRoLgpNdXN0IGJlIGV4YWN0bHkgMzIgYnl0ZXMgc28gaXQgY2FuIGJlIGZvcndhcmRlZCB0byB0aGUgYW5ub3VuY2VyLgAAAAAAEWVwaGVtZXJhbF9wdWJfa2V5AAAAAAAADgAAAHhBbm5vdW5jZW1lbnQgbWV0YWRhdGEgd2hvc2UgZmlyc3QgYnl0ZSBpcyB0aGUgdmlldyB0YWcKKGB2aWV3X3RhZ19idWNrZXQgPSBtZXRhZGF0YVswXSBhcyB1MzJgIHVuZGVyIG1ldGFkYXRhX2tpbmQgPSAxKS4AAAAIbWV0YWRhdGEAAAAOAAAAKFByZS1jb21wdXRlZCBzdGVhbHRoIGFkZHJlc3MgKHJlY2lwaWVudCkAAAAPc3RlYWx0aF9hZGRyZXNzAAAAABM=", + "AAAAAAAAAIVPbmUtdGltZSBzZXR1cCBvZiB0aGUgZ292ZXJuYW5jZSBzaWduZXIgc2V0IHVzZWQgdG8gYXV0aG9yaXNlIHNpZ25lcgpyb3RhdGlvbnMuIEluZGVwZW5kZW50IG9mIGBpbml0YCDigJQgZG9lcyBub3QgZ2F0ZSBgYmF0Y2hfc2VuZGAuAAAAAAAADWluaXRfbXVsdGlzaWcAAAAAAAACAAAAAAAAAAdzaWduZXJzAAAAA+oAAAATAAAAAAAAAAl0aHJlc2hvbGQAAAAAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", + "AAAAAAAAACVRdWVyeSB0aGUgbWF4aW11bSBhbGxvd2VkIGJhdGNoIHNpemUuAAAAAAAADm1heF9iYXRjaF9zaXplAAAAAAAAAAAAAQAAAAQ=", + "AAAAAAAAAC1UaGUgcGVuZGluZyBzaWduZXItcm90YXRpb24gcHJvcG9zYWwsIGlmIGFueS4AAAAAAAAQcGVuZGluZ19yb3RhdGlvbgAAAAAAAAABAAAD6AAAB9AAAAAQUm90YXRpb25Qcm9wb3NhbA==", + "AAAABAAAAK9FcnJvcnMgdGhhdCB0aGUgYmF0Y2gtc2VuZGVyIGNvbnRyYWN0IGNhbiBwcm9kdWNlLgoKQ29kZXMgYXJlIGFsbG9jYXRlZCBmcm9tIHRoZSBgMTMwMC0xMzk5YCByYW5nZSByZXNlcnZlZCBmb3IKYHN0ZWFsdGgtYmF0Y2gtc2VuZGVyYCBpbiBgRVJST1JTLm1kYCdzIGNvZGUtYWxsb2NhdGlvbiBwb2xpY3kuAAAAAAAAAAAQQmF0Y2hTZW5kZXJFcnJvcgAAABEAAAAqVGhlIGNvbnRyYWN0IGhhcyBhbHJlYWR5IGJlZW4gaW5pdGlhbGlzZWQuAAAAAAASQWxyZWFkeUluaXRpYWxpemVkAAAAAAUUAAAAKlRoZSBjb250cmFjdCBoYXMgbm90IGJlZW4gaW5pdGlhbGlzZWQgeWV0LgAAAAAADk5vdEluaXRpYWxpemVkAAAAAAUVAAAAIFRoZSBiYXRjaCBjb250YWlucyBubyB0cmFuc2ZlcnMuAAAACkVtcHR5QmF0Y2gAAAAABRYAAAAjVGhlIGJhdGNoIGV4Y2VlZHMgYE1BWF9CQVRDSF9TSVpFYC4AAAAADUJhdGNoVG9vTGFyZ2UAAAAAAAUXAAAAJ0EgdHJhbnNmZXIgYW1vdW50IHdhcyB6ZXJvIG9yIG5lZ2F0aXZlLgAAAAARTm9uUG9zaXRpdmVBbW91bnQAAAAAAAUYAAAAPEEgdHJhbnNmZXIncyBlcGhlbWVyYWwgcHVibGljIGtleSB3YXMgZW1wdHkgb3Igbm90IDMyIGJ5dGVzLgAAABFFbXB0eUVwaGVtZXJhbEtleQAAAAAABRkAAAAXVGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAABlBhdXNlZAAAAAAFGgAAADhUaGUgYXNzZXQgaXMgbm90IGFsbG93ZWQgYnkgdGhlIGNvbmZpZ3VyZWQgYXNzZXQgcG9saWN5LgAAAA9Bc3NldE5vdEFsbG93ZWQAAAAFGwAAADFUaGUgZ292ZXJuYW5jZSBtdWx0aXNpZyBoYXMgbm90IGJlZW4gaW5pdGlhbGlzZWQuAAAAAAAAFk11bHRpc2lnTm90SW5pdGlhbGl6ZWQAAAAABRwAAAA1VGhlIGdvdmVybmFuY2UgbXVsdGlzaWcgaGFzIGFscmVhZHkgYmVlbiBpbml0aWFsaXNlZC4AAAAAAAAaTXVsdGlzaWdBbHJlYWR5SW5pdGlhbGl6ZWQAAAAABR0AAAAuVGhlIGNhbGxlciBpcyBub3QgYSBjdXJyZW50IGdvdmVybmFuY2Ugc2lnbmVyLgAAAAAACU5vdFNpZ25lcgAAAAAABR4AAABIVGhlIHJlcXVlc3RlZCB0aHJlc2hvbGQgaXMgaW52YWxpZCAoemVybywgb3IgZ3JlYXRlciB0aGFuIHNpZ25lciBjb3VudCkuAAAAEEludmFsaWRUaHJlc2hvbGQAAAUfAAAALkEgc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsIGlzIGFscmVhZHkgcGVuZGluZy4AAAAAABZSb3RhdGlvbkFscmVhZHlQZW5kaW5nAAAAAAUgAAAAJ05vIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbCBpcyBwZW5kaW5nLgAAAAARTm9QZW5kaW5nUm90YXRpb24AAAAAAAUhAAAANVRoZSBjYWxsZXIgaGFzIGFscmVhZHkgYXBwcm92ZWQgdGhlIHBlbmRpbmcgcm90YXRpb24uAAAAAAAAF0FscmVhZHlBcHByb3ZlZFJvdGF0aW9uAAAABSIAAAA8VGhlIHBlbmRpbmcgcm90YXRpb24gaGFzIG5vdCBjb2xsZWN0ZWQgZW5vdWdoIGFwcHJvdmFscyB5ZXQuAAAADFF1b3J1bU5vdE1ldAAABSMAAAAqVGhlIHJvdGF0aW9uIHRpbWVsb2NrIGhhcyBub3QgZWxhcHNlZCB5ZXQuAAAAAAASVGltZWxvY2tOb3RFbGFwc2VkAAAAAAUk", + "AAAAAAAAADdDYW5jZWwgdGhlIHBlbmRpbmcgcm90YXRpb24sIGNsZWFyaW5nIGFsbCBvZiBpdHMgc3RhdGUuAAAAABVjYW5jZWxfcm90YXRlX3NpZ25lcnMAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", + "AAAAAAAAAC1BcHByb3ZlIHRoZSBwZW5kaW5nIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbC4AAAAAAAAWYXBwcm92ZV9yb3RhdGVfc2lnbmVycwAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", + "AAAAAAAAAGVFeGVjdXRlIHRoZSBwZW5kaW5nIHJvdGF0aW9uIG9uY2UgcXVvcnVtIGlzIG1ldCBhbmQgdGhlIHRpbWVsb2NrIGhhcwplbGFwc2VkLiBFbWl0cyBgU2lnbmVyc1JvdGF0ZWRgLgAAAAAAABZleGVjdXRlX3JvdGF0ZV9zaWduZXJzAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAABBCYXRjaFNlbmRlckVycm9y", + "AAAAAAAAAMJQcm9wb3NlIGEgbmV3IHNpZ25lciBzZXQgKyB0aHJlc2hvbGQgYmVoaW5kIHRoZSByb3RhdGlvbiB0aW1lbG9jay4KYGNhbGxlcmAgbXVzdCBiZSBhIGN1cnJlbnQgc2lnbmVyOyB0aGUgcHJvcG9zYWwgaXMgYXV0by1hcHByb3ZlZCBieQpgY2FsbGVyYC4gUmVqZWN0cyB0aHJlc2hvbGRzIHRoYXQgY291bGQgbmV2ZXIgcmVhY2ggcXVvcnVtLgAAAAAAFnByb3Bvc2Vfcm90YXRlX3NpZ25lcnMAAAAAAAMAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAALbmV3X3NpZ25lcnMAAAAD6gAAABMAAAAAAAAADW5ld190aHJlc2hvbGQAAAAAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAQQmF0Y2hTZW5kZXJFcnJvcg==", + "AAAAAQAAACNBIHBlbmRpbmcgc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsLgAAAAAAAAAAEFJvdGF0aW9uUHJvcG9zYWwAAAAEAAAAAAAAAAlhcHByb3ZhbHMAAAAAAAPqAAAAEwAAAAAAAAANZXhlY3V0YWJsZV9hdAAAAAAAAAYAAAAAAAAAC25ld19zaWduZXJzAAAAA+oAAAATAAAAAAAAAA1uZXdfdGhyZXNob2xkAAAAAAAABA==", + "AAAAAQAAAKpXcmFpdGggUHJvdG9jb2wgc3RhbmRhcmQgbWV0cmljIGV2ZW50IHNjaGVtYS4KCkFsbCBXcmFpdGggY29udHJhY3RzIGVtaXQgbWV0cmljIGV2ZW50cyB1c2luZyB0aGlzIHN0cnVjdHVyZSB0byBlbmFibGUKc3RhbmRhcmRpemVkIG9mZi1jaGFpbiBvYnNlcnZhYmlsaXR5IGFuZCBtb25pdG9yaW5nLgAAAAAAAAAAABFXcmFpdGhNZXRyaWNFdmVudAAAAAAAAAQAAABAQ29udHJhY3QgaWRlbnRpZmllciAoZS5nLiwgInN0ZWFsdGgtcmVnaXN0cnkiLCAic3RlYWx0aC1zZW5kZXIiKQAAAAhjb250cmFjdAAAABEAAABLT3B0aW9uYWwgZGltZW5zaW9ucyBmb3IgZmlsdGVyaW5nL2dyb3VwaW5nIChlLmcuLCB0b2tlbl9hZGRyZXNzLCBzY2hlbWVfaWQpAAAAAApkaW1lbnNpb25zAAAAAAPqAAAD7QAAAAIAAAARAAAAAAAAADNNZXRyaWMgbmFtZSAoZS5nLiwgInJlZ2lzdGVyX2NvdW50IiwgInNlbmRfdm9sdW1lIikAAAAAC21ldHJpY19uYW1lAAAAABEAAAAbTnVtZXJpYyB2YWx1ZSBvZiB0aGUgbWV0cmljAAAAAAV2YWx1ZQAAAAAAAAs=" ]), + options + ) } - public readonly fromJSON = { - init: this.txFromJSON>, pause: this.txFromJSON>, unpause: this.txFromJSON>, - is_paused: this.txFromJSON, batch_send: this.txFromJSON>, max_batch_size: this.txFromJSON, - init_multisig: this.txFromJSON>, signers: this.txFromJSON>, threshold: this.txFromJSON, - pending_rotation: this.txFromJSON>, propose_rotate_signers: this.txFromJSON>, - approve_rotate_signers: this.txFromJSON>, execute_rotate_signers: this.txFromJSON>, - cancel_rotate_signers: this.txFromJSON>, - }; -} + init: this.txFromJSON>, + pause: this.txFromJSON>, + signers: this.txFromJSON>, + unpause: this.txFromJSON>, + is_paused: this.txFromJSON, + threshold: this.txFromJSON, + batch_send: this.txFromJSON>, + init_multisig: this.txFromJSON>, + max_batch_size: this.txFromJSON, + pending_rotation: this.txFromJSON>, + cancel_rotate_signers: this.txFromJSON>, + approve_rotate_signers: this.txFromJSON>, + execute_rotate_signers: this.txFromJSON>, + propose_rotate_signers: this.txFromJSON> + } +} \ No newline at end of file diff --git a/stellar/bindings/typescript/stealth-batch-sender/tsconfig.json b/stellar/bindings/typescript/stealth-batch-sender/tsconfig.json new file mode 100644 index 00000000..acac1422 --- /dev/null +++ b/stellar/bindings/typescript/stealth-batch-sender/tsconfig.json @@ -0,0 +1,98 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "NodeNext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + // "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + // "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + // "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": [ + "src/*" + ] +} \ No newline at end of file diff --git a/stellar/bindings/typescript/stealth-registry/src/index.ts b/stellar/bindings/typescript/stealth-registry/src/index.ts index 38b13f01..1a9cf94c 100644 --- a/stellar/bindings/typescript/stealth-registry/src/index.ts +++ b/stellar/bindings/typescript/stealth-registry/src/index.ts @@ -52,7 +52,43 @@ export const RegistryError = { 2: {message:"NotRegistered"} } + +/** + * Wraith Protocol standard metric event schema. + * + * All Wraith contracts emit metric events using this structure to enable + * standardized off-chain observability and monitoring. + */ +export interface WraithMetricEvent { + /** + * Contract identifier (e.g., "stealth-registry", "stealth-sender") + */ +contract: string; + /** + * Optional dimensions for filtering/grouping (e.g., token_address, scheme_id) + */ +dimensions: Array; + /** + * Metric name (e.g., "register_count", "send_volume") + */ +metric_name: string; + /** + * Numeric value of the metric + */ +value: i128; +} + export interface Client { + /** + * Construct and simulate a remove_keys transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Remove a previously registered stealth meta-address. + * + * # Arguments + * * `registrant` - The address whose meta-address is being removed (must authorise). + * * `scheme_id` - The stealth address scheme identifier. + */ + remove_keys: ({registrant, scheme_id}: {registrant: string, scheme_id: u32}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a register_keys transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Register or update a stealth meta-address. @@ -93,14 +129,17 @@ export class Client extends ContractClient { constructor(public readonly options: ContractClientOptions) { super( new ContractSpec([ "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAEAAAABAAAAaU1hcHMgKHJlZ2lzdHJhbnQsIHNjaGVtZV9pZCkgdG8gdGhlaXIgc3RlYWx0aCBtZXRhLWFkZHJlc3MgKDY0IGJ5dGVzOgpzcGVuZGluZ19wdWJrZXkgfHwgdmlld2luZ19wdWJrZXkpLgAAAAAAAAtNZXRhQWRkcmVzcwAAAAACAAAAEwAAAAQ=", + "AAAAAAAAAMxSZW1vdmUgYSBwcmV2aW91c2x5IHJlZ2lzdGVyZWQgc3RlYWx0aCBtZXRhLWFkZHJlc3MuCgojIEFyZ3VtZW50cwoqIGByZWdpc3RyYW50YCAtIFRoZSBhZGRyZXNzIHdob3NlIG1ldGEtYWRkcmVzcyBpcyBiZWluZyByZW1vdmVkIChtdXN0IGF1dGhvcmlzZSkuCiogYHNjaGVtZV9pZGAgIC0gVGhlIHN0ZWFsdGggYWRkcmVzcyBzY2hlbWUgaWRlbnRpZmllci4AAAALcmVtb3ZlX2tleXMAAAAAAgAAAAAAAAAKcmVnaXN0cmFudAAAAAAAEwAAAAAAAAAJc2NoZW1lX2lkAAAAAAAABAAAAAEAAAPpAAAD7QAAAAAAAAfQAAAADVJlZ2lzdHJ5RXJyb3IAAAA=", "AAAAAAAAAQ1SZWdpc3RlciBvciB1cGRhdGUgYSBzdGVhbHRoIG1ldGEtYWRkcmVzcy4KCiMgQXJndW1lbnRzCiogYHJlZ2lzdHJhbnRgIC0gVGhlIGFkZHJlc3Mgd2hvc2UgbWV0YS1hZGRyZXNzIGlzIGJlaW5nIHNldCAobXVzdCBhdXRob3Jpc2UpLgoqIGBzY2hlbWVfaWRgICAtIFRoZSBzdGVhbHRoIGFkZHJlc3Mgc2NoZW1lIGlkZW50aWZpZXIuCiogYHN0ZWFsdGhfbWV0YV9hZGRyZXNzYCAtIDY0LWJ5dGUgdmFsdWU6IGBzcGVuZGluZ19wdWJrZXkgfHwgdmlld2luZ19wdWJrZXlgLgAAAAAAAA1yZWdpc3Rlcl9rZXlzAAAAAAAAAwAAAAAAAAAKcmVnaXN0cmFudAAAAAAAEwAAAAAAAAAJc2NoZW1lX2lkAAAAAAAABAAAAAAAAAAUc3RlYWx0aF9tZXRhX2FkZHJlc3MAAAAOAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAANUmVnaXN0cnlFcnJvcgAAAA==", "AAAABAAAACVFcnJvcnMgdGhhdCB0aGUgcmVnaXN0cnkgY2FuIHByb2R1Y2UuAAAAAAAAAAAAAA1SZWdpc3RyeUVycm9yAAAAAAAAAgAAADpUaGUgc3VwcGxpZWQgc3RlYWx0aCBtZXRhLWFkZHJlc3MgaXMgbm90IGV4YWN0bHkgNjQgYnl0ZXMuAAAAAAAYSW52YWxpZE1ldGFBZGRyZXNzTGVuZ3RoAAAAAQAAAE1ObyBzdGVhbHRoIG1ldGEtYWRkcmVzcyBoYXMgYmVlbiByZWdpc3RlcmVkIGZvciB0aGUgZ2l2ZW4gYWRkcmVzcyBhbmQgc2NoZW1lLgAAAAAAAA1Ob3RSZWdpc3RlcmVkAAAAAAAAAg==", - "AAAAAAAAAKNMb29rIHVwIGEgcHJldmlvdXNseSByZWdpc3RlcmVkIHN0ZWFsdGggbWV0YS1hZGRyZXNzLgoKIyBBcmd1bWVudHMKKiBgcmVnaXN0cmFudGAgLSBUaGUgYWRkcmVzcyB0byBsb29rIHVwLgoqIGBzY2hlbWVfaWRgICAtIFRoZSBzdGVhbHRoIGFkZHJlc3Mgc2NoZW1lIGlkZW50aWZpZXIuAAAAABdzdGVhbHRoX21ldGFfYWRkcmVzc19vZgAAAAACAAAAAAAAAApyZWdpc3RyYW50AAAAAAATAAAAAAAAAAlzY2hlbWVfaWQAAAAAAAAEAAAAAQAAA+kAAAAOAAAH0AAAAA1SZWdpc3RyeUVycm9yAAAA" ]), + "AAAAAAAAAKNMb29rIHVwIGEgcHJldmlvdXNseSByZWdpc3RlcmVkIHN0ZWFsdGggbWV0YS1hZGRyZXNzLgoKIyBBcmd1bWVudHMKKiBgcmVnaXN0cmFudGAgLSBUaGUgYWRkcmVzcyB0byBsb29rIHVwLgoqIGBzY2hlbWVfaWRgICAtIFRoZSBzdGVhbHRoIGFkZHJlc3Mgc2NoZW1lIGlkZW50aWZpZXIuAAAAABdzdGVhbHRoX21ldGFfYWRkcmVzc19vZgAAAAACAAAAAAAAAApyZWdpc3RyYW50AAAAAAATAAAAAAAAAAlzY2hlbWVfaWQAAAAAAAAEAAAAAQAAA+kAAAAOAAAH0AAAAA1SZWdpc3RyeUVycm9yAAAA", + "AAAAAQAAAKpXcmFpdGggUHJvdG9jb2wgc3RhbmRhcmQgbWV0cmljIGV2ZW50IHNjaGVtYS4KCkFsbCBXcmFpdGggY29udHJhY3RzIGVtaXQgbWV0cmljIGV2ZW50cyB1c2luZyB0aGlzIHN0cnVjdHVyZSB0byBlbmFibGUKc3RhbmRhcmRpemVkIG9mZi1jaGFpbiBvYnNlcnZhYmlsaXR5IGFuZCBtb25pdG9yaW5nLgAAAAAAAAAAABFXcmFpdGhNZXRyaWNFdmVudAAAAAAAAAQAAABAQ29udHJhY3QgaWRlbnRpZmllciAoZS5nLiwgInN0ZWFsdGgtcmVnaXN0cnkiLCAic3RlYWx0aC1zZW5kZXIiKQAAAAhjb250cmFjdAAAABEAAABLT3B0aW9uYWwgZGltZW5zaW9ucyBmb3IgZmlsdGVyaW5nL2dyb3VwaW5nIChlLmcuLCB0b2tlbl9hZGRyZXNzLCBzY2hlbWVfaWQpAAAAAApkaW1lbnNpb25zAAAAAAPqAAAD7QAAAAIAAAARAAAAAAAAADNNZXRyaWMgbmFtZSAoZS5nLiwgInJlZ2lzdGVyX2NvdW50IiwgInNlbmRfdm9sdW1lIikAAAAAC21ldHJpY19uYW1lAAAAABEAAAAbTnVtZXJpYyB2YWx1ZSBvZiB0aGUgbWV0cmljAAAAAAV2YWx1ZQAAAAAAAAs=" ]), options ) } public readonly fromJSON = { - register_keys: this.txFromJSON>, + remove_keys: this.txFromJSON>, + register_keys: this.txFromJSON>, stealth_meta_address_of: this.txFromJSON> } } \ No newline at end of file diff --git a/stellar/bindings/typescript/stealth-sender/src/index.ts b/stellar/bindings/typescript/stealth-sender/src/index.ts index 6d59b491..662ab14f 100644 --- a/stellar/bindings/typescript/stealth-sender/src/index.ts +++ b/stellar/bindings/typescript/stealth-sender/src/index.ts @@ -36,7 +36,7 @@ if (typeof window !== "undefined") { /** * Storage keys. */ -export type DataKey = {tag: "Announcer", values: void}; +export type DataKey = {tag: "Announcer", values: void} | {tag: "AssetPolicy", values: void} | {tag: "FeeRecipient", values: void} | {tag: "FeeBasisPoints", values: void} | {tag: "Admin", values: void} | {tag: "Paused", values: void} | {tag: "MultisigSigners", values: void} | {tag: "MultisigThreshold", values: void} | {tag: "PendingRotation", values: void}; /** * Errors that the sender contract can produce. @@ -53,17 +53,126 @@ export const SenderError = { /** * The batch input vectors have mismatched lengths. */ - 3: {message:"LengthMismatch"} + 3: {message:"LengthMismatch"}, + /** + * The token is not allowed by the asset policy. + */ + 4: {message:"TokenNotAllowed"}, + /** + * The fee configuration is invalid (e.g. fee > 50 bps, or fee > 0 with no recipient). + */ + 5: {message:"InvalidFeeConfig"}, + /** + * The contract is paused. + */ + 16: {message:"Paused"}, + /** + * The batch withdrawal exceeds the supported size cap. + */ + 6: {message:"BatchTooLarge"}, + /** + * The governance multisig has not been initialised. + */ + 7: {message:"MultisigNotInitialized"}, + /** + * The governance multisig has already been initialised. + */ + 8: {message:"MultisigAlreadyInitialized"}, + /** + * The caller is not a current governance signer. + */ + 9: {message:"NotSigner"}, + /** + * The requested threshold is invalid (zero, or greater than signer count). + */ + 10: {message:"InvalidThreshold"}, + /** + * A signer-rotation proposal is already pending. + */ + 11: {message:"RotationAlreadyPending"}, + /** + * No signer-rotation proposal is pending. + */ + 12: {message:"NoPendingRotation"}, + /** + * The caller has already approved the pending rotation. + */ + 13: {message:"AlreadyApprovedRotation"}, + /** + * The pending rotation has not collected enough approvals yet. + */ + 14: {message:"QuorumNotMet"}, + /** + * The rotation timelock has not elapsed yet. + */ + 15: {message:"TimelockNotElapsed"} +} + + +/** + * A single withdrawal entry for batched asset exits. + */ +export interface WithdrawalEntry { + /** + * The amount to transfer in the token's base unit. + */ +amount: i128; + /** + * The destination address for the withdrawal. + */ +to: string; + /** + * The token contract to withdraw from or to transfer through. + */ +token: string; +} + + +/** + * A pending signer-rotation proposal. + */ +export interface RotationProposal { + approvals: Array; + executable_at: u64; + new_signers: Array; + new_threshold: u32; +} + + +/** + * Wraith Protocol standard metric event schema. + * + * All Wraith contracts emit metric events using this structure to enable + * standardized off-chain observability and monitoring. + */ +export interface WraithMetricEvent { + /** + * Contract identifier (e.g., "stealth-registry", "stealth-sender") + */ +contract: string; + /** + * Optional dimensions for filtering/grouping (e.g., token_address, scheme_id) + */ +dimensions: Array; + /** + * Metric name (e.g., "register_count", "send_volume") + */ +metric_name: string; + /** + * Numeric value of the metric + */ +value: i128; } export interface Client { /** * Construct and simulate a init transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. - * Initialise the contract by storing the announcer address. + * Initialise the contract by storing the announcer address, optional asset policy, + * and optional protocol fee configuration. * * Must be called exactly once before any `send` or `batch_send`. */ - init: ({announcer}: {announcer: string}, options?: MethodOptions) => Promise>> + init: ({announcer, asset_policy, fee_recipient, fee_basis_points, admin}: {announcer: string, asset_policy: Option, fee_recipient: Option, fee_basis_points: u32, admin: string}, options?: MethodOptions) => Promise>> /** * Construct and simulate a send transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. @@ -80,6 +189,37 @@ export interface Client { */ send: ({sender, token, amount, scheme_id, stealth_address, ephemeral_pub_key, metadata}: {sender: string, token: string, amount: i128, scheme_id: u32, stealth_address: string, ephemeral_pub_key: Buffer, metadata: Buffer}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a pause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Pause the contract — admin only. + * Prevents all sends and batch_sends while paused. + */ + pause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current governance signer set. + */ + signers: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a unpause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Unpause the contract — admin only. + */ + unpause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a is_paused transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns true if the contract is paused. + */ + is_paused: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a threshold transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current governance quorum threshold. + */ + threshold: (options?: MethodOptions) => Promise> + /** * Construct and simulate a batch_send transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Batch version of `send` — transfers tokens to multiple stealth addresses @@ -89,6 +229,55 @@ export interface Client { */ batch_send: ({sender, token, scheme_id, stealth_addresses, ephemeral_pub_keys, metadatas, amounts}: {sender: string, token: string, scheme_id: u32, stealth_addresses: Array, ephemeral_pub_keys: Array, metadatas: Array, amounts: Array}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a init_multisig transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * One-time setup of the governance signer set used to authorise signer + * rotations. Independent of `init` — does not gate `send`/`batch_send`. + */ + init_multisig: ({signers, threshold}: {signers: Array, threshold: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a withdraw_many transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Withdraw assets to multiple destinations in a single atomic transaction. + * + * The batch is capped at 30 entries. If any single entry cannot be + * processed, the entire batch aborts and no state changes are retained. + */ + withdraw_many: ({withdrawer, entries}: {withdrawer: string, entries: Array}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a pending_rotation transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * The pending signer-rotation proposal, if any. + */ + pending_rotation: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a cancel_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Cancel the pending rotation, clearing all of its state. + */ + cancel_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a approve_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Approve the pending signer-rotation proposal. + */ + approve_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a execute_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Execute the pending rotation once quorum is met and the timelock has + * elapsed. Emits `SignersRotated`. + */ + execute_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a propose_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Propose a new signer set + threshold behind the rotation timelock. + * `caller` must be a current signer; the proposal is auto-approved by + * `caller`. Rejects thresholds that could never reach quorum. + */ + propose_rotate_signers: ({caller, new_signers, new_threshold}: {caller: string, new_signers: Array, new_threshold: u32}, options?: MethodOptions) => Promise>> + } export class Client extends ContractClient { static async deploy( @@ -107,17 +296,44 @@ export class Client extends ContractClient { } constructor(public readonly options: ContractClientOptions) { super( - new ContractSpec([ "AAAAAAAAAHlJbml0aWFsaXNlIHRoZSBjb250cmFjdCBieSBzdG9yaW5nIHRoZSBhbm5vdW5jZXIgYWRkcmVzcy4KCk11c3QgYmUgY2FsbGVkIGV4YWN0bHkgb25jZSBiZWZvcmUgYW55IGBzZW5kYCBvciBgYmF0Y2hfc2VuZGAuAAAAAAAABGluaXQAAAABAAAAAAAAAAlhbm5vdW5jZXIAAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAALU2VuZGVyRXJyb3IA", + new ContractSpec([ "AAAAAAAAALlJbml0aWFsaXNlIHRoZSBjb250cmFjdCBieSBzdG9yaW5nIHRoZSBhbm5vdW5jZXIgYWRkcmVzcywgb3B0aW9uYWwgYXNzZXQgcG9saWN5LAphbmQgb3B0aW9uYWwgcHJvdG9jb2wgZmVlIGNvbmZpZ3VyYXRpb24uCgpNdXN0IGJlIGNhbGxlZCBleGFjdGx5IG9uY2UgYmVmb3JlIGFueSBgc2VuZGAgb3IgYGJhdGNoX3NlbmRgLgAAAAAAAARpbml0AAAABQAAAAAAAAAJYW5ub3VuY2VyAAAAAAAAEwAAAAAAAAAMYXNzZXRfcG9saWN5AAAD6AAAABMAAAAAAAAADWZlZV9yZWNpcGllbnQAAAAAAAPoAAAAEwAAAAAAAAAQZmVlX2Jhc2lzX3BvaW50cwAAAAQAAAAAAAAABWFkbWluAAAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAC1NlbmRlckVycm9yAA==", "AAAAAAAAAglUcmFuc2ZlciB0b2tlbnMgdG8gYSBzdGVhbHRoIGFkZHJlc3MgYW5kIGVtaXQgYW4gYW5ub3VuY2VtZW50LgoKIyBBcmd1bWVudHMKKiBgc2VuZGVyYCAgICAgICAgICAgIC0gVGhlIGFkZHJlc3Mgc2VuZGluZyBmdW5kcyAobXVzdCBhdXRob3Jpc2UpLgoqIGB0b2tlbmAgICAgICAgICAgICAgLSBTQUMgdG9rZW4gY29udHJhY3QgYWRkcmVzcyAod29ya3MgZm9yIG5hdGl2ZSBYTE0gdG9vKS4KKiBgYW1vdW50YCAgICAgICAgICAgIC0gQW1vdW50IG9mIHRva2VucyB0byB0cmFuc2Zlci4KKiBgc2NoZW1lX2lkYCAgICAgICAgIC0gU3RlYWx0aCBhZGRyZXNzIHNjaGVtZSBpZGVudGlmaWVyLgoqIGBzdGVhbHRoX2FkZHJlc3NgICAgLSBUaGUgZGVyaXZlZCBvbmUtdGltZSBzdGVhbHRoIGFkZHJlc3MuCiogYGVwaGVtZXJhbF9wdWJfa2V5YCAtIEVwaGVtZXJhbCBwdWJsaWMga2V5IGZvciB0aGUgcmVjaXBpZW50IHRvIHNjYW4uCiogYG1ldGFkYXRhYCAgICAgICAgICAtIEV4dHJhIGRhdGEgKGUuZy4gdmlldyB0YWcpLgAAAAAAAARzZW5kAAAABwAAAAAAAAAGc2VuZGVyAAAAAAATAAAAAAAAAAV0b2tlbgAAAAAAABMAAAAAAAAABmFtb3VudAAAAAAACwAAAAAAAAAJc2NoZW1lX2lkAAAAAAAABAAAAAAAAAAPc3RlYWx0aF9hZGRyZXNzAAAAABMAAAAAAAAAEWVwaGVtZXJhbF9wdWJfa2V5AAAAAAAD7gAAACAAAAAAAAAACG1ldGFkYXRhAAAADgAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAC1NlbmRlckVycm9yAA==", - "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAEAAAAAAAAANlRoZSBhZGRyZXNzIG9mIHRoZSBkZXBsb3llZCBTdGVhbHRoQW5ub3VuY2VyIGNvbnRyYWN0LgAAAAAACUFubm91bmNlcgAAAA==", + "AAAAAAAAAFNQYXVzZSB0aGUgY29udHJhY3Qg4oCUIGFkbWluIG9ubHkuClByZXZlbnRzIGFsbCBzZW5kcyBhbmQgYmF0Y2hfc2VuZHMgd2hpbGUgcGF1c2VkLgAAAAAFcGF1c2UAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAtTZW5kZXJFcnJvcgA=", + "AAAAAAAAAB5DdXJyZW50IGdvdmVybmFuY2Ugc2lnbmVyIHNldC4AAAAAAAdzaWduZXJzAAAAAAAAAAABAAAD6gAAABM=", + "AAAAAAAAACRVbnBhdXNlIHRoZSBjb250cmFjdCDigJQgYWRtaW4gb25seS4AAAAHdW5wYXVzZQAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAtTZW5kZXJFcnJvcgA=", + "AAAAAAAAACdSZXR1cm5zIHRydWUgaWYgdGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAACWlzX3BhdXNlZAAAAAAAAAAAAAABAAAAAQ==", + "AAAAAAAAACRDdXJyZW50IGdvdmVybmFuY2UgcXVvcnVtIHRocmVzaG9sZC4AAAAJdGhyZXNob2xkAAAAAAAAAAAAAAEAAAAE", + "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAkAAAAAAAAANlRoZSBhZGRyZXNzIG9mIHRoZSBkZXBsb3llZCBTdGVhbHRoQW5ub3VuY2VyIGNvbnRyYWN0LgAAAAAACUFubm91bmNlcgAAAAAAAAAAAAAuT3B0aW9uYWwgYWRkcmVzcyBvZiB0aGUgYXNzZXQgcG9saWN5IGNvbnRyYWN0LgAAAAAAC0Fzc2V0UG9saWN5AAAAAAAAAAAvT3B0aW9uYWwgYWRkcmVzcyBvZiB0aGUgcHJvdG9jb2wgZmVlIHJlY2lwaWVudC4AAAAADEZlZVJlY2lwaWVudAAAAAAAAAA4UHJvdG9jb2wgZmVlIGluIGJhc2lzIHBvaW50cyAobWF4IDUwIGJwcywgMCA9IGRpc2FibGVkKS4AAAAORmVlQmFzaXNQb2ludHMAAAAAAAAAAAAUUGF1c2UgYWRtaW4gYWRkcmVzcy4AAAAFQWRtaW4AAAAAAAAAAAAAH1doZXRoZXIgdGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAABlBhdXNlZAAAAAAAAAAAAB9Hb3Zlcm5hbmNlIG11bHRpc2lnIHNpZ25lciBzZXQuAAAAAA9NdWx0aXNpZ1NpZ25lcnMAAAAAAAAAACVHb3Zlcm5hbmNlIG11bHRpc2lnIHF1b3J1bSB0aHJlc2hvbGQuAAAAAAAAEU11bHRpc2lnVGhyZXNob2xkAAAAAAAAAAAAAClQZW5kaW5nIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbCwgaWYgYW55LgAAAAAAAA9QZW5kaW5nUm90YXRpb24A", "AAAAAAAAAJxCYXRjaCB2ZXJzaW9uIG9mIGBzZW5kYCDigJQgdHJhbnNmZXJzIHRva2VucyB0byBtdWx0aXBsZSBzdGVhbHRoIGFkZHJlc3NlcwphbmQgZW1pdHMgYW4gYW5ub3VuY2VtZW50IGZvciBlYWNoLgoKQWxsIGlucHV0IHZlY3RvcnMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aC4AAAAKYmF0Y2hfc2VuZAAAAAAABwAAAAAAAAAGc2VuZGVyAAAAAAATAAAAAAAAAAV0b2tlbgAAAAAAABMAAAAAAAAACXNjaGVtZV9pZAAAAAAAAAQAAAAAAAAAEXN0ZWFsdGhfYWRkcmVzc2VzAAAAAAAD6gAAABMAAAAAAAAAEmVwaGVtZXJhbF9wdWJfa2V5cwAAAAAD6gAAA+4AAAAgAAAAAAAAAAltZXRhZGF0YXMAAAAAAAPqAAAADgAAAAAAAAAHYW1vdW50cwAAAAPqAAAACwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAC1NlbmRlckVycm9yAA==", - "AAAABAAAACxFcnJvcnMgdGhhdCB0aGUgc2VuZGVyIGNvbnRyYWN0IGNhbiBwcm9kdWNlLgAAAAAAAAALU2VuZGVyRXJyb3IAAAAAAwAAACpUaGUgY29udHJhY3QgaGFzIGFscmVhZHkgYmVlbiBpbml0aWFsaXNlZC4AAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAAEAAAAqVGhlIGNvbnRyYWN0IGhhcyBub3QgYmVlbiBpbml0aWFsaXNlZCB5ZXQuAAAAAAAOTm90SW5pdGlhbGl6ZWQAAAAAAAIAAAAwVGhlIGJhdGNoIGlucHV0IHZlY3RvcnMgaGF2ZSBtaXNtYXRjaGVkIGxlbmd0aHMuAAAADkxlbmd0aE1pc21hdGNoAAAAAAAD" ]), + "AAAAAAAAAIxPbmUtdGltZSBzZXR1cCBvZiB0aGUgZ292ZXJuYW5jZSBzaWduZXIgc2V0IHVzZWQgdG8gYXV0aG9yaXNlIHNpZ25lcgpyb3RhdGlvbnMuIEluZGVwZW5kZW50IG9mIGBpbml0YCDigJQgZG9lcyBub3QgZ2F0ZSBgc2VuZGAvYGJhdGNoX3NlbmRgLgAAAA1pbml0X211bHRpc2lnAAAAAAAAAgAAAAAAAAAHc2lnbmVycwAAAAPqAAAAEwAAAAAAAAAJdGhyZXNob2xkAAAAAAAABAAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAC1NlbmRlckVycm9yAA==", + "AAAAAAAAANBXaXRoZHJhdyBhc3NldHMgdG8gbXVsdGlwbGUgZGVzdGluYXRpb25zIGluIGEgc2luZ2xlIGF0b21pYyB0cmFuc2FjdGlvbi4KClRoZSBiYXRjaCBpcyBjYXBwZWQgYXQgMzAgZW50cmllcy4gSWYgYW55IHNpbmdsZSBlbnRyeSBjYW5ub3QgYmUKcHJvY2Vzc2VkLCB0aGUgZW50aXJlIGJhdGNoIGFib3J0cyBhbmQgbm8gc3RhdGUgY2hhbmdlcyBhcmUgcmV0YWluZWQuAAAADXdpdGhkcmF3X21hbnkAAAAAAAACAAAAAAAAAAp3aXRoZHJhd2VyAAAAAAATAAAAAAAAAAdlbnRyaWVzAAAAA+oAAAfQAAAAD1dpdGhkcmF3YWxFbnRyeQAAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAtTZW5kZXJFcnJvcgA=", + "AAAABAAAACxFcnJvcnMgdGhhdCB0aGUgc2VuZGVyIGNvbnRyYWN0IGNhbiBwcm9kdWNlLgAAAAAAAAALU2VuZGVyRXJyb3IAAAAAEAAAACpUaGUgY29udHJhY3QgaGFzIGFscmVhZHkgYmVlbiBpbml0aWFsaXNlZC4AAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAAEAAAAqVGhlIGNvbnRyYWN0IGhhcyBub3QgYmVlbiBpbml0aWFsaXNlZCB5ZXQuAAAAAAAOTm90SW5pdGlhbGl6ZWQAAAAAAAIAAAAwVGhlIGJhdGNoIGlucHV0IHZlY3RvcnMgaGF2ZSBtaXNtYXRjaGVkIGxlbmd0aHMuAAAADkxlbmd0aE1pc21hdGNoAAAAAAADAAAALVRoZSB0b2tlbiBpcyBub3QgYWxsb3dlZCBieSB0aGUgYXNzZXQgcG9saWN5LgAAAAAAAA9Ub2tlbk5vdEFsbG93ZWQAAAAABAAAAFNUaGUgZmVlIGNvbmZpZ3VyYXRpb24gaXMgaW52YWxpZCAoZS5nLiBmZWUgPiA1MCBicHMsIG9yIGZlZSA+IDAgd2l0aCBubyByZWNpcGllbnQpLgAAAAAQSW52YWxpZEZlZUNvbmZpZwAAAAUAAAAXVGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAABlBhdXNlZAAAAAAAEAAAADRUaGUgYmF0Y2ggd2l0aGRyYXdhbCBleGNlZWRzIHRoZSBzdXBwb3J0ZWQgc2l6ZSBjYXAuAAAADUJhdGNoVG9vTGFyZ2UAAAAAAAAGAAAAMVRoZSBnb3Zlcm5hbmNlIG11bHRpc2lnIGhhcyBub3QgYmVlbiBpbml0aWFsaXNlZC4AAAAAAAAWTXVsdGlzaWdOb3RJbml0aWFsaXplZAAAAAAABwAAADVUaGUgZ292ZXJuYW5jZSBtdWx0aXNpZyBoYXMgYWxyZWFkeSBiZWVuIGluaXRpYWxpc2VkLgAAAAAAABpNdWx0aXNpZ0FscmVhZHlJbml0aWFsaXplZAAAAAAACAAAAC5UaGUgY2FsbGVyIGlzIG5vdCBhIGN1cnJlbnQgZ292ZXJuYW5jZSBzaWduZXIuAAAAAAAJTm90U2lnbmVyAAAAAAAACQAAAEhUaGUgcmVxdWVzdGVkIHRocmVzaG9sZCBpcyBpbnZhbGlkICh6ZXJvLCBvciBncmVhdGVyIHRoYW4gc2lnbmVyIGNvdW50KS4AAAAQSW52YWxpZFRocmVzaG9sZAAAAAoAAAAuQSBzaWduZXItcm90YXRpb24gcHJvcG9zYWwgaXMgYWxyZWFkeSBwZW5kaW5nLgAAAAAAFlJvdGF0aW9uQWxyZWFkeVBlbmRpbmcAAAAAAAsAAAAnTm8gc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsIGlzIHBlbmRpbmcuAAAAABFOb1BlbmRpbmdSb3RhdGlvbgAAAAAAAAwAAAA1VGhlIGNhbGxlciBoYXMgYWxyZWFkeSBhcHByb3ZlZCB0aGUgcGVuZGluZyByb3RhdGlvbi4AAAAAAAAXQWxyZWFkeUFwcHJvdmVkUm90YXRpb24AAAAADQAAADxUaGUgcGVuZGluZyByb3RhdGlvbiBoYXMgbm90IGNvbGxlY3RlZCBlbm91Z2ggYXBwcm92YWxzIHlldC4AAAAMUXVvcnVtTm90TWV0AAAADgAAACpUaGUgcm90YXRpb24gdGltZWxvY2sgaGFzIG5vdCBlbGFwc2VkIHlldC4AAAAAABJUaW1lbG9ja05vdEVsYXBzZWQAAAAAAA8=", + "AAAAAAAAAC1UaGUgcGVuZGluZyBzaWduZXItcm90YXRpb24gcHJvcG9zYWwsIGlmIGFueS4AAAAAAAAQcGVuZGluZ19yb3RhdGlvbgAAAAAAAAABAAAD6AAAB9AAAAAQUm90YXRpb25Qcm9wb3NhbA==", + "AAAAAQAAADJBIHNpbmdsZSB3aXRoZHJhd2FsIGVudHJ5IGZvciBiYXRjaGVkIGFzc2V0IGV4aXRzLgAAAAAAAAAAAA9XaXRoZHJhd2FsRW50cnkAAAAAAwAAADBUaGUgYW1vdW50IHRvIHRyYW5zZmVyIGluIHRoZSB0b2tlbidzIGJhc2UgdW5pdC4AAAAGYW1vdW50AAAAAAALAAAAK1RoZSBkZXN0aW5hdGlvbiBhZGRyZXNzIGZvciB0aGUgd2l0aGRyYXdhbC4AAAAAAnRvAAAAAAATAAAAO1RoZSB0b2tlbiBjb250cmFjdCB0byB3aXRoZHJhdyBmcm9tIG9yIHRvIHRyYW5zZmVyIHRocm91Z2guAAAAAAV0b2tlbgAAAAAAABM=", + "AAAAAAAAADdDYW5jZWwgdGhlIHBlbmRpbmcgcm90YXRpb24sIGNsZWFyaW5nIGFsbCBvZiBpdHMgc3RhdGUuAAAAABVjYW5jZWxfcm90YXRlX3NpZ25lcnMAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAtTZW5kZXJFcnJvcgA=", + "AAAAAAAAAC1BcHByb3ZlIHRoZSBwZW5kaW5nIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbC4AAAAAAAAWYXBwcm92ZV9yb3RhdGVfc2lnbmVycwAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAALU2VuZGVyRXJyb3IA", + "AAAAAAAAAGVFeGVjdXRlIHRoZSBwZW5kaW5nIHJvdGF0aW9uIG9uY2UgcXVvcnVtIGlzIG1ldCBhbmQgdGhlIHRpbWVsb2NrIGhhcwplbGFwc2VkLiBFbWl0cyBgU2lnbmVyc1JvdGF0ZWRgLgAAAAAAABZleGVjdXRlX3JvdGF0ZV9zaWduZXJzAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAtTZW5kZXJFcnJvcgA=", + "AAAAAAAAAMJQcm9wb3NlIGEgbmV3IHNpZ25lciBzZXQgKyB0aHJlc2hvbGQgYmVoaW5kIHRoZSByb3RhdGlvbiB0aW1lbG9jay4KYGNhbGxlcmAgbXVzdCBiZSBhIGN1cnJlbnQgc2lnbmVyOyB0aGUgcHJvcG9zYWwgaXMgYXV0by1hcHByb3ZlZCBieQpgY2FsbGVyYC4gUmVqZWN0cyB0aHJlc2hvbGRzIHRoYXQgY291bGQgbmV2ZXIgcmVhY2ggcXVvcnVtLgAAAAAAFnByb3Bvc2Vfcm90YXRlX3NpZ25lcnMAAAAAAAMAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAALbmV3X3NpZ25lcnMAAAAD6gAAABMAAAAAAAAADW5ld190aHJlc2hvbGQAAAAAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAALU2VuZGVyRXJyb3IA", + "AAAAAQAAACNBIHBlbmRpbmcgc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsLgAAAAAAAAAAEFJvdGF0aW9uUHJvcG9zYWwAAAAEAAAAAAAAAAlhcHByb3ZhbHMAAAAAAAPqAAAAEwAAAAAAAAANZXhlY3V0YWJsZV9hdAAAAAAAAAYAAAAAAAAAC25ld19zaWduZXJzAAAAA+oAAAATAAAAAAAAAA1uZXdfdGhyZXNob2xkAAAAAAAABA==", + "AAAAAQAAAKpXcmFpdGggUHJvdG9jb2wgc3RhbmRhcmQgbWV0cmljIGV2ZW50IHNjaGVtYS4KCkFsbCBXcmFpdGggY29udHJhY3RzIGVtaXQgbWV0cmljIGV2ZW50cyB1c2luZyB0aGlzIHN0cnVjdHVyZSB0byBlbmFibGUKc3RhbmRhcmRpemVkIG9mZi1jaGFpbiBvYnNlcnZhYmlsaXR5IGFuZCBtb25pdG9yaW5nLgAAAAAAAAAAABFXcmFpdGhNZXRyaWNFdmVudAAAAAAAAAQAAABAQ29udHJhY3QgaWRlbnRpZmllciAoZS5nLiwgInN0ZWFsdGgtcmVnaXN0cnkiLCAic3RlYWx0aC1zZW5kZXIiKQAAAAhjb250cmFjdAAAABEAAABLT3B0aW9uYWwgZGltZW5zaW9ucyBmb3IgZmlsdGVyaW5nL2dyb3VwaW5nIChlLmcuLCB0b2tlbl9hZGRyZXNzLCBzY2hlbWVfaWQpAAAAAApkaW1lbnNpb25zAAAAAAPqAAAD7QAAAAIAAAARAAAAAAAAADNNZXRyaWMgbmFtZSAoZS5nLiwgInJlZ2lzdGVyX2NvdW50IiwgInNlbmRfdm9sdW1lIikAAAAAC21ldHJpY19uYW1lAAAAABEAAAAbTnVtZXJpYyB2YWx1ZSBvZiB0aGUgbWV0cmljAAAAAAV2YWx1ZQAAAAAAAAs=" ]), options ) } public readonly fromJSON = { init: this.txFromJSON>, send: this.txFromJSON>, - batch_send: this.txFromJSON> + pause: this.txFromJSON>, + signers: this.txFromJSON>, + unpause: this.txFromJSON>, + is_paused: this.txFromJSON, + threshold: this.txFromJSON, + batch_send: this.txFromJSON>, + init_multisig: this.txFromJSON>, + withdraw_many: this.txFromJSON>, + pending_rotation: this.txFromJSON>, + cancel_rotate_signers: this.txFromJSON>, + approve_rotate_signers: this.txFromJSON>, + execute_rotate_signers: this.txFromJSON>, + propose_rotate_signers: this.txFromJSON> } } \ No newline at end of file diff --git a/stellar/bindings/typescript/wraith-names/src/index.ts b/stellar/bindings/typescript/wraith-names/src/index.ts index 3002f087..844e2a21 100644 --- a/stellar/bindings/typescript/wraith-names/src/index.ts +++ b/stellar/bindings/typescript/wraith-names/src/index.ts @@ -36,25 +36,22 @@ if (typeof window !== "undefined") { /** * Storage keys. */ -export type DataKey = {tag: "Name", values: readonly [Buffer]} | {tag: "Reverse", values: readonly [Buffer]}; +export type DataKey = {tag: "Name", values: readonly [Buffer]} | {tag: "Reverse", values: readonly [Buffer]} | {tag: "Replay", values: readonly [Buffer]} | {tag: "Guardians", values: readonly [Buffer]} | {tag: "Recovery", values: readonly [Buffer]} | {tag: "Admin", values: void} | {tag: "Paused", values: void} | {tag: "MultisigSigners", values: void} | {tag: "MultisigThreshold", values: void} | {tag: "PendingRotation", values: void} | {tag: "PendingAuctionAdminRotation", values: void}; /** * A registered name entry. */ export interface NameEntry { + name: string; + owner: string; /** - * The human-readable name. + * For a subdomain (`sub.parent`), the name hash of the parent label. + * `None` for a flat top-level name. Existing flat names register with + * `None`, so prior behaviour is preserved. */ -name: string; - /** - * The registrant address (for auth). - */ -owner: string; - /** - * The 64-byte stealth meta-address (spending_pubkey || viewing_pubkey). - */ -stealth_meta_address: Buffer; +parent: Option; + stealth_meta_address: Buffer; } /** @@ -67,10 +64,274 @@ export const NamesError = { 4: {message:"InvalidNameCharacter"}, 5: {message:"InvalidMetaAddress"}, 6: {message:"NameNotFound"}, - 7: {message:"NotOwner"} + 7: {message:"NotOwner"}, + 8: {message:"SignatureExpired"}, + 9: {message:"SignatureReplay"}, + 10: {message:"InvalidSigner"}, + 11: {message:"NotGuardian"}, + 12: {message:"NoProposal"}, + 13: {message:"ProposalAlreadyExists"}, + 14: {message:"AlreadyApproved"}, + 15: {message:"DelayNotElapsed"}, + 16: {message:"ThresholdNotMet"}, + 17: {message:"TooManyGuardians"}, + 18: {message:"InvalidThreshold"}, + 19: {message:"InvalidExtendLedger"}, + 20: {message:"ParentNotFound"}, + /** + * The contract is paused. + */ + 32: {message:"Paused"}, + /** + * The protocol-level governance multisig has not been initialised. + */ + 21: {message:"MultisigNotInitialized"}, + /** + * The protocol-level governance multisig has already been initialised. + */ + 22: {message:"MultisigAlreadyInitialized"}, + /** + * The caller is not a current protocol-level governance signer. + */ + 23: {message:"NotSigner"}, + /** + * A signer-rotation proposal is already pending. + */ + 24: {message:"RotationAlreadyPending"}, + /** + * No signer-rotation proposal is pending. + */ + 25: {message:"NoPendingRotation"}, + /** + * The caller has already approved the pending rotation. + */ + 26: {message:"AlreadyApprovedRotation"}, + /** + * The pending rotation has not collected enough approvals yet. + */ + 27: {message:"QuorumNotMet"}, + /** + * The rotation timelock has not elapsed yet. + */ + 28: {message:"TimelockNotElapsed"}, + 29: {message:"NameTooDeep"}, + 30: {message:"BulkLimitExceeded"}, + /** + * The name is premium (<= 4 chars) and the auction window is active, so + * it can only be obtained through the sealed-bid auction. + */ + 31: {message:"PremiumAuctionRequired"}, + /** + * The auction subsystem has not been initialised, so there is no auction + * admin to rotate. + */ + 1600: {message:"AuctionsNotInitialized"}, + /** + * An auction has a revealed winner and has not settled yet, so the + * auction admin cannot be rotated out from under it. + */ + 1601: {message:"AuctionInProgress"} +} + + +/** + * Guardian configuration for a name. + */ +export interface GuardianConfig { + guardians: Array; + threshold: u32; +} + + +/** + * A pending recovery proposal. + */ +export interface RecoveryProposal { + approvals: Array; + new_meta_address: Buffer; + new_owner: string; + proposed_at: u32; +} + + +/** + * State of a single name auction. + */ +export interface Auction { + /** + * Timestamp at which the commit phase ends and the reveal phase begins. + */ +commit_end: u64; + /** + * Highest revealed bid amount so far. + */ +highest_amount: i128; + /** + * Highest revealed bidder so far. Ties go to the earliest reveal. + */ +highest_bidder: Option; + name: string; + /** + * Timestamp at which the reveal phase ends and settlement is possible. + */ +reveal_end: u64; + settled: boolean; +} + + +/** + * A sealed bid. + */ +export interface SealedBid { + /** + * sha256 commitment binding bidder, name, amount and salt. + */ +commitment: Buffer; + /** + * Tokens locked in the contract; refunded in full to losers. + */ +deposit: i128; + revealed: boolean; +} + +/** + * Storage keys for the auction subsystem. + */ +export type AuctionKey = {tag: "Config", values: void} | {tag: "Auction", values: readonly [Buffer]} | {tag: "Bid", values: readonly [Buffer, string]} | {tag: "PendingSettlements", values: void}; + +/** + * Auction errors. Codes start at 100 to stay disjoint from `NamesError`. + */ +export const AuctionError = { + 100: {message:"NotInitialized"}, + 101: {message:"AlreadyInitialized"}, + 102: {message:"InvalidConfig"}, + 103: {message:"WindowClosed"}, + 104: {message:"NotPremiumName"}, + 105: {message:"NameAlreadyRegistered"}, + 106: {message:"AuctionExists"}, + 107: {message:"NoAuction"}, + 108: {message:"CommitPhaseOver"}, + 109: {message:"AlreadyCommitted"}, + 110: {message:"DepositBelowReserve"}, + 111: {message:"RevealPhaseNotActive"}, + 112: {message:"NoBid"}, + 113: {message:"AlreadyRevealed"}, + 114: {message:"CommitmentMismatch"}, + 115: {message:"BidBelowReserve"}, + 116: {message:"BidExceedsDeposit"}, + 117: {message:"RevealPhaseNotOver"}, + 118: {message:"AlreadySettled"}, + 119: {message:"NotSettled"}, + 120: {message:"NotWinner"}, + 121: {message:"WinnerCannotWithdraw"}, + 122: {message:"InvalidMetaAddress"}, + 123: {message:"RegistrationFailed"} +} + + +/** + * Auction configuration, set once at initialization. + */ +export interface AuctionConfig { + /** + * Operator that runs settlements per the runbook. + */ +admin: string; + /** + * Duration of the commit phase of each auction, in seconds. + */ +commit_secs: u64; + /** + * Ledger timestamp at initialization; the premium window runs for + * `PREMIUM_WINDOW_SECS` from this point. + */ +launch_time: u64; + /** + * Minimum bid; deposits must also be at least this amount. + */ +reserve_price: i128; + /** + * Duration of the reveal phase of each auction, in seconds. + */ +reveal_secs: u64; + /** + * Payment token (native XLM SAC on mainnet). + */ +token: string; + /** + * Receives winning bids. + */ +treasury: string; +} + + +/** + * A pending signer-rotation proposal. + */ +export interface RotationProposal { + approvals: Array; + executable_at: u64; + new_signers: Array; + new_threshold: u32; +} + + +/** + * A pending auction-admin rotation proposal. Mirrors `RotationProposal` — + * same signer set, same quorum, same timelock — but carries the incoming + * auction operator address instead of a new signer set. + */ +export interface AdminRotationProposal { + approvals: Array; + executable_at: u64; + new_admin: string; +} + + +/** + * Wraith Protocol standard metric event schema. + * + * All Wraith contracts emit metric events using this structure to enable + * standardized off-chain observability and monitoring. + */ +export interface WraithMetricEvent { + /** + * Contract identifier (e.g., "stealth-registry", "stealth-sender") + */ +contract: string; + /** + * Optional dimensions for filtering/grouping (e.g., token_address, scheme_id) + */ +dimensions: Array; + /** + * Metric name (e.g., "register_count", "send_volume") + */ +metric_name: string; + /** + * Numeric value of the metric + */ +value: i128; } export interface Client { + /** + * Construct and simulate a init transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Initialise the contract by storing the pause admin. + * + * Must be called before `pause` / `unpause`. Idempotent: calling + * more than once is a no-op (the first admin sticks). + */ + init: ({admin}: {admin: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a pause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Pause the contract — admin only. + * Prevents all registrations, updates, releases and TTL extensions + * while paused. Lookups (`resolve`, `name_of`) remain available. + */ + pause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a update transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Update the meta-address for an existing name. @@ -93,21 +354,246 @@ export interface Client { /** * Construct and simulate a resolve transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Resolve a name to its stealth meta-address. + * + * For a subdomain (`payments.alice`) resolution walks to the parent + * (`alice`): if the parent no longer exists the subdomain does not resolve. */ resolve: ({name}: {name: string}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current protocol-level governance signer set. + */ + signers: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a unpause transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Unpause the contract — admin only. + */ + unpause: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a register transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Register a name mapped to a stealth meta-address. - * The caller (owner) must authorize. Ownership is tied to the caller's address. - * - * # Arguments - * * `owner` - The address registering the name (must authorize). - * * `name` - The human-readable name (lowercase alphanumeric, 3-32 chars). - * * `stealth_meta_address` - 64-byte stealth meta-address. */ register: ({owner, name, stealth_meta_address}: {owner: string, name: string, stealth_meta_address: Buffer}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a is_paused transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns true if the contract is paused. + */ + is_paused: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a threshold transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Current protocol-level governance quorum threshold. + */ + threshold: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a bulk_renew transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Renew (extend TTL for) multiple names in a single atomic transaction. + * + * All names must exist. If any name is not found, the entire operation + * reverts. + */ + bulk_renew: ({names, extend_to_ledger}: {names: Array, extend_to_ledger: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a claim_name transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Claim a won auction: registers the name to the winner with their + * stealth meta-address. + */ + claim_name: ({winner, name, stealth_meta_address}: {winner: string, name: string, stealth_meta_address: Buffer}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a commit_bid transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Commit a sealed bid. `commitment` hides the bid amount; `deposit` is + * transferred to the contract and must cover the bid revealed later. + */ + commit_bid: ({bidder, name, commitment, deposit}: {bidder: string, name: string, commitment: Buffer, deposit: i128}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a reveal_bid transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Reveal a previously committed bid by disclosing the amount and salt. + */ + reveal_bid: ({bidder, name, amount, salt}: {bidder: string, name: string, amount: i128, salt: Buffer}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a get_auction transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Read the auction state for a name, if any. + */ + get_auction: ({name}: {name: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a withdraw_bid transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Withdraw a losing (or unrevealed) bid deposit in full. + */ + withdraw_bid: ({bidder, name}: {bidder: string, name: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a bulk_register transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Register multiple names in a single atomic transaction. + * + * All names must be valid and not already taken. If any name fails, + * the entire operation reverts. + */ + bulk_register: ({owner, names, meta_addresses}: {owner: string, names: Array, meta_addresses: Array}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a init_auctions transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * One-time initialization of the premium-name auction system. + * + * `admin` operates settlements per the runbook, `treasury` receives + * winning bids, `token` is the payment asset (native XLM SAC on mainnet), + * `reserve_price` is the minimum bid, and `commit_secs` / `reveal_secs` + * are the phase durations for each auction. The 90-day premium window + * starts at the ledger timestamp of this call. + */ + init_auctions: ({admin, treasury, token, reserve_price, commit_secs, reveal_secs}: {admin: string, treasury: string, token: string, reserve_price: i128, commit_secs: u64, reveal_secs: u64}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a init_multisig transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * One-time setup of the protocol-level governance signer set used to + * authorise signer rotations. + */ + init_multisig: ({signers, threshold}: {signers: Array, threshold: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a start_auction transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Start a sealed-bid auction for a premium name (<= 4 chars, top-level). + * Permissionless: anyone may open the auction for an eligible name. + */ + start_auction: ({name}: {name: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a auction_config transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Read the auction configuration, if initialized. + */ + auction_config: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a settle_auction transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Settle an auction after the reveal phase: pays the winning bid to the + * treasury and refunds the winner's excess deposit. Permissionless so + * funds can never be trapped, operated by the admin per the runbook. + */ + settle_auction: ({name}: {name: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a extend_name_ttl transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Extend TTL for persistent storage entries only. + * Extend the TTL of a registered name to a future ledger. + * This is a permissionless function that anyone can call. + * Idempotent: calling twice in the same ledger has no additional effect. + */ + extend_name_ttl: ({name, extend_to_ledger}: {name: string, extend_to_ledger: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a pending_rotation transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * The pending signer-rotation proposal, if any. + */ + pending_rotation: (options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a update_on_behalf transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Update a name on behalf of an owner using a signed authorization. + */ + update_on_behalf: ({owner, name, new_meta_address, signature, expiry}: {owner: string, name: string, new_meta_address: Buffer, signature: Buffer, expiry: u64}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a release_on_behalf transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Release a name on behalf of an owner using a signed authorization. + */ + release_on_behalf: ({owner, name, signature, expiry}: {owner: string, name: string, signature: Buffer, expiry: u64}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a compute_commitment transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Compute the sealed-bid commitment for the given parameters. + * + * Intended for off-chain use (simulation only): calling this in a real + * transaction would leak the bid amount. + */ + compute_commitment: ({name, bidder, amount, salt}: {name: string, bidder: string, amount: i128, salt: Buffer}, options?: MethodOptions) => Promise> + + /** + * Construct and simulate a register_on_behalf transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Register a name on behalf of an owner using a signed authorization. + */ + register_on_behalf: ({owner, name, stealth_meta_address, signature, expiry}: {owner: string, name: string, stealth_meta_address: Buffer, signature: Buffer, expiry: u64}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a cancel_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Cancel the pending rotation, clearing all of its state. + */ + cancel_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a approve_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Approve the pending signer-rotation proposal. + */ + approve_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a execute_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Execute the pending rotation once quorum is met and the timelock has + * elapsed. Emits `SignersRotated`. + */ + execute_rotate_signers: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a propose_rotate_signers transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Propose a new signer set + threshold behind the rotation timelock. + * `caller` must be a current signer; the proposal is auto-approved by + * `caller`. Rejects thresholds that could never reach quorum. + */ + propose_rotate_signers: ({caller, new_signers, new_threshold}: {caller: string, new_signers: Array, new_threshold: u32}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a auctions_pending_settlement transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Auctions with a revealed winner that have not settled yet. While this + * is non-zero, `execute_rotate_auction_admin` is blocked. + */ + auctions_pending_settlement: (options?: MethodOptions) => Promise> + + /** + * Construct and simulate a cancel_rotate_auction_admin transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Cancel the pending auction-admin rotation, clearing all of its state. + */ + cancel_rotate_auction_admin: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a approve_rotate_auction_admin transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Approve the pending auction-admin rotation proposal. + */ + approve_rotate_auction_admin: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a execute_rotate_auction_admin transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Execute the pending auction-admin rotation once quorum is met and the + * timelock has elapsed. Emits `AuctionAdminRotated(old, new)`. + * + * Fails with `AuctionInProgress` while any auction is in its reveal or + * settle phase, leaving the proposal intact so it can be retried after + * settlement. + */ + execute_rotate_auction_admin: ({caller}: {caller: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a propose_rotate_auction_admin transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Propose a new premium-auction admin behind the 7-day rotation + * timelock, gated by the same governance signer set as + * `propose_rotate_signers`. `caller` must be a current signer; the + * proposal is auto-approved by `caller`. + */ + propose_rotate_auction_admin: ({caller, new_admin}: {caller: string, new_admin: string}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a pending_auction_admin_rotation transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * The pending auction-admin rotation proposal, if any. + */ + pending_auction_admin_rotation: (options?: MethodOptions) => Promise>> + } export class Client extends ContractClient { static async deploy( @@ -126,22 +612,100 @@ export class Client extends ContractClient { } constructor(public readonly options: ContractClientOptions) { super( - new ContractSpec([ "AAAAAAAAAFBVcGRhdGUgdGhlIG1ldGEtYWRkcmVzcyBmb3IgYW4gZXhpc3RpbmcgbmFtZS4KT25seSB0aGUgY3VycmVudCBvd25lciBjYW4gdXBkYXRlLgAAAAZ1cGRhdGUAAAAAAAMAAAAAAAAABW93bmVyAAAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAAEG5ld19tZXRhX2FkZHJlc3MAAAAOAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + new ContractSpec([ "AAAAAAAAAKdJbml0aWFsaXNlIHRoZSBjb250cmFjdCBieSBzdG9yaW5nIHRoZSBwYXVzZSBhZG1pbi4KCk11c3QgYmUgY2FsbGVkIGJlZm9yZSBgcGF1c2VgIC8gYHVucGF1c2VgLiBJZGVtcG90ZW50OiBjYWxsaW5nCm1vcmUgdGhhbiBvbmNlIGlzIGEgbm8tb3AgKHRoZSBmaXJzdCBhZG1pbiBzdGlja3MpLgAAAAAEaW5pdAAAAAEAAAAAAAAABWFkbWluAAAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAACk5hbWVzRXJyb3IAAA==", + "AAAAAAAAAKJQYXVzZSB0aGUgY29udHJhY3Qg4oCUIGFkbWluIG9ubHkuClByZXZlbnRzIGFsbCByZWdpc3RyYXRpb25zLCB1cGRhdGVzLCByZWxlYXNlcyBhbmQgVFRMIGV4dGVuc2lvbnMKd2hpbGUgcGF1c2VkLiBMb29rdXBzIChgcmVzb2x2ZWAsIGBuYW1lX29mYCkgcmVtYWluIGF2YWlsYWJsZS4AAAAAAAVwYXVzZQAAAAAAAAEAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAACk5hbWVzRXJyb3IAAA==", + "AAAAAAAAAFBVcGRhdGUgdGhlIG1ldGEtYWRkcmVzcyBmb3IgYW4gZXhpc3RpbmcgbmFtZS4KT25seSB0aGUgY3VycmVudCBvd25lciBjYW4gdXBkYXRlLgAAAAZ1cGRhdGUAAAAAAAMAAAAAAAAABW93bmVyAAAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAAEG5ld19tZXRhX2FkZHJlc3MAAAAOAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", "AAAAAAAAAD9SZXZlcnNlIGxvb2t1cDogZmluZCB0aGUgbmFtZSBmb3IgYSBnaXZlbiBzdGVhbHRoIG1ldGEtYWRkcmVzcy4AAAAAB25hbWVfb2YAAAAAAQAAAAAAAAAUc3RlYWx0aF9tZXRhX2FkZHJlc3MAAAAOAAAAAQAAA+kAAAAQAAAH0AAAAApOYW1lc0Vycm9yAAA=", "AAAAAAAAACpSZWxlYXNlIGEgbmFtZSwgbWFraW5nIGl0IGF2YWlsYWJsZSBhZ2Fpbi4AAAAAAAdyZWxlYXNlAAAAAAIAAAAAAAAABW93bmVyAAAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", - "AAAAAAAAACtSZXNvbHZlIGEgbmFtZSB0byBpdHMgc3RlYWx0aCBtZXRhLWFkZHJlc3MuAAAAAAdyZXNvbHZlAAAAAAEAAAAAAAAABG5hbWUAAAAQAAAAAQAAA+kAAAAOAAAH0AAAAApOYW1lc0Vycm9yAAA=", - "AAAAAAAAAU1SZWdpc3RlciBhIG5hbWUgbWFwcGVkIHRvIGEgc3RlYWx0aCBtZXRhLWFkZHJlc3MuClRoZSBjYWxsZXIgKG93bmVyKSBtdXN0IGF1dGhvcml6ZS4gT3duZXJzaGlwIGlzIHRpZWQgdG8gdGhlIGNhbGxlcidzIGFkZHJlc3MuCgojIEFyZ3VtZW50cwoqIGBvd25lcmAgLSBUaGUgYWRkcmVzcyByZWdpc3RlcmluZyB0aGUgbmFtZSAobXVzdCBhdXRob3JpemUpLgoqIGBuYW1lYCAtIFRoZSBodW1hbi1yZWFkYWJsZSBuYW1lIChsb3dlcmNhc2UgYWxwaGFudW1lcmljLCAzLTMyIGNoYXJzKS4KKiBgc3RlYWx0aF9tZXRhX2FkZHJlc3NgIC0gNjQtYnl0ZSBzdGVhbHRoIG1ldGEtYWRkcmVzcy4AAAAAAAAIcmVnaXN0ZXIAAAADAAAAAAAAAAVvd25lcgAAAAAAABMAAAAAAAAABG5hbWUAAAAQAAAAAAAAABRzdGVhbHRoX21ldGFfYWRkcmVzcwAAAA4AAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", - "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAIAAAABAAAAKU1hcHMgbmFtZSBoYXNoIChCeXRlc048MzI+KSB0byBOYW1lRW50cnkuAAAAAAAABE5hbWUAAAABAAAD7gAAACAAAAABAAAASVJldmVyc2UgbG9va3VwOiBtZXRhLWFkZHJlc3MgaGFzaCAoQnl0ZXNOPDMyPikgdG8gbmFtZSBoYXNoIChCeXRlc048MzI+KS4AAAAAAAAHUmV2ZXJzZQAAAAABAAAD7gAAACA=", - "AAAAAQAAABhBIHJlZ2lzdGVyZWQgbmFtZSBlbnRyeS4AAAAAAAAACU5hbWVFbnRyeQAAAAAAAAMAAAAYVGhlIGh1bWFuLXJlYWRhYmxlIG5hbWUuAAAABG5hbWUAAAAQAAAAIlRoZSByZWdpc3RyYW50IGFkZHJlc3MgKGZvciBhdXRoKS4AAAAAAAVvd25lcgAAAAAAABMAAABFVGhlIDY0LWJ5dGUgc3RlYWx0aCBtZXRhLWFkZHJlc3MgKHNwZW5kaW5nX3B1YmtleSB8fCB2aWV3aW5nX3B1YmtleSkuAAAAAAAAFHN0ZWFsdGhfbWV0YV9hZGRyZXNzAAAADg==", - "AAAABAAAAAdFcnJvcnMuAAAAAAAAAAAKTmFtZXNFcnJvcgAAAAAABwAAAAAAAAAJTmFtZVRha2VuAAAAAAAAAQAAAAAAAAAMTmFtZVRvb1Nob3J0AAAAAgAAAAAAAAALTmFtZVRvb0xvbmcAAAAAAwAAAAAAAAAUSW52YWxpZE5hbWVDaGFyYWN0ZXIAAAAEAAAAAAAAABJJbnZhbGlkTWV0YUFkZHJlc3MAAAAAAAUAAAAAAAAADE5hbWVOb3RGb3VuZAAAAAYAAAAAAAAACE5vdE93bmVyAAAABw==" ]), + "AAAAAAAAALhSZXNvbHZlIGEgbmFtZSB0byBpdHMgc3RlYWx0aCBtZXRhLWFkZHJlc3MuCgpGb3IgYSBzdWJkb21haW4gKGBwYXltZW50cy5hbGljZWApIHJlc29sdXRpb24gd2Fsa3MgdG8gdGhlIHBhcmVudAooYGFsaWNlYCk6IGlmIHRoZSBwYXJlbnQgbm8gbG9uZ2VyIGV4aXN0cyB0aGUgc3ViZG9tYWluIGRvZXMgbm90IHJlc29sdmUuAAAAB3Jlc29sdmUAAAAAAQAAAAAAAAAEbmFtZQAAABAAAAABAAAD6QAAAA4AAAfQAAAACk5hbWVzRXJyb3IAAA==", + "AAAAAAAAAC1DdXJyZW50IHByb3RvY29sLWxldmVsIGdvdmVybmFuY2Ugc2lnbmVyIHNldC4AAAAAAAAHc2lnbmVycwAAAAAAAAAAAQAAA+oAAAAT", + "AAAAAAAAACRVbnBhdXNlIHRoZSBjb250cmFjdCDigJQgYWRtaW4gb25seS4AAAAHdW5wYXVzZQAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAADFSZWdpc3RlciBhIG5hbWUgbWFwcGVkIHRvIGEgc3RlYWx0aCBtZXRhLWFkZHJlc3MuAAAAAAAACHJlZ2lzdGVyAAAAAwAAAAAAAAAFb3duZXIAAAAAAAATAAAAAAAAAARuYW1lAAAAEAAAAAAAAAAUc3RlYWx0aF9tZXRhX2FkZHJlc3MAAAAOAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + "AAAAAAAAACdSZXR1cm5zIHRydWUgaWYgdGhlIGNvbnRyYWN0IGlzIHBhdXNlZC4AAAAACWlzX3BhdXNlZAAAAAAAAAAAAAABAAAAAQ==", + "AAAAAAAAADNDdXJyZW50IHByb3RvY29sLWxldmVsIGdvdmVybmFuY2UgcXVvcnVtIHRocmVzaG9sZC4AAAAACXRocmVzaG9sZAAAAAAAAAAAAAABAAAABA==", + "AAAAAgAAAA1TdG9yYWdlIGtleXMuAAAAAAAAAAAAAAdEYXRhS2V5AAAAAAsAAAABAAAAKU1hcHMgbmFtZSBoYXNoIChCeXRlc048MzI+KSB0byBOYW1lRW50cnkuAAAAAAAABE5hbWUAAAABAAAD7gAAACAAAAABAAAAPlJldmVyc2UgbG9va3VwOiBtZXRhLWFkZHJlc3MgaGFzaCAoQnl0ZXNOPDMyPikgdG8gbmFtZSBzdHJpbmcuAAAAAAAHUmV2ZXJzZQAAAAABAAAD7gAAACAAAAABAAAALVJlcGxheSBwcm90ZWN0aW9uIGZvciBzaWduZWQgb24tYmVoYWxmIGNhbGxzLgAAAAAAAAZSZXBsYXkAAAAAAAEAAAPuAAAAIAAAAAEAAAAbR3VhcmRpYW4gY29uZmlnIGZvciBhIG5hbWUuAAAAAAlHdWFyZGlhbnMAAAAAAAABAAAD7gAAACAAAAABAAAAJVBlbmRpbmcgcmVjb3ZlcnkgcHJvcG9zYWwgZm9yIGEgbmFtZS4AAAAAAAAIUmVjb3ZlcnkAAAABAAAD7gAAACAAAAAAAAAAFFBhdXNlIGFkbWluIGFkZHJlc3MuAAAABUFkbWluAAAAAAAAAAAAAB9XaGV0aGVyIHRoZSBjb250cmFjdCBpcyBwYXVzZWQuAAAAAAZQYXVzZWQAAAAAAAAAAAAuUHJvdG9jb2wtbGV2ZWwgZ292ZXJuYW5jZSBtdWx0aXNpZyBzaWduZXIgc2V0LgAAAAAAD011bHRpc2lnU2lnbmVycwAAAAAAAAAANFByb3RvY29sLWxldmVsIGdvdmVybmFuY2UgbXVsdGlzaWcgcXVvcnVtIHRocmVzaG9sZC4AAAARTXVsdGlzaWdUaHJlc2hvbGQAAAAAAAAAAAAAOFBlbmRpbmcgcHJvdG9jb2wtbGV2ZWwgc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsLCBpZiBhbnkuAAAAD1BlbmRpbmdSb3RhdGlvbgAAAAAAAAAAMFBlbmRpbmcgYXVjdGlvbi1hZG1pbiByb3RhdGlvbiBwcm9wb3NhbCwgaWYgYW55LgAAABtQZW5kaW5nQXVjdGlvbkFkbWluUm90YXRpb24A", + "AAAAAAAAAJRSZW5ldyAoZXh0ZW5kIFRUTCBmb3IpIG11bHRpcGxlIG5hbWVzIGluIGEgc2luZ2xlIGF0b21pYyB0cmFuc2FjdGlvbi4KCkFsbCBuYW1lcyBtdXN0IGV4aXN0LiBJZiBhbnkgbmFtZSBpcyBub3QgZm91bmQsIHRoZSBlbnRpcmUgb3BlcmF0aW9uCnJldmVydHMuAAAACmJ1bGtfcmVuZXcAAAAAAAIAAAAAAAAABW5hbWVzAAAAAAAD6gAAABAAAAAAAAAAEGV4dGVuZF90b19sZWRnZXIAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + "AAAAAAAAAFZDbGFpbSBhIHdvbiBhdWN0aW9uOiByZWdpc3RlcnMgdGhlIG5hbWUgdG8gdGhlIHdpbm5lciB3aXRoIHRoZWlyCnN0ZWFsdGggbWV0YS1hZGRyZXNzLgAAAAAACmNsYWltX25hbWUAAAAAAAMAAAAAAAAABndpbm5lcgAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAAFHN0ZWFsdGhfbWV0YV9hZGRyZXNzAAAADgAAAAEAAAPpAAAD7QAAAAAAAAfQAAAADEF1Y3Rpb25FcnJvcg==", + "AAAAAAAAAIdDb21taXQgYSBzZWFsZWQgYmlkLiBgY29tbWl0bWVudGAgaGlkZXMgdGhlIGJpZCBhbW91bnQ7IGBkZXBvc2l0YCBpcwp0cmFuc2ZlcnJlZCB0byB0aGUgY29udHJhY3QgYW5kIG11c3QgY292ZXIgdGhlIGJpZCByZXZlYWxlZCBsYXRlci4AAAAACmNvbW1pdF9iaWQAAAAAAAQAAAAAAAAABmJpZGRlcgAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAACmNvbW1pdG1lbnQAAAAAA+4AAAAgAAAAAAAAAAdkZXBvc2l0AAAAAAsAAAABAAAD6QAAA+0AAAAAAAAH0AAAAAxBdWN0aW9uRXJyb3I=", + "AAAAAAAAAERSZXZlYWwgYSBwcmV2aW91c2x5IGNvbW1pdHRlZCBiaWQgYnkgZGlzY2xvc2luZyB0aGUgYW1vdW50IGFuZCBzYWx0LgAAAApyZXZlYWxfYmlkAAAAAAAEAAAAAAAAAAZiaWRkZXIAAAAAABMAAAAAAAAABG5hbWUAAAAQAAAAAAAAAAZhbW91bnQAAAAAAAsAAAAAAAAABHNhbHQAAAPuAAAAIAAAAAEAAAPpAAAD7QAAAAAAAAfQAAAADEF1Y3Rpb25FcnJvcg==", + "AAAAAAAAACpSZWFkIHRoZSBhdWN0aW9uIHN0YXRlIGZvciBhIG5hbWUsIGlmIGFueS4AAAAAAAtnZXRfYXVjdGlvbgAAAAABAAAAAAAAAARuYW1lAAAAEAAAAAEAAAPoAAAH0AAAAAdBdWN0aW9uAA==", + "AAAAAQAAABhBIHJlZ2lzdGVyZWQgbmFtZSBlbnRyeS4AAAAAAAAACU5hbWVFbnRyeQAAAAAAAAQAAAAAAAAABG5hbWUAAAAQAAAAAAAAAAVvd25lcgAAAAAAABMAAACvRm9yIGEgc3ViZG9tYWluIChgc3ViLnBhcmVudGApLCB0aGUgbmFtZSBoYXNoIG9mIHRoZSBwYXJlbnQgbGFiZWwuCmBOb25lYCBmb3IgYSBmbGF0IHRvcC1sZXZlbCBuYW1lLiBFeGlzdGluZyBmbGF0IG5hbWVzIHJlZ2lzdGVyIHdpdGgKYE5vbmVgLCBzbyBwcmlvciBiZWhhdmlvdXIgaXMgcHJlc2VydmVkLgAAAAAGcGFyZW50AAAAAAPoAAAD7gAAACAAAAAAAAAAFHN0ZWFsdGhfbWV0YV9hZGRyZXNzAAAADg==", + "AAAAAAAAADZXaXRoZHJhdyBhIGxvc2luZyAob3IgdW5yZXZlYWxlZCkgYmlkIGRlcG9zaXQgaW4gZnVsbC4AAAAAAAx3aXRoZHJhd19iaWQAAAACAAAAAAAAAAZiaWRkZXIAAAAAABMAAAAAAAAABG5hbWUAAAAQAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAMQXVjdGlvbkVycm9y", + "AAAABAAAAAdFcnJvcnMuAAAAAAAAAAAKTmFtZXNFcnJvcgAAAAAAIgAAAAAAAAAJTmFtZVRha2VuAAAAAAAAAQAAAAAAAAAMTmFtZVRvb1Nob3J0AAAAAgAAAAAAAAALTmFtZVRvb0xvbmcAAAAAAwAAAAAAAAAUSW52YWxpZE5hbWVDaGFyYWN0ZXIAAAAEAAAAAAAAABJJbnZhbGlkTWV0YUFkZHJlc3MAAAAAAAUAAAAAAAAADE5hbWVOb3RGb3VuZAAAAAYAAAAAAAAACE5vdE93bmVyAAAABwAAAAAAAAAQU2lnbmF0dXJlRXhwaXJlZAAAAAgAAAAAAAAAD1NpZ25hdHVyZVJlcGxheQAAAAAJAAAAAAAAAA1JbnZhbGlkU2lnbmVyAAAAAAAACgAAAAAAAAALTm90R3VhcmRpYW4AAAAACwAAAAAAAAAKTm9Qcm9wb3NhbAAAAAAADAAAAAAAAAAVUHJvcG9zYWxBbHJlYWR5RXhpc3RzAAAAAAAADQAAAAAAAAAPQWxyZWFkeUFwcHJvdmVkAAAAAA4AAAAAAAAAD0RlbGF5Tm90RWxhcHNlZAAAAAAPAAAAAAAAAA9UaHJlc2hvbGROb3RNZXQAAAAAEAAAAAAAAAAQVG9vTWFueUd1YXJkaWFucwAAABEAAAAAAAAAEEludmFsaWRUaHJlc2hvbGQAAAASAAAAAAAAABNJbnZhbGlkRXh0ZW5kTGVkZ2VyAAAAABMAAAAAAAAADlBhcmVudE5vdEZvdW5kAAAAAAAUAAAAF1RoZSBjb250cmFjdCBpcyBwYXVzZWQuAAAAAAZQYXVzZWQAAAAAACAAAABAVGhlIHByb3RvY29sLWxldmVsIGdvdmVybmFuY2UgbXVsdGlzaWcgaGFzIG5vdCBiZWVuIGluaXRpYWxpc2VkLgAAABZNdWx0aXNpZ05vdEluaXRpYWxpemVkAAAAAAAVAAAARFRoZSBwcm90b2NvbC1sZXZlbCBnb3Zlcm5hbmNlIG11bHRpc2lnIGhhcyBhbHJlYWR5IGJlZW4gaW5pdGlhbGlzZWQuAAAAGk11bHRpc2lnQWxyZWFkeUluaXRpYWxpemVkAAAAAAAWAAAAPVRoZSBjYWxsZXIgaXMgbm90IGEgY3VycmVudCBwcm90b2NvbC1sZXZlbCBnb3Zlcm5hbmNlIHNpZ25lci4AAAAAAAAJTm90U2lnbmVyAAAAAAAAFwAAAC5BIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbCBpcyBhbHJlYWR5IHBlbmRpbmcuAAAAAAAWUm90YXRpb25BbHJlYWR5UGVuZGluZwAAAAAAGAAAACdObyBzaWduZXItcm90YXRpb24gcHJvcG9zYWwgaXMgcGVuZGluZy4AAAAAEU5vUGVuZGluZ1JvdGF0aW9uAAAAAAAAGQAAADVUaGUgY2FsbGVyIGhhcyBhbHJlYWR5IGFwcHJvdmVkIHRoZSBwZW5kaW5nIHJvdGF0aW9uLgAAAAAAABdBbHJlYWR5QXBwcm92ZWRSb3RhdGlvbgAAAAAaAAAAPFRoZSBwZW5kaW5nIHJvdGF0aW9uIGhhcyBub3QgY29sbGVjdGVkIGVub3VnaCBhcHByb3ZhbHMgeWV0LgAAAAxRdW9ydW1Ob3RNZXQAAAAbAAAAKlRoZSByb3RhdGlvbiB0aW1lbG9jayBoYXMgbm90IGVsYXBzZWQgeWV0LgAAAAAAElRpbWVsb2NrTm90RWxhcHNlZAAAAAAAHAAAAAAAAAALTmFtZVRvb0RlZXAAAAAAHQAAAAAAAAARQnVsa0xpbWl0RXhjZWVkZWQAAAAAAAAeAAAAfVRoZSBuYW1lIGlzIHByZW1pdW0gKDw9IDQgY2hhcnMpIGFuZCB0aGUgYXVjdGlvbiB3aW5kb3cgaXMgYWN0aXZlLCBzbwppdCBjYW4gb25seSBiZSBvYnRhaW5lZCB0aHJvdWdoIHRoZSBzZWFsZWQtYmlkIGF1Y3Rpb24uAAAAAAAAFlByZW1pdW1BdWN0aW9uUmVxdWlyZWQAAAAAAB8AAABXVGhlIGF1Y3Rpb24gc3Vic3lzdGVtIGhhcyBub3QgYmVlbiBpbml0aWFsaXNlZCwgc28gdGhlcmUgaXMgbm8gYXVjdGlvbgphZG1pbiB0byByb3RhdGUuAAAAABZBdWN0aW9uc05vdEluaXRpYWxpemVkAAAAAAZAAAAAc0FuIGF1Y3Rpb24gaGFzIGEgcmV2ZWFsZWQgd2lubmVyIGFuZCBoYXMgbm90IHNldHRsZWQgeWV0LCBzbyB0aGUKYXVjdGlvbiBhZG1pbiBjYW5ub3QgYmUgcm90YXRlZCBvdXQgZnJvbSB1bmRlciBpdC4AAAAAEUF1Y3Rpb25JblByb2dyZXNzAAAAAAAGQQ==", + "AAAAAAAAAJhSZWdpc3RlciBtdWx0aXBsZSBuYW1lcyBpbiBhIHNpbmdsZSBhdG9taWMgdHJhbnNhY3Rpb24uCgpBbGwgbmFtZXMgbXVzdCBiZSB2YWxpZCBhbmQgbm90IGFscmVhZHkgdGFrZW4uIElmIGFueSBuYW1lIGZhaWxzLAp0aGUgZW50aXJlIG9wZXJhdGlvbiByZXZlcnRzLgAAAA1idWxrX3JlZ2lzdGVyAAAAAAAAAwAAAAAAAAAFb3duZXIAAAAAAAATAAAAAAAAAAVuYW1lcwAAAAAAA+oAAAAQAAAAAAAAAA5tZXRhX2FkZHJlc3NlcwAAAAAD6gAAAA4AAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAX1PbmUtdGltZSBpbml0aWFsaXphdGlvbiBvZiB0aGUgcHJlbWl1bS1uYW1lIGF1Y3Rpb24gc3lzdGVtLgoKYGFkbWluYCBvcGVyYXRlcyBzZXR0bGVtZW50cyBwZXIgdGhlIHJ1bmJvb2ssIGB0cmVhc3VyeWAgcmVjZWl2ZXMKd2lubmluZyBiaWRzLCBgdG9rZW5gIGlzIHRoZSBwYXltZW50IGFzc2V0IChuYXRpdmUgWExNIFNBQyBvbiBtYWlubmV0KSwKYHJlc2VydmVfcHJpY2VgIGlzIHRoZSBtaW5pbXVtIGJpZCwgYW5kIGBjb21taXRfc2Vjc2AgLyBgcmV2ZWFsX3NlY3NgCmFyZSB0aGUgcGhhc2UgZHVyYXRpb25zIGZvciBlYWNoIGF1Y3Rpb24uIFRoZSA5MC1kYXkgcHJlbWl1bSB3aW5kb3cKc3RhcnRzIGF0IHRoZSBsZWRnZXIgdGltZXN0YW1wIG9mIHRoaXMgY2FsbC4AAAAAAAANaW5pdF9hdWN0aW9ucwAAAAAAAAYAAAAAAAAABWFkbWluAAAAAAAAEwAAAAAAAAAIdHJlYXN1cnkAAAATAAAAAAAAAAV0b2tlbgAAAAAAABMAAAAAAAAADXJlc2VydmVfcHJpY2UAAAAAAAALAAAAAAAAAAtjb21taXRfc2VjcwAAAAAGAAAAAAAAAAtyZXZlYWxfc2VjcwAAAAAGAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAMQXVjdGlvbkVycm9y", + "AAAAAAAAAF5PbmUtdGltZSBzZXR1cCBvZiB0aGUgcHJvdG9jb2wtbGV2ZWwgZ292ZXJuYW5jZSBzaWduZXIgc2V0IHVzZWQgdG8KYXV0aG9yaXNlIHNpZ25lciByb3RhdGlvbnMuAAAAAAANaW5pdF9tdWx0aXNpZwAAAAAAAAIAAAAAAAAAB3NpZ25lcnMAAAAD6gAAABMAAAAAAAAACXRocmVzaG9sZAAAAAAAAAQAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAIhTdGFydCBhIHNlYWxlZC1iaWQgYXVjdGlvbiBmb3IgYSBwcmVtaXVtIG5hbWUgKDw9IDQgY2hhcnMsIHRvcC1sZXZlbCkuClBlcm1pc3Npb25sZXNzOiBhbnlvbmUgbWF5IG9wZW4gdGhlIGF1Y3Rpb24gZm9yIGFuIGVsaWdpYmxlIG5hbWUuAAAADXN0YXJ0X2F1Y3Rpb24AAAAAAAABAAAAAAAAAARuYW1lAAAAEAAAAAEAAAPpAAAD7QAAAAAAAAfQAAAADEF1Y3Rpb25FcnJvcg==", + "AAAAAAAAAC9SZWFkIHRoZSBhdWN0aW9uIGNvbmZpZ3VyYXRpb24sIGlmIGluaXRpYWxpemVkLgAAAAAOYXVjdGlvbl9jb25maWcAAAAAAAAAAAABAAAD6AAAB9AAAAANQXVjdGlvbkNvbmZpZwAAAA==", + "AAAAAAAAAMxTZXR0bGUgYW4gYXVjdGlvbiBhZnRlciB0aGUgcmV2ZWFsIHBoYXNlOiBwYXlzIHRoZSB3aW5uaW5nIGJpZCB0byB0aGUKdHJlYXN1cnkgYW5kIHJlZnVuZHMgdGhlIHdpbm5lcidzIGV4Y2VzcyBkZXBvc2l0LiBQZXJtaXNzaW9ubGVzcyBzbwpmdW5kcyBjYW4gbmV2ZXIgYmUgdHJhcHBlZCwgb3BlcmF0ZWQgYnkgdGhlIGFkbWluIHBlciB0aGUgcnVuYm9vay4AAAAOc2V0dGxlX2F1Y3Rpb24AAAAAAAEAAAAAAAAABG5hbWUAAAAQAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAMQXVjdGlvbkVycm9y", + "AAAAAAAAAOZFeHRlbmQgVFRMIGZvciBwZXJzaXN0ZW50IHN0b3JhZ2UgZW50cmllcyBvbmx5LgpFeHRlbmQgdGhlIFRUTCBvZiBhIHJlZ2lzdGVyZWQgbmFtZSB0byBhIGZ1dHVyZSBsZWRnZXIuClRoaXMgaXMgYSBwZXJtaXNzaW9ubGVzcyBmdW5jdGlvbiB0aGF0IGFueW9uZSBjYW4gY2FsbC4KSWRlbXBvdGVudDogY2FsbGluZyB0d2ljZSBpbiB0aGUgc2FtZSBsZWRnZXIgaGFzIG5vIGFkZGl0aW9uYWwgZWZmZWN0LgAAAAAAD2V4dGVuZF9uYW1lX3R0bAAAAAACAAAAAAAAAARuYW1lAAAAEAAAAAAAAAAQZXh0ZW5kX3RvX2xlZGdlcgAAAAQAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAC1UaGUgcGVuZGluZyBzaWduZXItcm90YXRpb24gcHJvcG9zYWwsIGlmIGFueS4AAAAAAAAQcGVuZGluZ19yb3RhdGlvbgAAAAAAAAABAAAD6AAAB9AAAAAQUm90YXRpb25Qcm9wb3NhbA==", + "AAAAAAAAAEFVcGRhdGUgYSBuYW1lIG9uIGJlaGFsZiBvZiBhbiBvd25lciB1c2luZyBhIHNpZ25lZCBhdXRob3JpemF0aW9uLgAAAAAAABB1cGRhdGVfb25fYmVoYWxmAAAABQAAAAAAAAAFb3duZXIAAAAAAAATAAAAAAAAAARuYW1lAAAAEAAAAAAAAAAQbmV3X21ldGFfYWRkcmVzcwAAAA4AAAAAAAAACXNpZ25hdHVyZQAAAAAAA+4AAABAAAAAAAAAAAZleHBpcnkAAAAAAAYAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAQAAACJHdWFyZGlhbiBjb25maWd1cmF0aW9uIGZvciBhIG5hbWUuAAAAAAAAAAAADkd1YXJkaWFuQ29uZmlnAAAAAAACAAAAAAAAAAlndWFyZGlhbnMAAAAAAAPqAAAAEwAAAAAAAAAJdGhyZXNob2xkAAAAAAAABA==", + "AAAAAAAAAEJSZWxlYXNlIGEgbmFtZSBvbiBiZWhhbGYgb2YgYW4gb3duZXIgdXNpbmcgYSBzaWduZWQgYXV0aG9yaXphdGlvbi4AAAAAABFyZWxlYXNlX29uX2JlaGFsZgAAAAAAAAQAAAAAAAAABW93bmVyAAAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAACXNpZ25hdHVyZQAAAAAAA+4AAABAAAAAAAAAAAZleHBpcnkAAAAAAAYAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAKhDb21wdXRlIHRoZSBzZWFsZWQtYmlkIGNvbW1pdG1lbnQgZm9yIHRoZSBnaXZlbiBwYXJhbWV0ZXJzLgoKSW50ZW5kZWQgZm9yIG9mZi1jaGFpbiB1c2UgKHNpbXVsYXRpb24gb25seSk6IGNhbGxpbmcgdGhpcyBpbiBhIHJlYWwKdHJhbnNhY3Rpb24gd291bGQgbGVhayB0aGUgYmlkIGFtb3VudC4AAAASY29tcHV0ZV9jb21taXRtZW50AAAAAAAEAAAAAAAAAARuYW1lAAAAEAAAAAAAAAAGYmlkZGVyAAAAAAATAAAAAAAAAAZhbW91bnQAAAAAAAsAAAAAAAAABHNhbHQAAAPuAAAAIAAAAAEAAAPuAAAAIA==", + "AAAAAAAAAENSZWdpc3RlciBhIG5hbWUgb24gYmVoYWxmIG9mIGFuIG93bmVyIHVzaW5nIGEgc2lnbmVkIGF1dGhvcml6YXRpb24uAAAAABJyZWdpc3Rlcl9vbl9iZWhhbGYAAAAAAAUAAAAAAAAABW93bmVyAAAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAAFHN0ZWFsdGhfbWV0YV9hZGRyZXNzAAAADgAAAAAAAAAJc2lnbmF0dXJlAAAAAAAD7gAAAEAAAAAAAAAABmV4cGlyeQAAAAAABgAAAAEAAAPpAAAD7QAAAAAAAAfQAAAACk5hbWVzRXJyb3IAAA==", + "AAAAAQAAABxBIHBlbmRpbmcgcmVjb3ZlcnkgcHJvcG9zYWwuAAAAAAAAABBSZWNvdmVyeVByb3Bvc2FsAAAABAAAAAAAAAAJYXBwcm92YWxzAAAAAAAD6gAAABMAAAAAAAAAEG5ld19tZXRhX2FkZHJlc3MAAAAOAAAAAAAAAAluZXdfb3duZXIAAAAAAAATAAAAAAAAAAtwcm9wb3NlZF9hdAAAAAAE", + "AAAAAAAAADdDYW5jZWwgdGhlIHBlbmRpbmcgcm90YXRpb24sIGNsZWFyaW5nIGFsbCBvZiBpdHMgc3RhdGUuAAAAABVjYW5jZWxfcm90YXRlX3NpZ25lcnMAAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAC1BcHByb3ZlIHRoZSBwZW5kaW5nIHNpZ25lci1yb3RhdGlvbiBwcm9wb3NhbC4AAAAAAAAWYXBwcm92ZV9yb3RhdGVfc2lnbmVycwAAAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + "AAAAAAAAAGVFeGVjdXRlIHRoZSBwZW5kaW5nIHJvdGF0aW9uIG9uY2UgcXVvcnVtIGlzIG1ldCBhbmQgdGhlIHRpbWVsb2NrIGhhcwplbGFwc2VkLiBFbWl0cyBgU2lnbmVyc1JvdGF0ZWRgLgAAAAAAABZleGVjdXRlX3JvdGF0ZV9zaWduZXJzAAAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAAMJQcm9wb3NlIGEgbmV3IHNpZ25lciBzZXQgKyB0aHJlc2hvbGQgYmVoaW5kIHRoZSByb3RhdGlvbiB0aW1lbG9jay4KYGNhbGxlcmAgbXVzdCBiZSBhIGN1cnJlbnQgc2lnbmVyOyB0aGUgcHJvcG9zYWwgaXMgYXV0by1hcHByb3ZlZCBieQpgY2FsbGVyYC4gUmVqZWN0cyB0aHJlc2hvbGRzIHRoYXQgY291bGQgbmV2ZXIgcmVhY2ggcXVvcnVtLgAAAAAAFnByb3Bvc2Vfcm90YXRlX3NpZ25lcnMAAAAAAAMAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAALbmV3X3NpZ25lcnMAAAAD6gAAABMAAAAAAAAADW5ld190aHJlc2hvbGQAAAAAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + "AAAAAAAAAH1BdWN0aW9ucyB3aXRoIGEgcmV2ZWFsZWQgd2lubmVyIHRoYXQgaGF2ZSBub3Qgc2V0dGxlZCB5ZXQuIFdoaWxlIHRoaXMKaXMgbm9uLXplcm8sIGBleGVjdXRlX3JvdGF0ZV9hdWN0aW9uX2FkbWluYCBpcyBibG9ja2VkLgAAAAAAABthdWN0aW9uc19wZW5kaW5nX3NldHRsZW1lbnQAAAAAAAAAAAEAAAAE", + "AAAAAAAAAEVDYW5jZWwgdGhlIHBlbmRpbmcgYXVjdGlvbi1hZG1pbiByb3RhdGlvbiwgY2xlYXJpbmcgYWxsIG9mIGl0cyBzdGF0ZS4AAAAAAAAbY2FuY2VsX3JvdGF0ZV9hdWN0aW9uX2FkbWluAAAAAAEAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAACk5hbWVzRXJyb3IAAA==", + "AAAAAAAAADRBcHByb3ZlIHRoZSBwZW5kaW5nIGF1Y3Rpb24tYWRtaW4gcm90YXRpb24gcHJvcG9zYWwuAAAAHGFwcHJvdmVfcm90YXRlX2F1Y3Rpb25fYWRtaW4AAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAARlFeGVjdXRlIHRoZSBwZW5kaW5nIGF1Y3Rpb24tYWRtaW4gcm90YXRpb24gb25jZSBxdW9ydW0gaXMgbWV0IGFuZCB0aGUKdGltZWxvY2sgaGFzIGVsYXBzZWQuIEVtaXRzIGBBdWN0aW9uQWRtaW5Sb3RhdGVkKG9sZCwgbmV3KWAuCgpGYWlscyB3aXRoIGBBdWN0aW9uSW5Qcm9ncmVzc2Agd2hpbGUgYW55IGF1Y3Rpb24gaXMgaW4gaXRzIHJldmVhbCBvcgpzZXR0bGUgcGhhc2UsIGxlYXZpbmcgdGhlIHByb3Bvc2FsIGludGFjdCBzbyBpdCBjYW4gYmUgcmV0cmllZCBhZnRlcgpzZXR0bGVtZW50LgAAAAAAABxleGVjdXRlX3JvdGF0ZV9hdWN0aW9uX2FkbWluAAAAAQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKTmFtZXNFcnJvcgAA", + "AAAAAAAAANpQcm9wb3NlIGEgbmV3IHByZW1pdW0tYXVjdGlvbiBhZG1pbiBiZWhpbmQgdGhlIDctZGF5IHJvdGF0aW9uCnRpbWVsb2NrLCBnYXRlZCBieSB0aGUgc2FtZSBnb3Zlcm5hbmNlIHNpZ25lciBzZXQgYXMKYHByb3Bvc2Vfcm90YXRlX3NpZ25lcnNgLiBgY2FsbGVyYCBtdXN0IGJlIGEgY3VycmVudCBzaWduZXI7IHRoZQpwcm9wb3NhbCBpcyBhdXRvLWFwcHJvdmVkIGJ5IGBjYWxsZXJgLgAAAAAAHHByb3Bvc2Vfcm90YXRlX2F1Y3Rpb25fYWRtaW4AAAACAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAACW5ld19hZG1pbgAAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApOYW1lc0Vycm9yAAA=", + "AAAAAAAAADRUaGUgcGVuZGluZyBhdWN0aW9uLWFkbWluIHJvdGF0aW9uIHByb3Bvc2FsLCBpZiBhbnkuAAAAHnBlbmRpbmdfYXVjdGlvbl9hZG1pbl9yb3RhdGlvbgAAAAAAAAAAAAEAAAPoAAAH0AAAABVBZG1pblJvdGF0aW9uUHJvcG9zYWwAAAA=", + "AAAAAQAAAB9TdGF0ZSBvZiBhIHNpbmdsZSBuYW1lIGF1Y3Rpb24uAAAAAAAAAAAHQXVjdGlvbgAAAAAGAAAARVRpbWVzdGFtcCBhdCB3aGljaCB0aGUgY29tbWl0IHBoYXNlIGVuZHMgYW5kIHRoZSByZXZlYWwgcGhhc2UgYmVnaW5zLgAAAAAAAApjb21taXRfZW5kAAAAAAAGAAAAI0hpZ2hlc3QgcmV2ZWFsZWQgYmlkIGFtb3VudCBzbyBmYXIuAAAAAA5oaWdoZXN0X2Ftb3VudAAAAAAACwAAAD9IaWdoZXN0IHJldmVhbGVkIGJpZGRlciBzbyBmYXIuIFRpZXMgZ28gdG8gdGhlIGVhcmxpZXN0IHJldmVhbC4AAAAADmhpZ2hlc3RfYmlkZGVyAAAAAAPoAAAAEwAAAAAAAAAEbmFtZQAAABAAAABEVGltZXN0YW1wIGF0IHdoaWNoIHRoZSByZXZlYWwgcGhhc2UgZW5kcyBhbmQgc2V0dGxlbWVudCBpcyBwb3NzaWJsZS4AAAAKcmV2ZWFsX2VuZAAAAAAABgAAAAAAAAAHc2V0dGxlZAAAAAAB", + "AAAAAQAAAA1BIHNlYWxlZCBiaWQuAAAAAAAAAAAAAAlTZWFsZWRCaWQAAAAAAAADAAAAOHNoYTI1NiBjb21taXRtZW50IGJpbmRpbmcgYmlkZGVyLCBuYW1lLCBhbW91bnQgYW5kIHNhbHQuAAAACmNvbW1pdG1lbnQAAAAAA+4AAAAgAAAAOlRva2VucyBsb2NrZWQgaW4gdGhlIGNvbnRyYWN0OyByZWZ1bmRlZCBpbiBmdWxsIHRvIGxvc2Vycy4AAAAAAAdkZXBvc2l0AAAAAAsAAAAAAAAACHJldmVhbGVkAAAAAQ==", + "AAAAAgAAACdTdG9yYWdlIGtleXMgZm9yIHRoZSBhdWN0aW9uIHN1YnN5c3RlbS4AAAAAAAAAAApBdWN0aW9uS2V5AAAAAAAEAAAAAAAAAClBdWN0aW9uIGNvbmZpZ3VyYXRpb24gKGluc3RhbmNlIHN0b3JhZ2UpLgAAAAAAAAZDb25maWcAAAAAAAEAAAAcQXVjdGlvbiBzdGF0ZSBwZXIgbmFtZSBoYXNoLgAAAAdBdWN0aW9uAAAAAAEAAAPuAAAAIAAAAAEAAAAjU2VhbGVkIGJpZCBwZXIgKG5hbWUgaGFzaCwgYmlkZGVyKS4AAAAAA0JpZAAAAAACAAAD7gAAACAAAAATAAAAAAAAAHVDb3VudCBvZiBhdWN0aW9ucyB3aXRoIGEgcmV2ZWFsZWQgd2lubmVyIHRoYXQgaGF2ZSBub3Qgc2V0dGxlZCB5ZXQKKGluc3RhbmNlIHN0b3JhZ2UpLiBHdWFyZHMgYXVjdGlvbi1hZG1pbiByb3RhdGlvbi4AAAAAAAASUGVuZGluZ1NldHRsZW1lbnRzAAA=", + "AAAABAAAAEZBdWN0aW9uIGVycm9ycy4gQ29kZXMgc3RhcnQgYXQgMTAwIHRvIHN0YXkgZGlzam9pbnQgZnJvbSBgTmFtZXNFcnJvcmAuAAAAAAAAAAAADEF1Y3Rpb25FcnJvcgAAABgAAAAAAAAADk5vdEluaXRpYWxpemVkAAAAAABkAAAAAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAGUAAAAAAAAADUludmFsaWRDb25maWcAAAAAAABmAAAAAAAAAAxXaW5kb3dDbG9zZWQAAABnAAAAAAAAAA5Ob3RQcmVtaXVtTmFtZQAAAAAAaAAAAAAAAAAVTmFtZUFscmVhZHlSZWdpc3RlcmVkAAAAAAAAaQAAAAAAAAANQXVjdGlvbkV4aXN0cwAAAAAAAGoAAAAAAAAACU5vQXVjdGlvbgAAAAAAAGsAAAAAAAAAD0NvbW1pdFBoYXNlT3ZlcgAAAABsAAAAAAAAABBBbHJlYWR5Q29tbWl0dGVkAAAAbQAAAAAAAAATRGVwb3NpdEJlbG93UmVzZXJ2ZQAAAABuAAAAAAAAABRSZXZlYWxQaGFzZU5vdEFjdGl2ZQAAAG8AAAAAAAAABU5vQmlkAAAAAAAAcAAAAAAAAAAPQWxyZWFkeVJldmVhbGVkAAAAAHEAAAAAAAAAEkNvbW1pdG1lbnRNaXNtYXRjaAAAAAAAcgAAAAAAAAAPQmlkQmVsb3dSZXNlcnZlAAAAAHMAAAAAAAAAEUJpZEV4Y2VlZHNEZXBvc2l0AAAAAAAAdAAAAAAAAAASUmV2ZWFsUGhhc2VOb3RPdmVyAAAAAAB1AAAAAAAAAA5BbHJlYWR5U2V0dGxlZAAAAAAAdgAAAAAAAAAKTm90U2V0dGxlZAAAAAAAdwAAAAAAAAAJTm90V2lubmVyAAAAAAAAeAAAAAAAAAAUV2lubmVyQ2Fubm90V2l0aGRyYXcAAAB5AAAAAAAAABJJbnZhbGlkTWV0YUFkZHJlc3MAAAAAAHoAAAAAAAAAElJlZ2lzdHJhdGlvbkZhaWxlZAAAAAAAew==", + "AAAAAQAAADJBdWN0aW9uIGNvbmZpZ3VyYXRpb24sIHNldCBvbmNlIGF0IGluaXRpYWxpemF0aW9uLgAAAAAAAAAAAA1BdWN0aW9uQ29uZmlnAAAAAAAABwAAAC9PcGVyYXRvciB0aGF0IHJ1bnMgc2V0dGxlbWVudHMgcGVyIHRoZSBydW5ib29rLgAAAAAFYWRtaW4AAAAAAAATAAAAOUR1cmF0aW9uIG9mIHRoZSBjb21taXQgcGhhc2Ugb2YgZWFjaCBhdWN0aW9uLCBpbiBzZWNvbmRzLgAAAAAAAAtjb21taXRfc2VjcwAAAAAGAAAAZkxlZGdlciB0aW1lc3RhbXAgYXQgaW5pdGlhbGl6YXRpb247IHRoZSBwcmVtaXVtIHdpbmRvdyBydW5zIGZvcgpgUFJFTUlVTV9XSU5ET1dfU0VDU2AgZnJvbSB0aGlzIHBvaW50LgAAAAAAC2xhdW5jaF90aW1lAAAAAAYAAAA4TWluaW11bSBiaWQ7IGRlcG9zaXRzIG11c3QgYWxzbyBiZSBhdCBsZWFzdCB0aGlzIGFtb3VudC4AAAANcmVzZXJ2ZV9wcmljZQAAAAAAAAsAAAA5RHVyYXRpb24gb2YgdGhlIHJldmVhbCBwaGFzZSBvZiBlYWNoIGF1Y3Rpb24sIGluIHNlY29uZHMuAAAAAAAAC3JldmVhbF9zZWNzAAAAAAYAAAAqUGF5bWVudCB0b2tlbiAobmF0aXZlIFhMTSBTQUMgb24gbWFpbm5ldCkuAAAAAAAFdG9rZW4AAAAAAAATAAAAFlJlY2VpdmVzIHdpbm5pbmcgYmlkcy4AAAAAAAh0cmVhc3VyeQAAABM=", + "AAAAAQAAACNBIHBlbmRpbmcgc2lnbmVyLXJvdGF0aW9uIHByb3Bvc2FsLgAAAAAAAAAAEFJvdGF0aW9uUHJvcG9zYWwAAAAEAAAAAAAAAAlhcHByb3ZhbHMAAAAAAAPqAAAAEwAAAAAAAAANZXhlY3V0YWJsZV9hdAAAAAAAAAYAAAAAAAAAC25ld19zaWduZXJzAAAAA+oAAAATAAAAAAAAAA1uZXdfdGhyZXNob2xkAAAAAAAABA==", + "AAAAAQAAAMhBIHBlbmRpbmcgYXVjdGlvbi1hZG1pbiByb3RhdGlvbiBwcm9wb3NhbC4gTWlycm9ycyBgUm90YXRpb25Qcm9wb3NhbGAg4oCUCnNhbWUgc2lnbmVyIHNldCwgc2FtZSBxdW9ydW0sIHNhbWUgdGltZWxvY2sg4oCUIGJ1dCBjYXJyaWVzIHRoZSBpbmNvbWluZwphdWN0aW9uIG9wZXJhdG9yIGFkZHJlc3MgaW5zdGVhZCBvZiBhIG5ldyBzaWduZXIgc2V0LgAAAAAAAAAVQWRtaW5Sb3RhdGlvblByb3Bvc2FsAAAAAAAAAwAAAAAAAAAJYXBwcm92YWxzAAAAAAAD6gAAABMAAAAAAAAADWV4ZWN1dGFibGVfYXQAAAAAAAAGAAAAAAAAAAluZXdfYWRtaW4AAAAAAAAT", + "AAAAAQAAAKpXcmFpdGggUHJvdG9jb2wgc3RhbmRhcmQgbWV0cmljIGV2ZW50IHNjaGVtYS4KCkFsbCBXcmFpdGggY29udHJhY3RzIGVtaXQgbWV0cmljIGV2ZW50cyB1c2luZyB0aGlzIHN0cnVjdHVyZSB0byBlbmFibGUKc3RhbmRhcmRpemVkIG9mZi1jaGFpbiBvYnNlcnZhYmlsaXR5IGFuZCBtb25pdG9yaW5nLgAAAAAAAAAAABFXcmFpdGhNZXRyaWNFdmVudAAAAAAAAAQAAABAQ29udHJhY3QgaWRlbnRpZmllciAoZS5nLiwgInN0ZWFsdGgtcmVnaXN0cnkiLCAic3RlYWx0aC1zZW5kZXIiKQAAAAhjb250cmFjdAAAABEAAABLT3B0aW9uYWwgZGltZW5zaW9ucyBmb3IgZmlsdGVyaW5nL2dyb3VwaW5nIChlLmcuLCB0b2tlbl9hZGRyZXNzLCBzY2hlbWVfaWQpAAAAAApkaW1lbnNpb25zAAAAAAPqAAAD7QAAAAIAAAARAAAAAAAAADNNZXRyaWMgbmFtZSAoZS5nLiwgInJlZ2lzdGVyX2NvdW50IiwgInNlbmRfdm9sdW1lIikAAAAAC21ldHJpY19uYW1lAAAAABEAAAAbTnVtZXJpYyB2YWx1ZSBvZiB0aGUgbWV0cmljAAAAAAV2YWx1ZQAAAAAAAAs=" ]), options ) } public readonly fromJSON = { - update: this.txFromJSON>, + init: this.txFromJSON>, + pause: this.txFromJSON>, + update: this.txFromJSON>, name_of: this.txFromJSON>, release: this.txFromJSON>, resolve: this.txFromJSON>, - register: this.txFromJSON> + signers: this.txFromJSON>, + unpause: this.txFromJSON>, + register: this.txFromJSON>, + is_paused: this.txFromJSON, + threshold: this.txFromJSON, + bulk_renew: this.txFromJSON>, + claim_name: this.txFromJSON>, + commit_bid: this.txFromJSON>, + reveal_bid: this.txFromJSON>, + get_auction: this.txFromJSON>, + withdraw_bid: this.txFromJSON>, + bulk_register: this.txFromJSON>, + init_auctions: this.txFromJSON>, + init_multisig: this.txFromJSON>, + start_auction: this.txFromJSON>, + auction_config: this.txFromJSON>, + settle_auction: this.txFromJSON>, + extend_name_ttl: this.txFromJSON>, + pending_rotation: this.txFromJSON>, + update_on_behalf: this.txFromJSON>, + release_on_behalf: this.txFromJSON>, + compute_commitment: this.txFromJSON, + register_on_behalf: this.txFromJSON>, + cancel_rotate_signers: this.txFromJSON>, + approve_rotate_signers: this.txFromJSON>, + execute_rotate_signers: this.txFromJSON>, + propose_rotate_signers: this.txFromJSON>, + auctions_pending_settlement: this.txFromJSON, + cancel_rotate_auction_admin: this.txFromJSON>, + approve_rotate_auction_admin: this.txFromJSON>, + execute_rotate_auction_admin: this.txFromJSON>, + propose_rotate_auction_admin: this.txFromJSON>, + pending_auction_admin_rotation: this.txFromJSON> } } \ No newline at end of file diff --git a/stellar/scripts/generate-bindings.ts b/stellar/scripts/generate-bindings.ts index 5a8243e0..21ec3716 100644 --- a/stellar/scripts/generate-bindings.ts +++ b/stellar/scripts/generate-bindings.ts @@ -237,9 +237,12 @@ async function main() { console.log(); } - // Create global index.ts file re-exporting all clients + // Create global index.ts file re-exporting all clients. + // + // Keep this byte-for-byte deterministic: CI regenerates the bindings and + // fails the PR on any diff, so a timestamp here would make every run look + // like drift. const indexContent = `// Auto-generated Stellar TypeScript bindings re-exports -// Generated on ${new Date().toISOString()} export * as StealthAnnouncer from './stealth-announcer/src/index'; export * as StealthRegistry from './stealth-registry/src/index'; From 6f1af71358817510884aef64ba6d9a5ce3cd3920 Mon Sep 17 00:00:00 2001 From: Elthelthetallgirl <331852652+Elthelthetallgirl@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:47:40 -0700 Subject: [PATCH 4/5] ci(stellar): make the WASM, size, bindings and ABI checks blocking Every artifact step in the stellar job had continue-on-error, and the drift checks were guarded by `if: steps.x.outcome == 'success'`, so the job reported success while the WASM build, the size gate, the TypeScript bindings and the ABI snapshots were all failing. The comments blamed a soroban-sdk 22.0.11 and rustc incompatibility; the build failure was actually the workspace selecting testutils-enabled members, and the toolchain bump that was being waited on would not have fixed anything. - Pin stellar-cli 26.1.0. Its bundled wasm-opt validates the four contracts that emit memory.copy/memory.fill, which 22.0.1's rejected outright, so the size gate could never have passed for them. The pinned hash is now the digest upstream publishes for the release asset instead of a hash taken from the archive on first use. - Fix the optimized filename the size gate reads. `contract optimize` writes .optimized.wasm; the step stat'ed _optimized.wasm, and the "no artifacts, skipping" branch turned an empty build into a pass. - Fail when the build produces no artifacts instead of skipping. - Scope both drift checks to stellar/bindings and abi/. A bare `git diff --exit-code` also covered the soroban test_snapshots that `cargo test --workspace` rewrites earlier in the same job, so it would have failed PRs for unrelated snapshot churn. --- .github/workflows/ci.yml | 70 ++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be94ae36..265a7e33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,9 +16,10 @@ env: RUST_NIGHTLY_TOOLCHAIN: 'nightly-2026-09-01' NODE_VERSION: '22.23.2' PNPM_VERSION: '10.28.2' - STELLAR_CLI_VERSION: '22.0.1' - # sha256 of stellar-cli-${STELLAR_CLI_VERSION}-x86_64-unknown-linux-gnu.tar.gz - STELLAR_CLI_SHA256: '02cb00cf57ce8f432e0cc1653a1b603353a97079c22a8370dac60c21eca18fe3' + STELLAR_CLI_VERSION: '26.1.0' + # sha256 of stellar-cli-${STELLAR_CLI_VERSION}-x86_64-unknown-linux-gnu.tar.gz, + # as published by the upstream release. + STELLAR_CLI_SHA256: 'e18d5a7629102e1ccc07241acbcbebfc05b1c02476ce7d3204ba2d7418be5c0c' FOUNDRY_VERSION: 'v1.8.3' SLITHER_VERSION: '0.11.4' KANI_VERSION: '0.68.0' @@ -233,24 +234,26 @@ jobs: path: | stellar/bench/data/crossover.csv stellar/bench/data/crossover-chart.md - # WASM build depends on soroban-sdk 22.0.11 compiling under current - # stable rustc, which fails with 162 unresolved-import errors in the - # SDK's transitive deps. This is a soroban-sdk 22.0.11 bug fixed in - # 23.x/27.x — bumping is a major API migration owned separately. - # Keep the step visible but non-blocking so it doesn't gate wave PRs. - - name: Build WASM (soroban-sdk 22 vs current rustc; non-blocking) - continue-on-error: true + # The 162 errors this step used to produce were not a soroban-sdk/rustc + # incompatibility: a plain `cargo build` in a virtual workspace selects + # every member, and bench, bench-crossover and integration-tests enable + # soroban-sdk/testutils, which the SDK refuses to compile for wasm32. + # default-members in stellar/Cargo.toml limits the default build to the + # contract crates. See SUPPLY_CHAIN.md for the pins and upgrade path. + - name: Build WASM run: cargo build --target wasm32-unknown-unknown --release - name: Optimize and Check WASM Size - continue-on-error: true run: | - if ! ls target/wasm32-unknown-unknown/release/*.wasm > /dev/null 2>&1; then - echo "No WASM artifacts (build step above did not produce output); skipping optimize." - exit 0 + shopt -s nullglob + artifacts=(target/wasm32-unknown-unknown/release/*.wasm) + if [ ${#artifacts[@]} -eq 0 ]; then + echo "Error: the WASM build produced no artifacts." + exit 1 fi - for wasm in target/wasm32-unknown-unknown/release/*.wasm; do - soroban contract optimize --wasm "$wasm" - opt_wasm="${wasm%.*}_optimized.wasm" + for wasm in "${artifacts[@]}"; do + stellar contract optimize --wasm "$wasm" + # `contract optimize` writes ".optimized.wasm" beside the input. + opt_wasm="${wasm%.wasm}.optimized.wasm" SIZE=$(stat -c%s "$opt_wasm") echo "$opt_wasm size is $SIZE bytes" if [ "$SIZE" -gt 112640 ]; then @@ -262,30 +265,33 @@ jobs: - name: Run Upgrade Authority Enforcement Tests run: cargo test upgrade_auth --workspace - # Bindings depend on a successful workspace WASM build (currently - # non-blocking; see the note on the Build WASM step). Mark this - # non-blocking too so bindings-drift detection doesn't spuriously - # fail wave PRs. - name: Generate Stellar TypeScript bindings - id: bindings - continue-on-error: true run: pnpm bindings:stellar working-directory: . + # Scoped to the generated artifacts: `cargo test --workspace` earlier in + # this job rewrites soroban test_snapshots, and that churn must not be + # attributed to the bindings. - name: Check for bindings drift (diff detection) - if: steps.bindings.outcome == 'success' - run: git diff --exit-code working-directory: . - # ABI extraction depends on the same soroban-sdk 22 WASM build as above. - # When the SDK bump (23.x/27.x) lands, remove continue-on-error to - # enforce ABI snapshot freshness on every PR. + run: | + if [ -n "$(git status --porcelain --untracked-files=all -- stellar/bindings)" ]; then + git --no-pager status --short --untracked-files=all -- stellar/bindings + git --no-pager diff -- stellar/bindings + echo "Error: Stellar bindings are out of date. Run pnpm bindings:stellar and commit the result." + exit 1 + fi + - name: Extract ABI snapshots - id: abi - continue-on-error: true run: ./abi/update.sh - name: Check ABI snapshots - if: steps.abi.outcome == 'success' - run: git diff --exit-code abi/ + run: | + if [ -n "$(git status --porcelain --untracked-files=all -- abi/)" ]; then + git --no-pager status --short --untracked-files=all -- abi/ + git --no-pager diff --stat -- abi/ + echo "Error: ABI snapshots are out of date. Run stellar/abi/update.sh and commit the result." + exit 1 + fi stellar-kani: needs: changes From a9e0c89de88ebd1f963bc5f8329409d8a28580d0 Mon Sep 17 00:00:00 2001 From: Elthelthetallgirl <331852652+Elthelthetallgirl@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:48:16 -0700 Subject: [PATCH 5/5] docs(stellar): record the artifact pins, their constraints and the upgrade path SUPPLY_CHAIN.md gains a Stellar artifact checks section: the three things that decide the pins, namely testutils staying out of the default wasm target set, contract code not being allowed to use host-only SDK APIs, and the optimizer having to accept bulk memory. Plus the upgrade path: a CLI bump is an artifact-regeneration PR because the template drives every client's package.json, 28.x renames type_ to type in the ABI output and deprecates the TypeScript bindings generator, and the release container still builds with stellar-cli 22.0.0, which needs a planned redeploy rather than a silent bump. SIZE.md corrected: it claimed wraith_names cannot be compiled for wasm32 with soroban-sdk 22.0.11 and told CI to keep a stale 9,755-byte baseline forever. Neither the claim nor the workaround is right; the contract now builds, and the fresh measurement of all nine payloads is recorded (largest is wraith_names at 57,575 bytes, 51.11% of the 112,640-byte gate). The documented glob _optimized.wasm was also wrong, and the "-p only" workaround is replaced by the default-members explanation. DEPLOYMENT.md moves the CLI requirement to 26.1.0 with the reason. stellar/README.md and scripts/keeper/README.md now say --workspace, because a plain `cargo test` at the workspace root no longer includes the host-only members. --- SUPPLY_CHAIN.md | 60 ++++++++++++++++++++-- stellar/DEPLOYMENT.md | 18 ++++--- stellar/README.md | 6 +++ stellar/SIZE.md | 86 +++++++++++++++++++------------- stellar/scripts/keeper/README.md | 2 +- 5 files changed, 128 insertions(+), 44 deletions(-) diff --git a/SUPPLY_CHAIN.md b/SUPPLY_CHAIN.md index 144d2324..80d62a4f 100644 --- a/SUPPLY_CHAIN.md +++ b/SUPPLY_CHAIN.md @@ -49,7 +49,7 @@ Declared once per workflow in a top-level `env:` block headed | Rust (Solana) | `1.91.0` action / `1.89.0` `solana/rust-toolchain.toml` | `ci.yml` | rustup channel manifest signatures | | Node.js | `22.23.2` | `ci.yml`, `audit-freeze.yml`, `stellar-verification.yml`, `supply-chain.yml` | `actions/setup-node` release checksums | | pnpm | `10.28.2` | same as Node.js, and `packageManager` in `package.json` | corepack npm registry signature | -| stellar-cli (CI) | `22.0.1` | `ci.yml` (`STELLAR_CLI_SHA256`) | `sha256sum -c` against the pinned hash | +| stellar-cli (CI) | `26.1.0` | `ci.yml` (`STELLAR_CLI_SHA256`) | `sha256sum -c` against the pinned hash | | stellar-cli (Futurenet) | `28.0.0` | `integration-futurenet.yml` | `cargo install --locked` (crates.io checksums) | | Foundry | `v1.8.3` | `ci.yml` | `foundry-rs/foundry-toolchain` | | slither-analyzer | `0.11.4`, solc `0.8.28` | `ci.yml` | PyPI via `crytic/slither-action` | @@ -59,6 +59,52 @@ Declared once per workflow in a top-level `env:` block headed | cargo-tarpaulin | `0.37.4` | `coverage.yml` | `cargo install --locked` | | cosign | `v2.2.4` | `stellar-attestation.yml` | `sigstore/cosign-installer` checksum | +### Stellar artifact checks + +The `stellar` job builds the contract WASM, optimizes it, regenerates +`stellar/bindings/typescript/**` and `stellar/abi/*.json`, and fails the PR if +either set of checked-in artifacts moves. Nothing in that chain is +`continue-on-error` any more, so the three constraints below decide the pins. + +- **The wasm32 target set must stay free of `soroban-sdk/testutils`.** The SDK + guards that feature with `compile_error!` on wasm, and a plain `cargo build` in + a virtual workspace selects *every* member, including the host-only `bench`, + `bench-crossover` and `integration-tests` crates that enable it. + `default-members` in `stellar/Cargo.toml` is what keeps + `cargo build --target wasm32-unknown-unknown --release` building only the ten + deployable members (nine cdylibs and the `wraith-metrics` helper library, which + emits no WASM). A new member that enables `testutils` has to stay out of that + list; otherwise the wasm build fails with hundreds of errors inside the SDK + rather than in the new crate, which reads like a toolchain bug. +- **Contract code may not use host-only SDK APIs.** Converting an `Address` into + an `xdr::ScAddress` exists only behind `cfg(not(target_family = "wasm"))`, and + linking `alloc` unconditionally leaves the cdylib without a global allocator. + Both failures surface in this blocking step, not in `cargo test`. +- **`contract optimize` needs a wasm-opt that accepts bulk memory.** rustc emits + `memory.copy`/`memory.fill` for four of the nine contracts on every toolchain + tested (1.88.0 and 1.98.1), and stellar-cli 22.0.1's bundled optimizer rejects + them during validation, so the size gate could never pass for those artifacts. + 26.1.0 validates all nine and is the CI pin. + +The upgrade path, in short: + +- 26.1.0 is the version that produced the bindings already committed here. Its + template emits `@stellar/stellar-sdk` `^14.5.0` and no `networks` block, which + is what every checked-in client looks like. Pinning a different CLI therefore + regenerates all five clients and their `package.json`, so a CLI bump is an + artifact-regeneration PR with reviewable output, never a one-line config bump. +- Do not move past 26.x without checking both outputs. stellar-cli 28.1.0 renames + the `type_` key to `type` in `contract info interface --output json-formatted`, + which rewrites every `stellar/abi/*.json` snapshot, and marks + `contract bindings typescript` deprecated in favour of the JavaScript SDK + generator. Each needs a decision and a fresh baseline before the pin moves. + 28.1.0's optimizer produces the same payloads as 26.1.0, so the size gate is + not what holds the pin back. +- The release container (next section) still builds with stellar-cli 22.0.0, + which cannot validate those four contracts, so `stellar/build/build.sh` needs + the same bump. That changes deployed hashes, so it belongs to a planned + redeploy rather than to this check; tracked as a known gap below. + ### Release build (Stellar reproducible build) | Input | Pin | Where | @@ -185,8 +231,16 @@ any other `.github/` change. - `model-checking/kani-github-action` and `heyAyushh/setup-anchor` call further actions by moving tag internally. We pin the outer action. Upgrading those inner actions requires bumping the outer SHA. -- stellar-cli `22.0.1` publishes neither checksums nor build provenance. The - pinned hash was taken from the GitHub release asset on first use. +- stellar-cli `22.0.1`, the previous CI pin, published neither checksums nor + build provenance, and its optimizer cannot validate the workspace's + bulk-memory contracts. `26.1.0` publishes a sha256 digest per release asset; + `STELLAR_CLI_SHA256` is that upstream digest, and CI re-checks the downloaded + archive against it. +- The release container's stellar-cli `22.0.0` has the same optimizer as the old + CI pin, so `stellar/build/build.sh` aborts on the four contracts that use bulk + memory. Bumping it changes the optimized bytes, which changes the hashes + `stellar/build/verify.js` compares against deployed contracts, so it belongs to + a planned redeploy rather than to the CI pin above. - The repository dependency graph is not enabled. Enabling it (Settings → Code security) would additionally allow `actions/dependency-review-action` for license policy. The OSV review above does not require it. diff --git a/stellar/DEPLOYMENT.md b/stellar/DEPLOYMENT.md index fbdb14ad..b8bac4c6 100644 --- a/stellar/DEPLOYMENT.md +++ b/stellar/DEPLOYMENT.md @@ -49,7 +49,7 @@ STELLAR_ADMIN_SECRET=SCVAL... \ ### Requirements - `STELLAR_ADMIN_SECRET` env var (Stellar secret key, must be funded on futurenet) -- `stellar-cli >= 22.0.1` (or `soroban-cli`) +- `stellar-cli >= 26.1.0` (or `soroban-cli`) - Rust `wasm32-unknown-unknown` target installed - The admin account must have sufficient XLM balance (≥ 10 XLM recommended) @@ -102,13 +102,19 @@ This script runs on the `stellar-nightly` schedule in CI. See |---|---|---| | Rust toolchain | stable ≥ 1.78 | `rustup update stable` | | wasm32 target | any | `rustup target add wasm32-unknown-unknown` | -| stellar-cli | 22.0.1 | `cargo install stellar-cli --locked` | +| stellar-cli | 26.1.0 | `cargo install stellar-cli --locked` | | Funded identity | — | see section below | -> **Why 22.0.1?** Earlier versions do not support the `--fee` flag on contract -> invocations used by the `init` call. Attempting to deploy with an older CLI -> will succeed for upload/deploy but fail silently on init with a fee-budget -> error that is only visible in the node logs. +> **Why 26.1.0?** Two reasons, both learned the hard way. Earlier versions do +> not support the `--fee` flag on contract invocations used by the `init` +> call, so a deploy succeeds for upload/deploy but fails silently on init with a +> fee-budget error that is only visible in the node logs. And the 22.x CLI cannot +> optimize this workspace: rustc emits bulk-memory instructions for four of the +> nine contracts, which the wasm-opt bundled with 22.x rejects during validation. +> CI pins the same 26.1.0 and regenerates the TypeScript bindings with it, so a +> different CLI still deploys fine but will not reproduce +> `stellar/bindings/typescript`. See +> [`../SUPPLY_CHAIN.md`](../SUPPLY_CHAIN.md). --- diff --git a/stellar/README.md b/stellar/README.md index 84aecc49..8b9e2aa8 100644 --- a/stellar/README.md +++ b/stellar/README.md @@ -38,6 +38,12 @@ To run tests for all contracts: cargo test ``` +`cargo test` from this directory covers the crates in `default-members`, which +is the deployable set. The host-only members (`bench`, `bench-crossover`, +`integration-tests`) enable `soroban-sdk/testutils` and are excluded from the +default target set so that the wasm build stays clean; add `--workspace` to run +them too. + ## Audits & Formal Verification Per-contract audit write-ups for the contracts that custody user funds: diff --git a/stellar/SIZE.md b/stellar/SIZE.md index 52616a43..8951534a 100644 --- a/stellar/SIZE.md +++ b/stellar/SIZE.md @@ -38,15 +38,39 @@ case; it is already 80.40% below budget. Symbol stripping is safe for these cdyli artifacts: it removes non-executable metadata only and therefore has no runtime or storage semantics. -wraith_names is retained in the historical baseline below, but cannot be -compiled for wasm32-unknown-unknown with the repository's pinned -soroban-sdk 22.0.11: its existing ScAddress: TryFrom<&Address> conversion -fails before code generation. This is an unrelated pre-existing compile error; -CI should keep this contract's existing 9,755-byte optimized baseline until that -source/toolchain mismatch is fixed. - -Historical contract Previous optimized baseline (bytes) -wraith_names 9,755 +wraith_names was excluded from the table above on the grounds that it "cannot be +compiled for wasm32-unknown-unknown with the repository's pinned soroban-sdk +22.0.11". That claim was wrong. Two separate defects were to blame, and neither +is a toolchain incompatibility: + +a plain `cargo build` in this virtual workspace selected the host-only members +(bench, bench-crossover, integration-tests), which enable soroban-sdk/testutils; +the SDK rejects that feature for wasm32, so every wasm build died. +`default-members` in stellar/Cargo.toml now limits the default build to the +contract crates. +wraith-names converted the owner `Address` into an `xdr::ScAddress`, an impl the +SDK gates behind `cfg(not(target_family = "wasm"))`. It now decodes the owner's +strkey on chain, so the wasm artifact builds. + +Current measurement for wraith_names, with the CI toolchain (Rust 1.98.1, +stellar-cli 26.1.0): 75,055 bytes built, 57,575 bytes optimized, which is 48.89% +below the 112,640-byte budget and the largest payload in the workspace. + +Current workspace payload +Fresh measurement of every contract member with the CI toolchain (Rust 1.98.1, +stellar-cli 26.1.0), run as CI runs it. "Budget used" is the optimized payload +against the 112,640-byte gate. + +Contract Built (bytes) Optimized (bytes) Budget used +wraith_names 75,055 57,575 51.11% +stealth_sender 34,177 24,986 22.18% +stealth_batch_sender 29,068 21,902 19.44% +governance 24,044 18,506 16.43% +stealth_splitter 21,502 16,899 15.00% +stealth_vault 22,637 16,585 14.72% +stealth_announcer 8,228 6,575 5.84% +stealth_registry 8,246 5,973 5.30% +wraith_asset_policy 6,245 4,559 4.05% Metric emission delta (wraith_metrics wiring) Wiring wraith_metrics::emit_metric into wraith-names, stealth-splitter, @@ -60,16 +84,14 @@ Contract Before metrics (bytes) After metrics (bytes) Delta Growth stealth_splitter 9,774 10,720 +946 +9.68% stealth_vault 9,237 11,117 +1,880 +20.35% governance 16,589 18,506 +1,917 +11.56% -wraith_names not measurable not measurable -- -- -All three measurable payloads stay far below the 112,640-byte CI budget; the -largest, governance, is 83.57% below it. +wraith_names -- 57,575 -- -- +Every payload stays far below the 112,640-byte CI budget; the largest, +wraith_names, is 48.89% below it. -wraith_names cannot be compiled for wasm32-unknown-unknown at all (see -the note above), so its metric-emission delta cannot be measured on this toolchain. -The failure reproduces identically on the parent commit, so it is unrelated to the -metric wiring. Once the soroban-sdk bump lands and the contract builds, -re-run the command below and fill the row in the wiring adds five call sites, -so it should land in the same +1 to +2 KB range as the other three. +wraith_names carries the metrics wiring in the commit that made it build for +wasm32, so there is no "before" payload to measure against on any toolchain that +compiles it. Its 57,575-byte optimized payload is therefore the current +absolute, not a delta. Batch-sender hardening pass the stealth_batch_sender contract gained init, pause/admin, typed errors, and @@ -88,24 +110,20 @@ cargo build --target wasm32-unknown-unknown --release for wasm in target/wasm32-unknown-unknown/release/*.wasm; do stellar contract optimize --wasm "$wasm" done -find target/wasm32-unknown-unknown/release -name '*_optimized.wasm' +find target/wasm32-unknown-unknown/release -name '*.optimized.wasm' \ -printf '%f %s bytes\n' | sort The optimizer is deliberately run on the release output, as the network deploys the optimized payload rather than the intermediate compiler artifact. CI rejects any optimized payload over 112,640 bytes. -A workspace-wide wasm32 build fails because integration-tests pulls -soroban-sdk with the testutils feature and Cargo unifies that feature across -the whole build. To measure a single contract, name it explicitly so the -testutil-enabled members stay out of the graph: - -Shell - -cargo build -p stealth-vault -p stealth-splitter -p governance \ - --target wasm32-unknown-unknown --release -for wasm in target/wasm32-unknown-unknown/release/*.wasm; do - stellar contract optimize --wasm "$wasm" -done - -Note that stellar-cli 27.x writes .optimized.wasm where the 22.0.1 CLI -pinned in CI writes _optimized.wasm; match the glob to the CLI in use. +`stellar contract optimize` writes the result beside the input as +`.optimized.wasm`. The workflow previously stat'ed `_optimized.wasm`, +so the size gate never read a real file and the step failed even when the payload +was well within budget. + +The wasm32 build used to be restricted to explicitly named contracts because a +plain workspace build pulled in integration-tests, which enables soroban-sdk +with the testutils feature, and Cargo unifies that feature across the whole +build graph. `default-members` in stellar/Cargo.toml now keeps the testutils-only +members out of the default target set, so the plain build above produces exactly +the deployable contract artifacts. diff --git a/stellar/scripts/keeper/README.md b/stellar/scripts/keeper/README.md index 7f1173db..f68f1b2e 100644 --- a/stellar/scripts/keeper/README.md +++ b/stellar/scripts/keeper/README.md @@ -260,7 +260,7 @@ Run the keeper tests: pnpm test scripts/keeper # Integration test with local contract -cargo test --manifest-path stellar/Cargo.toml +cargo test --workspace --manifest-path stellar/Cargo.toml ``` ## Cost Model