diff --git a/elip-wallet-abi.mediawiki b/elip-wallet-abi.mediawiki new file mode 100644 index 0000000..a6ce481 --- /dev/null +++ b/elip-wallet-abi.mediawiki @@ -0,0 +1,1067 @@ +
+ ELIP: ? + Layer: Wallet + Title: Wallet ABI Transaction Creation Protocol + Author: Kyrylo Riabov+ +== Introduction == + +=== Abstract === + ++ Artem Chystiakov + Comments-Summary: No comments yet. + Comments-URI: TBD + Status: Draft + Type: Standards Track + Created: 2026-05-07 + License: BSD-3-Clause +
wallet-abi-0.1 defines a JSON request/response protocol for transaction construction. The caller declares
+intended inputs, outputs, fee hints, locktime hints, issuance metadata, and finalization rules. The wallet/runtime
+validates the request against its active ELIP-0144 chain_id and wallet state, opens a request-scoped
+wallet snapshot, resolves wallet-owned and caller-provided prevouts, materializes declared outputs, appends fee/change
+outputs as needed, signs/finalizes inputs, optionally broadcasts, and returns either a finalized transaction or a structured error.
+
+The protocol is '''state-aware and non-idempotent'''. The same request may yield different successful transactions
+when wallet state, fee policy, UTXO availability, or broadcast state changes.
+
+=== Copyright ===
+
+This document is licensed under the 3-clause BSD license.
+
+=== Motivation ===
+
+Applications need a standard way to ask a wallet to construct and sign a transaction from an application-level intent
+while keeping wallet-owned UTXOs private to the wallet. This protocol defines a communication schema that gives the requester
+a signing/construction capability without requiring the wallet to share its UTXO set, balances, or wallet-internal selection state.
+
+=== Goals and non-goals ===
+
+==== Goals ====
+
+# Provide a reviewable definition of all Wallet ABI request and response fields.
+# Make the user experience clear enough for wallet/application communication.
+# Provide JSON examples and a complete JSON schema.
+
+==== Non-goals ====
+
+# Define a final WalletConnect, JSON-RPC, or transport-level standard. This document describes the ABI payload.
+# Define full SimplicityHL semantic validation. This document describes how the payload is carried and resolved.
+# Guarantee exact final transaction shape from declared outputs. The runtime may add fee and change outputs.
+
+== Specification ==
+
+=== Normative language ===
+
+The words '''MUST''', '''SHOULD''', '''MAY''', and '''MUST NOT''' are used in the RFC 2119 sense for this draft.
+
+=== Terminology ===
+
+{| class="wikitable"
+|-
+! Term
+! Definition
+|-
+| Caller / Producer / Application
+| Application or protocol participant that creates a TxCreateRequest.
+|-
+| Consumer / runtime
+| Wallet/mobile/daemon side that processes the request.
+|-
+| Wallet snapshot
+| Request-scoped view of spendable wallet UTXOs used during fee estimation and final construction.
+|-
+| Declared input/output
+| Input/output explicitly present in params.inputs or params.outputs; the opposite of a runtime-added input/output.
+|-
+| Runtime-added input/output
+| Wallet input, fee output, or change output added by the runtime to satisfy funding/balancing.
+|-
+| Finalizer
+| Rule for producing input witness/finalization data or deriving a finalizer-owned output lock.
+|-
+| SIMF
+| SimplicityHL finalization payload carrying source, compiler version, JSON arguments, JSON witness values, and internal key source.
+|-
+| Internal key source
+| Selector that returns a Taproot/BIP-340 x-only public key for control-block/script derivation.
+|-
+| ELIP-0144 chain ID
+| The chain_id string defined by ELIP-0144, e.g. bip122:<32-lowercase-hex>.
+|-
+| ELIP-0144 asset ID
+| The asset_id string defined by ELIP-0144, encoded as chain_id/elip144:asset_reference.
+|-
+| Asset reference
+| The raw 32-byte Elements asset identifier carried inside an ELIP-0144 asset ID after /elip144:. It is used internally when materializing transaction outputs and SIMF u256 values.
+|-
+| Input blinding secret key
+| Secret key material used to unblind a confidential prevout. It is not a wallet signing key or spend authorization key.
+|-
+| Inflation token
+| Reissuance token minted by a new issuance. This draft uses inflation_amount_sat for the amount of these token units.
+|-
+| Static SIMF value
+| Caller-known SIMF argument or witness value carried under static_values. Each entry is keyed by a SimplicityHL argument/witness name and encoded as { "value": string, "type": string }.
+|-
+| Runtime SIMF value
+| SIMF argument or witness value that the runtime derives only after wallet state, issuance metadata, selected UTXOs, or the transaction sighash are known.
+|-
+| App/request identity
+| Authenticated context that lets a wallet show which actor initiated the request. This ABI does not define the identity system; it only requires wallets not to trust self-declared JSON labels as identity.
+|}
+
+=== Wallet/application user experience guidance ===
+
+==== Caller-side flow ====
+
+# The caller builds a transaction intention in terms of wallet inputs, provided inputs, requested outputs, issuance outputs, and finalizers.
+# The caller generates a fresh request_id for this user action.
+# The caller sends a TxCreateRequest over the chosen transport.
+# The caller treats the returned TxCreateResponse as the only authoritative result for this processing attempt.
+
+==== Wallet/consumer-side review UI ====
+
+A wallet UI SHOULD present, before approval:
+
+{| class="wikitable"
+|-
+! UI item
+! Why it matters
+|-
+| App/request identity
+| Helps the user connect request to the initiating action.
+|-
+| chain_id
+| Prevents Liquid mainnet/testnet/regtest confusion. Show the ELIP-0144 chain ID and, if known, a friendly network label.
+|-
+| request_id
+| Helps support/debug correlation. It MUST NOT be described as replay protection.
+|-
+| broadcast
+| Distinguishes "build/sign only" from "publish to network".
+|-
+| Requested outputs
+| Shows labels, assets, amounts, lock type, and blinding mode.
+|-
+| Runtime-added fee/change
+| The declared output set is not the final transaction set.
+|-
+| Wallet asset deltas
+| Shows net wallet effect, not just declared outputs.
+|-
+| Explicit outputs
+| Warn when amount/asset confidentiality is disabled.
+|-
+| Provided input blinding-secret-key use
+| Warn because request payload may contain sensitive prevout-unblinding material.
+|-
+| Issuance/reissuance
+| Show minted asset amounts, inflation_amount_sat, confidential-token requirements, and positional input references.
+|-
+| SIMF/finalizer locks
+| Show program identity/hash/source summary, simplicity_hl_version, signer key use, and internal_key source.
+|-
+| Locktime/sequence
+| Warn that lock_time is ineffective when all sequences are final.
+|}
+
+A wallet MUST NOT identify the caller from self-declared labels inside the request payload.
+Authenticated app/request identity MUST come from the transport, platform binding, or another out-of-band trust system.
+
+==== Response UX ====
+
+The response is not a deterministic preview of an abstract request. It is the result of a specific processing attempt
+against a specific wallet state. On success, the UI SHOULD show whether the transaction was merely built or was broadcast.
+On error, application logic SHOULD branch on error.code, while error.message is technical context.
+
+=== Non-idempotency and deterministic boundaries ===
+
+TxCreateRequest.request_id is a correlation identifier and is not replay protection.
+Requests are '''not idempotent''', especially when broadcast = true.
+
+The runtime SHOULD provide deterministic behavior only within this narrower boundary:
+
+# Open one request-scoped wallet session for one processing lifecycle.
+# Use the same spendable_utxos snapshot across fee estimation and final build.
+# Return the same wallet output template for the same (session, request) pair.
+# Resolve declared inputs in order and update funding state sequentially.
+
+=== Wire-format rules ===
+
+# Payloads are JSON objects unless a variant is explicitly serialized as a string.
+# Enum variants use snake_case.
+# TxCreateRequest and RuntimeParams reject unknown fields in the attached JSON Schema.
+# Numeric satoshi amounts are unsigned 64-bit values encoded as decimal JSON strings, with no leading zeroes except "0".
+# Byte-array fields, such as issuance entropy, are serialized as JSON arrays of integers from 0 to 255.
+# FinalizerSpec::Simf.arguments and FinalizerSpec::Simf.witness are JSON objects.
+# Hex fields other than ELIP-0144 chain_id and asset_id values are lowercase by convention.
+# chain_id and explicit asset_id values MUST use the ELIP-0144 wire shapes.
+# Secrets, including provided input blinding secret keys and intermediate PSET material, MUST NOT be logged.
+
+=== Request envelope: TxCreateRequest ===
+
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "params": { "inputs": [], "outputs": [] },
+ "broadcast": false
+}
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! style="text-align: center;"| Required
+! Definition
+|-
+| abi_version
+| style="text-align: right;"| string
+| style="text-align: center;"| yes
+| MUST equal wallet-abi-0.1. Anti-confusion/version guard.
+|-
+| request_id
+| style="text-align: right;"| UUID string
+| style="text-align: center;"| yes
+| Caller-generated correlation identifier. Generate fresh per user action. Not replay protection.
+|-
+| chain_id
+| style="text-align: right;"| Elip144ChainId
+| style="text-align: center;"| yes
+| Target Elements/Liquid chain ID as defined by ELIP-0144. MUST match the runtime chain ID before side effects.
+|-
+| params
+| style="text-align: right;"| RuntimeParams
+| style="text-align: center;"| yes
+| Transaction-construction body.
+|-
+| broadcast
+| style="text-align: right;"| boolean
+| style="text-align: center;"| yes
+| true means publish through wallet broadcaster after finalization. false means build/finalize only; runtime may still sync/fetch.
+|}
+
+==== Elip144ChainId ====
+
+chain_id MUST use the chain ID wire shape defined by ELIP-0144:
+
+bip122:00000000000000000000000000000000+where the reference is the first 32 characters of the network genesis block hash. The runtime MUST derive its active +chain ID from the active Elements node or equivalent runtime context and reject a request whose
chain_id does
+not match.
+
+==== Elip144AssetId ====
+
+Explicit caller-provided asset IDs MUST use the ELIP-0144 asset ID wire shape:
+
+bip122:00000000000000000000000000000000/elip144:0000000000000000000000000000000000000000000000000000000000000000+ +The part before
/elip144: is the ELIP-0144 chain_id. It MUST equal TxCreateRequest.chain_id.
+The part after /elip144: is the 32-byte Elements asset reference encoded as 64 lowercase hex characters.
+Raw asset references are not accepted as explicit caller-provided asset identifiers in this ABI.
+
+Transport profiles that expose account identity SHOULD use the ELIP-0144 account ID form chain_id:dwid and
+MUST ensure that the account chain prefix matches TxCreateRequest.chain_id.
+
+=== Runtime parameters: RuntimeParams ===
+
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! style="text-align: center;"| Required
+! Definition
+|-
+| inputs
+| style="text-align: right;"| InputSchema[]
+| style="text-align: center;"| yes
+| Declared inputs, resolved sequentially in declaration order. Runtime may append wallet inputs after declared-input resolution.
+|-
+| outputs
+| style="text-align: right;"| OutputSchema[]
+| style="text-align: center;"| yes
+| Declared outputs, materialized in declaration order. Runtime may append fee and change outputs.
+|-
+| fee_rate_sat_kvb
+| style="text-align: right;"| float
+| style="text-align: center;"| no
+| Fee-rate override in sat/kvB. MUST be finite and non-negative. If omitted, runtime policy applies.
+|-
+| lock_time
+| style="text-align: right;"| LockTime
+| style="text-align: center;"| no
+| Fallback locktime written to PSET global tx data. Effective locktime still depends on input sequences.
+|}
+
+inputs and outputs are request requirements, not a complete transaction template.
+
+=== Input schema: InputSchema ===
+
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! style="text-align: center;"| Required
+! Definition
+|-
+| id
+| style="text-align: right;"| string
+| style="text-align: center;"| yes
+| Caller label for diagnostics/UI.
+|-
+| utxo_source
+| style="text-align: right;"| UTXOSource
+| style="text-align: center;"| yes
+| Prevout source selector.
+|-
+| unblinding
+| style="text-align: right;"| InputUnblinding
+| style="text-align: center;"| yes
+| How to resolve explicit or confidential prevout values.
+|-
+| sequence
+| style="text-align: right;"| u32
+| style="text-align: center;"| yes
+| Input sequence controlling finality, locktime activation, relative locktime, and RBF semantics.
+|-
+| issuance
+| style="text-align: right;"| InputIssuance
+| style="text-align: center;"| no
+| Issuance/reissuance metadata for this input. Required when outputs reference issuance-derived asset IDs.
+|-
+| finalizer
+| style="text-align: right;"| FinalizerSpec
+| style="text-align: center;"| yes
+| Input finalization strategy.
+|}
+
+==== UTXOSource ====
+
+{
+ "wallet": {
+ "filter": {
+ "asset": "none",
+ "amount": "none",
+ "lock": "none"
+ }
+ }
+}
+
+or
+
+{
+ "provided": {
+ "outpoint": "0000000000000000000000000000000000000000000000000000000000000000:0"
+ }
+}
+
+{| class="wikitable"
+|-
+! Variant
+! Fields
+! Definition
+|-
+| wallet
+| filter: WalletSourceFilter
+| Runtime selects a wallet UTXO from the request-scoped snapshot. Filters are conjunctive.
+|-
+| provided
+| outpoint
+| Caller supplies an outpoint. Runtime fetches prevout and resolves unblinding according to unblinding.
+|}
+
+==== WalletSourceFilter ====
+
+{| class="wikitable"
+|-
+! Field
+! Variants
+! Definition
+|-
+| asset
+| "none" or {"exact":{"asset_id"}}
+| No asset constraint, or exact ELIP-0144 asset ID match. The asset ID chain prefix MUST match TxCreateRequest.chain_id.
+|-
+| amount
+| "none", {"exact":{"amount_sat"}}, {"min":{"amount_sat"}}
+| No amount constraint, exact amount, or minimum amount. amount_sat is a u64 decimal string.
+|-
+| lock
+| "none" or {"script":{"script"}}
+| No script constraint, or exact script-pubkey bytes.
+|}
+
+==== InputUnblinding ====
+
+{| class="wikitable"
+|-
+! Variant
+! Definition
+|-
+| "wallet"
+| Use wallet-owned descriptor/blinding material.
+|-
+| {"provided":{"blinding_secret_key":"..."}}
+| Use caller-supplied input blinding secret key for a confidential prevout. This is prevout-unblinding material, not a wallet signing key. Sensitive by default; '''never log'''.
+|-
+| "explicit"
+| Require explicit non-confidential prevout values. Runtime MUST reject confidential prevouts.
+|}
+
+==== InputIssuance ====
+
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! Definition
+|-
+| kind
+| style="text-align: right;"| enum
+| One of "new" or "reissue".
+|-
+| asset_amount_sat
+| style="text-align: right;"| u64 decimal string
+| Amount of issued/reissued asset units to mint.
+|-
+| inflation_amount_sat
+| style="text-align: right;"| u64 decimal string
+| Amount of reissuance/inflation-token units to mint.
+|-
+| entropy
+| style="text-align: right;"| [u8; 32]
+| For new, contract-hash entropy; for reissue, already-derived asset entropy.
+|}
+
+Issuance-derived outputs reference inputs by positional input_index. Reordering inputs changes
+the derived asset references and therefore the derived ELIP-0144 asset IDs. If a new issuance mints a nonzero inflation_amount_sat, outputs that carry the derived
+inflation token must satisfy the confidentiality rule in [[#AssetVariant|AssetVariant]].
+
+=== Output schema: OutputSchema ===
+
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! style="text-align: center;"| Required
+! Definition
+|-
+| id
+| style="text-align: right;"| string
+| style="text-align: center;"| yes
+| Caller label for diagnostics/UI.
+|-
+| amount_sat
+| style="text-align: right;"| u64 decimal string
+| style="text-align: center;"| yes
+| Requested output amount.
+|-
+| lock
+| style="text-align: right;"| LockVariant
+| style="text-align: center;"| yes
+| Script-pubkey derivation rule.
+|-
+| asset
+| style="text-align: right;"| AssetVariant
+| style="text-align: center;"| yes
+| Asset selector.
+|-
+| blinder
+| style="text-align: right;"| BlinderVariant
+| style="text-align: center;"| yes
+| Output confidentiality policy.
+|}
+
+==== LockVariant ====
+
+{| class="wikitable"
+|-
+! Variant
+! Wire shape
+! Definition
+|-
+| wallet
+| {"type":"wallet"}
+| Use wallet receive output template.
+|-
+| script
+| {"type":"script","script":"0014aabbccddeeff00112233445566778899aabbccdd"}
+| Use raw script-pubkey bytes (includes OP_RETURN, burn, etc.). Runtime MUST reject empty scripts.
+|-
+| finalizer
+| {"type":"finalizer","finalizer": ...}
+| Derive output lock from finalizer/program.
+|}
+
+==== AssetVariant ====
+
+{| class="wikitable"
+|-
+! Variant
+! Definition
+|-
+| asset_id
+| Caller-provided ELIP-0144 asset ID. The chain_id prefix MUST equal TxCreateRequest.chain_id.
+|-
+| new_issuance_asset
+| ELIP-0144 asset ID derived from a new issuance input using TxCreateRequest.chain_id and the derived asset reference.
+|-
+| new_issuance_token
+| Confidential reissuance/inflation-token ELIP-0144 asset ID derived from a new issuance input using TxCreateRequest.chain_id and the derived token asset reference.
+|-
+| re_issuance_asset
+| ELIP-0144 asset ID derived from a reissue input using TxCreateRequest.chain_id and the reissued asset reference.
+|}
+
+new_issuance_asset and new_issuance_token require params.inputs[input_index].issuance.kind == "new".
+re_issuance_asset requires kind == "reissue".
+
+In this ABI, new_issuance_token denotes the confidential reissuance/inflation-token variant.
+Any output whose asset resolves to new_issuance_token MUST be confidential:
+the runtime MUST reject blinder = "explicit" for that output.
+
+==== BlinderVariant ====
+
+{| class="wikitable"
+|-
+! Variant
+! Definition
+|-
+| "wallet"
+| Use wallet output template blinding pubkey. Normally paired with lock.type = "wallet".
+|-
+| {"provided":{"pubkey":"..."}}
+| Use caller-supplied blinding public key.
+|-
+| "explicit"
+| Disable output asset/value confidentiality for this output.
+|}
+
+=== Finalizer specification: FinalizerSpec ===
+
+==== Wallet finalizer ====
+
+{ "type": "wallet" }
+Delegates input finalization to the wallet signer/miniscript stack.
+
+==== SIMF finalizer ====
+
+{
+ "type": "simf",
+ "source_simf": "...",
+ "simplicity_hl_version": "0.4.2",
+ "internal_key": "bip0341",
+ "arguments": {
+ "static_values": {
+ "CONTRACT_NONCE": { "value": "1", "type": "u32" }
+ },
+ "runtime_arguments": {
+ "COLLATERAL_ASSET_ID": { "new_issuance_asset": { "input_index": 0 } }
+ }
+ },
+ "witness": {
+ "static_values": {
+ "PATH": {
+ "value": "Right(Left((false, 10, 1000)))",
+ "type": "Either(...)"
+ }
+ },
+ "runtime_arguments": [
+ { "sig_hash_all": { "name": "USER_SIGHASH_ALL", "public_key": "73c5da0a4f7b8f2e91cd5f8f0c7a6d5b4c3a291817161514131211100f0e0d0c" } }
+ ]
+ }
+}
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! style="text-align: center;"| Required
+! Definition
+|-
+| source_simf
+| style="text-align: right;"| string
+| style="text-align: center;"| yes
+| UTF-8 SimplicityHL source loaded and instantiated by runtime.
+|-
+| simplicity_hl_version
+| style="text-align: right;"| string
+| style="text-align: center;"| yes
+| Exact Cargo/SimplicityHL compiler version that the runtime MUST use for compilation, address derivation, and script derivation. If the runtime cannot compile with this exact version, it MUST reject the request before deriving addresses or finalizing.
+|-
+| internal_key
+| style="text-align: right;"| InternalKeySource
+| style="text-align: center;"| yes
+| Taproot internal key source.
+|-
+| arguments
+| style="text-align: right;"| SimfArguments JSON object
+| style="text-align: center;"| yes
+| SIMF argument payload as JSON. Contains caller-known static_values and runtime-resolved runtime_arguments.
+|-
+| witness
+| style="text-align: right;"| SimfWitness JSON object
+| style="text-align: center;"| yes
+| SIMF witness payload as JSON. Contains caller-known static_values and runtime-resolved runtime_arguments.
+|}
+
+A runtime MUST compile source_simf with the requested simplicity_hl_version;
+it MUST NOT silently substitute a different compiler version. When a SIMF finalizer is used for an input, the runtime
+MUST derive the expected finalizer script pubkey from the explicitly requested SIMF source, version, internal_key,
+and finalizer payload. After resolving utxo_source, the runtime MUST verify that the resolved prevout script
+pubkey matches that computed script pubkey before signing or finalizing. A mismatch MUST be rejected.
+
+=== Internal key source ===
+
+==== Stable variant: bip0341 ====
+
+"bip0341"+A runtime MUST return this value: + +
50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0+ +=== SIMF argument and witness payloads === + +
FinalizerSpec::Simf.arguments and FinalizerSpec::Simf.witness are JSON objects
+at the ABI wire level. They are not UTF-8 byte arrays in this standard.
+
+==== static_values ====
+
+static_values carries caller-known values that are already available when the app constructs the request.
+A static value is not necessarily derived or finalized by the runtime; it is simply known before the wallet selects UTXOs,
+derives issuance IDs, computes a sighash, or signs.
+
+Each top-level key is a SimplicityHL argument or witness name, and each value has two string fields:
+
+{
+ "NAME": {
+ "value": "Right(Left((false, 10, 1000)))",
+ "type": "Either(...)"
+ }
+}
+value MUST be encoded as a JSON string, even for numbers and booleans. type MUST also be encoded as a JSON string.
+The runtime MUST treat both fields as untrusted compiler input and parse/type-check them with the requested simplicity_hl_version.
+
+For arguments.static_values, keys are static SimplicityHL argument/parameter names.
+For witness.static_values, keys are static SimplicityHL witness names.
+The exact accepted names and types are defined by source_simf and the requested compiler version.
+
+==== runtime_arguments ====
+
+runtime_arguments carries directives for values the app cannot know at request-construction time.
+Examples include an issued asset reference that depends on the wallet-selected issuance input, a confidential
+reissuance-token asset reference, or a transaction signature that depends on the final transaction sighash.
+
+For FinalizerSpec::Simf.arguments, runtime_arguments is an object keyed by target SimplicityHL argument names:
+
+{
+ "static_values": {
+ "CONTRACT_NONCE": { "value": "1", "type": "u32" }
+ },
+ "runtime_arguments": {
+ "COLLATERAL_ASSET_ID": { "new_issuance_asset": { "input_index": 0 } },
+ "COLLATERAL_TOKEN_ID": { "new_issuance_token": { "input_index": 0 } }
+ }
+}
+Supported runtime argument directives:
+
+{| class="wikitable"
+|-
+! Runtime argument
+! Definition
+|-
+| new_issuance_asset
+| Resolve a u256 value from the issued asset reference of a new issuance input.
+|-
+| new_issuance_token
+| Resolve a u256 value from the confidential reissuance/inflation-token asset reference of a new issuance input.
+|}
+
+For FinalizerSpec::Simf.witness, runtime_arguments is an array of witness directives:
+
+{
+ "static_values": {
+ "PATH": {
+ "value": "Right(Left((false, 10, 1000)))",
+ "type": "Either(...)"
+ }
+ },
+ "runtime_arguments": [
+ {
+ "sig_hash_all": {
+ "name": "USER_SIGHASH_ALL",
+ "public_key": "73c5da0a4f7b8f2e91cd5f8f0c7a6d5b4c3a291817161514131211100f0e0d0c"
+ }
+ }
+ ]
+}
+sig_hash_all.public_key MUST match the runtime signer x-only public key before the runtime signs.
+
+=== Runtime processing model ===
+
+Provider-specific state objects and wallet output allocation internals are outside this specification and are left to runtime implementations.
+
+A conforming runtime MAY process a request in this order:
+
+abi_version and chain_id against runtime context.source_simf with simplicity_hl_version, derive the expected finalizer script pubkey, and reject if the resolved UTXO script pubkey does not match.asset_id, verify that the asset chain prefix equals TxCreateRequest.chain_id, then extract the asset_reference for transaction construction.broadcast = true, perform any separate broadcast approval required by runtime policy, then broadcast and return the backend-reported txid.TxCreateResponse with status = "ok" or status = "error".TxCreateResponse remains the only authoritative result of the processing attempt.
+
+=== Response envelope: TxCreateResponse ===
+
+==== Success ====
+
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "status": "ok",
+ "transaction": {
+ "tx_hex": "02000000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "txid": "5f5a9b3d8a1a55cb2fbc4f61b2b7bc4f4b6a8f8ebd5d39fb7d3e8bfe8b6a1a00"
+ },
+ "artifacts": {}
+}
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! Definition
+|-
+| abi_version
+| style="text-align: right;"| string
+| Response ABI version.
+|-
+| request_id
+| style="text-align: right;"| UUID
+| Copied from request.
+|-
+| chain_id
+| style="text-align: right;"| Elip144ChainId
+| Copied/confirmed chain context.
+|-
+| status
+| style="text-align: right;"| "ok"
+| Success marker.
+|-
+| transaction.tx_hex
+| style="text-align: right;"| hex
+| Fully signed Elements transaction.
+|-
+| transaction.txid
+| style="text-align: right;"| txid
+| Transaction ID of tx_hex; if broadcasted, SHOULD match backend-reported txid.
+|-
+| artifacts
+| style="text-align: right;"| object
+| Optional producer metadata. Open-ended; consumers MUST ignore unknown keys.
+|}
+
+==== Error ====
+
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "status": "error",
+ "error": {
+ "code": "funding",
+ "message": "insufficient wallet balance",
+ "details": {}
+ }
+}
+{| class="wikitable"
+|-
+! Field
+! style="text-align: right;"| Type
+! Definition
+|-
+| status
+| style="text-align: right;"| "error"
+| Error marker.
+|-
+| error.code
+| style="text-align: right;"| string
+| Stable machine category. Consumers SHOULD preserve/tolerate unknown strings.
+|-
+| error.message
+| style="text-align: right;"| string
+| Human-readable technical diagnostic, not a stable discriminator.
+|-
+| error.details
+| style="text-align: right;"| JSON
+| Optional producer-defined diagnostics. Treat as untrusted.
+|}
+
+=== Canonical error code set ===
+
+{| class="wikitable"
+|-
+! Code
+! Typical meaning
+|-
+| invalid_request
+| Request shape, incompatible fields, bad chain/version, missing referenced input.
+|-
+| serde
+| Serialization/deserialization failure.
+|-
+| program_error
+| SimplicityHL/program-level failure, including unsupported compiler version when surfaced through the program layer.
+|-
+| derivation
+| Key/script/address/asset derivation failure.
+|-
+| try_from_int
+| Integer conversion overflow/failure.
+|-
+| funding
+| Insufficient or unavailable wallet funds.
+|-
+| invalid_signer_config
+| Signer unavailable or configured with wrong key.
+|-
+| invalid_response
+| Runtime/adapter response invariant failure.
+|-
+| pset
+| PSET construction/finalization failure.
+|-
+| pset_blind
+| PSET blinding failure.
+|-
+| amount_proof_verification
+| Confidential amount proof verification failure.
+|-
+| invalid_finalization_steps
+| Finalization sequence or witness construction failure.
+|}
+
+=== Versioning and extension rules ===
+
+# abi_version changes are required for incompatible request/response shape changes.
+# New enum variants SHOULD be gated by ABI version or explicit capability negotiation.
+# artifacts is the preferred place for producer-defined metadata that does not break older consumers.
+# Unknown request fields are rejected by the current JSON Schema request/runtime parameter definitions; do not use unknown fields for extension.
+# Runtimes that cannot satisfy simplicity_hl_version MUST reject rather than silently compiling with another version.
+# A future ABI may define friendly network aliases, but wire-level matching in this ABI is by ELIP-0144 chain_id.
+# Changes to the static_values {value,type} shape or the signature-embedding rules require an ABI update or explicit capability negotiation.
+
+== Security Considerations ==
+
+# Treat all request data as untrusted, including scripts, outpoints, finalizer source, and pubkeys.
+# Never log InputUnblinding.provided.blinding_secret_key or intermediate PSETs containing resolved input secrets.
+# InputUnblinding.provided.blinding_secret_key is not a signing key, but it can reveal confidential prevout values and is sensitive unless explicitly policy-marked as public.
+# broadcast = false does not mean offline/no-network; runtime may sync wallet state and fetch prevouts.
+# explicit outputs reveal amount and asset.
+# Outputs carrying new_issuance_token MUST NOT be explicit in this ABI.
+# provided outpoints may be spent, nonexistent, or maliciously selected; resolve/fetch before relying on them.
+# lock_time can be ineffective if input sequences are final.
+# SIMF sig_hash_all.public_key must equal the runtime signer x-only key.
+# source_simf must be compiled with the requested simplicity_hl_version; runtimes MUST NOT silently substitute a different compiler version.
+# Consumer UIs SHOULD make chain ID and broadcast status prominent.
+# Consumers SHOULD ignore unknown artifacts keys and sanitize error.message/error.details before rendering.
+# Wallets MUST NOT trust self-declared app names, labels, URLs, or icons in the request payload as authenticated caller identity. Authenticated app/request identity must come from the transport/platform binding or another out-of-band trust system.
+# static_values.value and static_values.type are untrusted SimplicityHL compiler inputs. Parse and type-check them with the requested simplicity_hl_version; do not evaluate them with an ad hoc parser outside the compiler boundary.
+# For SIMF-finalized inputs, the resolved UTXO script pubkey must match the script pubkey derived from the requested SIMF finalizer before signing/finalization.
+
+== Rationale ==
+
+=== Canonical identifiers and wire encoding ===
+
+The chain validation rules in [[#Elip144ChainId|Elip144ChainId]] use ELIP-0144 chain_id values
+instead of bare network names. This gives wallets a canonical chain identity to compare against the active Elements
+chain before producing side effects. It also avoids ambiguity between Liquid mainnet, Liquid testnet, Liquid regtest,
+and custom Elements networks.
+
+The explicit asset rules in [[#Elip144AssetId|Elip144AssetId]] use ELIP-0144 asset_id values
+for the same anti-confusion reason. Wallet-connection transports, review UIs, and cross-chain applications can use one
+asset identifier syntax, while the runtime can still extract the raw Elements asset_reference when it
+constructs transaction outputs or fills SIMF u256 arguments.
+
+The decimal-string amount rule in [[#Wire-format rules|Wire-format rules]] avoids precision loss in JavaScript and other
+environments whose native JSON number handling cannot safely represent every unsigned 64-bit satoshi/base-unit amount.
+The string form preserves the full u64 domain without requiring binary encoding or language-specific bigint extensions at the ABI boundary.
+
+=== Request identity, mutable wallet state, and caller identity ===
+
+The request identity and state model in [[#Non-idempotency and deterministic boundaries|Non-idempotency and deterministic boundaries]]
+intentionally treats request_id as correlation data, not replay protection or an idempotency key.
+Wallet state, UTXO availability, fee policy, chain height, change-output selection, and broadcast outcomes can change between attempts.
+For that reason, promising that the same JSON body always produces the same transaction would be misleading.
+
+The caller-identity rule in [[#Wallet/consumer-side review UI|Wallet/consumer-side review UI]] keeps authenticated
+app/request identity outside the JSON payload. A browser origin/RP ID, native-app association, pairing session,
+signed registry entry, or another out-of-band identity system can supply that context.
+Self-declared labels inside the request are therefore treated as review and diagnostic metadata, not trusted identity.
+
+=== Unblinding, spend authorization, and confidentiality boundaries ===
+
+The unblinding options in [[#InputUnblinding|InputUnblinding]] separate prevout-unblinding material
+from spend authorization. A caller may provide blinding_secret_key only when it already knows the prevout
+unblinding material out of band or when a protocol intentionally uses shared or known blinding material.
+The field is named after its cryptographic role so it is not confused with a wallet signing key.
+
+The issuance rules in [[#AssetVariant|AssetVariant]] require outputs carrying new_issuance_token to be confidential.
+This keeps the ABI aligned with the current Liquid reissuance-token constraint and avoids introducing an explicit-token
+mode without a separate capability profile.
+
+=== SIMF payloads, compiler versioning, and internal-key stability ===
+
+The SIMF payload rules in [[#SIMF argument and witness payloads|SIMF argument and witness payloads]] keep arguments
+and witness as JSON objects at the ABI wire level.
+Static values use the SimplicityHL witness-style { "value": string, "type": string } shape because
+the requested compiler, not the ABI, is responsible for parsing and type-checking SimplicityHL literals.
+
+The exact-version rule in [[#Finalizer specification: FinalizerSpec|FinalizerSpec]] requires simplicity_hl_version
+because different compiler versions may produce different compiled programs, addresses, script pubkeys, or finalization behavior
+for the same source_simf.
+
+The stable bip0341 internal key source in [[#Stable variant: bip0341|Internal key source]] uses the
+deterministic BIP-341 NUMS/example x-only internal key as the initial interoperability baseline. Future internal-key
+variants require an ABI/capability update.
+
+=== Runtime review, approval staging, and responses ===
+
+The review and response rules in [[#Runtime processing model|Runtime processing model]] and [[#Response envelope: TxCreateResponse|TxCreateResponse]]
+leave approval staging to the runtime. Some runtimes are non-interactive; others split approval across wallet UI, hardware prompts, finalization, and broadcast confirmation.
+In every case, the response remains the authoritative result of that processing attempt.
+
+== Backwards Compatibility ==
+
+This ELIP defines a new application/wallet ABI and does not change Elements consensus rules, peer-to-peer networking,
+transaction validity, or the PSET format. Existing wallets and applications that do not implement this ABI are unaffected.
+
+Unknown request fields are rejected by the current JSON Schema request/runtime definitions. Incompatible wire-shape changes require
+an abi_version change or explicit capability negotiation.
+
+== Reference Implementation ==
+
+No final reference implementation is specified by this draft. The auxiliary JSON Schema and examples are review aids
+for implementers, but semantic validation remains the responsibility of the wallet/runtime.
+
+The current example files are mock fixtures for reviewing the ABI wire shape. They are not final conformance vectors
+and are expected to be corrected or replaced after the first proper wallet/runtime implementation validates the full transaction-construction flow.
+
+A future implementation may include a wallet/runtime adapter, JSON Schema validation tests, SimplicityHL compiler-version
+dispatch, finalizer script-pubkey verification tests, and fixtures covering confidential issuance-token outputs.
+
+== Test Vectors and Auxiliary Files ==
+
+The auxiliary files below are intended to be committed with this draft in the elip-wallet-abi/ subdirectory.
+
+The example request and response files are mock fixtures for the current draft. They exercise the proposed JSON shape
+and schema constraints, but they are expected to be corrected or replaced after the first proper wallet/runtime implementation is available.
+
+{| class="wikitable"
+|-
+! File
+! Purpose
+|-
+| [[elip-wallet-abi/01_request_wallet_to_script.json|01_request_wallet_to_script.json]]
+| Simple wallet-funded build-only payment to an explicit script output using chain_id = "bip122:a771da8e52ee6ad581ed1e9a99825e5b" and ELIP-0144 asset IDs.
+|-
+| [[elip-wallet-abi/02_response_ok_build_only.json|02_response_ok_build_only.json]]
+| Success response for the build-only example, using the same Elip144ChainId and open-ended artifacts.
+|-
+| [[elip-wallet-abi/03_response_error_funding.json|03_response_error_funding.json]]
+| Error response with canonical funding code and optional diagnostic details.
+|-
+| [[elip-wallet-abi/04_request_simf_bip0341_issuance.json|04_request_simf_bip0341_issuance.json]]
+| Issuance request using a SIMF finalizer, stable bip0341 internal key, simplicity_hl_version, JSON arguments/witness, static_values examples, inflation_amount_sat, and confidential new_issuance_token output.
+|-
+| [[elip-wallet-abi/wallet-abi-tx-create.schema.json|wallet-abi-tx-create.schema.json]]
+| Complete JSON Schema for request/response shape. It includes ELIP-0144 chain and asset ID patterns, decimal-string u64 amounts, blinding_secret_key, inflation_amount_sat, simplicity_hl_version, JSON SIMF payloads, static_values typed literals, stable bip0341, and a schema-level rejection of blinder = "explicit" when asset.type = "new_issuance_token".
+|}
+
+=== Static value examples ===
+
+For readability, the examples below abbreviate long SimplicityHL sum types as Either(...).
+The auxiliary request fixture contains concrete mock type strings.
+
+A single branch selector known by the application at request-construction time:
+
+{
+ "PATH": {
+ "value": "Right(Right((false, 10, 1000)))",
+ "type": "Either(...)"
+ }
+}
+
+The same witness name selecting a different branch:
+
+{
+ "PATH": {
+ "value": "Right(Left((false, 10, 1000)))",
+ "type": "Either(...)"
+ }
+}
+
+Multiple static witness values:
+
+{
+ "PATH": {
+ "value": "Left(Right(Left((false, 10, 1000, 500))))",
+ "type": "Either(...)"
+ },
+ "COLLATERAL_AMOUNT": {
+ "value": "10",
+ "type": "u32"
+ }
+}
+
+== Appendix A: Future Work ==
+
+This appendix collects ideas that are intentionally not part of the wallet-abi-0.1 core.
+
+=== A.1 Standardized preview artifacts ===
+
+A future ABI may standardize an artifacts.preview object containing wallet deltas, selected inputs, fee,
+change, confidentiality choices, and issuance effects. For wallet-abi-0.1, artifacts remains
+open-ended producer metadata.
+
+=== A.2 Transport and capability negotiation ===
+
+A future profile may define a WalletConnect, JSON-RPC, or other transport binding; capability negotiation
+for enum variants; and supported simplicity_hl_version discovery.
+
+=== A.3 Friendly network aliases and local-chain metadata ===
+
+The wire chain_id is the ELIP-0144 chain ID in this draft. A future profile may define friendly labels,
+policy-asset metadata, and local/custom Elements network registry entries, but those aliases must not replace ELIP-0144 chain ID matching in the core validation path.
+
+=== A.4 Explicit reissuance-token support ===
+
+Explicit reissuance-token support, if added later, would require an ABI/capability update and a validation model that safely supports non-confidential token outputs.
+
+=== A.5 Witness signature embedding ===
+
+sig_hash_all names the target witness slot (name) and expected signer x-only public key (public_key).
+A future ABI will need to finalize how the generated BIP-340 signature is embedded back into the SimplicityHL WitnessValues structure,
+including structures that contain branching such as Right(Left((, ...))) .
+
+=== A.6 State Management ===
+
+A future ABI MAY extend [[#Finalizer specification: FinalizerSpec|FinalizerSpec]] and/or [[#InternalKeySource|InternalKeySource]]
+to support Simplicity covenants whose Taproot output commits to contract state.
+
+== Appendix B: JSON Schema ==
+
+The review schema for wallet-abi-0.1 request/response payloads is provided as
+[[elip-wallet-abi/wallet-abi-tx-create.schema.json|wallet-abi-tx-create.schema.json]].
diff --git a/elip-wallet-abi/01_request_wallet_to_script.json b/elip-wallet-abi/01_request_wallet_to_script.json
new file mode 100644
index 0000000..d8a8b82
--- /dev/null
+++ b/elip-wallet-abi/01_request_wallet_to_script.json
@@ -0,0 +1,51 @@
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "params": {
+ "inputs": [
+ {
+ "id": "wallet-lbtc-funding",
+ "utxo_source": {
+ "wallet": {
+ "filter": {
+ "asset": {
+ "exact": {
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49"
+ }
+ },
+ "amount": {
+ "min": {
+ "amount_sat": "150000"
+ }
+ },
+ "lock": "none"
+ }
+ }
+ },
+ "unblinding": "wallet",
+ "sequence": 4294967295,
+ "finalizer": {
+ "type": "wallet"
+ }
+ }
+ ],
+ "outputs": [
+ {
+ "id": "merchant-payment",
+ "amount_sat": "100000",
+ "lock": {
+ "type": "script",
+ "script": "0014aabbccddeeff00112233445566778899aabbccdd"
+ },
+ "asset": {
+ "type": "asset_id",
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49"
+ },
+ "blinder": "explicit"
+ }
+ ],
+ "fee_rate_sat_kvb": 0.1
+ },
+ "broadcast": false
+}
diff --git a/elip-wallet-abi/02_response_ok_build_only.json b/elip-wallet-abi/02_response_ok_build_only.json
new file mode 100644
index 0000000..ceba7a2
--- /dev/null
+++ b/elip-wallet-abi/02_response_ok_build_only.json
@@ -0,0 +1,35 @@
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "status": "ok",
+ "transaction": {
+ "tx_hex": "02000000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "txid": "5f5a9b3d8a1a55cb2fbc4f61b2b7bc4f4b6a8f8ebd5d39fb7d3e8bfe8b6a1a00"
+ },
+ "artifacts": {
+ "example_note": "artifacts is producer-defined; consumers must ignore unknown keys",
+ "broadcast": false,
+ "selected_inputs": [
+ {
+ "input_id": "wallet-lbtc-funding",
+ "source": "wallet",
+ "outpoint": "0101010101010101010101010101010101010101010101010101010101010101:0",
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49",
+ "amount_sat": "150000"
+ }
+ ],
+ "appended_outputs": [
+ {
+ "kind": "fee",
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49",
+ "amount_sat": "450"
+ },
+ {
+ "kind": "change",
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49",
+ "amount_sat": "49550"
+ }
+ ]
+ }
+}
diff --git a/elip-wallet-abi/03_response_error_funding.json b/elip-wallet-abi/03_response_error_funding.json
new file mode 100644
index 0000000..c92e45d
--- /dev/null
+++ b/elip-wallet-abi/03_response_error_funding.json
@@ -0,0 +1,16 @@
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "0d6d53cd-a040-4f0c-8d28-c67b6608fb14",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "status": "error",
+ "error": {
+ "code": "funding",
+ "message": "insufficient wallet balance for asset bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49",
+ "details": {
+ "requested_asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49",
+ "requested_amount_sat": "150000",
+ "available_amount_sat": "12345",
+ "broadcast_attempted": false
+ }
+ }
+}
diff --git a/elip-wallet-abi/04_request_simf_bip0341_issuance.json b/elip-wallet-abi/04_request_simf_bip0341_issuance.json
new file mode 100644
index 0000000..23b2aed
--- /dev/null
+++ b/elip-wallet-abi/04_request_simf_bip0341_issuance.json
@@ -0,0 +1,154 @@
+{
+ "abi_version": "wallet-abi-0.1",
+ "request_id": "216113a8-8eb7-4d1f-8573-8b6ed04f4ad5",
+ "chain_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b",
+ "params": {
+ "inputs": [
+ {
+ "id": "issuance-funding-input",
+ "utxo_source": {
+ "wallet": {
+ "filter": {
+ "asset": {
+ "exact": {
+ "asset_id": "bip122:a771da8e52ee6ad581ed1e9a99825e5b/elip144:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49"
+ }
+ },
+ "amount": {
+ "min": {
+ "amount_sat": "250000"
+ }
+ },
+ "lock": "none"
+ }
+ }
+ },
+ "unblinding": "wallet",
+ "sequence": 4294967294,
+ "issuance": {
+ "kind": "new",
+ "asset_amount_sat": "1",
+ "inflation_amount_sat": "1",
+ "entropy": [
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7
+ ]
+ },
+ "finalizer": {
+ "type": "wallet"
+ }
+ }
+ ],
+ "outputs": [
+ {
+ "id": "issued-asset-to-simf-lock",
+ "amount_sat": "1",
+ "lock": {
+ "type": "finalizer",
+ "finalizer": {
+ "type": "simf",
+ "source_simf": "-- SimplicityHL source placeholder for review wire-shape only\n-- Replace with canonical source before production.",
+ "simplicity_hl_version": "0.4.2",
+ "internal_key": "bip0341",
+ "arguments": {
+ "static_values": {
+ "CONTRACT_NONCE": {
+ "value": "1",
+ "type": "u32"
+ }
+ },
+ "runtime_arguments": {
+ "COLLATERAL_ASSET_ID": {
+ "new_issuance_asset": {
+ "input_index": 0
+ }
+ },
+ "COLLATERAL_TOKEN_ID": {
+ "new_issuance_token": {
+ "input_index": 0
+ }
+ }
+ }
+ },
+ "witness": {
+ "static_values": {
+ "PATH": {
+ "value": "Left(Right(Left((false, 10, 1000, 500))))",
+ "type": "Either