From fbf1fba8c838d93e7c535aa65e02dbcd1afe2be0 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Wed, 27 May 2026 14:19:21 +0300 Subject: [PATCH 1/8] liquid-rpc-profile: add initial draft --- elip-liquid-wallet-rpc-profile.mediawiki | 1099 ++++++++++++++++++++++ 1 file changed, 1099 insertions(+) create mode 100644 elip-liquid-wallet-rpc-profile.mediawiki diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki new file mode 100644 index 0000000..6824b45 --- /dev/null +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -0,0 +1,1099 @@ +
+  ELIP: TBD
+  Layer: Wallet
+  Title: Liquid Wallet RPC Profile
+  Author: Kyrylo Riabov 
+          Artem Chystiakov 
+  Comments-Summary: No comments yet.
+  Comments-URI: TBD
+  Status: Draft
+  Type: Standards Track
+  Created: 2026-05-19
+  License: BSD-3-Clause
+
+ +==Abstract== + +This ELIP defines a Liquid wallet JSON-RPC profile for the wallet SDKs and other dapp-to-wallet transports. +It specifies how a dapp identifies a connected Liquid account, requests public wallet descriptors, reads wallet-computed +balances and UTXOs, requests transfers, requests PSET signatures, signs messages, uses deterministic identity keys, +delegates complex confidential transaction construction to the Wallet ABI transaction protocol, and receives descriptor-change events. + +The profile uses the chain_id and asset identifier syntax from [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144]. +It uses [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] output descriptors, +optional [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath descriptors, +and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] public CT descriptors. +It does not export view descriptors, private blinding keys, spend descriptors, private spend keys, asset blinding factors, +value blinding factors, or shared nonces. + +==Copyright== + +This document is licensed under the 3-clause BSD license. + +==Motivation== + +Bitcoin integrations can use public addresses and PSBTs as their main wallet-facing primitives. +Liquid wallets require a more explicit profile because Liquid has confidential transactions, multiple issued assets, +network-specific policy assets, CT descriptors, blinding material, and PSETs. + +Dapps need enough public wallet information to identify the connected account, construct descriptor-aware receive +and change logic, read user-approved balances and UTXOs, and build valid PSET signing requests. At the same time, +wallets must not leak view material merely to support these flows. This ELIP separates public descriptor disclosure +from wallet-computed balance and UTXO disclosure, and it defines a descriptor-format negotiation mechanism +based on descriptor representations. + +==Terminology== + +The following terms are used throughout this ELIP. + +{| class="wikitable" +! Term !! Definition +|- +| Caller / Producer / Application / Dapp || The application that sends JSON-RPC requests to the wallet. +|- +| Wallet || The wallet or wallet SDK that receives JSON-RPC requests, applies wallet policy, obtains user approval where needed, and returns JSON-RPC responses. +|- +| Active Liquid or Elements chain || The Liquid or Elements chain selected by the wallet. The active chain is identified on the wire by the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain_id. +|- +| chain_id || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain identifier: "bip122:" + first_32_lowercase_hex_characters_of_genesis_block_hash. +|- +| Public wallet descriptor || An ordinary Liquid/Elements output descriptor with public spend-key material and no ct(...) wrapper. It can derive scriptPubKeys and unconfidential addresses. It cannot derive confidential addresses, unblind outputs, or spend funds. +|- +| Account identifier || The profile-specific account suffix selected by this ELIP: the first external unconfidential address at index 0 derived from the public wallet descriptor. +|- +| Connected account || The account string displayed and persisted by the dapp: chain_id + ":" + account_identifier. +|- +| Public confidential descriptor || An [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor with public blinding-key material only. It can derive confidential addresses. It cannot derive private blinding keys and cannot unblind outputs. +|- +| View descriptor || A CT descriptor that lets the holder derive private blinding keys or otherwise unblind wallet outputs. Examples include descriptors using [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private master blinding material, private descriptor blinding keys, descriptor blinding xprvs, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] ct(elip151, <DESCRIPTOR>). View descriptors MUST NOT be returned by this profile. +|- +| Wallet blinding policy || The wallet rule that determines how confidential addresses and output blinding keys are derived for a script tree, for example [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], public [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] blinding-key material, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151]. +|- +| Derived view material || Any descriptor, key, or deterministic derivation result that lets the holder derive private blinding keys or unblind wallet outputs. +|- +| Descriptor format profile || A named descriptor representation that a dapp can request and parse. +|- +| Multipath descriptor || A descriptor using [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] syntax, such as <0;1>/*, to represent multiple derivation branches in one descriptor. +|- +| Split branch descriptors || Separate descriptors for the external branch and internal/change branch, without [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath syntax. +|- +| Asset ID || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset identifier: chain_id + "/" + asset_namespace + ":" + asset_reference, where asset_namespace is elip144 and asset_reference is the 64-character lowercase hexadecimal Elements asset identifier. +|- +| Policy asset || The native fee asset of the active Liquid or Elements chain. The policy asset is identified with the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID syntax. +|- +| PSET || A Partially Signed Elements Transaction. PSET follows the [https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki BIP-174] PSBT key-value model and the [https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki BIP-370] PSBTv2 model with Elements-specific fields. +|- +| Confidential UTXO || A wallet UTXO whose Elements TxOut contains confidential asset and/or value commitments. Wallets may unblind such UTXOs internally and return wallet-computed asset and amount values through getBalance or getUTXOs, but must not return blinding secrets. +|} + +==Specification== + +The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [https://www.rfc-editor.org/rfc/rfc2119 RFC 2119]. + +Unless a method explicitly contains an account parameter, the wallet applies the method to the account +authorized for the JSON-RPC request by the transport session. If more than one account is in scope and session +context is insufficient to choose one, the wallet MUST reject the request or require an account-scoped request form. + +===Account identifier=== + +A Liquid wallet account in this profile is encoded as follows: + +
+account            = chain_id + ":" + account_identifier
+chain_id           = "bip122:" + first_32_lowercase_hex_characters_of_genesis_block_hash
+account_identifier = first external unconfidential address at index 0 derived from the public wallet descriptor
+
+ +Wallets and dapps MUST follow these rules: + +# Dapps MUST display and persist this account identifier as the connected account. +# Wallets MUST only offer identifiers that belong to the active Liquid or Elements chain. +# Dapps MUST NOT treat this identifier as a receive address, a balance handle, or a sufficient description of the wallet's UTXO set. + +The chain_id prefix identifies the network. Liquid mainnet uses bip122:1466275836220db2944ca059a3a10ef6. +Liquid testnet uses bip122:a771da8e52ee6ad581ed1e9a99825e5b. +Custom Elements chains MUST use the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] bip122 +chain identifier derived from their own genesis block hash. + +Example account material: + +
+public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
+account_identifier       = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+account                  = bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+
+ +===Derivation paths and descriptors=== + +Liquid account derivation paths MUST be interpreted using [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], +[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], and [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044]: + +
+m / purpose' / coin_type' / account' / change / address_index
+
+ +The purpose value identifies the script family. This profile recognizes [https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP-49] +for P2SH-wrapped SegWit descriptors, [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84] for native SegWit descriptors, +and [https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki BIP-86] for single-key Taproot descriptors. +Taproot spend keys and signatures use [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP-340] keys and +the Taproot construction defined by [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP-341]. + +Liquid mainnet uses coin_type = 1776 as registered in [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044]. +Liquid testnet and Liquid regtest use coin_type = 1. The change level MUST use 0 +for the external branch and 1 for the internal/change branch. The address_index level identifies +the concrete address or script. + +Descriptors returned by this profile MUST use the output descriptor syntax defined by [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380]. +Multipath descriptors MAY use [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] syntax such +as <0;1>/*. Elements script expressions such as elwpkh(...), elsh(...), elwsh(...), +and eltr(...) MAY be used where supported by the wallet. + +A wallet MUST NOT return a public wallet descriptor if the wallet blinding policy makes the ordinary descriptor +sufficient to reconstruct derived view material. For example, a wallet using +[https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] MUST treat the ordinary descriptor +as view-capable because ct(elip151, <DESCRIPTOR>) deterministically derives its view key from <DESCRIPTOR>. + +===Asset identifiers=== + +Liquid asset identifiers MUST use the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID form: + +
+asset_id = chain_id + "/" + asset_namespace + ":" + asset_reference
+asset_namespace = "elip144"
+asset_reference = 64 lowercase hex characters
+
+ +The Liquid mainnet policy asset ID is: + +
+bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d
+
+ +===Descriptor disclosure and format profiles=== + +The only descriptor disclosure types that getWalletDescriptor may return are publicWalletDescriptor +and publicConfidentialDescriptor. A wallet MUST NOT return a viewDescriptor through this profile. + +The recognized descriptor format profiles are: + +{| class="wikitable" +! Format profile !! Descriptor type !! Branch layout !! Standards used +|- +| bip380-bip389-multipath || publicWalletDescriptor || One descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044], the relevant purpose BIP such as [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84], [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380], and [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] +|- +| bip380-split-branches || publicWalletDescriptor || Separate external and internal descriptors without multipath syntax || [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044], the relevant purpose BIP such as [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84], and [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] +|- +| elip150-public-ct-bip389-multipath || publicConfidentialDescriptor || One [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-bip389-multipath +|- +| elip150-public-ct-split-branches || publicConfidentialDescriptor || Separate external and internal [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptors without multipath syntax || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-split-branches +|} + +A wallet MAY define additional format profiles in a future revision. A wallet MUST ignore unknown accept +entries when it can satisfy another entry in the same request. If no requested format is supported or permitted +by wallet policy, the wallet MUST return a JSON-RPC error with reason = "unsupported_descriptor_format" +and SHOULD include the requested and supported format profile names in error.data. + +Returned descriptors MUST be normalized and include a valid [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] checksum. +A dapp MUST verify the descriptor checksum and MUST verify that the external branch at index 0 derives +the returned accountIdentifier. For publicConfidentialDescriptor, the embedded ordinary descriptor +MUST describe the same script tree as the corresponding publicWalletDescriptor, and its external branch at +index 0 MUST correspond to the same accountIdentifier script. + +===RPC methods=== + +====sendTransfer==== + +This method signs and submits a transfer of a Liquid asset to a single recipient address. If assetId +is omitted, the wallet MUST send the network policy asset. If assetId is present, +it MUST be an [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID +whose chain_id matches the active Liquid or Elements chain. + +The recipient address SHOULD be a confidential Liquid address. If a wallet accepts an unconfidential address, +it MUST disclose the loss of output confidentiality before user approval. +The transaction MUST be constructed, blinded whenever possible, signed, and broadcast after user approval. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| recipientAddress || String || Yes || Recipient Liquid address. Confidential addresses SHOULD be used. +|- +| amount || String || Yes || Amount in the asset base unit, encoded as a decimal string. +|- +| assetId || String || No || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. +|- +| account || String || No || Connected account. If omitted, the wallet chooses the connected account according to session context and MUST show the selected account before approval. +|- +| changeAddress || String || No || Confidential Liquid change address. Wallets MAY ignore this field and derive change internally. +|- +| memo || String || No || Hex-encoded bytes without 0x. Wallets that support memos MUST encode the value as an OP_RETURN output and MUST enforce a maximum of 80 bytes. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| txid || String || Yes || Transaction ID as 64 lowercase hex characters. +|} + +Example request: + +
+{
+  "id": 1,
+  "jsonrpc": "2.0",
+  "method": "sendTransfer",
+  "params": {
+    "account": "bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "recipientAddress": "lq1qqfk0uw9vlmqlggzs7cxmw49x8ks37l87udspmpt3ssgxjrkqqlww63xvus3c5gaz89r2kd393c4fvurwxf06qj87y2kd3vsln",
+    "amount": "123000000",
+    "memo": "4c69717569642057616c6c6574205250432050726f66696c65"
+  }
+}
+
+ +Example result: + +
+{
+  "id": 1,
+  "jsonrpc": "2.0",
+  "result": {
+    "txid": "f007551f169722ce74104d6673bd46ce193c624b8550889526d1b93820d725f7"
+  }
+}
+
+ +====getWalletDescriptor==== + +This method returns public descriptor material for the connected Liquid account. +The caller selects the disclosure type with descriptorType and MAY provide an ordered accept +list of descriptor format profiles that it can parse. + +The default descriptorType is publicWalletDescriptor. +Wallets MUST NOT return publicConfidentialDescriptor unless it was explicitly requested and approved. +Wallets MUST NOT return viewDescriptor from this method. + +If accept is provided, the wallet MUST return one of the requested format profiles or reject the request. +If accept is omitted, the wallet MAY choose any supported format profile for the requested descriptorType +and MUST identify the selected profile in the result. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| descriptorType || String || No || Requested descriptor disclosure type. Valid values are publicWalletDescriptor and publicConfidentialDescriptor. Default is publicWalletDescriptor. +|- +| accept || Array || No || Ordered descriptor format profiles accepted by the dapp. Each entry is an object with a required format field. Unknown formats are ignored if another accepted format can be returned. +|} + +Allowed accept[].format values are bip380-bip389-multipath, bip380-split-branches, +elip150-public-ct-bip389-multipath, and elip150-public-ct-split-branches. + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +|- +| accountIdentifier || String || Yes || Connected account identifier. +|- +| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +|- +| descriptors || Array || Yes || Descriptor entries returned by the wallet. Every entry MUST match the requested descriptorType and selected format profile. +|} + +Each descriptor entry has the following fields: + +{| class="wikitable" +! Field !! Type !! Required !! Description +|- +| descriptorType || String || Yes || publicWalletDescriptor or publicConfidentialDescriptor. +|- +| format || String || Yes || Selected descriptor format profile. +|- +| branchLayout || String || Yes || multipath or split. +|- +| standardsUsed || String[] || Yes || Exact standards used by the returned representation, such as bip-0032, bip-0044, slip-0044, bip-0084, bip-0380, bip-0389, and elip-0150. +|- +| descriptor || String || Conditional || Required when branchLayout is multipath. Normalized descriptor string with checksum. +|- +| branchDescriptors || Array || Conditional || Required when branchLayout is split. Each entry contains branch, change, and descriptor. +|- +| branches || Array || No || Metadata for branches represented by a multipath descriptor. Each entry contains branch, change, and addressIndex. +|- +| canDeriveScriptPubKeys || Boolean || Yes || Whether the descriptor entry can derive scriptPubKeys. +|- +| canDeriveConfidentialAddresses || Boolean || Yes || Whether the descriptor entry can derive confidential addresses. +|- +| canUnblindOutputs || Boolean || Yes || MUST be false for every descriptor returned by this profile. +|} + +Wallets MUST reject unsupported descriptorType values. Wallets MUST NOT return any descriptor type that +was not requested. Wallets SHOULD respect the order of the accept list. +Wallets MUST NOT return private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, +descriptor blinding xprvs, asset blinding factors, value blinding factors, shared nonces, or per-address private blinding keys. +Wallets MUST derive accountIdentifier from the public wallet descriptor, even when returning a public confidential descriptor. + +Example request for a public wallet descriptor with [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath fallback to split branches: + +
+{
+  "id": 2,
+  "jsonrpc": "2.0",
+  "method": "getWalletDescriptor",
+  "params": {
+    "descriptorType": "publicWalletDescriptor",
+    "accept": [
+      { "format": "bip380-bip389-multipath" },
+      { "format": "bip380-split-branches" }
+    ]
+  }
+}
+
+ +Example result: + +
+{
+  "id": 2,
+  "jsonrpc": "2.0",
+  "result": {
+    "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
+    "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "descriptors": [
+      {
+        "descriptorType": "publicWalletDescriptor",
+        "format": "bip380-bip389-multipath",
+        "branchLayout": "multipath",
+        "standardsUsed": [
+          "bip-0032",
+          "bip-0044",
+          "slip-0044",
+          "bip-0084",
+          "bip-0380",
+          "bip-0389"
+        ],
+        "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv",
+        "branches": [
+          { "branch": "external", "change": 0, "addressIndex": "*" },
+          { "branch": "internal", "change": 1, "addressIndex": "*" }
+        ],
+        "canDeriveScriptPubKeys": true,
+        "canDeriveConfidentialAddresses": false,
+        "canUnblindOutputs": false
+      }
+    ]
+  }
+}
+
+ +Example split-branch descriptors: + +
+elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/0/*)#w7nj838h
+elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/1/*)#l2kn6yh0
+
+ +Example public confidential descriptor: + +
+ct(02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623,elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*))#06l0zt2p
+
+ +====getBalance==== + +This method returns the wallet-computed balance for the connected Liquid account. The only filter parameter +is assetId. If assetId is omitted, the wallet MUST return the balance for the network policy asset. +If assetId is provided, the wallet MUST return the balance for that exact +[https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID and MUST reject the +request if the asset ID chain_id does not match the active Liquid or Elements chain. + +For confidential outputs, the wallet unblinds internally and returns only the resulting asset ID and amount. +This method MUST NOT return blinding private keys, master blinding keys, descriptor blinding private keys, +asset blinding factors, value blinding factors, shared nonces, or view-capable descriptor material. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| assetId || String || No || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +|- +| accountIdentifier || String || Yes || Connected account identifier. +|- +| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +|- +| assetId || String || Yes || Asset ID whose balance was returned. +|- +| balance || String || Yes || Sum of known unspent wallet outputs for assetId, encoded as a decimal string in the asset base unit. +|} + +Example request: + +
+{
+  "id": 4,
+  "jsonrpc": "2.0",
+  "method": "getBalance",
+  "params": {
+    "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d"
+  }
+}
+
+ +Example result: + +
+{
+  "id": 4,
+  "jsonrpc": "2.0",
+  "result": {
+    "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
+    "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "balance": "123456"
+  }
+}
+
+ +====getUTXOs==== + +This method returns UTXOs for the connected Liquid account. The only filter parameter is assetId. +If assetId is omitted, the wallet MUST return UTXOs for the network policy asset. +If assetId is provided, the wallet MUST return UTXOs for that exact [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID +and MUST reject the request if the asset ID chain_id does not match the active Liquid or Elements chain. + +For confidential UTXOs, assetId and amount are wallet-unblinded values. +The txOut field is the raw previous output as serialized in the Elements transaction and may contain confidential commitments. +This method MUST NOT return blinding private keys, master blinding keys, descriptor blinding private keys, asset blinding factors, +value blinding factors, shared nonces, or view-capable descriptor material. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| assetId || String || No || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +|- +| accountIdentifier || String || Yes || Connected account identifier. +|- +| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +|- +| assetId || String || Yes || Asset ID used to filter returned UTXOs. +|- +| utxos || Array || Yes || UTXOs for the requested asset. +|} + +Each UTXO entry has the following fields: + +{| class="wikitable" +! Field !! Type !! Required !! Description +|- +| txid || String || Yes || Transaction ID as 64 lowercase hex characters. +|- +| vout || Integer || Yes || Output index. +|- +| assetId || String || Yes || Wallet-unblinded [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the UTXO. +|- +| amount || String || Yes || Wallet-unblinded amount in the asset base unit, encoded as a decimal string. +|- +| address || String || Yes || Liquid confidential or unconfidential address whose script identifies the spend key for this UTXO. A dapp SHOULD use this value in signPset.signInputs[].address when constructing a PSET from this UTXO. +|- +| scriptPubKey || String || Yes || Raw scriptPubKey bytes as lowercase hex without 0x. +|- +| txOut || String || Yes || Raw Elements TxOut consensus serialization as lowercase hex without 0x. +|- +| confidential || Boolean || Yes || Whether the previous output is confidential. +|- +| spendable || Boolean || Yes || Whether the wallet currently considers the UTXO spendable under wallet policy. +|} + +Wallets MUST return only UTXOs matching the selected assetId, using wallet-unblinded asset IDs for confidential outputs. +Wallets MUST return an empty utxos array when the connected account has no known UTXOs for the selected asset. +Dapps that construct a PSET from returned UTXOs SHOULD include the returned txOut as the previous output +for the corresponding PSET input and SHOULD use the returned address in signPset.signInputs. +Wallets MUST re-check ownership, asset, amount, and confidentiality data during signPset; dapp-provided PSET +data is not trusted merely because it was based on getUTXOs output. + +Example request: + +
+{
+  "id": 5,
+  "jsonrpc": "2.0",
+  "method": "getUTXOs",
+  "params": {
+    "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d"
+  }
+}
+
+ +Example result: + +
+{
+  "id": 5,
+  "jsonrpc": "2.0",
+  "result": {
+    "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
+    "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "utxos": [
+      {
+        "txid": "4b33bd9a251311bd7f247ea19b3cf9887977ba4d9abe2ec7886de24094252586",
+        "vout": 0,
+        "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+        "amount": "123456",
+        "address": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+        "scriptPubKey": "0014272f557c30d2f520b6d4ae1dbdddaaf08708939f",
+        "txOut": "016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04ede979026f01000000000001e24000160014272f557c30d2f520b6d4ae1dbdddaaf08708939f",
+        "confidential": false,
+        "spendable": true
+      }
+    ]
+  }
+}
+
+ +====getIdentityPublicKey==== + +This method returns the deterministic public key used for identity-signing flows. +It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. +The identity key is not a transaction spend key and MUST NOT be derived from a wallet address path. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI shown to the user. +|- +| curve || String || Yes || Supported value: nist256p1. +|- +| index || Integer || No || Identity-key index. Default is 0. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI. +|- +| curve || String || Yes || MUST be nist256p1. +|- +| index || Integer || Yes || Identity-key index. +|- +| type || String || Yes || MUST be slip-0013. +|- +| publicKey || String || Yes || Uncompressed public key as lowercase hex without 0x. +|} + +Example request: + +
+{
+  "id": 6,
+  "jsonrpc": "2.0",
+  "method": "getIdentityPublicKey",
+  "params": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "index": 0
+  }
+}
+
+ +Example result: + +
+{
+  "id": 6,
+  "jsonrpc": "2.0",
+  "result": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "index": 0,
+    "type": "slip-0013",
+    "publicKey": "04012c4f72037ddf467581dd8081bd365b668c9e00fdec2a9c9ff7f4a23df3ff747cd1fb99256b631c6316d1f1b692df829d3c6a687d327d3a3942822499a2abc1"
+  }
+}
+
+ +====getIdentitySharedKey==== + +This method returns a shared key for an identity and a counterparty public key. +It follows [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017]. +The default KDF is none, which returns the raw 32-byte ECDH result. The optional KDF hkdf-sha256 +applies [https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 to the raw ECDH result. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI shown to the user. +|- +| curve || String || Yes || Supported value: nist256p1. +|- +| theirPublicKey || String || Yes || Counterparty uncompressed public key as lowercase hex without 0x. +|- +| index || Integer || No || Identity-key index. Default is 0. +|- +| kdf || String || No || Supported values: none and hkdf-sha256. Default is none. +|- +| kdfSalt || String || Conditional || Required when kdf is hkdf-sha256. Salt bytes as lowercase hex without 0x. +|- +| kdfInfo || String || Conditional || Required when kdf is hkdf-sha256. Info bytes as lowercase hex without 0x. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI. +|- +| curve || String || Yes || MUST be nist256p1. +|- +| index || Integer || Yes || Identity-key index. +|- +| type || String || Yes || MUST be slip-0017. +|- +| publicKey || String || Yes || Wallet identity public key as lowercase hex without 0x. +|- +| sharedKey || String || Yes || Raw ECDH result or HKDF output as lowercase hex without 0x. +|- +| kdf || String || Yes || Applied KDF: none or hkdf-sha256. +|} + +Example request: + +
+{
+  "id": 7,
+  "jsonrpc": "2.0",
+  "method": "getIdentitySharedKey",
+  "params": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "theirPublicKey": "04c95ff5052c66d17ecbf08eafe00aade2071830b0bafc8e87b3debffbfa1b733272900303e6688e025f9744e6c6e6961c5861138cc4e909eeedd84c84311b5ca1",
+    "index": 0,
+    "kdf": "hkdf-sha256",
+    "kdfSalt": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+    "kdfInfo": "4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631"
+  }
+}
+
+ +Example result: + +
+{
+  "id": 7,
+  "jsonrpc": "2.0",
+  "result": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "index": 0,
+    "type": "slip-0017",
+    "publicKey": "045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f23589c696aba3c36c1b08eae7a3c8b9d81878ccddf84adce4d72811867de60922f70fa1a",
+    "sharedKey": "b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e",
+    "kdf": "hkdf-sha256"
+  }
+}
+
+ +====signIdentity==== + +This method signs a caller-provided challenge with the deterministic identity-signing key. +It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. +This method is for identity proof and MUST NOT be displayed or interpreted as transaction approval. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI shown to the user. +|- +| curve || String || Yes || Supported value: nist256p1. +|- +| challenge || String || Yes || Challenge bytes as lowercase hex without 0x. +|- +| index || Integer || No || Identity-key index. Default is 0. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| identity || String || Yes || Identity URI. +|- +| curve || String || Yes || MUST be nist256p1. +|- +| index || Integer || Yes || Identity-key index. +|- +| type || String || Yes || MUST be slip-0013. +|- +| publicKey || String || Yes || Uncompressed public key as lowercase hex without 0x. +|- +| signature || String || Yes || Identity signature as lowercase hex without 0x. +|} + +Example request: + +
+{
+  "id": 8,
+  "jsonrpc": "2.0",
+  "method": "signIdentity",
+  "params": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "challenge": "4c69717569642057616c6c6574205250432050726f66696c65206964656e74697479206368616c6c656e6765",
+    "index": 0
+  }
+}
+
+ +Example result: + +
+{
+  "id": 8,
+  "jsonrpc": "2.0",
+  "result": {
+    "identity": "ssh://jade@blockstream.com",
+    "curve": "nist256p1",
+    "index": 0,
+    "type": "slip-0013",
+    "publicKey": "04012c4f72037ddf467581dd8081bd365b668c9e00fdec2a9c9ff7f4a23df3ff747cd1fb99256b631c6316d1f1b692df829d3c6a687d327d3a3942822499a2abc1",
+    "signature": "00c3fec3b39151ec274f7fb821e6b019c02625e2bfea74fca6635b19d28bef9de53fd7937ca7b10e6be7e228ae96923a45dd4add2aa94920fe660b522b6a9bf6c2"
+  }
+}
+
+ +====signPset==== + +This method requests signatures for a PSET. +Wallets MUST reject PSETs that cannot be associated with the active Liquid or Elements chain. +Wallets MUST NOT add unrelated wallet UTXOs to a caller-provided PSET. +Wallets MUST NOT sign inputs that are not explicitly listed in signInputs. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| pset || String || Yes || Base64-encoded PSET. +|- +| signInputs || Array || Yes || Inputs that the wallet is requested to sign. +|- +| broadcast || Boolean || No || If true, the wallet MAY finalize and broadcast the transaction after signing. Default is false. +|} + +Each signInputs entry has the following fields: + +{| class="wikitable" +! Field !! Type !! Required !! Description +|- +| index || Integer || Yes || Input index in the PSET. +|- +| address || String || Yes || Liquid confidential or unconfidential address whose script identifies the spend key for this input. If a confidential address is supplied, the wallet MUST use only its script address component for spend-key selection. +|- +| sighashTypes || Integer[] || No || Allowed signature hash modes for this input. Each value MUST be a fully encoded standard Elements ECDSA sighash integer from the table below. Default is [1]. +|} + +The signature hash mode applies to a single PSET input. +The sighashTypes array is the set of modes the requester permits the wallet to use for the corresponding signInputs entry. +If the PSET input already declares a sighash type, that value MUST be included in sighashTypes; +otherwise the wallet MUST reject the request. +If the PSET input does not declare a sighash type, the wallet MUST sign with one of the permitted values and SHOULD prefer 1 when it is permitted. + +128 (0x80) is the SIGHASH_ANYONECANPAY flag. +It is listed here because it changes the meaning of the complete sighash mode, but it is not a complete mode by itself. +Wallets MUST reject bare 128 in sighashTypes. + +{| class="wikitable" +! Decimal !! Hex !! Name !! Signing scope +|- +| 1 || 0x01 || SIGHASH_ALL || Signs all outputs. +|- +| 2 || 0x02 || SIGHASH_NONE || Signs no outputs. +|- +| 3 || 0x03 || SIGHASH_SINGLE || Signs the output whose index matches this input index. Wallets MUST reject this mode if the matching output is absent. +|- +| 128 || 0x80 || SIGHASH_ANYONECANPAY || Flag only. When combined with a base mode, signs only this input. MUST NOT be used alone. +|- +| 129 || 0x81 || SIGHASH_ALL | SIGHASH_ANYONECANPAY || Signs all outputs and only this input. +|- +| 130 || 0x82 || SIGHASH_NONE | SIGHASH_ANYONECANPAY || Signs no outputs and only this input. +|- +| 131 || 0x83 || SIGHASH_SINGLE | SIGHASH_ANYONECANPAY || Signs the output whose index matches this input index and only this input. Wallets MUST reject this mode if the matching output is absent. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| pset || String || Yes || Base64-encoded signed PSET. +|- +| txid || String || Conditional || Transaction ID as 64 lowercase hex characters. This field MUST be returned if the transaction was broadcast. +|} + +Wallets MUST verify that each listed address corresponds to the input's previous-output script or +to a descriptor path controlled by the connected wallet. +Wallets MUST verify all confidential transaction data needed for safe signing from the PSET and wallet policy. +This method does not define separate asset metadata, review hints, output hints, or trusted-commitment fields. +When signing a PSET constructed from getUTXOs results, wallets MUST verify that each +signed input still refers to a known wallet UTXO and that the PSET previous-output data matches wallet state. +If broadcast is true, wallets MAY broadcast only after the transaction is complete and user approval covers broadcast. + +Example request: + +
+{
+  "id": 9,
+  "jsonrpc": "2.0",
+  "method": "signPset",
+  "params": {
+    "pset": "cHNldP8BAgQCAAAAAQMEAAAAAAEEAQEBBQECAfsEAgAAAAABAUIBbVIcOOweoVc0riK3xGBkQSgpwNBXnwpxPRwE7el5Am8BAAAAAAAB4kAAFgAUJy9VfDDS9SC21K4dvd2q8IcIk58BAwQBAAAAIgYCP06cFjyQLJeyxqg+4HURV79xbc6PX2QF93G9akTPadQYc8XaClQAAIDwBgCAAAAAgAAAAAAAAAAAAQ4ghiUllEDibYjHLr6aTbp3eYj5PJuhfiR/vRETJZq9M0sBDwQAAAAAARAE/////wv8CGVsZW1lbnRzAAhA4gEAAAAAAAv8CGVsZW1lbnRzASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv8CGVsZW1lbnRzAiBtUhw47B6hVzSuIrfEYGRBKCnA0FefCnE9HATt6XkCbwv8CGVsZW1lbnRzAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwhY3gEAAAAAAAEEFgAURMzkI4ojojlGqzYljiqWcG4yX6AH/ARwc2V0AiBtUhw47B6hVzSuIrfEYGRBKCnA0FefCnE9HATt6XkCbwABAwjoAwAAAAAAAAEEAAf8BHBzZXQCIG1SHDjsHqFXNK4it8RgZEEoKcDQV58KcT0cBO3peQJvAA==",
+    "signInputs": [
+      {
+        "index": 0,
+        "address": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+        "sighashTypes": [
+          1
+        ]
+      }
+    ],
+    "broadcast": false
+  }
+}
+
+ +Example result: + +
+{
+  "id": 9,
+  "jsonrpc": "2.0",
+  "result": {
+    "pset": "cHNldP8BAgQCAAAAAQMEAAAAAAEEAQEBBQECAfsEAgAAAAABAUIBbVIcOOweoVc0riK3xGBkQSgpwNBXnwpxPRwE7el5Am8BAAAAAAAB4kAAFgAUJy9VfDDS9SC21K4dvd2q8IcIk58iAgI/TpwWPJAsl7LGqD7gdRFXv3Ftzo9fZAX3cb1qRM9p1EcwRAIgHqSC9I+L6FpaEb4Iw4DJ7GX+0XlfxW93J4lU55aXAN0CIFYlEbL09G8II2LRlweBm4WBPAhTd93skfqE4eg/lQgcAQEDBAEAAAAiBgI/TpwWPJAsl7LGqD7gdRFXv3Ftzo9fZAX3cb1qRM9p1BhzxdoKVAAAgPAGAIAAAACAAAAAAAAAAAABDiCGJSWUQOJtiMcuvppNund5iPk8m6F+JH+9ERMlmr0zSwEPBAAAAAABEAT/////C/wIZWxlbWVudHMACEDiAQAAAAAAC/wIZWxlbWVudHMBIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/wIZWxlbWVudHMCIG1SHDjsHqFXNK4it8RgZEEoKcDQV58KcT0cBO3peQJvC/wIZWxlbWVudHMDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDCFjeAQAAAAAAB/wEcHNldAIgbVIcOOweoVc0riK3xGBkQSgpwNBXnwpxPRwE7el5Am8BBBYAFETM5COKI6I5Rqs2JY4qlnBuMl+gAAEDCOgDAAAAAAAAB/wEcHNldAIgbVIcOOweoVc0riK3xGBkQSgpwNBXnwpxPRwE7el5Am8BBAAA"
+  }
+}
+
+ +====signMessage==== + +This method signs a message with the spend key for a connected Liquid address. Message signing uses spend keys, not descriptor blinding keys or view keys. + +{| class="wikitable" +! Parameter !! Type !! Required !! Description +|- +| message || String || Yes || UTF-8 message shown to the user. +|- +| address || String || Yes || Liquid confidential or unconfidential address whose spend key signs the message. If a confidential address is supplied, the wallet MUST use only its script address component for spend-key selection. +|- +| protocol || String || No || Supported values: ecdsa and bip322. Default is ecdsa. +|} + +{| class="wikitable" +! Result field !! Type !! Required !! Description +|- +| address || String || Yes || Liquid address used for signing. +|- +| signature || String || Yes || Encoded signature. +|- +| signatureEncoding || String || Yes || hex-recoverable-ecdsa-65 when protocol is ecdsa; bip322 when protocol is bip322. +|- +| protocol || String || Yes || Applied protocol: ecdsa or bip322. +|- +| messageHash || String || Conditional || Required when protocol is ecdsa. 32-byte legacy message digest as lowercase hex without 0x. +|} + +For protocol = ecdsa, the wallet MUST compute messageHash as: + +
+SHA256d(0x18 || "Bitcoin Signed Message:\n" || CompactSize(message_byte_length) || message_bytes)
+
+ +For protocol = ecdsa, signature MUST be the 65-byte recoverable ECDSA signature encoded as +lowercase hex without 0x. For protocol = bip322, the wallet SHOULD implement the +generic message-signing construction defined by [https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki BIP-322]. +The signature field MUST be the [https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki BIP-322] +signature string, including the required variant prefix such as smp, ful, or pof. +This method MUST NOT sign arbitrary transaction hex, arbitrary hashes, or PSET internals. + +Example request: + +
+{
+  "id": 10,
+  "jsonrpc": "2.0",
+  "method": "signMessage",
+  "params": {
+    "message": "Authorize Liquid Wallet RPC Profile example",
+    "address": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "protocol": "ecdsa"
+  }
+}
+
+ +Example result: + +
+{
+  "id": 10,
+  "jsonrpc": "2.0",
+  "result": {
+    "address": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+    "signature": "ded4c5a767265f1df01b5453da8df9d364d81775d780c8f52707573a68c485152f59a354eec5c935072eff8e6d14d3c6744659fc405cad88e395afd9493cdd3a00",
+    "signatureEncoding": "hex-recoverable-ecdsa-65",
+    "protocol": "ecdsa",
+    "messageHash": "95b7987475f7157b80aa3c5087d910e44429f410cd3b12c25a652e9c2d480d89"
+  }
+}
+
+ +====processConfidentialTransaction==== + +This method is optional. It delegates request and response shape to the Wallet ABI transaction creation protocol. + +Wallets that support this method MUST implement it as described by the +[https://github.com/KyrylR/ELIPs/blob/c946695f75f98477008bad0059d2894696bbaadd/elip-wallet-abi.mediawiki Wallet ABI Transaction Creation Protocol]. +The JSON-RPC request MUST carry the Wallet ABI transaction request object. +The JSON-RPC result MUST carry the Wallet ABI transaction response object. + +===Events=== + +====bip122_walletDescriptorChanged==== + +This event notifies dapps that descriptor metadata for the connected Liquid account changed. +The event data has the same shape as the getWalletDescriptor result. + +Wallets SHOULD emit this event when the descriptor set for the connected account changes, +when the account identifier derived from the public wallet descriptor changes, +or when the network policy asset ID changes because the wallet switched Liquid or Elements chains. +Wallets MUST NOT emit viewDescriptor, view-capable descriptor material, or blinding secrets through this event. +Descriptor entries in event data MUST be publicWalletDescriptor or publicConfidentialDescriptor +and MUST match descriptor disclosure authorized for the session. + +Example session_event payload as received by a dapp: + +
+{
+  "id": 1675759795769538,
+  "topic": "95d6aca451b8e3c6d9d176761bf786f1cc0a6d38dffd31ed896306bb37f6ae8d",
+  "params": {
+    "event": {
+      "name": "bip122_walletDescriptorChanged",
+      "data": {
+        "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
+        "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a",
+        "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+        "descriptors": [
+          {
+            "descriptorType": "publicWalletDescriptor",
+            "format": "bip380-bip389-multipath",
+            "branchLayout": "multipath",
+            "standardsUsed": ["bip-0032", "bip-0044", "slip-0044", "bip-0084", "bip-0380", "bip-0389"],
+            "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv",
+            "canDeriveScriptPubKeys": true,
+            "canDeriveConfidentialAddresses": false,
+            "canUnblindOutputs": false
+          }
+        ]
+      }
+    },
+    "chainId": "bip122:1466275836220db2944ca059a3a10ef6"
+  }
+}
+
+ +In the example above, id, topic, and other fields outside params.event are illustrative transport fields. +This profile specifies the event name and event.data shape; transport-layer fields are controlled by the transport used by the implementation. + +==Security Considerations== + +* Wallets MUST validate that every chainId, account, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] assetId refers to the active Liquid or Elements chain. +* Wallets MUST derive the active chain ID from node or runtime context, not from user-facing labels such as Liquid, testnet-liquid, or localtest-liquid. +* Wallets MUST display asset, amount, recipient, fee asset, broadcast status, and confidentiality status before approving sendTransfer. +* Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before approving getWalletDescriptor. +* Wallets MUST treat [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], private-key, xprv, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] CT descriptors as view-capable material that is not exported by this profile. +* Wallets MUST NOT return view-capable CT descriptors, private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, per-address private blinding keys, asset blinding factors, value blinding factors, or shared nonces through this profile. The only CT descriptor that may be returned is publicConfidentialDescriptor with public blinding-key material. +* Wallets MUST NOT log view-capable descriptor material, private blinding material, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data. +* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active session. +* Dapps MUST NOT assume that a public descriptor or an account identifier is sufficient to calculate balances or reconstruct the wallet UTXO set. +* Identity keys MUST be domain-separated from transaction spend keys and descriptor blinding keys. + +==Rationale== + +This profile uses the first external unconfidential address derived from the public wallet descriptor as +the account identifier because dapps need a stable identifier that they can display, persist, and verify against the returned public descriptor. +The account identifier is not a receive address and does not describe wallet balance or UTXO state. + +Descriptor format negotiation is expressed as an ordered accept list of descriptor format profiles +rather than as a list of individual BIPs, SLIPs, and ELIPs. +This keeps the request focused on what the dapp can parse and use. +For example, a dapp that cannot parse [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] +can request bip380-split-branches instead of trying to exclude [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] +while still naming all other standards. + +The profile separates descriptor disclosure from balance and UTXO disclosure. +A public wallet descriptor is useful for derivation and verification, but it is not enough to compute confidential balances. +getBalance and getUTXOs return wallet-computed values without exporting view descriptors or blinding secrets. + +The profile permits public confidential descriptors only when the blinding material is public and +not recoverable as private view material from data disclosed to the dapp. +It does not return [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] descriptors, +[https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private material, descriptor blinding private keys, +or descriptor blinding xprvs, because those forms let the holder unblind wallet outputs. + +processConfidentialTransaction is delegated to the Wallet ABI transaction creation protocol to avoid duplicating +a larger confidential transaction schema in this profile. +This ELIP specifies the JSON-RPC binding and leaves the transaction object shapes to that protocol. + +==Reference Implementation== + +TBD. + +==Test Vectors== + +The following values were derived and statically validated with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. + +
+public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
+account_identifier       = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+account                  = bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+policy_asset_id          = bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d
+
+ +Split branch descriptors for the same public wallet descriptor are: + +
+external_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/0/*)#w7nj838h
+internal_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/1/*)#l2kn6yh0
+
+ + +The following identity and signing vectors use the same mnemonic. The identity keys are derived with [https://github.com/satoshilabs/slips/blob/master/slip-0010.md SLIP-0010] over NIST P-256 and the [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013] or [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017] identity path for ssh://jade@blockstream.com at index 0. + +
+slip0013_public_key = 04012c4f72037ddf467581dd8081bd365b668c9e00fdec2a9c9ff7f4a23df3ff747cd1fb99256b631c6316d1f1b692df829d3c6a687d327d3a3942822499a2abc1
+slip0013_challenge  = 4c69717569642057616c6c6574205250432050726f66696c65206964656e74697479206368616c6c656e6765
+slip0013_signature  = 00c3fec3b39151ec274f7fb821e6b019c02625e2bfea74fca6635b19d28bef9de53fd7937ca7b10e6be7e228ae96923a45dd4add2aa94920fe660b522b6a9bf6c2
+slip0017_public_key = 045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f23589c696aba3c36c1b08eae7a3c8b9d81878ccddf84adce4d72811867de60922f70fa1a
+peer_public_key     = 04c95ff5052c66d17ecbf08eafe00aade2071830b0bafc8e87b3debffbfa1b733272900303e6688e025f9744e6c6e6961c5861138cc4e909eeedd84c84311b5ca1
+raw_shared_key      = c78d6f0cde624fdbadb88c7d6af291530ee0a203938c7d88b6a2c5ab4d85d3c8
+hkdf_salt           = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+hkdf_info           = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631
+hkdf_shared_key     = b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e
+message_hash        = 95b7987475f7157b80aa3c5087d910e44429f410cd3b12c25a652e9c2d480d89
+message_signature   = ded4c5a767265f1df01b5453da8df9d364d81775d780c8f52707573a68c485152f59a354eec5c935072eff8e6d14d3c6744659fc405cad88e395afd9493cdd3a00
+
+ +The following PSET values are constructed from an explicit policy-asset UTXO at the account identifier script and were parsed with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. The signed PSET was produced with the Liquid Wallet Kit signer for the same mnemonic. + +
+example_utxo_txid = 4b33bd9a251311bd7f247ea19b3cf9887977ba4d9abe2ec7886de24094252586
+example_utxo_vout = 0
+example_utxo_txout = 016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04ede979026f01000000000001e24000160014272f557c30d2f520b6d4ae1dbdddaaf08708939f
+example_pset_unique_id = b32487878e61f1765058bc566c6f51bb851df3710323c464988202758f25d32c
+example_pset_partial_signature = 304402201ea482f48f8be85a5a11be08c380c9ec65fed1795fc56f77278954e7969700dd0220562511b2f4f46f082362d19707819b85813c085377ddec91fa84e1e83f95081c01
+
From b85c222ac3d025d0bb1677a3f5cc29b87b62e7e9 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Thu, 28 May 2026 13:47:19 +0300 Subject: [PATCH 2/8] liquid-rpc-profile: address some gaps in definitions and UX --- elip-liquid-wallet-rpc-profile.mediawiki | 223 +++++++++++++++-------- 1 file changed, 150 insertions(+), 73 deletions(-) diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki index 6824b45..69e657f 100644 --- a/elip-liquid-wallet-rpc-profile.mediawiki +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -59,13 +59,15 @@ The following terms are used throughout this ELIP. |- | Public wallet descriptor || An ordinary Liquid/Elements output descriptor with public spend-key material and no ct(...) wrapper. It can derive scriptPubKeys and unconfidential addresses. It cannot derive confidential addresses, unblind outputs, or spend funds. |- -| Account identifier || The profile-specific account suffix selected by this ELIP: the first external unconfidential address at index 0 derived from the public wallet descriptor. +| Account identifier || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] Liquid account ID for the connected wallet account: chain_id + ":" + dwid. This value is used in accountIdentifier result fields and in account request parameters. |- -| Connected account || The account string displayed and persisted by the dapp: chain_id + ":" + account_identifier. +| DWID || The Deterministic Wallet IDentifier defined by [https://github.com/ElementsProject/ELIPs/blob/main/elip-0152.mediawiki ELIP-0152]. In this profile, the DWID component of an account identifier MUST identify the same wallet descriptor set as the public wallet descriptor returned for the connected account. +|- +| Connected account || The account identifier authorized for the active transport session. |- | Public confidential descriptor || An [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor with public blinding-key material only. It can derive confidential addresses. It cannot derive private blinding keys and cannot unblind outputs. |- -| View descriptor || A CT descriptor that lets the holder derive private blinding keys or otherwise unblind wallet outputs. Examples include descriptors using [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private master blinding material, private descriptor blinding keys, descriptor blinding xprvs, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] ct(elip151, <DESCRIPTOR>). View descriptors MUST NOT be returned by this profile. +| View descriptor || A CT descriptor that lets the holder derive private blinding keys or otherwise unblind wallet outputs. Examples include descriptors using [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private master blinding material, private descriptor blinding keys, descriptor blinding xprvs, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] ct(elip151, ). View descriptors MUST NOT be returned by this profile. |- | Wallet blinding policy || The wallet rule that determines how confidential addresses and output blinding keys are derived for a script tree, for example [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], public [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] blinding-key material, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151]. |- @@ -73,7 +75,7 @@ The following terms are used throughout this ELIP. |- | Descriptor format profile || A named descriptor representation that a dapp can request and parse. |- -| Multipath descriptor || A descriptor using [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] syntax, such as <0;1>/*, to represent multiple derivation branches in one descriptor. +| Multipath descriptor || A descriptor using [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] syntax, such as <0;1>/*, to represent multiple derivation branches in one descriptor. |- | Split branch descriptors || Separate descriptors for the external branch and internal/change branch, without [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath syntax. |- @@ -96,18 +98,19 @@ context is insufficient to choose one, the wallet MUST reject the request or req ===Account identifier=== -A Liquid wallet account in this profile is encoded as follows: +A Liquid wallet account identifier in this profile is the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID:
-account            = chain_id + ":" + account_identifier
+account_identifier = chain_id + ":" + dwid
 chain_id           = "bip122:" + first_32_lowercase_hex_characters_of_genesis_block_hash
-account_identifier = first external unconfidential address at index 0 derived from the public wallet descriptor
+dwid               = Deterministic Wallet IDentifier as defined by ELIP-0152
 
+The account request parameter, where present, MUST contain this full account_identifier value. Wallets and dapps MUST follow these rules: # Dapps MUST display and persist this account identifier as the connected account. -# Wallets MUST only offer identifiers that belong to the active Liquid or Elements chain. +# Wallets MUST only offer account identifiers that belong to the active Liquid or Elements chain. # Dapps MUST NOT treat this identifier as a receive address, a balance handle, or a sufficient description of the wallet's UTXO set. The chain_id prefix identifies the network. Liquid mainnet uses bip122:1466275836220db2944ca059a3a10ef6. @@ -118,9 +121,9 @@ chain identifier derived from their own genesis block hash. Example account material:
-public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
-account_identifier       = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
-account                  = bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
+dwid                     = b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
+account_identifier       = bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
 
===Derivation paths and descriptors=== @@ -145,13 +148,13 @@ the concrete address or script. Descriptors returned by this profile MUST use the output descriptor syntax defined by [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380]. Multipath descriptors MAY use [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] syntax such -as <0;1>/*. Elements script expressions such as elwpkh(...), elsh(...), elwsh(...), +as <0;1>/*. Elements script expressions such as elwpkh(...), elsh(...), elwsh(...), and eltr(...) MAY be used where supported by the wallet. A wallet MUST NOT return a public wallet descriptor if the wallet blinding policy makes the ordinary descriptor sufficient to reconstruct derived view material. For example, a wallet using [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] MUST treat the ordinary descriptor -as view-capable because ct(elip151, <DESCRIPTOR>) deterministically derives its view key from <DESCRIPTOR>. +as view-capable because ct(elip151, ) deterministically derives its view key from . ===Asset identifiers=== @@ -179,11 +182,11 @@ The recognized descriptor format profiles are: {| class="wikitable" ! Format profile !! Descriptor type !! Branch layout !! Standards used |- -| bip380-bip389-multipath || publicWalletDescriptor || One descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044], the relevant purpose BIP such as [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84], [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380], and [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] +| bip380-bip389-multipath || publicWalletDescriptor || One descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044], the relevant purpose BIP such as [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84], [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380], and [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] |- | bip380-split-branches || publicWalletDescriptor || Separate external and internal descriptors without multipath syntax || [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-32], [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-44], [https://slips.readthedocs.io/en/latest/slip-0044/ SLIP-0044], the relevant purpose BIP such as [https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP-84], and [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] |- -| elip150-public-ct-bip389-multipath || publicConfidentialDescriptor || One [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-bip389-multipath +| elip150-public-ct-bip389-multipath || publicConfidentialDescriptor || One [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor using a multipath branch expression such as <0;1>/* || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-bip389-multipath |- | elip150-public-ct-split-branches || publicConfidentialDescriptor || Separate external and internal [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptors without multipath syntax || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-split-branches |} @@ -194,10 +197,9 @@ by wallet policy, the wallet MUST return a JSON-RPC error with reason = "u and SHOULD include the requested and supported format profile names in error.data. Returned descriptors MUST be normalized and include a valid [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] checksum. -A dapp MUST verify the descriptor checksum and MUST verify that the external branch at index 0 derives -the returned accountIdentifier. For publicConfidentialDescriptor, the embedded ordinary descriptor -MUST describe the same script tree as the corresponding publicWalletDescriptor, and its external branch at -index 0 MUST correspond to the same accountIdentifier script. +Wallets MUST ensure that every descriptor returned in one response belongs to the same connected account identifier. +For publicConfidentialDescriptor, the embedded ordinary descriptor MUST describe the same script tree as the corresponding publicWalletDescriptor. +Dapps MUST verify descriptor checksums before using returned descriptors. ===RPC methods=== @@ -223,8 +225,6 @@ The transaction MUST be constructed, blinded whenever possible, signed, and broa |- | account || String || No || Connected account. If omitted, the wallet chooses the connected account according to session context and MUST show the selected account before approval. |- -| changeAddress || String || No || Confidential Liquid change address. Wallets MAY ignore this field and derive change internally. -|- | memo || String || No || Hex-encoded bytes without 0x. Wallets that support memos MUST encode the value as an OP_RETURN output and MUST enforce a maximum of 80 bytes. |} @@ -242,7 +242,7 @@ Example request: "jsonrpc": "2.0", "method": "sendTransfer", "params": { - "account": "bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a", + "account": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799", "recipientAddress": "lq1qqfk0uw9vlmqlggzs7cxmw49x8ks37l87udspmpt3ssgxjrkqqlww63xvus3c5gaz89r2kd393c4fvurwxf06qj87y2kd3vsln", "amount": "123000000", "memo": "4c69717569642057616c6c6574205250432050726f66696c65" @@ -268,7 +268,11 @@ This method returns public descriptor material for the connected Liquid account. The caller selects the disclosure type with descriptorType and MAY provide an ordered accept list of descriptor format profiles that it can parse. -The default descriptorType is publicWalletDescriptor. +Descriptor disclosure is watch-only script-graph disclosure. Wallets MUST NOT return publicWalletDescriptor +or publicConfidentialDescriptor unless descriptor disclosure for the connected account is authorized by +the active session or approved for the individual request. The default descriptorType is +publicWalletDescriptor, but the default only selects the requested disclosure type; it does not remove +the authorization or approval requirement. Wallets MUST NOT return publicConfidentialDescriptor unless it was explicitly requested and approved. Wallets MUST NOT return viewDescriptor from this method. @@ -292,7 +296,7 @@ Allowed accept[].format values are bip380-bip389-multipathchainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || Connected account identifier. +| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- | policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- @@ -326,10 +330,12 @@ Each descriptor entry has the following fields: |} Wallets MUST reject unsupported descriptorType values. Wallets MUST NOT return any descriptor type that -was not requested. Wallets SHOULD respect the order of the accept list. +was not requested. Wallets MUST verify that the session permission or per-request approval covers the requested +descriptorType and selected descriptor format profile. Wallets SHOULD respect the order of the accept list. Wallets MUST NOT return private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, asset blinding factors, value blinding factors, shared nonces, or per-address private blinding keys. -Wallets MUST derive accountIdentifier from the public wallet descriptor, even when returning a public confidential descriptor. +Wallets MUST return the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account identifier +for the same descriptor set as the returned public wallet descriptor, even when returning a public confidential descriptor. Example request for a public wallet descriptor with [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath fallback to split branches: @@ -356,7 +362,7 @@ Example result: "jsonrpc": "2.0", "result": { "chainId": "bip122:1466275836220db2944ca059a3a10ef6", - "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a", + "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799", "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "descriptors": [ { @@ -371,7 +377,7 @@ Example result: "bip-0380", "bip-0389" ], - "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv", + "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv", "branches": [ { "branch": "external", "change": 0, "addressIndex": "*" }, { "branch": "internal", "change": 1, "addressIndex": "*" } @@ -395,13 +401,18 @@ elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANU Example public confidential descriptor:
-ct(02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623,elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*))#06l0zt2p
+ct(036907dadd77ba1798e89237874c52c6c6954b2f64490d48aadc5b0cbed3f589d5,elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*))#em5whsyz
 
====getBalance==== This method returns the wallet-computed balance for the connected Liquid account. The only filter parameter -is assetId. If assetId is omitted, the wallet MUST return the balance for the network policy asset. +is assetId. Wallets MUST treat this method as account-state disclosure and MUST require either +session authorization for balance reads or per-request user approval. The authorization or approval MUST identify +the connected account and whether it covers the policy asset, the requested assetId, or all assets, and +it MUST be bounded by the active session lifetime. If the requested asset scope is not authorized by the session, +the wallet MUST require per-request approval. +If assetId is omitted, the wallet MUST return the balance for the network policy asset. If assetId is provided, the wallet MUST return the balance for that exact [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID and MUST reject the request if the asset ID chain_id does not match the active Liquid or Elements chain. @@ -421,7 +432,7 @@ asset blinding factors, value blinding factors, shared nonces, or view-capable d |- | chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || Connected account identifier. +| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- | policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- @@ -451,7 +462,7 @@ Example result: "jsonrpc": "2.0", "result": { "chainId": "bip122:1466275836220db2944ca059a3a10ef6", - "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a", + "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799", "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "balance": "123456" @@ -462,6 +473,11 @@ Example result: ====getUTXOs==== This method returns UTXOs for the connected Liquid account. The only filter parameter is assetId. +Wallets MUST treat this method as account-state disclosure and MUST require either session authorization +for UTXO reads or per-request user approval. The authorization or approval MUST identify the connected account +and whether it covers the policy asset, the requested assetId, or all assets, and it MUST be bounded by +the active session lifetime. If the requested asset scope is not authorized by the session, the wallet MUST require +per-request approval. If assetId is omitted, the wallet MUST return UTXOs for the network policy asset. If assetId is provided, the wallet MUST return UTXOs for that exact [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID and MUST reject the request if the asset ID chain_id does not match the active Liquid or Elements chain. @@ -482,7 +498,7 @@ value blinding factors, shared nonces, or view-capable descriptor material. |- | chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || Connected account identifier. +| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- | policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- @@ -543,7 +559,7 @@ Example result: "jsonrpc": "2.0", "result": { "chainId": "bip122:1466275836220db2944ca059a3a10ef6", - "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a", + "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799", "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "assetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "utxos": [ @@ -568,6 +584,8 @@ Example result: This method returns the deterministic public key used for identity-signing flows. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. The identity key is not a transaction spend key and MUST NOT be derived from a wallet address path. +Wallets MUST display the identity string, curve, and index before approval unless the exact identity key disclosure +is already authorized by the session. {| class="wikitable" ! Parameter !! Type !! Required !! Description @@ -626,10 +644,15 @@ Example result: ====getIdentitySharedKey==== -This method returns a shared key for an identity and a counterparty public key. -It follows [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017]. -The default KDF is none, which returns the raw 32-byte ECDH result. The optional KDF hkdf-sha256 -applies [https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 to the raw ECDH result. +This method returns a domain-separated shared key for an identity and a counterparty public key. +It follows [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017] for identity-key derivation and +[https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 for the returned key. + +Wallets MUST validate that theirPublicKey is a valid point on nist256p1 and MUST reject invalid, +low-order, or unsupported public keys. Wallets MUST bind authorization for this method to the authenticated caller +origin or transport identity and to the connected account. Wallets MUST display the identity string, counterparty +key fingerprint, curve, index, connected account, and domain-separation context before approval unless the exact +origin-bound and account-bound request is already authorized by the session. {| class="wikitable" ! Parameter !! Type !! Required !! Description @@ -642,11 +665,11 @@ applies [https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 to the raw |- | index || Integer || No || Identity-key index. Default is 0. |- -| kdf || String || No || Supported values: none and hkdf-sha256. Default is none. +| kdf || String || Yes || Supported value: hkdf-sha256. |- -| kdfSalt || String || Conditional || Required when kdf is hkdf-sha256. Salt bytes as lowercase hex without 0x. +| kdfSalt || String || Yes || HKDF salt bytes as lowercase hex without 0x. |- -| kdfInfo || String || Conditional || Required when kdf is hkdf-sha256. Info bytes as lowercase hex without 0x. +| kdfInfo || String || Yes || HKDF info bytes as lowercase hex without 0x. The value MUST domain-separate the intended protocol and MUST commit to the dapp origin or transport identity, active chain_id, and account identifier. Wallets MUST reject the request when this context is absent or inconsistent with the authenticated caller or connected account. |} {| class="wikitable" @@ -662,9 +685,9 @@ applies [https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 to the raw |- | publicKey || String || Yes || Wallet identity public key as lowercase hex without 0x. |- -| sharedKey || String || Yes || Raw ECDH result or HKDF output as lowercase hex without 0x. +| sharedKey || String || Yes || HKDF-SHA256 output as lowercase hex without 0x. |- -| kdf || String || Yes || Applied KDF: none or hkdf-sha256. +| kdf || String || Yes || Applied KDF: hkdf-sha256. |} Example request: @@ -681,7 +704,7 @@ Example request: "index": 0, "kdf": "hkdf-sha256", "kdfSalt": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", - "kdfInfo": "4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631" + "kdfInfo": "4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b65792076317c6f726967696e3d68747470733a2f2f6578616d706c652e636f6d7c636861696e5f69643d6269703132323a31343636323735383336323230646232393434636130353961336131306566367c6163636f756e743d6269703132323a31343636323735383336323230646232393434636130353961336131306566363a623738312d376263372d646236342d633364652d333933372d376562372d633961622d66373939" } } @@ -698,7 +721,7 @@ Example result: "index": 0, "type": "slip-0017", "publicKey": "045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f23589c696aba3c36c1b08eae7a3c8b9d81878ccddf84adce4d72811867de60922f70fa1a", - "sharedKey": "b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e", + "sharedKey": "fd1efbd05dbd13aa8e33d498f3d3b0e3b1a635fa1925fa64902fc43ac17524fb", "kdf": "hkdf-sha256" } } @@ -709,6 +732,8 @@ Example result: This method signs a caller-provided challenge with the deterministic identity-signing key. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. This method is for identity proof and MUST NOT be displayed or interpreted as transaction approval. +Wallets MUST display the identity string, challenge summary, curve, and index before approval unless the exact +signing request is already authorized by the session. {| class="wikitable" ! Parameter !! Type !! Required !! Description @@ -821,11 +846,11 @@ Wallets MUST reject bare 128 in sighashTypes. |- | 128 || 0x80 || SIGHASH_ANYONECANPAY || Flag only. When combined with a base mode, signs only this input. MUST NOT be used alone. |- -| 129 || 0x81 || SIGHASH_ALL | SIGHASH_ANYONECANPAY || Signs all outputs and only this input. +| 129 || 0x81 || SIGHASH_ALL | SIGHASH_ANYONECANPAY || Signs all outputs and only this input. |- -| 130 || 0x82 || SIGHASH_NONE | SIGHASH_ANYONECANPAY || Signs no outputs and only this input. +| 130 || 0x82 || SIGHASH_NONE | SIGHASH_ANYONECANPAY || Signs no outputs and only this input. |- -| 131 || 0x83 || SIGHASH_SINGLE | SIGHASH_ANYONECANPAY || Signs the output whose index matches this input index and only this input. Wallets MUST reject this mode if the matching output is absent. +| 131 || 0x83 || SIGHASH_SINGLE | SIGHASH_ANYONECANPAY || Signs the output whose index matches this input index and only this input. Wallets MUST reject this mode if the matching output is absent. |} {| class="wikitable" @@ -840,6 +865,16 @@ Wallets MUST verify that each listed address corresponds to the inp to a descriptor path controlled by the connected wallet. Wallets MUST verify all confidential transaction data needed for safe signing from the PSET and wallet policy. This method does not define separate asset metadata, review hints, output hints, or trusted-commitment fields. +Wallets MUST display the requested input indexes, allowed sighash modes, broadcast flag, and wallet-computed +net asset movement before approval. Wallets MUST reject the request if they cannot compute a safe review of +wallet inputs, wallet outputs, fees, and confidentiality status. +Before returning a PSET, wallets MUST NOT add wallet-derived blinding private keys, master blinding keys, +descriptor blinding private keys, asset blinding factors, value blinding factors, shared nonces, or other unblinding secrets. +If a received PSET already contains such data, including fields such +as [https://github.com/ElementsProject/ELIPs/blob/main/elip-0102.mediawiki ELIP-0102] asset blinding factor extensions, +or if wallet signing would otherwise add such data, wallets MUST redact wallet-derived secrets before returning the PSET. +If redaction is not possible without changing the requested signing result, wallets MUST reject the request instead of +returning a PSET that contains wallet-derived unblinding secrets. When signing a PSET constructed from getUTXOs results, wallets MUST verify that each signed input still refers to a known wallet UTXO and that the PSET previous-output data matches wallet state. If broadcast is true, wallets MAY broadcast only after the transaction is complete and user approval covers broadcast. @@ -959,6 +994,9 @@ Wallets that support this method MUST implement it as described by the [https://github.com/KyrylR/ELIPs/blob/c946695f75f98477008bad0059d2894696bbaadd/elip-wallet-abi.mediawiki Wallet ABI Transaction Creation Protocol]. The JSON-RPC request MUST carry the Wallet ABI transaction request object. The JSON-RPC result MUST carry the Wallet ABI transaction response object. +Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, approval requirements, or redaction +requirements are not supported or authorized. The Wallet ABI reference above is provisional; before this ELIP is finalized, +it MUST be replaced by a canonical Wallet ABI ELIP or upstream repository reference. ===Events=== @@ -968,7 +1006,7 @@ This event notifies dapps that descriptor metadata for the connected Liquid acco The event data has the same shape as the getWalletDescriptor result. Wallets SHOULD emit this event when the descriptor set for the connected account changes, -when the account identifier derived from the public wallet descriptor changes, +when the account identifier for the connected account changes, or when the network policy asset ID changes because the wallet switched Liquid or Elements chains. Wallets MUST NOT emit viewDescriptor, view-capable descriptor material, or blinding secrets through this event. Descriptor entries in event data MUST be publicWalletDescriptor or publicConfidentialDescriptor @@ -985,7 +1023,7 @@ Example session_event payload as received by a dapp: "name": "bip122_walletDescriptorChanged", "data": { "chainId": "bip122:1466275836220db2944ca059a3a10ef6", - "accountIdentifier": "ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a", + "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799", "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", "descriptors": [ { @@ -993,7 +1031,7 @@ Example session_event payload as received by a dapp: "format": "bip380-bip389-multipath", "branchLayout": "multipath", "standardsUsed": ["bip-0032", "bip-0044", "slip-0044", "bip-0084", "bip-0380", "bip-0389"], - "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv", + "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv", "canDeriveScriptPubKeys": true, "canDeriveConfidentialAddresses": false, "canUnblindOutputs": false @@ -1014,40 +1052,78 @@ This profile specifies the event name and event.data shape; transpo * Wallets MUST validate that every chainId, account, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] assetId refers to the active Liquid or Elements chain. * Wallets MUST derive the active chain ID from node or runtime context, not from user-facing labels such as Liquid, testnet-liquid, or localtest-liquid. * Wallets MUST display asset, amount, recipient, fee asset, broadcast status, and confidentiality status before approving sendTransfer. -* Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before approving getWalletDescriptor. +* Wallets MUST treat getWalletDescriptor as descriptor disclosure and MUST only answer after descriptor disclosure is authorized by the active session or approved for the individual request. Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before per-request approval. * Wallets MUST treat [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], private-key, xprv, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] CT descriptors as view-capable material that is not exported by this profile. * Wallets MUST NOT return view-capable CT descriptors, private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, per-address private blinding keys, asset blinding factors, value blinding factors, or shared nonces through this profile. The only CT descriptor that may be returned is publicConfidentialDescriptor with public blinding-key material. * Wallets MUST NOT log view-capable descriptor material, private blinding material, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data. -* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active session. +* Wallets that support processConfidentialTransaction MUST enforce the Wallet ABI version, account scope, transaction approval, result shape, and artifact redaction rules from the referenced Wallet ABI protocol. +* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active session and after the relevant session permission or per-request approval. The permission or approval MUST define the account, method, asset scope, and active-session lifetime. +* Wallets MUST treat signPset as transaction approval, display sighash scope and wallet-computed net asset movement, and MUST redact wallet-derived blinding secrets from the PSET response or reject the request. +* Wallets MUST require domain separation for getIdentitySharedKey by applying hkdf-sha256 with caller-provided salt and info that commits to the authenticated caller origin or transport identity, active chain_id, and account identifier. * Dapps MUST NOT assume that a public descriptor or an account identifier is sufficient to calculate balances or reconstruct the wallet UTXO set. * Identity keys MUST be domain-separated from transaction spend keys and descriptor blinding keys. ==Rationale== -This profile uses the first external unconfidential address derived from the public wallet descriptor as -the account identifier because dapps need a stable identifier that they can display, persist, and verify against the returned public descriptor. -The account identifier is not a receive address and does not describe wallet balance or UTXO state. +===ELIP-0144 account identifiers=== + +This profile uses the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] +chain_id:dwid account ID form because Liquid accounts should not be represented by receive addresses. +The DWID component identifies the wallet descriptor set without turning an address into a long-lived account handle. -Descriptor format negotiation is expressed as an ordered accept list of descriptor format profiles -rather than as a list of individual BIPs, SLIPs, and ELIPs. +For display, applications can abbreviate the account identifier by showing a short prefix of the chain_id +and the start and end of the DWID, for example 14662758…0ef6:b781…f799. +The full account identifier remains the value that is persisted and compared. + +===Descriptor format profiles=== + +Descriptor format negotiation is expressed as an ordered accept list of descriptor format profiles rather +than as a list of individual BIPs, SLIPs, and ELIPs. This keeps the request focused on what the dapp can parse and use. For example, a dapp that cannot parse [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] -can request bip380-split-branches instead of trying to exclude [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] -while still naming all other standards. +can request bip380-split-branches instead of trying to +exclude [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] while still naming all other standards. + +===Descriptor disclosure and wallet state disclosure=== The profile separates descriptor disclosure from balance and UTXO disclosure. A public wallet descriptor is useful for derivation and verification, but it is not enough to compute confidential balances. getBalance and getUTXOs return wallet-computed values without exporting view descriptors or blinding secrets. -The profile permits public confidential descriptors only when the blinding material is public and -not recoverable as private view material from data disclosed to the dapp. +===Public confidential descriptors=== + +The profile permits public confidential descriptors only when the blinding material is public and not recoverable +as private view material from data disclosed to the dapp. It does not return [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] descriptors, -[https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private material, descriptor blinding private keys, -or descriptor blinding xprvs, because those forms let the holder unblind wallet outputs. +[https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private material, descriptor blinding +private keys, or descriptor blinding xprvs, because those forms let the holder unblind wallet outputs. + +===No caller-provided change address=== + +This profile does not define a caller-provided change address field for sendTransfer. +Caller-provided change addresses are a fund-loss footgun when the address is not wallet-owned or does not match wallet policy. +Wallets derive change internally instead. + +===PSET signing and response redaction=== + +PSET signing can expose more than signatures if a wallet adds wallet-derived blinding data to the returned PSET. +The signing method therefore requires wallet-side review and requires wallets to redact wallet-derived secrets from the +returned PSET or reject the request when safe redaction is not possible. + +===Identity shared keys=== + +The shared-key method returns an application key, not raw ECDH output. +Requiring HKDF-SHA256 and caller-provided domain-separation data that commits to the caller origin, +active chain_id, and account identifier prevents the same raw ECDH value from being reused across +protocols, origins, chains, or accounts. + +===Wallet ABI delegation=== -processConfidentialTransaction is delegated to the Wallet ABI transaction creation protocol to avoid duplicating -a larger confidential transaction schema in this profile. -This ELIP specifies the JSON-RPC binding and leaves the transaction object shapes to that protocol. +processConfidentialTransaction is delegated to the Wallet ABI transaction creation protocol to +avoid duplicating a larger confidential transaction schema in this profile. +This ELIP specifies the JSON-RPC binding and leaves account scoping, ABI versioning, transaction approval, +result shape, and artifact redaction rules to that protocol. Because the reference is still provisional, this ELIP +must be updated to point at a canonical Wallet ABI ELIP or upstream repository reference before finalization. ==Reference Implementation== @@ -1058,9 +1134,10 @@ TBD. The following values were derived and statically validated with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit].
-public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
-account_identifier       = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
-account                  = bip122:1466275836220db2944ca059a3a10ef6:ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
+public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
+dwid                     = b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
+account_identifier       = bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
+address_index_0          = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
 policy_asset_id          = bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d
 
@@ -1082,13 +1159,13 @@ slip0017_public_key = 045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f peer_public_key = 04c95ff5052c66d17ecbf08eafe00aade2071830b0bafc8e87b3debffbfa1b733272900303e6688e025f9744e6c6e6961c5861138cc4e909eeedd84c84311b5ca1 raw_shared_key = c78d6f0cde624fdbadb88c7d6af291530ee0a203938c7d88b6a2c5ab4d85d3c8 hkdf_salt = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f -hkdf_info = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631 -hkdf_shared_key = b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e +hkdf_info = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b65792076317c6f726967696e3d68747470733a2f2f6578616d706c652e636f6d7c636861696e5f69643d6269703132323a31343636323735383336323230646232393434636130353961336131306566367c6163636f756e743d6269703132323a31343636323735383336323230646232393434636130353961336131306566363a623738312d376263372d646236342d633364652d333933372d376562372d633961622d66373939 +hkdf_shared_key = fd1efbd05dbd13aa8e33d498f3d3b0e3b1a635fa1925fa64902fc43ac17524fb message_hash = 95b7987475f7157b80aa3c5087d910e44429f410cd3b12c25a652e9c2d480d89 message_signature = ded4c5a767265f1df01b5453da8df9d364d81775d780c8f52707573a68c485152f59a354eec5c935072eff8e6d14d3c6744659fc405cad88e395afd9493cdd3a00 -The following PSET values are constructed from an explicit policy-asset UTXO at the account identifier script and were parsed with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. The signed PSET was produced with the Liquid Wallet Kit signer for the same mnemonic. +The following PSET values are constructed from an explicit policy-asset UTXO at the example script and were parsed with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. The signed PSET was produced with the Liquid Wallet Kit signer for the same mnemonic.
 example_utxo_txid = 4b33bd9a251311bd7f247ea19b3cf9887977ba4d9abe2ec7886de24094252586

From 3468df034e40a02d18a147eb378d5775493624db Mon Sep 17 00:00:00 2001
From: Kyryl R 
Date: Thu, 28 May 2026 18:39:18 +0300
Subject: [PATCH 3/8] liquid-rpc-profile: clarified wording around the
 view-capable descriptor material

---
 elip-liquid-wallet-rpc-profile.mediawiki | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki
index 69e657f..7de7c2a 100644
--- a/elip-liquid-wallet-rpc-profile.mediawiki
+++ b/elip-liquid-wallet-rpc-profile.mediawiki
@@ -34,7 +34,7 @@ This document is licensed under the 3-clause BSD license.
 
 Bitcoin integrations can use public addresses and PSBTs as their main wallet-facing primitives.
 Liquid wallets require a more explicit profile because Liquid has confidential transactions, multiple issued assets,
-network-specific policy assets, CT descriptors, blinding material, and PSETs.
+network-specific policy assets, CT descriptors, blinding keys, and PSETs.
 
 Dapps need enough public wallet information to identify the connected account, construct descriptor-aware receive
 and change logic, read user-approved balances and UTXOs, and build valid PSET signing requests. At the same time,
@@ -57,7 +57,7 @@ The following terms are used throughout this ELIP.
 |-
 | chain_id || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain identifier: "bip122:" + first_32_lowercase_hex_characters_of_genesis_block_hash.
 |-
-| Public wallet descriptor || An ordinary Liquid/Elements output descriptor with public spend-key material and no ct(...) wrapper. It can derive scriptPubKeys and unconfidential addresses. It cannot derive confidential addresses, unblind outputs, or spend funds.
+| Public wallet descriptor || An ordinary Liquid/Elements output descriptor with public spend-key and no ct(...) wrapper. It can derive scriptPubKeys and unconfidential addresses. It cannot derive confidential addresses, unblind outputs, or spend funds.
 |-
 | Account identifier || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] Liquid account ID for the connected wallet account: chain_id + ":" + dwid. This value is used in accountIdentifier result fields and in account request parameters.
 |-
@@ -65,11 +65,11 @@ The following terms are used throughout this ELIP.
 |-
 | Connected account || The account identifier authorized for the active transport session.
 |-
-| Public confidential descriptor || An [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor with public blinding-key material only. It can derive confidential addresses. It cannot derive private blinding keys and cannot unblind outputs.
+| Public confidential descriptor || An [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor with public blinding-key only. It can derive confidential addresses. It cannot derive private blinding keys and cannot unblind outputs.
 |-
-| View descriptor || A CT descriptor that lets the holder derive private blinding keys or otherwise unblind wallet outputs. Examples include descriptors using [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private master blinding material, private descriptor blinding keys, descriptor blinding xprvs, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] ct(elip151, ). View descriptors MUST NOT be returned by this profile.
+| View descriptor || A CT descriptor that lets the holder derive private blinding keys or otherwise unblind wallet outputs. Examples include descriptors using [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private master blinding key, private descriptor blinding keys, descriptor blinding xprvs, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] ct(elip151, ). View descriptors MUST NOT be returned by this profile.
 |-
-| Wallet blinding policy || The wallet rule that determines how confidential addresses and output blinding keys are derived for a script tree, for example [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], public [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] blinding-key material, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151].
+| Wallet blinding policy || The wallet rule that determines how confidential addresses and output blinding keys are derived for a script tree, for example [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], public [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] blinding-key, or [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151].
 |-
 | Derived view material || Any descriptor, key, or deterministic derivation result that lets the holder derive private blinding keys or unblind wallet outputs.
 |-
@@ -118,7 +118,7 @@ Liquid testnet uses bip122:a771da8e52ee6ad581ed1e9a99825e5b.
 Custom Elements chains MUST use the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] bip122
 chain identifier derived from their own genesis block hash.
 
-Example account material:
+Example account identifier values:
 
 
 public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
@@ -264,7 +264,7 @@ Example result:
 
 ====getWalletDescriptor====
 
-This method returns public descriptor material for the connected Liquid account.
+This method returns public descriptor for the connected Liquid account.
 The caller selects the disclosure type with descriptorType and MAY provide an ordered accept
 list of descriptor format profiles that it can parse.
 
@@ -1055,7 +1055,7 @@ This profile specifies the event name and event.data shape; transpo
 * Wallets MUST treat getWalletDescriptor as descriptor disclosure and MUST only answer after descriptor disclosure is authorized by the active session or approved for the individual request. Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before per-request approval.
 * Wallets MUST treat [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], private-key, xprv, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] CT descriptors as view-capable material that is not exported by this profile.
 * Wallets MUST NOT return view-capable CT descriptors, private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, per-address private blinding keys, asset blinding factors, value blinding factors, or shared nonces through this profile. The only CT descriptor that may be returned is publicConfidentialDescriptor with public blinding-key material.
-* Wallets MUST NOT log view-capable descriptor material, private blinding material, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data.
+* Wallets MUST NOT log view-capable descriptor material, private blinding keys, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data.
 * Wallets that support processConfidentialTransaction MUST enforce the Wallet ABI version, account scope, transaction approval, result shape, and artifact redaction rules from the referenced Wallet ABI protocol.
 * Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active session and after the relevant session permission or per-request approval. The permission or approval MUST define the account, method, asset scope, and active-session lifetime.
 * Wallets MUST treat signPset as transaction approval, display sighash scope and wallet-computed net asset movement, and MUST redact wallet-derived blinding secrets from the PSET response or reject the request.
@@ -1092,10 +1092,10 @@ A public wallet descriptor is useful for derivation and verification, but it is
 
 ===Public confidential descriptors===
 
-The profile permits public confidential descriptors only when the blinding material is public and not recoverable
+The profile permits public confidential descriptors only when the blinding keys is public and not recoverable
 as private view material from data disclosed to the dapp.
 It does not return [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] descriptors,
-[https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private material, descriptor blinding
+[https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private keys, descriptor blinding
 private keys, or descriptor blinding xprvs, because those forms let the holder unblind wallet outputs.
 
 ===No caller-provided change address===

From b5178f29b940dc7d81f8bdd8fab21bdfaf3a990b Mon Sep 17 00:00:00 2001
From: Kyryl R 
Date: Fri, 29 May 2026 17:44:49 +0300
Subject: [PATCH 4/8] liquid-rpc-profile: addressed reviewer comments

---
 elip-liquid-wallet-rpc-profile.mediawiki | 196 +++++++++++------------
 1 file changed, 92 insertions(+), 104 deletions(-)

diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki
index 7de7c2a..4ff280c 100644
--- a/elip-liquid-wallet-rpc-profile.mediawiki
+++ b/elip-liquid-wallet-rpc-profile.mediawiki
@@ -34,7 +34,7 @@ This document is licensed under the 3-clause BSD license.
 
 Bitcoin integrations can use public addresses and PSBTs as their main wallet-facing primitives.
 Liquid wallets require a more explicit profile because Liquid has confidential transactions, multiple issued assets,
-network-specific policy assets, CT descriptors, blinding keys, and PSETs.
+network-specific policy assets, CT descriptors, blinding keys, PSETs, and Simplicity.
 
 Dapps need enough public wallet information to identify the connected account, construct descriptor-aware receive
 and change logic, read user-approved balances and UTXOs, and build valid PSET signing requests. At the same time,
@@ -53,6 +53,8 @@ The following terms are used throughout this ELIP.
 |-
 | Wallet || The wallet or wallet SDK that receives JSON-RPC requests, applies wallet policy, obtains user approval where needed, and returns JSON-RPC responses.
 |-
+| Wallet policy || The wallet's account-scoped rules for deriving scripts, selecting inputs, creating change, approving disclosures and signatures, and redacting secrets.
+|-
 | Active Liquid or Elements chain || The Liquid or Elements chain selected by the wallet. The active chain is identified on the wire by the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain_id.
 |-
 | chain_id || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain identifier: "bip122:" + first_32_lowercase_hex_characters_of_genesis_block_hash.
@@ -63,7 +65,7 @@ The following terms are used throughout this ELIP.
 |-
 | DWID || The Deterministic Wallet IDentifier defined by [https://github.com/ElementsProject/ELIPs/blob/main/elip-0152.mediawiki ELIP-0152]. In this profile, the DWID component of an account identifier MUST identify the same wallet descriptor set as the public wallet descriptor returned for the connected account.
 |-
-| Connected account || The account identifier authorized for the active transport session.
+| Connected account || The account identifier authorized for the active request or connection context.
 |-
 | Public confidential descriptor || An [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptor with public blinding-key only. It can derive confidential addresses. It cannot derive private blinding keys and cannot unblind outputs.
 |-
@@ -92,6 +94,8 @@ The following terms are used throughout this ELIP.
 
 The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [https://www.rfc-editor.org/rfc/rfc2119 RFC 2119].
 
+===General===
+
 Unless a method explicitly contains an account parameter, the wallet applies the method to the account
 authorized for the JSON-RPC request by the transport session. If more than one account is in scope and session
 context is insufficient to choose one, the wallet MUST reject the request or require an account-scoped request form.
@@ -174,7 +178,7 @@ bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928
 
 ===Descriptor disclosure and format profiles===
 
-The only descriptor disclosure types that getWalletDescriptor may return are publicWalletDescriptor
+The only descriptor disclosure types that this ELIP may return are publicWalletDescriptor
 and publicConfidentialDescriptor. A wallet MUST NOT return a viewDescriptor through this profile.
 
 The recognized descriptor format profiles are:
@@ -191,15 +195,7 @@ The recognized descriptor format profiles are:
 | elip150-public-ct-split-branches || publicConfidentialDescriptor || Separate external and internal [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] CT descriptors without multipath syntax || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-0150] plus the standards used by bip380-split-branches
 |}
 
-A wallet MAY define additional format profiles in a future revision. A wallet MUST ignore unknown accept
-entries when it can satisfy another entry in the same request. If no requested format is supported or permitted
-by wallet policy, the wallet MUST return a JSON-RPC error with reason = "unsupported_descriptor_format"
-and SHOULD include the requested and supported format profile names in error.data.
-
-Returned descriptors MUST be normalized and include a valid [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] checksum.
-Wallets MUST ensure that every descriptor returned in one response belongs to the same connected account identifier.
-For publicConfidentialDescriptor, the embedded ordinary descriptor MUST describe the same script tree as the corresponding publicWalletDescriptor.
-Dapps MUST verify descriptor checksums before using returned descriptors.
+Future ELIPs MAY define additional descriptor format profiles.
 
 ===RPC methods===
 
@@ -265,19 +261,17 @@ Example result:
 ====getWalletDescriptor====
 
 This method returns public descriptor for the connected Liquid account.
-The caller selects the disclosure type with descriptorType and MAY provide an ordered accept
+The caller selects the disclosure type with descriptorType and MAY provide an ordered descriptorFormat
 list of descriptor format profiles that it can parse.
 
-Descriptor disclosure is watch-only script-graph disclosure. Wallets MUST NOT return publicWalletDescriptor
-or publicConfidentialDescriptor unless descriptor disclosure for the connected account is authorized by
-the active session or approved for the individual request. The default descriptorType is
-publicWalletDescriptor, but the default only selects the requested disclosure type; it does not remove
-the authorization or approval requirement.
+The default descriptorType is publicWalletDescriptor.
+Wallets MUST require request-context permission or per-request user approval before returning any descriptor,
+including publicWalletDescriptor.
 Wallets MUST NOT return publicConfidentialDescriptor unless it was explicitly requested and approved.
 Wallets MUST NOT return viewDescriptor from this method.
 
-If accept is provided, the wallet MUST return one of the requested format profiles or reject the request.
-If accept is omitted, the wallet MAY choose any supported format profile for the requested descriptorType
+If descriptorFormat is provided, the wallet MUST return one of the requested format profiles or reject the request.
+If descriptorFormat is omitted, the wallet MAY choose any supported format profile for the requested descriptorType
 and MUST identify the selected profile in the result.
 
 {| class="wikitable"
@@ -285,10 +279,10 @@ and MUST identify the selected profile in the result.
 |-
 | descriptorType || String || No || Requested descriptor disclosure type. Valid values are publicWalletDescriptor and publicConfidentialDescriptor. Default is publicWalletDescriptor.
 |-
-| accept || Array || No || Ordered descriptor format profiles accepted by the dapp. Each entry is an object with a required format field. Unknown formats are ignored if another accepted format can be returned.
+| descriptorFormat || Array || No || Ordered descriptor format profiles accepted by the dapp. Each entry is an object with a required format field. Unknown formats are ignored if another accepted format can be returned.
 |}
 
-Allowed accept[].format values are bip380-bip389-multipath, bip380-split-branches,
+Allowed descriptorFormat[].format values are bip380-bip389-multipath, bip380-split-branches,
 elip150-public-ct-bip389-multipath, and elip150-public-ct-split-branches.
 
 {| class="wikitable"
@@ -329,14 +323,23 @@ Each descriptor entry has the following fields:
 | canUnblindOutputs || Boolean || Yes || MUST be false for every descriptor returned by this profile.
 |}
 
-Wallets MUST reject unsupported descriptorType values. Wallets MUST NOT return any descriptor type that
-was not requested. Wallets MUST verify that the session permission or per-request approval covers the requested
-descriptorType and selected descriptor format profile. Wallets SHOULD respect the order of the accept list.
+Wallets MUST reject unsupported descriptorType values.
+Wallets MUST NOT return any descriptor type that was not requested.
+Wallets MUST respect the order of the descriptorFormat list when more than one requested format is supported and permitted.
+
+Returned descriptors MUST be normalized and include a valid [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-380] checksum.
+Wallets MUST ensure that every descriptor returned in one response belongs to the same connected account identifier.
+For publicConfidentialDescriptor, the embedded ordinary descriptor MUST describe the same script tree as the corresponding publicWalletDescriptor.
+Dapps MUST verify descriptor checksums before using returned descriptors.
+
 Wallets MUST NOT return private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys,
 descriptor blinding xprvs, asset blinding factors, value blinding factors, shared nonces, or per-address private blinding keys.
 Wallets MUST return the [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account identifier
 for the same descriptor set as the returned public wallet descriptor, even when returning a public confidential descriptor.
 
+If no requested format is supported or permitted by wallet policy, the wallet MUST return a JSON-RPC error
+with reason = "unsupported_descriptor_format"and SHOULD include the requested and supported format profile names in error.data.
+
 Example request for a public wallet descriptor with [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath fallback to split branches:
 
 
@@ -346,7 +349,7 @@ Example request for a public wallet descriptor with [https://github.com/bitcoin/
   "method": "getWalletDescriptor",
   "params": {
     "descriptorType": "publicWalletDescriptor",
-    "accept": [
+    "descriptorFormat": [
       { "format": "bip380-bip389-multipath" },
       { "format": "bip380-split-branches" }
     ]
@@ -408,10 +411,7 @@ ct(036907dadd77ba1798e89237874c52c6c6954b2f64490d48aadc5b0cbed3f589d5,elwpkh([73
 
 This method returns the wallet-computed balance for the connected Liquid account. The only filter parameter
 is assetId. Wallets MUST treat this method as account-state disclosure and MUST require either
-session authorization for balance reads or per-request user approval. The authorization or approval MUST identify
-the connected account and whether it covers the policy asset, the requested assetId, or all assets, and
-it MUST be bounded by the active session lifetime. If the requested asset scope is not authorized by the session,
-the wallet MUST require per-request approval.
+request-context authorization for balance reads or per-request user approval.
 If assetId is omitted, the wallet MUST return the balance for the network policy asset.
 If assetId is provided, the wallet MUST return the balance for that exact
 [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID and MUST reject the
@@ -473,11 +473,8 @@ Example result:
 ====getUTXOs====
 
 This method returns UTXOs for the connected Liquid account. The only filter parameter is assetId.
-Wallets MUST treat this method as account-state disclosure and MUST require either session authorization
-for UTXO reads or per-request user approval. The authorization or approval MUST identify the connected account
-and whether it covers the policy asset, the requested assetId, or all assets, and it MUST be bounded by
-the active session lifetime. If the requested asset scope is not authorized by the session, the wallet MUST require
-per-request approval.
+Wallets MUST treat this method as account-state disclosure and MUST require either request-context authorization
+for UTXO reads or per-request user approval.
 If assetId is omitted, the wallet MUST return UTXOs for the network policy asset.
 If assetId is provided, the wallet MUST return UTXOs for that exact [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID
 and MUST reject the request if the asset ID chain_id does not match the active Liquid or Elements chain.
@@ -524,7 +521,7 @@ Each UTXO entry has the following fields:
 |-
 | scriptPubKey || String || Yes || Raw scriptPubKey bytes as lowercase hex without 0x.
 |-
-| txOut || String || Yes || Raw Elements TxOut consensus serialization as lowercase hex without 0x.
+| txOut || String || Yes || Raw Elements TxOut consensus serialization as lowercase hex without 0x. It excludes output witness data.
 |-
 | confidential || Boolean || Yes || Whether the previous output is confidential.
 |-
@@ -536,7 +533,7 @@ Wallets MUST return an empty utxos array when the connected account
 Dapps that construct a PSET from returned UTXOs SHOULD include the returned txOut as the previous output
 for the corresponding PSET input and SHOULD use the returned address in signPset.signInputs.
 Wallets MUST re-check ownership, asset, amount, and confidentiality data during signPset; dapp-provided PSET
-data is not trusted merely because it was based on getUTXOs output.
+data MUST NOT be trusted merely because it was based on getUTXOs output.
 
 Example request:
 
@@ -585,7 +582,7 @@ This method returns the deterministic public key used for identity-signing flows
 It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013].
 The identity key is not a transaction spend key and MUST NOT be derived from a wallet address path.
 Wallets MUST display the identity string, curve, and index before approval unless the exact identity key disclosure
-is already authorized by the session.
+is already authorized by the request context.
 
 {| class="wikitable"
 ! Parameter !! Type !! Required !! Description
@@ -608,7 +605,7 @@ is already authorized by the session.
 |-
 | type || String || Yes || MUST be slip-0013.
 |-
-| publicKey || String || Yes || Uncompressed public key as lowercase hex without 0x.
+| publicKey || String || Yes || Uncompressed 65-byte public key as 130 lowercase hex characters without 0x.
 |}
 
 Example request:
@@ -649,10 +646,8 @@ It follows [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0
 [https://www.rfc-editor.org/rfc/rfc5869 RFC 5869] HKDF-SHA256 for the returned key.
 
 Wallets MUST validate that theirPublicKey is a valid point on nist256p1 and MUST reject invalid,
-low-order, or unsupported public keys. Wallets MUST bind authorization for this method to the authenticated caller
-origin or transport identity and to the connected account. Wallets MUST display the identity string, counterparty
-key fingerprint, curve, index, connected account, and domain-separation context before approval unless the exact
-origin-bound and account-bound request is already authorized by the session.
+low-order, or unsupported public keys. Wallets MUST display the identity string, counterparty key fingerprint,
+curve, index, and domain-separation context before approval unless the exact request is already authorized by the request context.
 
 {| class="wikitable"
 ! Parameter !! Type !! Required !! Description
@@ -661,7 +656,7 @@ origin-bound and account-bound request is already authorized by the session.
 |-
 | curve || String || Yes || Supported value: nist256p1.
 |-
-| theirPublicKey || String || Yes || Counterparty uncompressed public key as lowercase hex without 0x.
+| theirPublicKey || String || Yes || Counterparty uncompressed 65-byte public key as 130 lowercase hex characters without 0x.
 |-
 | index || Integer || No || Identity-key index. Default is 0.
 |-
@@ -669,7 +664,7 @@ origin-bound and account-bound request is already authorized by the session.
 |-
 | kdfSalt || String || Yes || HKDF salt bytes as lowercase hex without 0x.
 |-
-| kdfInfo || String || Yes || HKDF info bytes as lowercase hex without 0x. The value MUST domain-separate the intended protocol and MUST commit to the dapp origin or transport identity, active chain_id, and account identifier. Wallets MUST reject the request when this context is absent or inconsistent with the authenticated caller or connected account.
+| kdfInfo || String || Yes || HKDF info bytes as lowercase hex without 0x. The value MUST domain-separate the intended protocol and MUST commit to the application origin or authenticated caller identity when available, active chain_id, and account identifier.
 |}
 
 {| class="wikitable"
@@ -683,7 +678,7 @@ origin-bound and account-bound request is already authorized by the session.
 |-
 | type || String || Yes || MUST be slip-0017.
 |-
-| publicKey || String || Yes || Wallet identity public key as lowercase hex without 0x.
+| publicKey || String || Yes || Wallet identity uncompressed 65-byte public key as 130 lowercase hex characters without 0x.
 |-
 | sharedKey || String || Yes || HKDF-SHA256 output as lowercase hex without 0x.
 |-
@@ -704,7 +699,7 @@ Example request:
     "index": 0,
     "kdf": "hkdf-sha256",
     "kdfSalt": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
-    "kdfInfo": "4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b65792076317c6f726967696e3d68747470733a2f2f6578616d706c652e636f6d7c636861696e5f69643d6269703132323a31343636323735383336323230646232393434636130353961336131306566367c6163636f756e743d6269703132323a31343636323735383336323230646232393434636130353961336131306566363a623738312d376263372d646236342d633364652d333933372d376562372d633961622d66373939"
+    "kdfInfo": "4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631"
   }
 }
 
@@ -721,7 +716,7 @@ Example result: "index": 0, "type": "slip-0017", "publicKey": "045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f23589c696aba3c36c1b08eae7a3c8b9d81878ccddf84adce4d72811867de60922f70fa1a", - "sharedKey": "fd1efbd05dbd13aa8e33d498f3d3b0e3b1a635fa1925fa64902fc43ac17524fb", + "sharedKey": "b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e", "kdf": "hkdf-sha256" } } @@ -733,7 +728,7 @@ This method signs a caller-provided challenge with the deterministic identity-si It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. This method is for identity proof and MUST NOT be displayed or interpreted as transaction approval. Wallets MUST display the identity string, challenge summary, curve, and index before approval unless the exact -signing request is already authorized by the session. +signing request is already authorized by the request context. {| class="wikitable" ! Parameter !! Type !! Required !! Description @@ -742,7 +737,7 @@ signing request is already authorized by the session. |- | curve || String || Yes || Supported value: nist256p1. |- -| challenge || String || Yes || Challenge bytes as lowercase hex without 0x. +| challenge || String || Yes || Challenge bytes as lowercase hex without 0x. Bytes length MAY depend on the wallet implementation. |- | index || Integer || No || Identity-key index. Default is 0. |} @@ -758,7 +753,7 @@ signing request is already authorized by the session. |- | type || String || Yes || MUST be slip-0013. |- -| publicKey || String || Yes || Uncompressed public key as lowercase hex without 0x. +| publicKey || String || Yes || Uncompressed 65-byte public key as 130 lowercase hex characters without 0x. |- | signature || String || Yes || Identity signature as lowercase hex without 0x. |} @@ -806,13 +801,18 @@ Wallets MUST NOT sign inputs that are not explicitly listed in signInputs< {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| pset || String || Yes || Base64-encoded PSET. +| pset || String || Yes || Base64-encoded complete PSET serialization. |- | signInputs || Array || Yes || Inputs that the wallet is requested to sign. |- | broadcast || Boolean || No || If true, the wallet MAY finalize and broadcast the transaction after signing. Default is false. |} +The pset parameter MUST be the base64 encoding of a complete PSET serialization, including the PSET magic bytes, +global map, input maps, output maps, and map separators defined by the Elements PSET format. It MUST NOT be a raw Elements +transaction, a transaction hex string, or a Bitcoin PSBT. Transaction data to be reviewed and signed MUST be present in the PSET +or be available from wallet state for wallet-owned inputs. + Each signInputs entry has the following fields: {| class="wikitable" @@ -865,16 +865,14 @@ Wallets MUST verify that each listed address corresponds to the inp to a descriptor path controlled by the connected wallet. Wallets MUST verify all confidential transaction data needed for safe signing from the PSET and wallet policy. This method does not define separate asset metadata, review hints, output hints, or trusted-commitment fields. + Wallets MUST display the requested input indexes, allowed sighash modes, broadcast flag, and wallet-computed net asset movement before approval. Wallets MUST reject the request if they cannot compute a safe review of wallet inputs, wallet outputs, fees, and confidentiality status. + Before returning a PSET, wallets MUST NOT add wallet-derived blinding private keys, master blinding keys, descriptor blinding private keys, asset blinding factors, value blinding factors, shared nonces, or other unblinding secrets. -If a received PSET already contains such data, including fields such -as [https://github.com/ElementsProject/ELIPs/blob/main/elip-0102.mediawiki ELIP-0102] asset blinding factor extensions, -or if wallet signing would otherwise add such data, wallets MUST redact wallet-derived secrets before returning the PSET. -If redaction is not possible without changing the requested signing result, wallets MUST reject the request instead of -returning a PSET that contains wallet-derived unblinding secrets. + When signing a PSET constructed from getUTXOs results, wallets MUST verify that each signed input still refers to a known wallet UTXO and that the PSET previous-output data matches wallet state. If broadcast is true, wallets MAY broadcast only after the transaction is complete and user approval covers broadcast. @@ -994,9 +992,9 @@ Wallets that support this method MUST implement it as described by the [https://github.com/KyrylR/ELIPs/blob/c946695f75f98477008bad0059d2894696bbaadd/elip-wallet-abi.mediawiki Wallet ABI Transaction Creation Protocol]. The JSON-RPC request MUST carry the Wallet ABI transaction request object. The JSON-RPC result MUST carry the Wallet ABI transaction response object. -Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, approval requirements, or redaction -requirements are not supported or authorized. The Wallet ABI reference above is provisional; before this ELIP is finalized, -it MUST be replaced by a canonical Wallet ABI ELIP or upstream repository reference. +Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, approval requirements are not supported or authorized. + +// TODO The Wallet ABI reference above is provisional; before this ELIP is finalized, it MUST be replaced by a canonical Wallet ABI ELIP or upstream repository reference. ===Events=== @@ -1010,56 +1008,48 @@ when the account identifier for the connected account changes, or when the network policy asset ID changes because the wallet switched Liquid or Elements chains. Wallets MUST NOT emit viewDescriptor, view-capable descriptor material, or blinding secrets through this event. Descriptor entries in event data MUST be publicWalletDescriptor or publicConfidentialDescriptor -and MUST match descriptor disclosure authorized for the session. +and MUST match descriptor disclosure authorized for the request context. -Example session_event payload as received by a dapp: +Example event object:
 {
-  "id": 1675759795769538,
-  "topic": "95d6aca451b8e3c6d9d176761bf786f1cc0a6d38dffd31ed896306bb37f6ae8d",
-  "params": {
-    "event": {
-      "name": "bip122_walletDescriptorChanged",
-      "data": {
-        "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
-        "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799",
-        "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
-        "descriptors": [
-          {
-            "descriptorType": "publicWalletDescriptor",
-            "format": "bip380-bip389-multipath",
-            "branchLayout": "multipath",
-            "standardsUsed": ["bip-0032", "bip-0044", "slip-0044", "bip-0084", "bip-0380", "bip-0389"],
-            "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv",
-            "canDeriveScriptPubKeys": true,
-            "canDeriveConfidentialAddresses": false,
-            "canUnblindOutputs": false
-          }
-        ]
+  "name": "bip122_walletDescriptorChanged",
+  "data": {
+    "chainId": "bip122:1466275836220db2944ca059a3a10ef6",
+    "accountIdentifier": "bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799",
+    "policyAssetId": "bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
+    "descriptors": [
+      {
+        "descriptorType": "publicWalletDescriptor",
+        "format": "bip380-bip389-multipath",
+        "branchLayout": "multipath",
+        "standardsUsed": ["bip-0032", "bip-0044", "slip-0044", "bip-0084", "bip-0380", "bip-0389"],
+        "descriptor": "elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv",
+        "canDeriveScriptPubKeys": true,
+        "canDeriveConfidentialAddresses": false,
+        "canUnblindOutputs": false
       }
-    },
-    "chainId": "bip122:1466275836220db2944ca059a3a10ef6"
+    ]
   }
 }
 
-In the example above, id, topic, and other fields outside params.event are illustrative transport fields. -This profile specifies the event name and event.data shape; transport-layer fields are controlled by the transport used by the implementation. +This profile specifies the event name and data shape. Envelope fields such as request identifiers, +routing metadata, or delivery acknowledgements are outside this profile and are controlled by the implementation context. ==Security Considerations== * Wallets MUST validate that every chainId, account, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] assetId refers to the active Liquid or Elements chain. * Wallets MUST derive the active chain ID from node or runtime context, not from user-facing labels such as Liquid, testnet-liquid, or localtest-liquid. * Wallets MUST display asset, amount, recipient, fee asset, broadcast status, and confidentiality status before approving sendTransfer. -* Wallets MUST treat getWalletDescriptor as descriptor disclosure and MUST only answer after descriptor disclosure is authorized by the active session or approved for the individual request. Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before per-request approval. +* Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before approving getWalletDescriptor. * Wallets MUST treat [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], private-key, xprv, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] CT descriptors as view-capable material that is not exported by this profile. * Wallets MUST NOT return view-capable CT descriptors, private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, per-address private blinding keys, asset blinding factors, value blinding factors, or shared nonces through this profile. The only CT descriptor that may be returned is publicConfidentialDescriptor with public blinding-key material. * Wallets MUST NOT log view-capable descriptor material, private blinding keys, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data. -* Wallets that support processConfidentialTransaction MUST enforce the Wallet ABI version, account scope, transaction approval, result shape, and artifact redaction rules from the referenced Wallet ABI protocol. -* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active session and after the relevant session permission or per-request approval. The permission or approval MUST define the account, method, asset scope, and active-session lifetime. -* Wallets MUST treat signPset as transaction approval, display sighash scope and wallet-computed net asset movement, and MUST redact wallet-derived blinding secrets from the PSET response or reject the request. -* Wallets MUST require domain separation for getIdentitySharedKey by applying hkdf-sha256 with caller-provided salt and info that commits to the authenticated caller origin or transport identity, active chain_id, and account identifier. +* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active request or connection context and after the relevant request-context permission or per-request approval. +* Wallets MUST treat signPset as transaction approval, display sighash scope and wallet-computed net asset movement, and MUST redact or reject PSET responses that would return wallet-derived blinding secrets. +* Wallets MUST require domain separation for getIdentitySharedKey by applying hkdf-sha256 with caller-provided salt and info that binds the protocol, caller context when available, active chain_id, and account identifier. * Dapps MUST NOT assume that a public descriptor or an account identifier is sufficient to calculate balances or reconstruct the wallet UTXO set. * Identity keys MUST be domain-separated from transaction spend keys and descriptor blinding keys. @@ -1077,8 +1067,8 @@ The full account identifier remains the value that is persisted and compared. ===Descriptor format profiles=== -Descriptor format negotiation is expressed as an ordered accept list of descriptor format profiles rather -than as a list of individual BIPs, SLIPs, and ELIPs. +An ordered descriptorFormat list identifies supported descriptor format profiles instead of an array of ELIPs +list to simplify wallet integration with dapps. This keeps the request focused on what the dapp can parse and use. For example, a dapp that cannot parse [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] can request bip380-split-branches instead of trying to @@ -1092,7 +1082,7 @@ A public wallet descriptor is useful for derivation and verification, but it is ===Public confidential descriptors=== -The profile permits public confidential descriptors only when the blinding keys is public and not recoverable +The profile permits public confidential descriptors only when the blinding keys are public and not recoverable as private view material from data disclosed to the dapp. It does not return [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] descriptors, [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077] private keys, descriptor blinding @@ -1107,23 +1097,21 @@ Wallets derive change internally instead. ===PSET signing and response redaction=== PSET signing can expose more than signatures if a wallet adds wallet-derived blinding data to the returned PSET. -The signing method therefore requires wallet-side review and requires wallets to redact wallet-derived secrets from the -returned PSET or reject the request when safe redaction is not possible. +The signing method therefore requires wallet-side review and requires wallets to redact or reject returned PSETs +that would expose wallet-derived blinding secrets. ===Identity shared keys=== The shared-key method returns an application key, not raw ECDH output. -Requiring HKDF-SHA256 and caller-provided domain-separation data that commits to the caller origin, -active chain_id, and account identifier prevents the same raw ECDH value from being reused across -protocols, origins, chains, or accounts. +Requiring HKDF-SHA256 and caller-provided domain-separation data prevents the same raw ECDH value +from being reused across protocols or origins. ===Wallet ABI delegation=== processConfidentialTransaction is delegated to the Wallet ABI transaction creation protocol to avoid duplicating a larger confidential transaction schema in this profile. This ELIP specifies the JSON-RPC binding and leaves account scoping, ABI versioning, transaction approval, -result shape, and artifact redaction rules to that protocol. Because the reference is still provisional, this ELIP -must be updated to point at a canonical Wallet ABI ELIP or upstream repository reference before finalization. +result shape, and artifact redaction rules to that protocol. ==Reference Implementation== @@ -1159,8 +1147,8 @@ slip0017_public_key = 045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f peer_public_key = 04c95ff5052c66d17ecbf08eafe00aade2071830b0bafc8e87b3debffbfa1b733272900303e6688e025f9744e6c6e6961c5861138cc4e909eeedd84c84311b5ca1 raw_shared_key = c78d6f0cde624fdbadb88c7d6af291530ee0a203938c7d88b6a2c5ab4d85d3c8 hkdf_salt = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f -hkdf_info = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b65792076317c6f726967696e3d68747470733a2f2f6578616d706c652e636f6d7c636861696e5f69643d6269703132323a31343636323735383336323230646232393434636130353961336131306566367c6163636f756e743d6269703132323a31343636323735383336323230646232393434636130353961336131306566363a623738312d376263372d646236342d633364652d333933372d376562372d633961622d66373939 -hkdf_shared_key = fd1efbd05dbd13aa8e33d498f3d3b0e3b1a635fa1925fa64902fc43ac17524fb +hkdf_info = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631 +hkdf_shared_key = b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e message_hash = 95b7987475f7157b80aa3c5087d910e44429f410cd3b12c25a652e9c2d480d89 message_signature = ded4c5a767265f1df01b5453da8df9d364d81775d780c8f52707573a68c485152f59a354eec5c935072eff8e6d14d3c6744659fc405cad88e395afd9493cdd3a00
From 5774f5533dd726678ebbc4cdcf0ae8d7593cb861 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Mon, 1 Jun 2026 12:38:22 +0300 Subject: [PATCH 5/8] liquid-rpc-profile: update the signPset and reformat TODO --- elip-liquid-wallet-rpc-profile.mediawiki | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki index 4ff280c..615a75e 100644 --- a/elip-liquid-wallet-rpc-profile.mediawiki +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -808,10 +808,10 @@ Wallets MUST NOT sign inputs that are not explicitly listed in signInputs< | broadcast || Boolean || No || If true, the wallet MAY finalize and broadcast the transaction after signing. Default is false. |} -The pset parameter MUST be the base64 encoding of a complete PSET serialization, including the PSET magic bytes, -global map, input maps, output maps, and map separators defined by the Elements PSET format. It MUST NOT be a raw Elements -transaction, a transaction hex string, or a Bitcoin PSBT. Transaction data to be reviewed and signed MUST be present in the PSET -or be available from wallet state for wallet-owned inputs. +The method MUST ignore signing inputs that were not requested. + +During the signing process, a PSET can contain Simplicity inputs or any other inputs for which the wallet cannot provide valid witness data. +Therefore, if the user requests signing for such an input, the wallet MUST return an error. Each signInputs entry has the following fields: @@ -994,7 +994,7 @@ The JSON-RPC request MUST carry the Wallet ABI transaction request object. The JSON-RPC result MUST carry the Wallet ABI transaction response object. Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, approval requirements are not supported or authorized. -// TODO The Wallet ABI reference above is provisional; before this ELIP is finalized, it MUST be replaced by a canonical Wallet ABI ELIP or upstream repository reference. + ===Events=== From 510a0257907fe7acdbf22bdfc3e77b79ed343cd7 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Mon, 1 Jun 2026 12:42:48 +0300 Subject: [PATCH 6/8] liquid-rpc-profile: removed security section, reformatted section headers --- elip-liquid-wallet-rpc-profile.mediawiki | 43 ++++++++---------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki index 615a75e..8bb1380 100644 --- a/elip-liquid-wallet-rpc-profile.mediawiki +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -94,7 +94,7 @@ The following terms are used throughout this ELIP. The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [https://www.rfc-editor.org/rfc/rfc2119 RFC 2119]. -===General=== +==General== Unless a method explicitly contains an account parameter, the wallet applies the method to the account authorized for the JSON-RPC request by the transport session. If more than one account is in scope and session @@ -197,9 +197,9 @@ The recognized descriptor format profiles are: Future ELIPs MAY define additional descriptor format profiles. -===RPC methods=== +==RPC methods== -====sendTransfer==== +===sendTransfer=== This method signs and submits a transfer of a Liquid asset to a single recipient address. If assetId is omitted, the wallet MUST send the network policy asset. If assetId is present, @@ -258,7 +258,7 @@ Example result: }
-====getWalletDescriptor==== +===getWalletDescriptor=== This method returns public descriptor for the connected Liquid account. The caller selects the disclosure type with descriptorType and MAY provide an ordered descriptorFormat @@ -407,7 +407,7 @@ Example public confidential descriptor: ct(036907dadd77ba1798e89237874c52c6c6954b2f64490d48aadc5b0cbed3f589d5,elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*))#em5whsyz -====getBalance==== +===getBalance=== This method returns the wallet-computed balance for the connected Liquid account. The only filter parameter is assetId. Wallets MUST treat this method as account-state disclosure and MUST require either @@ -470,7 +470,7 @@ Example result: } -====getUTXOs==== +===getUTXOs=== This method returns UTXOs for the connected Liquid account. The only filter parameter is assetId. Wallets MUST treat this method as account-state disclosure and MUST require either request-context authorization @@ -576,7 +576,7 @@ Example result: } -====getIdentityPublicKey==== +===getIdentityPublicKey=== This method returns the deterministic public key used for identity-signing flows. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. @@ -639,7 +639,7 @@ Example result: } -====getIdentitySharedKey==== +===getIdentitySharedKey=== This method returns a domain-separated shared key for an identity and a counterparty public key. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017] for identity-key derivation and @@ -722,7 +722,7 @@ Example result: } -====signIdentity==== +===signIdentity=== This method signs a caller-provided challenge with the deterministic identity-signing key. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. @@ -791,7 +791,7 @@ Example result: } -====signPset==== +===signPset=== This method requests signatures for a PSET. Wallets MUST reject PSETs that cannot be associated with the active Liquid or Elements chain. @@ -912,7 +912,7 @@ Example result: } -====signMessage==== +===signMessage=== This method signs a message with the spend key for a connected Liquid address. Message signing uses spend keys, not descriptor blinding keys or view keys. @@ -984,7 +984,7 @@ Example result: } -====processConfidentialTransaction==== +===processConfidentialTransaction=== This method is optional. It delegates request and response shape to the Wallet ABI transaction creation protocol. @@ -996,9 +996,9 @@ Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, -===Events=== +==Events== -====bip122_walletDescriptorChanged==== +===bip122_walletDescriptorChanged=== This event notifies dapps that descriptor metadata for the connected Liquid account changed. The event data has the same shape as the getWalletDescriptor result. @@ -1038,21 +1038,6 @@ Example event object: This profile specifies the event name and data shape. Envelope fields such as request identifiers, routing metadata, or delivery acknowledgements are outside this profile and are controlled by the implementation context. -==Security Considerations== - -* Wallets MUST validate that every chainId, account, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] assetId refers to the active Liquid or Elements chain. -* Wallets MUST derive the active chain ID from node or runtime context, not from user-facing labels such as Liquid, testnet-liquid, or localtest-liquid. -* Wallets MUST display asset, amount, recipient, fee asset, broadcast status, and confidentiality status before approving sendTransfer. -* Wallets MUST display descriptor type, selected descriptor format, and disclosure consequences before approving getWalletDescriptor. -* Wallets MUST treat [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-0077], private-key, xprv, and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-0151] CT descriptors as view-capable material that is not exported by this profile. -* Wallets MUST NOT return view-capable CT descriptors, private spend keys, spend descriptors, master blinding keys, descriptor blinding private keys, descriptor blinding xprvs, per-address private blinding keys, asset blinding factors, value blinding factors, or shared nonces through this profile. The only CT descriptor that may be returned is publicConfidentialDescriptor with public blinding-key material. -* Wallets MUST NOT log view-capable descriptor material, private blinding keys, identity shared keys, intermediate PSETs containing secrets, or Wallet ABI payloads containing unblinding data. -* Wallets MUST treat getBalance and getUTXOs as account-state disclosure methods and MUST only answer them for accounts authorized in the active request or connection context and after the relevant request-context permission or per-request approval. -* Wallets MUST treat signPset as transaction approval, display sighash scope and wallet-computed net asset movement, and MUST redact or reject PSET responses that would return wallet-derived blinding secrets. -* Wallets MUST require domain separation for getIdentitySharedKey by applying hkdf-sha256 with caller-provided salt and info that binds the protocol, caller context when available, active chain_id, and account identifier. -* Dapps MUST NOT assume that a public descriptor or an account identifier is sufficient to calculate balances or reconstruct the wallet UTXO set. -* Identity keys MUST be domain-separated from transaction spend keys and descriptor blinding keys. - ==Rationale== ===ELIP-0144 account identifiers=== From 05837a64156394c7f401b1d7c6f83388e514c9b2 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Mon, 1 Jun 2026 16:26:45 +0300 Subject: [PATCH 7/8] liquid-rpc-profile: fix grammar, remove test vectors --- elip-liquid-wallet-rpc-profile.mediawiki | 204 +++++++++-------------- 1 file changed, 79 insertions(+), 125 deletions(-) diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki index 8bb1380..9106225 100644 --- a/elip-liquid-wallet-rpc-profile.mediawiki +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -201,7 +201,7 @@ Future ELIPs MAY define additional descriptor format profiles. ===sendTransfer=== -This method signs and submits a transfer of a Liquid asset to a single recipient address. If assetId +This method is used to sign and submit a transfer of a Liquid asset to a single recipient address. If assetId is omitted, the wallet MUST send the network policy asset. If assetId is present, it MUST be an [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID whose chain_id matches the active Liquid or Elements chain. @@ -213,21 +213,21 @@ The transaction MUST be constructed, blinded whenever possible, signed, and broa {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| recipientAddress || String || Yes || Recipient Liquid address. Confidential addresses SHOULD be used. +| recipientAddress || String || Yes || The recipient's Liquid address. Confidential addresses SHOULD be used. |- -| amount || String || Yes || Amount in the asset base unit, encoded as a decimal string. +| amount || String || Yes || The amount to send in the asset base unit, encoded as a decimal string. |- -| assetId || String || No || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. +| assetId || String || No || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. |- -| account || String || No || Connected account. If omitted, the wallet chooses the connected account according to session context and MUST show the selected account before approval. +| account || String || No || The connected account. If omitted, the wallet chooses the connected account according to the session context and MUST show the selected account before approval. |- -| memo || String || No || Hex-encoded bytes without 0x. Wallets that support memos MUST encode the value as an OP_RETURN output and MUST enforce a maximum of 80 bytes. +| memo || String || No || The hex-encoded bytes without 0x. Wallets that support memos MUST encode the value as an OP_RETURN output and MUST enforce a maximum of 80 bytes. |} {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| txid || String || Yes || Transaction ID as 64 lowercase hex characters. +| txid || String || Yes || The transaction ID as 64 lowercase hex characters. |} Example request: @@ -260,7 +260,7 @@ Example result: ===getWalletDescriptor=== -This method returns public descriptor for the connected Liquid account. +This method returns a public descriptor for the connected Liquid account. The caller selects the disclosure type with descriptorType and MAY provide an ordered descriptorFormat list of descriptor format profiles that it can parse. @@ -277,9 +277,9 @@ and MUST identify the selected profile in the result. {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| descriptorType || String || No || Requested descriptor disclosure type. Valid values are publicWalletDescriptor and publicConfidentialDescriptor. Default is publicWalletDescriptor. +| descriptorType || String || No || The requested descriptor disclosure type. Valid values are publicWalletDescriptor and publicConfidentialDescriptor. Default is publicWalletDescriptor. |- -| descriptorFormat || Array || No || Ordered descriptor format profiles accepted by the dapp. Each entry is an object with a required format field. Unknown formats are ignored if another accepted format can be returned. +| descriptorFormat || Array || No || The ordered descriptor format profiles accepted by the dapp. Each entry is an object with a required format field. Unknown formats are ignored if another accepted format can be returned. |} Allowed descriptorFormat[].format values are bip380-bip389-multipath, bip380-split-branches, @@ -288,13 +288,13 @@ Allowed descriptorFormat[].format values are bip380-bip389-mu {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +| chainId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. +| accountIdentifier || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- -| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +| policyAssetId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- -| descriptors || Array || Yes || Descriptor entries returned by the wallet. Every entry MUST match the requested descriptorType and selected format profile. +| descriptors || Array || Yes || The descriptor entries returned by the wallet. Every entry MUST match the requested descriptorType and selected format profile. |} Each descriptor entry has the following fields: @@ -304,21 +304,21 @@ Each descriptor entry has the following fields: |- | descriptorType || String || Yes || publicWalletDescriptor or publicConfidentialDescriptor. |- -| format || String || Yes || Selected descriptor format profile. +| format || String || Yes || The selected descriptor format profile. |- | branchLayout || String || Yes || multipath or split. |- -| standardsUsed || String[] || Yes || Exact standards used by the returned representation, such as bip-0032, bip-0044, slip-0044, bip-0084, bip-0380, bip-0389, and elip-0150. +| standardsUsed || String[] || Yes || The exact standards used by the returned representation, such as bip-0032, bip-0044, slip-0044, bip-0084, bip-0380, bip-0389, and elip-0150. |- -| descriptor || String || Conditional || Required when branchLayout is multipath. Normalized descriptor string with checksum. +| descriptor || String || Conditional || Required when branchLayout is multipath. The normalized descriptor string with a checksum. |- | branchDescriptors || Array || Conditional || Required when branchLayout is split. Each entry contains branch, change, and descriptor. |- -| branches || Array || No || Metadata for branches represented by a multipath descriptor. Each entry contains branch, change, and addressIndex. +| branches || Array || No || Metadata for the branches represented by a multipath descriptor. Each entry contains branch, change, and addressIndex. |- -| canDeriveScriptPubKeys || Boolean || Yes || Whether the descriptor entry can derive scriptPubKeys. +| canDeriveScriptPubKeys || Boolean || Yes || Indicates whether the descriptor entry can derive scriptPubKeys. |- -| canDeriveConfidentialAddresses || Boolean || Yes || Whether the descriptor entry can derive confidential addresses. +| canDeriveConfidentialAddresses || Boolean || Yes || Indicates whether the descriptor entry can derive confidential addresses. |- | canUnblindOutputs || Boolean || Yes || MUST be false for every descriptor returned by this profile. |} @@ -338,7 +338,7 @@ Wallets MUST return the [https://github.com/ElementsProject/ELIPs/blob/main/elip for the same descriptor set as the returned public wallet descriptor, even when returning a public confidential descriptor. If no requested format is supported or permitted by wallet policy, the wallet MUST return a JSON-RPC error -with reason = "unsupported_descriptor_format"and SHOULD include the requested and supported format profile names in error.data. +with reason = "unsupported_descriptor_format" and SHOULD include the requested and supported format profile names in error.data. Example request for a public wallet descriptor with [https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki BIP-389] multipath fallback to split branches: @@ -430,15 +430,15 @@ asset blinding factors, value blinding factors, shared nonces, or view-capable d {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +| chainId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. +| accountIdentifier || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- -| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +| policyAssetId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- -| assetId || String || Yes || Asset ID whose balance was returned. +| assetId || String || Yes || The asset ID whose balance was returned. |- -| balance || String || Yes || Sum of known unspent wallet outputs for assetId, encoded as a decimal string in the asset base unit. +| balance || String || Yes || The sum of known unspent wallet outputs for assetId, encoded as a decimal string in the asset base unit. |} Example request: @@ -487,21 +487,21 @@ value blinding factors, shared nonces, or view-capable descriptor material. {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| assetId || String || No || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. +| assetId || String || No || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID. If omitted, the network policy asset is used. |} {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| chainId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. +| chainId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] chain ID. |- -| accountIdentifier || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. +| accountIdentifier || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] account ID for the connected account. |- -| policyAssetId || String || Yes || [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. +| policyAssetId || String || Yes || The [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the network policy asset. |- -| assetId || String || Yes || Asset ID used to filter returned UTXOs. +| assetId || String || Yes || The asset ID used to filter the returned UTXOs. |- -| utxos || Array || Yes || UTXOs for the requested asset. +| utxos || Array || Yes || The UTXOs for the requested asset. |} Each UTXO entry has the following fields: @@ -509,23 +509,23 @@ Each UTXO entry has the following fields: {| class="wikitable" ! Field !! Type !! Required !! Description |- -| txid || String || Yes || Transaction ID as 64 lowercase hex characters. +| txid || String || Yes || The transaction ID as 64 lowercase hex characters. |- -| vout || Integer || Yes || Output index. +| vout || Integer || Yes || The output index. |- -| assetId || String || Yes || Wallet-unblinded [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the UTXO. +| assetId || String || Yes || The wallet-unblinded [https://github.com/ElementsProject/ELIPs/blob/main/elip-0144.mediawiki ELIP-0144] asset ID of the UTXO. |- -| amount || String || Yes || Wallet-unblinded amount in the asset base unit, encoded as a decimal string. +| amount || String || Yes || The wallet-unblinded amount in the asset base unit, encoded as a decimal string. |- | address || String || Yes || Liquid confidential or unconfidential address whose script identifies the spend key for this UTXO. A dapp SHOULD use this value in signPset.signInputs[].address when constructing a PSET from this UTXO. |- -| scriptPubKey || String || Yes || Raw scriptPubKey bytes as lowercase hex without 0x. +| scriptPubKey || String || Yes || The raw scriptPubKey bytes as lowercase hex without 0x. |- -| txOut || String || Yes || Raw Elements TxOut consensus serialization as lowercase hex without 0x. It excludes output witness data. +| txOut || String || Yes || The raw Elements TxOut consensus serialization as lowercase hex without 0x. It excludes output witness data. |- -| confidential || Boolean || Yes || Whether the previous output is confidential. +| confidential || Boolean || Yes || Indicates whether the previous output is confidential. |- -| spendable || Boolean || Yes || Whether the wallet currently considers the UTXO spendable under wallet policy. +| spendable || Boolean || Yes || Indicates whether the wallet currently considers the UTXO spendable under wallet policy. |} Wallets MUST return only UTXOs matching the selected assetId, using wallet-unblinded asset IDs for confidential outputs. @@ -587,25 +587,25 @@ is already authorized by the request context. {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI shown to the user. +| identity || String || Yes || The identity URI shown to the user. |- | curve || String || Yes || Supported value: nist256p1. |- -| index || Integer || No || Identity-key index. Default is 0. +| index || Integer || No || The identity-key index. Default is 0. |} {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI. +| identity || String || Yes || The identity URI. |- | curve || String || Yes || MUST be nist256p1. |- -| index || Integer || Yes || Identity-key index. +| index || Integer || Yes || The identity-key index. |- | type || String || Yes || MUST be slip-0013. |- -| publicKey || String || Yes || Uncompressed 65-byte public key as 130 lowercase hex characters without 0x. +| publicKey || String || Yes || The uncompressed 65-byte public key as 130 lowercase hex characters without 0x. |} Example request: @@ -652,35 +652,35 @@ curve, index, and domain-separation context before approval unless the exact req {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI shown to the user. +| identity || String || Yes || The identity URI shown to the user. |- | curve || String || Yes || Supported value: nist256p1. |- -| theirPublicKey || String || Yes || Counterparty uncompressed 65-byte public key as 130 lowercase hex characters without 0x. +| theirPublicKey || String || Yes || The counterparty's uncompressed 65-byte public key as 130 lowercase hex characters without 0x. |- -| index || Integer || No || Identity-key index. Default is 0. +| index || Integer || No || The identity-key index. Default is 0. |- | kdf || String || Yes || Supported value: hkdf-sha256. |- -| kdfSalt || String || Yes || HKDF salt bytes as lowercase hex without 0x. +| kdfSalt || String || Yes || The HKDF salt bytes as lowercase hex without 0x. |- -| kdfInfo || String || Yes || HKDF info bytes as lowercase hex without 0x. The value MUST domain-separate the intended protocol and MUST commit to the application origin or authenticated caller identity when available, active chain_id, and account identifier. +| kdfInfo || String || Yes || The HKDF info bytes as lowercase hex without 0x. The value MUST domain-separate the intended protocol and MUST commit to the application origin or authenticated caller identity when available, the active chain_id, and the account identifier. |} {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI. +| identity || String || Yes || The identity URI. |- | curve || String || Yes || MUST be nist256p1. |- -| index || Integer || Yes || Identity-key index. +| index || Integer || Yes || The identity-key index. |- | type || String || Yes || MUST be slip-0017. |- -| publicKey || String || Yes || Wallet identity uncompressed 65-byte public key as 130 lowercase hex characters without 0x. +| publicKey || String || Yes || The wallet identity's uncompressed 65-byte public key as 130 lowercase hex characters without 0x. |- -| sharedKey || String || Yes || HKDF-SHA256 output as lowercase hex without 0x. +| sharedKey || String || Yes || The HKDF-SHA256 output as lowercase hex without 0x. |- | kdf || String || Yes || Applied KDF: hkdf-sha256. |} @@ -724,38 +724,38 @@ Example result: ===signIdentity=== -This method signs a caller-provided challenge with the deterministic identity-signing key. +This method is used to sign a caller-provided challenge with the deterministic identity-signing key. It follows [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013]. -This method is for identity proof and MUST NOT be displayed or interpreted as transaction approval. +This method is used for an identity proof and MUST NOT be displayed or interpreted as transaction approval. Wallets MUST display the identity string, challenge summary, curve, and index before approval unless the exact signing request is already authorized by the request context. {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI shown to the user. +| identity || String || Yes || The identity URI shown to the user. |- | curve || String || Yes || Supported value: nist256p1. |- -| challenge || String || Yes || Challenge bytes as lowercase hex without 0x. Bytes length MAY depend on the wallet implementation. +| challenge || String || Yes || The challenge bytes as lowercase hex without 0x. The byte length MAY depend on the wallet implementation. |- -| index || Integer || No || Identity-key index. Default is 0. +| index || Integer || No || The identity-key index. Default is 0. |} {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| identity || String || Yes || Identity URI. +| identity || String || Yes || The identity URI. |- | curve || String || Yes || MUST be nist256p1. |- -| index || Integer || Yes || Identity-key index. +| index || Integer || Yes || The identity-key index. |- | type || String || Yes || MUST be slip-0013. |- -| publicKey || String || Yes || Uncompressed 65-byte public key as 130 lowercase hex characters without 0x. +| publicKey || String || Yes || The uncompressed 65-byte public key as 130 lowercase hex characters without 0x. |- -| signature || String || Yes || Identity signature as lowercase hex without 0x. +| signature || String || Yes || The identity signature as lowercase hex without 0x. |} Example request: @@ -793,7 +793,7 @@ Example result: ===signPset=== -This method requests signatures for a PSET. +This method is used to request signatures for a PSET. Wallets MUST reject PSETs that cannot be associated with the active Liquid or Elements chain. Wallets MUST NOT add unrelated wallet UTXOs to a caller-provided PSET. Wallets MUST NOT sign inputs that are not explicitly listed in signInputs. @@ -801,9 +801,9 @@ Wallets MUST NOT sign inputs that are not explicitly listed in signInputs< {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| pset || String || Yes || Base64-encoded complete PSET serialization. +| pset || String || Yes || The complete PSET serialization, encoded as base64. |- -| signInputs || Array || Yes || Inputs that the wallet is requested to sign. +| signInputs || Array || Yes || The inputs that the wallet is requested to sign. |- | broadcast || Boolean || No || If true, the wallet MAY finalize and broadcast the transaction after signing. Default is false. |} @@ -818,11 +818,11 @@ Each signInputs entry has the following fields: {| class="wikitable" ! Field !! Type !! Required !! Description |- -| index || Integer || Yes || Input index in the PSET. +| index || Integer || Yes || The input index in the PSET. |- | address || String || Yes || Liquid confidential or unconfidential address whose script identifies the spend key for this input. If a confidential address is supplied, the wallet MUST use only its script address component for spend-key selection. |- -| sighashTypes || Integer[] || No || Allowed signature hash modes for this input. Each value MUST be a fully encoded standard Elements ECDSA sighash integer from the table below. Default is [1]. +| sighashTypes || Integer[] || No || The allowed signature hash modes for this input. Each value MUST be a fully encoded standard Elements ECDSA sighash integer from the table below. Default is [1]. |} The signature hash mode applies to a single PSET input. @@ -856,9 +856,9 @@ Wallets MUST reject bare 128 in sighashTypes. {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| pset || String || Yes || Base64-encoded signed PSET. +| pset || String || Yes || The signed PSET, encoded as base64. |- -| txid || String || Conditional || Transaction ID as 64 lowercase hex characters. This field MUST be returned if the transaction was broadcast. +| txid || String || Conditional || The transaction ID as 64 lowercase hex characters. This field MUST be returned if the transaction was broadcast. |} Wallets MUST verify that each listed address corresponds to the input's previous-output script or @@ -914,12 +914,12 @@ Example result: ===signMessage=== -This method signs a message with the spend key for a connected Liquid address. Message signing uses spend keys, not descriptor blinding keys or view keys. +This method is used to sign a message with the spend key for a connected Liquid address. Message signing uses spend keys, not descriptor blinding keys or view keys. {| class="wikitable" ! Parameter !! Type !! Required !! Description |- -| message || String || Yes || UTF-8 message shown to the user. +| message || String || Yes || The UTF-8 message shown to the user. |- | address || String || Yes || Liquid confidential or unconfidential address whose spend key signs the message. If a confidential address is supplied, the wallet MUST use only its script address component for spend-key selection. |- @@ -929,15 +929,15 @@ This method signs a message with the spend key for a connected Liquid address. M {| class="wikitable" ! Result field !! Type !! Required !! Description |- -| address || String || Yes || Liquid address used for signing. +| address || String || Yes || The Liquid address used for signing. |- -| signature || String || Yes || Encoded signature. +| signature || String || Yes || The encoded signature. |- | signatureEncoding || String || Yes || hex-recoverable-ecdsa-65 when protocol is ecdsa; bip322 when protocol is bip322. |- -| protocol || String || Yes || Applied protocol: ecdsa or bip322. +| protocol || String || Yes || The applied protocol: ecdsa or bip322. |- -| messageHash || String || Conditional || Required when protocol is ecdsa. 32-byte legacy message digest as lowercase hex without 0x. +| messageHash || String || Conditional || Required when protocol is ecdsa. The 32-byte legacy message digest as lowercase hex without 0x. |} For protocol = ecdsa, the wallet MUST compute messageHash as: @@ -986,13 +986,13 @@ Example result: ===processConfidentialTransaction=== -This method is optional. It delegates request and response shape to the Wallet ABI transaction creation protocol. +This method is optional. It delegates the request and response shapes to the Wallet ABI transaction creation protocol. Wallets that support this method MUST implement it as described by the [https://github.com/KyrylR/ELIPs/blob/c946695f75f98477008bad0059d2894696bbaadd/elip-wallet-abi.mediawiki Wallet ABI Transaction Creation Protocol]. The JSON-RPC request MUST carry the Wallet ABI transaction request object. The JSON-RPC result MUST carry the Wallet ABI transaction response object. -Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, approval requirements are not supported or authorized. +Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, or approval requirements are not supported or authorized. @@ -1000,7 +1000,7 @@ Wallets MUST reject requests whose Wallet ABI version, account scope, chain ID, ===bip122_walletDescriptorChanged=== -This event notifies dapps that descriptor metadata for the connected Liquid account changed. +This event is used by wallets to notify dapps that descriptor metadata for the connected Liquid account changed. The event data has the same shape as the getWalletDescriptor result. Wallets SHOULD emit this event when the descriptor set for the connected account changes, @@ -1101,49 +1101,3 @@ result shape, and artifact redaction rules to that protocol. ==Reference Implementation== TBD. - -==Test Vectors== - -The following values were derived and statically validated with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. - -
-public_wallet_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/<0;1>/*)#csxkmyvv
-dwid                     = b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
-account_identifier       = bip122:1466275836220db2944ca059a3a10ef6:b781-7bc7-db64-c3de-3937-7eb7-c9ab-f799
-address_index_0          = ex1qyuh42lps6t6jpdk54cwmmhd27zrs3yulrc7t5a
-policy_asset_id          = bip122:1466275836220db2944ca059a3a10ef6/elip144:6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d
-
- -Split branch descriptors for the same public wallet descriptor are: - -
-external_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/0/*)#w7nj838h
-internal_descriptor = elwpkh([73c5da0a/84'/1776'/0']xpub6CRFzUgHFDaiDAQFNX7VeV9JNPDRabq6NYSpzVZ8zW8ANUCiDdenkb1gBoEZuXNZb3wPc1SVcDXgD2ww5UBtTb8s8ArAbTkoRQ8qn34KgcY/1/*)#l2kn6yh0
-
- - -The following identity and signing vectors use the same mnemonic. The identity keys are derived with [https://github.com/satoshilabs/slips/blob/master/slip-0010.md SLIP-0010] over NIST P-256 and the [https://github.com/satoshilabs/slips/blob/master/slip-0013.md SLIP-0013] or [https://github.com/satoshilabs/slips/blob/master/slip-0017.md SLIP-0017] identity path for ssh://jade@blockstream.com at index 0. - -
-slip0013_public_key = 04012c4f72037ddf467581dd8081bd365b668c9e00fdec2a9c9ff7f4a23df3ff747cd1fb99256b631c6316d1f1b692df829d3c6a687d327d3a3942822499a2abc1
-slip0013_challenge  = 4c69717569642057616c6c6574205250432050726f66696c65206964656e74697479206368616c6c656e6765
-slip0013_signature  = 00c3fec3b39151ec274f7fb821e6b019c02625e2bfea74fca6635b19d28bef9de53fd7937ca7b10e6be7e228ae96923a45dd4add2aa94920fe660b522b6a9bf6c2
-slip0017_public_key = 045b2d18e9ce5c62c6dff146c3453e672ea83606b9841e32fa6793115f23589c696aba3c36c1b08eae7a3c8b9d81878ccddf84adce4d72811867de60922f70fa1a
-peer_public_key     = 04c95ff5052c66d17ecbf08eafe00aade2071830b0bafc8e87b3debffbfa1b733272900303e6688e025f9744e6c6e6961c5861138cc4e909eeedd84c84311b5ca1
-raw_shared_key      = c78d6f0cde624fdbadb88c7d6af291530ee0a203938c7d88b6a2c5ab4d85d3c8
-hkdf_salt           = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
-hkdf_info           = 4c69717569642057616c6c6574205250432050726f66696c65206964656e7469747920736861726564206b6579207631
-hkdf_shared_key     = b5adc5d2a7d19baff144e765eb448fbf1decc7e6bc6b309d8ed0f7a202d1561e
-message_hash        = 95b7987475f7157b80aa3c5087d910e44429f410cd3b12c25a652e9c2d480d89
-message_signature   = ded4c5a767265f1df01b5453da8df9d364d81775d780c8f52707573a68c485152f59a354eec5c935072eff8e6d14d3c6744659fc405cad88e395afd9493cdd3a00
-
- -The following PSET values are constructed from an explicit policy-asset UTXO at the example script and were parsed with [https://docs.rs/lwk_bindings/latest/lwk/ Liquid Wallet Kit]. The signed PSET was produced with the Liquid Wallet Kit signer for the same mnemonic. - -
-example_utxo_txid = 4b33bd9a251311bd7f247ea19b3cf9887977ba4d9abe2ec7886de24094252586
-example_utxo_vout = 0
-example_utxo_txout = 016d521c38ec1ea15734ae22b7c46064412829c0d0579f0a713d1c04ede979026f01000000000001e24000160014272f557c30d2f520b6d4ae1dbdddaaf08708939f
-example_pset_unique_id = b32487878e61f1765058bc566c6f51bb851df3710323c464988202758f25d32c
-example_pset_partial_signature = 304402201ea482f48f8be85a5a11be08c380c9ec65fed1795fc56f77278954e7969700dd0220562511b2f4f46f082362d19707819b85813c085377ddec91fa84e1e83f95081c01
-
From d5b713cbbad5a13f15baa35073e8dda53886f0b0 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Mon, 1 Jun 2026 16:41:08 +0300 Subject: [PATCH 8/8] liquid-rpc-profile: recreate security considerations --- elip-liquid-wallet-rpc-profile.mediawiki | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/elip-liquid-wallet-rpc-profile.mediawiki b/elip-liquid-wallet-rpc-profile.mediawiki index 9106225..5dd5ac0 100644 --- a/elip-liquid-wallet-rpc-profile.mediawiki +++ b/elip-liquid-wallet-rpc-profile.mediawiki @@ -1098,6 +1098,47 @@ avoid duplicating a larger confidential transaction schema in this profile. This ELIP specifies the JSON-RPC binding and leaves account scoping, ABI versioning, transaction approval, result shape, and artifact redaction rules to that protocol. +==Security Considerations== + +===Transport integrity=== + +Implementers of this RPC profile should account for common transport-layer attacks, such as man-in-the-middle +attacks, replay, request substitution, and response substitution. The transport used to carry these JSON-RPC +messages should provide authenticated peers, message integrity, and confidentiality appropriate for the deployment. + +===Blind signing and transaction review=== + +Wallets that implement this profile should make a best effort to prevent blind signing. If a transaction or PSET +cannot be explained to the user with high assurance, the wallet should reject the request instead of asking the +user to approve data that the wallet cannot safely interpret. + +===ECDSA signature encoding=== + +Methods that return ECDSA signatures, such as signIdentity and signMessage when +protocol = ecdsa, should use canonical signature encodings. ECDSA signatures are malleable unless +the s value is normalized or otherwise constrained; for a valid (r, s) signature, the +corresponding high-S or low-S form can also verify if the implementation accepts both. + +Some recoverable ECDSA encodings include a recovery identifier, commonly called v or +recId. This value is metadata used for public-key recovery and address or key-context selection. +It should not be interpreted as a second user approval or as the reason that multiple ECDSA encodings can verify +the same message. Implementations that compare signatures as authorization artifacts should compare canonicalized +signatures or verify the signed message and public key instead of relying on raw signature-byte equality. + +===Shared-key approval context=== + +The kdfInfo value in getIdentitySharedKey is caller-provided domain-separation data. +Wallets should treat it with caution when presenting an approval prompt. If the wallet cannot parse or explain +the protocol, origin or authenticated caller identity, active chain_id, and account commitment in +kdfInfo, the request should be treated as the same class of blind-approval risk as blind signing. + +===Privacy disclosure=== + +In the worst case, authorized use of this profile can expose the account's derivable address chain, current +balances, and UTXO set at a particular point in time. Correct implementations of this profile do not return +descriptors or other material with unblinding capabilities. This design is intended to prevent common privacy +footguns in privacy-oriented Liquid applications. + ==Reference Implementation== TBD.