syntax = "proto3"; package spark; option go_package = "github.com/lightsparkdev/spark/proto/spark"; import "google/protobuf/timestamp.proto"; import "google/protobuf/empty.proto"; import "validate/validate.proto"; import "common.proto"; service SparkService { rpc generate_deposit_address(GenerateDepositAddressRequest) returns (GenerateDepositAddressResponse) {} // Generates a new static deposit address of the user or returns the existing one for the specified network. rpc generate_static_deposit_address(GenerateStaticDepositAddressRequest) returns (GenerateStaticDepositAddressResponse) {} // Archives the current default static deposit address and generates a new one for the user. rpc rotate_static_deposit_address(RotateStaticDepositAddressRequest) returns (RotateStaticDepositAddressResponse) {} rpc start_deposit_tree_creation(StartDepositTreeCreationRequest) returns (StartDepositTreeCreationResponse) {} // Creates a deposit tree with the commitments from get_signing_commitments, after they are signed. Fails if the tree already exists. rpc finalize_deposit_tree_creation(FinalizeDepositTreeCreationRequest) returns (FinalizeDepositTreeCreationResponse) {} rpc finalize_transfer_with_transfer_package(FinalizeTransferWithTransferPackageRequest) returns (FinalizeTransferResponse) {} rpc query_pending_transfers(TransferFilter) returns (QueryTransfersResponse) {} rpc query_all_transfers(TransferFilter) returns (QueryTransfersResponse) {} rpc query_transfers_by_id(QueryTransfersByIdRequest) returns (QueryTransfersResponse) {} rpc claim_transfer_tweak_keys(ClaimTransferTweakKeysRequest) returns (google.protobuf.Empty) {} rpc store_preimage_share(StorePreimageShareRequest) returns (google.protobuf.Empty) {} rpc store_preimage_share_v2(StorePreimageShareV2Request) returns (google.protobuf.Empty) {} // Gets a specified number of signing commmitments for a set of nodes, which can be used as // part of a transfer package. rpc get_signing_commitments(GetSigningCommitmentsRequest) returns (GetSigningCommitmentsResponse) {} rpc provide_preimage(ProvidePreimageRequest) returns (ProvidePreimageResponse) {} // Used to check if a user has provided the preimage for a HODL invoice in lightning receive flow. rpc query_preimage(QueryPreimageRequest) returns (QueryPreimageResponse) {} rpc query_htlc(QueryHtlcRequest) returns (QueryHtlcResponse) {} // Resets the timelocks for a leaf's transactions. Can be used to reset the // refund transaction timelock for a leaf (when the node transaction // timelock is still > 300) or reset the node and refund transaction // timelock. Returns an error if a leaf is not yet eligible to renew the // timelocks, see RenewLeafRequest for more details. rpc renew_leaf(RenewLeafRequest) returns (RenewLeafResponse) {} rpc get_signing_operator_list(google.protobuf.Empty) returns (GetSigningOperatorListResponse) {} rpc query_nodes(QueryNodesRequest) returns (QueryNodesResponse) {} rpc query_balance(QueryBalanceRequest) returns (QueryBalanceResponse) {} rpc query_user_signed_refunds(QueryUserSignedRefundsRequest) returns (QueryUserSignedRefundsResponse) {} rpc query_unused_deposit_addresses(QueryUnusedDepositAddressesRequest) returns (QueryUnusedDepositAddressesResponse) {} rpc query_static_deposit_addresses(QueryStaticDepositAddressesRequest) returns (QueryStaticDepositAddressesResponse) {} rpc subscribe_to_events(SubscribeToEventsRequest) returns (stream SubscribeToEventsResponse) {} // Signs the provided refund transaction which spends the UTXO from a static // deposit address. If successful, the UTXO will no longer be available to claim on // the Spark network, and the refund transaction must be broadcasted on L1 to claim // the funds. Returns an error if the UTXO has already been claimed. rpc initiate_static_deposit_utxo_refund(InitiateStaticDepositUtxoRefundRequest) returns (InitiateStaticDepositUtxoRefundResponse) {} rpc exit_single_node_trees(ExitSingleNodeTreesRequest) returns (ExitSingleNodeTreesResponse) {} // The following endpoints enforce inclusion of Direct Transactions used // for unilateral exits rpc cooperative_exit_v2(CooperativeExitRequest) returns (CooperativeExitResponse) {} rpc claim_transfer_sign_refunds_v2(ClaimTransferSignRefundsRequest) returns (ClaimTransferSignRefundsResponse) {} rpc finalize_node_signatures_v2(FinalizeNodeSignaturesRequest) returns (FinalizeNodeSignaturesResponse) {} rpc initiate_preimage_swap_v2(InitiatePreimageSwapRequest) returns (InitiatePreimageSwapResponse) {} rpc initiate_preimage_swap_v3(InitiatePreimageSwapRequest) returns (InitiatePreimageSwapResponse) {} rpc start_transfer_v2(StartTransferRequest) returns (StartTransferResponse) {} rpc start_transfer_v3(StartTransferV3Request) returns (StartTransferResponse) {} rpc claim_transfer(ClaimTransferRequest) returns (ClaimTransferResponse) {} rpc get_utxos_for_address(GetUtxosForAddressRequest) returns (GetUtxosForAddressResponse) {} rpc get_utxos_for_identity(GetUtxosForIdentityRequest) returns (GetUtxosForIdentityResponse) {} rpc query_spark_invoices(QuerySparkInvoicesRequest) returns (QuerySparkInvoicesResponse) {} // Inititiates a primary transfer in a Swap V3 protocol. The sender submits the // transfer package, but the SOs will not tweak the keys at this stage of the flow. // It will be done later, when the SSP initiates a counter swap. rpc initiate_swap_primary_transfer(InitiateSwapPrimaryTransferRequest) returns (InitiateSwapPrimaryTransferResponse) {} rpc update_wallet_setting(UpdateWalletSettingRequest) returns (UpdateWalletSettingResponse) {} rpc query_wallet_setting(QueryWalletSettingRequest) returns (QueryWalletSettingResponse) {} } message SubscribeToEventsRequest { bytes identity_public_key = 10; } message SubscribeToEventsResponse { oneof event { // Include json_name for backwards compatibility for those who are using json serialization. TransferEvent receiver_transfer = 1 [json_name = "transfer"]; DepositEvent deposit = 2; ConnectedEvent connected = 3; TransferEvent sender_transfer = 4; HeartbeatEvent heartbeat = 5; TokenTransactionEvent token_transaction = 6; } } message TokenTransactionEvent { bytes token_transaction_hash = 1; repeated bytes token_identifiers = 2; repeated string spark_invoices = 3; } message ConnectedEvent { } message HeartbeatEvent { } message TransferEvent { Transfer transfer = 10; string trace_id = 11; } message DepositEvent { TreeNode deposit = 10; string trace_id = 11; } /** * Network is the network type of the bitcoin network. */ enum Network { UNSPECIFIED = 0; MAINNET = 1; REGTEST = 2; TESTNET = 3; SIGNET = 4; } message PageRequest { int32 unsafe_page_size = 1 [(validate.rules).int32 = { gte: 0, lte: 1000 }]; uint32 page_size = 4 [(validate.rules).uint32 = { gte: 0, lte: 1000 }]; string cursor = 2; Direction direction = 3; } enum Direction { NEXT = 0; PREVIOUS = 1; } message PageResponse { bool has_next_page = 1; bool has_previous_page = 2; string next_cursor = 3; string previous_cursor = 4; } /** * DepositAddressProof is the proof of possession of the deposit address. * When a user wants to generate a deposit address, they are sending their public key to the SE, * and the SE will respond with an address of user's public key + SE's public key. * * In the trusty deposit flow, user will need to know that this address is valid, and no single SE * can generate this address. * * The SE will need to sign the address with their identity keys, and have a proof of possession of * the signing key piece that the SE holds. */ message DepositAddressProof { // The signatures of the address by the SE's identity keys. map address_signatures = 1; // The proof of possession of the signing key piece by the SE. bytes proof_of_possession_signature = 2; } /** * GenerateDepositAddressRequest is the request to generate a deposit address. * The user will send their public key to the SE, and the SE will respond with an address of user's * public key + SE's public key. */ message GenerateDepositAddressRequest { // The signing public key of the user. bytes signing_public_key = 1; // The identity public key of the user. bytes identity_public_key = 2; // The network of the bitcoin network. Network network = 3 [(validate.rules).enum = {not_in: [0]}]; // The UUID to use for the created TreeNode optional string leaf_id = 4 [(validate.rules).string.uuid = true]; // Generate static deposit address optional bool is_static = 5; // The hash variant to use for computing the proof of possession message hash. HashVariant hash_variant = 6; } /** * Address is the address of the user's public key + SE's public key. */ message Address { // The p2tr address of the user's public key + SE's public key. string address = 1; // The verifying key of the address, which is user's public key + SE's public key. bytes verifying_key = 2; // The proof of possession of the address by the SE. DepositAddressProof deposit_address_proof = 3; // Is it a static deposit address bool is_static = 5; } /** * GenerateDepositAddressResponse is the response to the request to generate a deposit address. */ message GenerateDepositAddressResponse { Address deposit_address = 1; } /** * GenerateStaticDepositAddressRequest is the request to generate a static deposit address. */ message GenerateStaticDepositAddressRequest { // The signing public key of the user. bytes signing_public_key = 1 [(validate.rules).bytes.len = 33]; // The identity public key of the user. bytes identity_public_key = 2 [(validate.rules).bytes.len = 33]; // The network of the bitcoin network. Network network = 3 [(validate.rules).enum = {not_in: [0]}]; // The hash variant to use for computing the proof of possession message hash. HashVariant hash_variant = 4; } /** * GenerateStaticDepositAddressResponse is the response to the request to generate a static deposit address. */ message GenerateStaticDepositAddressResponse { Address deposit_address = 1; } /** * Request to rotate a static deposit address. * This archives the current default address and generates a new one. * Old address still can be used to receive deposits. */ message RotateStaticDepositAddressRequest { // The signing public key of the user to aggregate with SO keys and produce the // final pubkey used to generate P2TR address. bytes signing_public_key = 1 [(validate.rules).bytes.len = 33]; // The network of the bitcoin network. Network network = 2 [(validate.rules).enum = {not_in: [0]}]; // The hash variant to use for computing the proof of possession message hash. HashVariant hash_variant = 3; } /** * Response to the request to rotate a static deposit address. */ message RotateStaticDepositAddressResponse { // The newly generated default deposit address. Address new_deposit_address = 1; // The archived (previous default) deposit address. Address archived_deposit_address = 2; } /** * UTXO represents a utxo on the bitcoin network. * The UTXO is used to create a tree on Spark, it can also be an off-chain utxo so that the user * can create the tree first and the broadcast the transaction. */ message UTXO { // The raw transaction of the utxo (optional). bytes raw_tx = 1; // The vout of the raw transaction for the utxo, which will be used to create the tree. Required. uint32 vout = 2; // The network of the bitcoin network. Required. Network network = 3 [(validate.rules).enum = {not_in: [0]}]; // Transaction Id string, produced from transaction hash by reversing the bytes, // converted to bytes. Required, but older code may not provide it. bytes txid = 4; } message AddressedUtxo { string address = 1; UTXO utxo = 2; bool is_confirmed = 3; } /** * NodeOutput represents a node on the tree. * This is similar to a UTXO, which is used to create a subtree on Spark. But instead of using * a utxo, a existing node on the tree is used as the utxo. */ message NodeOutput { // The id of the node. string node_id = 1; // The vout of the raw transaction for the node, which will be used to create the tree. uint32 vout = 2; } /** * SigningJob is the job for signing a transaction. * The signing job is used to sign a bitcoin transaction using Spark FROST. */ message SigningJob { // The signing public key of the user. bytes signing_public_key = 1; // The unsigned raw transaction to be signed. bytes raw_tx = 2; // The signing nonce commitment of the user. common.SigningCommitment signing_nonce_commitment = 3; } /** * SigningKeyshare is the keyshare information of the SE keyshare group. */ message SigningKeyshare { // The identifiers of the owners of the keyshare. repeated string owner_identifiers = 1; // The threshold of the keyshare. uint32 threshold = 2; // The public key of the keyshare. bytes public_key = 3; // The public shares of the keyshare. map public_shares = 4; // The latest update time of the keyshare. google.protobuf.Timestamp updated_time = 5; } /** * SigningResult is the result of the signing job from the SE keyshare group. * It contains all the information for user to sign their part. After user signs, the signature * can be aggregated to form the final signature. */ message SigningResult { // The public keys of the SE keyshare group. map public_keys = 1; // The signing nonce commitments of the SE keyshare group. map signing_nonce_commitments = 2; // The signature shares of the SE keyshare group. map signature_shares = 3; // The keyshare information of the SE keyshare group. SigningKeyshare signing_keyshare = 4; } message RenewLeafRequest { string leaf_id = 1; oneof signing_jobs { // Resets the node transaction timelock and refund transaction timelock // for a leaf to 2000. The old node transaction is invalidated by // introducing a "split node" with zero timelock that spends to a new // node transaction. Takes in the signing jobs for the updated // node, refund, and split node transactions with the new timelocks. // Requires that the existing node transaction timelock is <= 300 // at the time this function is called. Returns an error if these // conditions are not met. RenewNodeTimelockSigningJob renew_node_timelock_signing_job = 2; // Resets the refund transaction timelock for a leaf to 2000. Takes in // the signing jobs for the updated transactions with the new timelocks. // Requires that the existing refund transaction timelock is <= 300 and // the node transaction timelock > 300 at the time this function is // called. Returns an error if these conditions are not met. RenewRefundTimelockSigningJob renew_refund_timelock_signing_job = 3; // A special case of refresh for when the node transaction is at 0 and // cannot be decremented further. This operation resets the refund // transaction's timelock and, similar to renew node, adds an additional // node transaction to the transaction chain with zero timelock as well. // This case is mostly used for user-created trees from L1 deposits. RenewNodeZeroTimelockSigningJob renew_node_zero_timelock_signing_job = 4; } } message RenewNodeTimelockSigningJob { // Signing job with the new "split node" transaction. This spends the // inputs of the old node transaction and its outputs are spent by the new // node transaction. Timelock of split node transaction must be 0. UserSignedTxSigningJob split_node_tx_signing_job = 1; UserSignedTxSigningJob split_node_direct_tx_signing_job = 2; // Signing job with the updated node transaction. The updated transaction is // expected to have a timelock of 2000. UserSignedTxSigningJob node_tx_signing_job = 3; UserSignedTxSigningJob refund_tx_signing_job = 4; UserSignedTxSigningJob direct_node_tx_signing_job = 5; UserSignedTxSigningJob direct_refund_tx_signing_job = 6; UserSignedTxSigningJob direct_from_cpfp_refund_tx_signing_job = 7; } message RenewRefundTimelockSigningJob { // Signing job with the updated node transaction. The updated transaction is // expected to have a timelock of 100 less than the existing node transaction. UserSignedTxSigningJob node_tx_signing_job = 1; // Signing job with the updated refund transaction. This updated transaction // must have a timelock of 2000. UserSignedTxSigningJob refund_tx_signing_job = 2; UserSignedTxSigningJob direct_node_tx_signing_job = 3; UserSignedTxSigningJob direct_refund_tx_signing_job = 4; UserSignedTxSigningJob direct_from_cpfp_refund_tx_signing_job = 5; } message RenewNodeZeroTimelockSigningJob { reserved 4; // Signing job with the new node transaction. The updated transaction is // expected to have a timelock of 0. UserSignedTxSigningJob node_tx_signing_job = 1; // Signing job with the updated refund transaction. This updated transaction // must have a timelock of 2000. UserSignedTxSigningJob refund_tx_signing_job = 2; UserSignedTxSigningJob direct_node_tx_signing_job = 3; UserSignedTxSigningJob direct_from_cpfp_refund_tx_signing_job = 5; // Notice no signing job for the split node; we will be using the existing // node transaction. } message RenewLeafResponse { oneof renew_result { RenewNodeTimelockResult renew_node_timelock_result = 1; RenewRefundTimelockResult renew_refund_timelock_result = 2; RenewNodeZeroTimelockResult renew_node_zero_timelock_result = 3; } } message RenewNodeTimelockResult { TreeNode split_node = 1; TreeNode node = 2; } message RenewRefundTimelockResult { TreeNode node = 1; } message RenewNodeZeroTimelockResult { TreeNode split_node = 1; TreeNode node = 2; } /** * NodeSignatureShares is the signature shares for a node on the tree. * For each tree node, the verifying key stays the same for both transactions. */ message NodeSignatureShares { // The id of the node. string node_id = 1; // The signing result of the node's transaction. This transaction is to pay to self. SigningResult node_tx_signing_result = 2; // The signing result of the node's refund transaction. This transaction is to pay to the user. SigningResult refund_tx_signing_result = 3; // The verifying key of the node. bytes verifying_key = 4; // The signing result of the node's transaction. This transaction is to pay to self. SigningResult direct_node_tx_signing_result = 5 [deprecated = true]; // The signing result of the node's direct refund transaction. This transaction is to broadcast for the SO. SigningResult direct_refund_tx_signing_result = 6 [deprecated = true]; // The signing result of the node's direct from cpfp refund transaction. This transaction is to broadcast for the SO. SigningResult direct_from_cpfp_refund_tx_signing_result = 7; } /** * NodeSignatures is the final signatures for a node on the tree. * It contains the signature for the node's transaction and refund transaction. */ message NodeSignatures { // The id of the node. string node_id = 1; // The final signature of the node's cpfp transaction. This transaction is to pay to self. bytes node_tx_signature = 2; // The final signature of the node's cpfp refund transaction. This transaction is to pay to the user. bytes refund_tx_signature = 3; // The final signature of the node's direct transaction. This transaction is to pay for the watchtower. bytes direct_node_tx_signature = 4; // The final signature of the node's direct refund transaction. This transaction is to pay for the watchtower. bytes direct_refund_tx_signature = 5; // The final signature of the node's direct from cpfp refund transaction. This transaction is to pay for the watchtower. bytes direct_from_cpfp_refund_tx_signature = 6; } /** * StartTreeCreationRequest is the request to start the tree creation for a tree root node. */ message StartTreeCreationRequest { // The identity public key of the user. bytes identity_public_key = 1; // The on-chain utxo to be used to be spent by the root node. UTXO on_chain_utxo = 2; // The signing job for the root node's cpfp transaction. SigningJob root_tx_signing_job = 3; // The signing job for the root node's cpfp refund transaction. SigningJob refund_tx_signing_job = 4; // The signing job for the root node's direct transaction. SigningJob direct_root_tx_signing_job = 5; // The signing job for the root node's direct refund transaction SigningJob direct_refund_tx_signing_job = 6; // The signing job for the root node's direct refund transaction SigningJob direct_from_cpfp_refund_tx_signing_job = 7; } /** * StartTreeCreationResponse is the response to the request to start the tree creation for a tree root node. */ message StartTreeCreationResponse { // The id of the tree. string tree_id = 1; // The signature shares for the root node. NodeSignatureShares root_node_signature_shares = 2; } /** * StartDepositTreeCreationRequest is the request to start the tree creation for a tree root node. */ message StartDepositTreeCreationRequest { // The identity public key of the user. bytes identity_public_key = 1; // The on-chain utxo to be used to be spent by the root node. UTXO on_chain_utxo = 2; // The signing job for the root node's transaction. SigningJob root_tx_signing_job = 3; // The signing job for the root node's refund transaction. SigningJob refund_tx_signing_job = 4; // The direct signing job for the root node's transaction. SigningJob direct_root_tx_signing_job = 5 [deprecated = true]; // The signing job for the root node's direct refund transaction. SigningJob direct_refund_tx_signing_job = 6 [deprecated = true]; // The signing job for the root node's direct from cpfp refund transaction. SigningJob direct_from_cpfp_refund_tx_signing_job = 7; } /** * StartDepositTreeCreationResponse is the response to the request to start the tree creation for a tree root node. */ message StartDepositTreeCreationResponse { // The id of the tree. string tree_id = 1; // The signature shares for the root node. NodeSignatureShares root_node_signature_shares = 2; } /** * FinalizeDepositTreeCreationRequest is the request to finalize the tree creation for a tree root node. */ message FinalizeDepositTreeCreationRequest { // The identity public key of the user bytes identity_public_key = 1 [(validate.rules).bytes.len = 33]; // The on-chain utxo UTXO on_chain_utxo = 2; // User-signed transactions (with user signature shares, aggregated by server) UserSignedTxSigningJob root_tx_signing_job = 3; UserSignedTxSigningJob refund_tx_signing_job = 4; UserSignedTxSigningJob direct_from_cpfp_refund_tx_signing_job = 5; // Additional on-chain UTXOs for non-static deposits with multiple UTXOs. // All additional UTXOs must pay to the same deposit address as on_chain_utxo. // For multi-UTXO deposits, all UTXOs (primary + additional) must be confirmed // on-chain before finalization. The root_tx_signing_job.additional_inputs must // contain one InputSigningData per additional UTXO, in the same order. repeated UTXO additional_on_chain_utxos = 6; } /** * FinalizeDepositTreeCreationResponse is the response to the request to finalize the tree creation for a tree root node. */ message FinalizeDepositTreeCreationResponse { // the root node of the created tree TreeNode root_node = 1; } /** * TreeNode represents a node on the tree. */ message TreeNode { // The id of the node. string id = 1; // The id of the tree for this node . string tree_id = 2; // The value that this node holds. uint64 value = 3; // The id of the parent node. optional string parent_node_id = 4; // The cpfp transaction of the node, this transaction is to pay to the same address as the node. bytes node_tx = 5; // The refund transaction of the node, this transaction is to pay to the user. bytes refund_tx = 6; // This vout is the vout to spend the previous transaction, which is in the parent node. uint32 vout = 7; // The verifying public key of the node. bytes verifying_public_key = 8; // The identity public key of the owner of the node. bytes owner_identity_public_key = 9; // The signing keyshare information of the node on the SE side. SigningKeyshare signing_keyshare = 10; // The status of the node. string status = 11; // The network of the node. Network network = 12; // The creation time of the node. google.protobuf.Timestamp created_time = 13; // The latest update time of the node. google.protobuf.Timestamp updated_time = 14; // The signing public key of the owner of the node. bytes owner_signing_public_key = 15; // The direct transaction of the node, this transaction is for the watchtower to broadcast. bytes direct_tx = 16; // The refund transaction of the node, this transaction is to pay to the user. bytes direct_refund_tx = 17; // The refund transaction of the node, this transaction is to pay to the user. bytes direct_from_cpfp_refund_tx = 18; // The status of the node as a typed enum. TreeNodeStatus treenode_status = 19; } /** * FinalizeNodeSignaturesRequest is the request to finalize the signatures for a node. */ message FinalizeNodeSignaturesRequest { // The intent of the signature. common.SignatureIntent intent = 1; // The signatures for the node. repeated NodeSignatures node_signatures = 2; } /** * FinalizeNodeSignaturesResponse is the response to the request to finalize the signatures for a node. */ message FinalizeNodeSignaturesResponse { // The nodes that are finalized. repeated TreeNode nodes = 1; } /** * SecretShare is a secret share of a secret, using Feldman VSS. * The secret share is in the field of secp256k1 scalar field. */ message SecretShare { // The secret share. bytes secret_share = 1; // The proofs for the secret share. They are the compressed public keys in secp256k1 curve. // proofs[0] is the public key of the secret, while proofs[1..n] are the public key of the polynomial. repeated bytes proofs = 2; } /** * SecretProof is the proof for a secret share using Feldman VSS. * The proof is the compressed public keys in secp256k1 curve. */ message SecretProof { // The proofs for the secret share. // proofs[0] is the public key of the secret, while proofs[1..n] are the public key of the polynomial. repeated bytes proofs = 1; } message LeafRefundTxSigningJob { string leaf_id = 1; SigningJob refund_tx_signing_job = 2; SigningJob direct_refund_tx_signing_job = 3; SigningJob direct_from_cpfp_refund_tx_signing_job = 4; } message UserSignedTxSigningJob { string leaf_id = 1; bytes signing_public_key = 2; // CPFP Refund Tx that is created when the User signs refunds. It spends the // node transaction to the receiver. bytes raw_tx = 3; common.SigningCommitment signing_nonce_commitment = 4; bytes user_signature = 5; SigningCommitments signing_commitments = 6; // Additional inputs for multi-UTXO root transactions. Each entry carries // the signing data for one additional root tx input (inputs 1..N). // Input 0 uses the fields above for backward compatibility. repeated InputSigningData additional_inputs = 7; } // InputSigningData carries the per-input signing data for additional root tx // inputs in a multi-UTXO deposit. message InputSigningData { // The user's nonce commitment for this input's FROST signing round. common.SigningCommitment signing_nonce_commitment = 1; bytes user_signature = 2; // The SE (Signing Entity) operators' nonce commitments for this input, keyed by operator identifier. SigningCommitments signing_commitments = 3; } message LeafRefundTxSigningResult { string leaf_id = 1; SigningResult refund_tx_signing_result = 2; bytes verifying_key = 3; SigningResult direct_refund_tx_signing_result = 4; SigningResult direct_from_cpfp_refund_tx_signing_result = 5; } message StartUserSignedTransferRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; repeated UserSignedTxSigningJob leaves_to_send = 3; bytes receiver_identity_public_key = 4; google.protobuf.Timestamp expiry_time = 5; repeated UserSignedTxSigningJob direct_leaves_to_send = 6; repeated UserSignedTxSigningJob direct_from_cpfp_leaves_to_send = 7; } message StartTransferRequest { reserved 6; reserved 9; string transfer_id = 1; bytes owner_identity_public_key = 2; // This field is used for swap and coop exits. Regular transfers must use // the transfer_package field. repeated LeafRefundTxSigningJob leaves_to_send = 3; bytes receiver_identity_public_key = 4; google.protobuf.Timestamp expiry_time = 5; // This field is required for transfers of type "transfer". If this field // is set, the leaves_to_send and key_tweak_proofs will be ignored. TransferPackage transfer_package = 7; // The invoice this transfer pays. string spark_invoice = 10; } message StartTransferResponse { Transfer transfer = 1; repeated LeafRefundTxSigningResult signing_results = 2; } message SenderTransferPackage { bytes owner_identity_public_key = 1; TransferPackage transfer_package = 2; // The transfer package contains leaves that may be meant for multiple receivers. // This maps leaf_id to receiver_identity_public_key for each leaf. map receiver_identity_public_keys = 3; } // Request to transfer leaves from multiple senders to multiple receivers // in a single atomic operation. message StartTransferV3Request { string transfer_id = 1; // One entry per sender. Leaf IDs must be disjoint across entries. repeated SenderTransferPackage sender_packages = 2; // Expiry time for the entire transfer google.protobuf.Timestamp expiry_time = 3; } /** * TransferPackage is a package of leaves to send and key tweaks to send. * This is in the improved send transfer flow where the sender can send the transfer in one call to * the coordinator SO. */ message TransferPackage { // The leaves to send, with user signed cpfp refunds and signing package. repeated UserSignedTxSigningJob leaves_to_send = 1; // The map of SO identifier to ciphertext of SendLeafTweaks. map key_tweak_package = 2; // The signature of user to prove that the key_tweak_package is not tampered. bytes user_signature = 3; // The leaves to send, with user signed direct refunds and signing package. repeated UserSignedTxSigningJob direct_leaves_to_send = 4; // The leaves to send, with user signed direct from cpfp refunds and signing package. repeated UserSignedTxSigningJob direct_from_cpfp_leaves_to_send = 5; // The hash variant to use for computing the transfer package signing payload. HashVariant hash_variant = 6; } message SendLeafKeyTweaks { repeated SendLeafKeyTweak leaves_to_send = 1; } message SendLeafKeyTweak { string leaf_id = 1; SecretShare secret_share_tweak = 2; map pubkey_shares_tweak = 3; bytes secret_cipher = 4; // Signature over Sha256(leaf_id||transfer_id||secret_cipher). oneof sig { bytes signature = 5; common.Signature typed_signature = 9; } bytes refund_signature = 6; bytes direct_refund_signature = 7; bytes direct_from_cpfp_refund_signature = 8; } message FinalizeTransferRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; repeated SendLeafKeyTweak leaves_to_send = 3; string spark_payment_intent = 4; } message FinalizeTransferWithTransferPackageRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; TransferPackage transfer_package = 3; } message FinalizeTransferResponse { Transfer transfer = 1; } enum TransferStatus { TRANSFER_STATUS_SENDER_INITIATED = 0; TRANSFER_STATUS_SENDER_KEY_TWEAK_PENDING = 1; TRANSFER_STATUS_SENDER_KEY_TWEAKED = 2; TRANSFER_STATUS_RECEIVER_KEY_TWEAKED = 3; TRANSFER_STATUS_RECEIVER_REFUND_SIGNED = 4; TRANSFER_STATUS_COMPLETED = 5; TRANSFER_STATUS_EXPIRED = 6; TRANSFER_STATUS_RETURNED = 7; TRANSFER_STATUS_SENDER_INITIATED_COORDINATOR = 8; TRANSFER_STATUS_RECEIVER_KEY_TWEAK_LOCKED = 9; TRANSFER_STATUS_RECEIVER_KEY_TWEAK_APPLIED = 10; TRANSFER_STATUS_APPLYING_SENDER_KEY_TWEAK = 11; } // Per-receiver status on the receiver edge of a Transfer. For single-receiver // (V2) transfers this is always lock-step with Transfer.status. For // multi-receiver (V3) transfers each receiver advances independently. // This is the authoritative per-receiver state. enum TransferReceiverStatus { TRANSFER_RECEIVER_STATUS_INITIATED = 0; TRANSFER_RECEIVER_STATUS_CLAIM_PENDING = 1; TRANSFER_RECEIVER_STATUS_KEY_TWEAKED = 2; TRANSFER_RECEIVER_STATUS_KEY_TWEAK_LOCKED = 3; TRANSFER_RECEIVER_STATUS_KEY_TWEAK_APPLIED = 4; TRANSFER_RECEIVER_STATUS_REFUND_SIGNED = 5; TRANSFER_RECEIVER_STATUS_COMPLETED = 6; TRANSFER_RECEIVER_STATUS_CANCELLED = 7; } enum TransferType { PREIMAGE_SWAP = 0; COOPERATIVE_EXIT = 1; TRANSFER = 2; UTXO_SWAP = 3; SWAP = 30; COUNTER_SWAP = 40; PRIMARY_SWAP_V3 = 4; COUNTER_SWAP_V3 = 5; } enum Order { DESCENDING = 0; ASCENDING = 1; } // Per-receiver summary within a Transfer response. message TransferReceiver { bytes identity_public_key = 1; uint64 amount_sats = 2; TransferReceiverStatus status = 3; string id = 4; google.protobuf.Timestamp completion_time = 5; } // Per-sender summary within a Transfer response. message TransferSender { string id = 1; bytes identity_public_key = 2; } message Transfer { string id = 1; bytes sender_identity_public_key = 2; bytes receiver_identity_public_key = 3; TransferStatus status = 4; uint64 total_value = 5; google.protobuf.Timestamp expiry_time = 6; repeated TransferLeaf leaves = 7; google.protobuf.Timestamp created_time = 8; google.protobuf.Timestamp updated_time = 9; TransferType type = 10; string spark_invoice = 11; Network network = 12; repeated TransferReceiver receivers = 13; repeated TransferSender senders = 14; } message TransferLeaf { TreeNode leaf = 1; bytes secret_cipher = 2; oneof sig { bytes signature = 3; common.Signature typed_signature = 10; } bytes intermediate_refund_tx = 4; bytes intermediate_direct_refund_tx = 5; bytes intermediate_direct_from_cpfp_refund_tx = 6; bytes pending_key_tweak_public_key = 7; string transfer_receiver_id = 8; string transfer_sender_id = 9; } // Describes how a transfer redistributes value across its senders and receivers. message TransferManifest { // Manifest format version. uint32 version = 1 [(validate.rules).uint32 = {gt: 0}]; // The transfer this manifest describes (uuid_v7). string transfer_id = 2 [(validate.rules).string.uuid = true]; // The network this transfer operates within. Network network = 3 [(validate.rules).enum = {not_in: [0]}]; // The transfer's refund timelock. google.protobuf.Timestamp transfer_expiry_time = 4; // Directed (sender -> receiver) gross amounts — the value movement. repeated ManifestEdge edges = 5 [(validate.rules).repeated.min_items = 1]; // Per-component fee breakdown. repeated FeeComponent fees = 6; // When the SSP's quote expires. google.protobuf.Timestamp quote_expiry_time = 7; } // An amount as absolute sats or basis points of gross. message ManifestAmount { oneof amount { uint64 sats = 1; uint32 bps = 2; // basis points of gross } } // One directed amount from a sender to a receiver. message ManifestEdge { bytes sender_identity_public_key = 1 [(validate.rules).bytes.len = 33]; bytes receiver_identity_public_key = 2 [(validate.rules).bytes.len = 33]; ManifestAmount amount = 3; } // One fee: category, amount, and recipient. message FeeComponent { FeeSource source = 1; FeeRole role = 2; // markup split role ManifestAmount amount = 3; bytes recipient_identity_public_key = 4; // empty if SSP-retained } // The kind of fee. enum FeeSource { FEE_SOURCE_UNSPECIFIED = 0; FEE_SOURCE_PARTNER_MARKUP = 1; // configurable markup FEE_SOURCE_BASE = 2; // platform usage fee FEE_SOURCE_NETWORK = 3; // network security fee } // Markup split role (for PARTNER_MARKUP). enum FeeRole { FEE_ROLE_UNSPECIFIED = 0; FEE_ROLE_AFFILIATE = 1; FEE_ROLE_PARTNER = 2; FEE_ROLE_LS = 3; } message TransferFilter { oneof participant { bytes receiver_identity_public_key = 1; bytes sender_identity_public_key = 2; // This will include transfers where this public key is the sender or receiver. bytes sender_or_receiver_identity_public_key = 60; } repeated string transfer_ids = 3; int64 limit = 40; int64 offset = 50; repeated TransferType types = 70; Network network = 4; repeated TransferStatus statuses = 80; Order order = 5; oneof time_filter { // Filter transfers created strictly after this timestamp (exclusive) google.protobuf.Timestamp created_after = 6; // Filter transfers created strictly before this timestamp (exclusive) google.protobuf.Timestamp created_before = 7; } } message QueryTransfersResponse { repeated Transfer transfers = 1; int64 offset = 2; } // Deliberately narrow by-ID shape; no participant/status/type/pagination filters. message QueryTransfersByIdRequest { repeated string transfer_ids = 1 [(validate.rules).repeated = {min_items: 1, max_items: 1000, items: {string: {uuid: true}}}]; Network network = 2 [(validate.rules).enum = {defined_only: true, not_in: [0]}]; } message ClaimLeafKeyTweak { string leaf_id = 1; SecretShare secret_share_tweak = 2; map pubkey_shares_tweak = 3; } message ClaimLeafKeyTweaks { repeated ClaimLeafKeyTweak leaves_to_receive = 1; } /** * ClaimPackage is a package of leaves to claim and key tweaks to apply. * This is in the improved claim transfer flow where the receiver can claim the transfer in one call * to the coordinator SO, similar to how TransferPackage works for the sender. */ message ClaimPackage { // The leaves to claim, with user signed cpfp refunds and signing package. repeated UserSignedTxSigningJob leaves_to_claim = 1; // The map of SO identifier to serialized ClaimLeafKeyTweaks. map key_tweak_package = 2; // The signature of user to prove that the key_tweak_package is not tampered. bytes user_signature = 3; // The leaves to claim, with user signed direct refunds and signing package. repeated UserSignedTxSigningJob direct_leaves_to_claim = 4; // The leaves to claim, with user signed direct from cpfp refunds and signing package. repeated UserSignedTxSigningJob direct_from_cpfp_leaves_to_claim = 5; // The hash variant to use for computing the claim package signing payload. HashVariant hash_variant = 6; } message ClaimTransferRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; ClaimPackage claim_package = 3; } message ClaimTransferResponse { Transfer transfer = 1; } message ClaimTransferTweakKeysRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; repeated ClaimLeafKeyTweak leaves_to_receive = 3; } message ClaimTransferSignRefundsRequest { string transfer_id = 1; bytes owner_identity_public_key = 2; repeated LeafRefundTxSigningJob signing_jobs = 3; reserved 4; } message ClaimTransferSignRefundsResponse { repeated LeafRefundTxSigningResult signing_results = 1; } message StorePreimageShareRequest { bytes payment_hash = 1; SecretShare preimage_share = 2; uint32 threshold = 3; string invoice_string = 4; bytes user_identity_public_key = 5; } message StorePreimageShareV2Request { bytes payment_hash = 1; // SO identifier -> ECIES-encrypted SecretShare protobuf map encrypted_preimage_shares = 2; uint32 threshold = 3; string invoice_string = 4; bytes user_identity_public_key = 5; reserved 6; reserved "user_signature"; } message RequestedSigningCommitments { map signing_nonce_commitments = 1; } message GetSigningCommitmentsRequest { // The node IDs for which to get signing commitments. repeated string node_ids = 1; // The number of signing commitments to get per node ID. uint32 count = 2; // Alternative to passing the node IDs: the number of node IDs for which to get signing commitments. // Either `node_ids` or `node_id_count` should be passed, but not both. uint32 node_id_count = 3; } message GetSigningCommitmentsResponse { // A list of signing commitments for each requested node ID. The signing commitments will be // ordered in the same order as the requested node IDs, repeated for the number of commitments // requested. For example, if node_ids = [A, B] and count = 2, the response will contain: // // [commitment_A1, commitment_B1, commitment_A2, commitment_B2] repeated RequestedSigningCommitments signing_commitments = 1; } message SigningCommitments { // A map of signing operator ID (i.e. 000...01) to the signing commitment provided by that // operator. map signing_commitments = 1; } message UserSignedRefund { string node_id = 1; bytes refund_tx = 2; bytes user_signature = 3; SigningCommitments signing_commitments = 4; common.SigningCommitment user_signature_commitment = 5; Network network = 6 [(validate.rules).enum = {not_in: [0]}]; } message InvoiceAmountProof { string bolt11_invoice = 1; } message InvoiceAmount { uint64 value_sats = 1; InvoiceAmountProof invoice_amount_proof = 2; } message InitiatePreimageSwapRequest { bytes payment_hash = 1; InvoiceAmount invoice_amount = 2; enum Reason { // The associated lightning service is sending the payment. REASON_SEND = 0; // The associated lightning service is receiving the payment. REASON_RECEIVE = 1; } Reason reason = 3; StartUserSignedTransferRequest transfer = 4; bytes receiver_identity_public_key = 5; uint64 fee_sats = 6; StartTransferRequest transfer_request = 7; } message InitiatePreimageSwapResponse { bytes preimage = 1; Transfer transfer = 2; } message OutPoint { bytes txid = 1; uint32 vout = 2; } message CooperativeExitRequest { StartTransferRequest transfer = 1; string exit_id = 2; bytes exit_txid = 3; bytes connector_tx = 4; } message CooperativeExitResponse { Transfer transfer = 1; repeated LeafRefundTxSigningResult signing_results = 2; } message CounterLeafSwapRequest { StartTransferRequest transfer = 1; string swap_id = 2; bytes adaptor_public_key = 3; bytes direct_adaptor_public_key = 4; bytes direct_from_cpfp_adaptor_public_key = 5; } message CounterLeafSwapResponse { Transfer transfer = 1; repeated LeafRefundTxSigningResult signing_results = 2; } message RefreshTimelockRequest { string leaf_id = 1; bytes owner_identity_public_key = 2; repeated SigningJob signing_jobs = 3; } message RefreshTimelockSigningResult { SigningResult signing_result = 1; bytes verifying_key = 2; // Should maybe just be a part of SigningResult? } message RefreshTimelockResponse { repeated RefreshTimelockSigningResult signing_results = 1; } message ExtendLeafRequest { string leaf_id = 1; bytes owner_identity_public_key = 2; SigningJob node_tx_signing_job = 3; SigningJob refund_tx_signing_job = 4; SigningJob direct_node_tx_signing_job = 5; SigningJob direct_refund_tx_signing_job = 6; SigningJob direct_from_cpfp_refund_tx_signing_job = 7; } message ExtendLeafSigningResult { SigningResult signing_result = 1; bytes verifying_key = 2; } message ExtendLeafResponse { string leaf_id = 1; ExtendLeafSigningResult node_tx_signing_result = 2; ExtendLeafSigningResult refund_tx_signing_result = 3; ExtendLeafSigningResult direct_node_tx_signing_result = 4; ExtendLeafSigningResult direct_refund_tx_signing_result = 5; ExtendLeafSigningResult direct_from_cpfp_refund_tx_signing_result = 6; } message AddressRequestNode { bytes user_public_key = 1; repeated AddressRequestNode children = 2; } message PrepareTreeAddressRequest { oneof source { NodeOutput parent_node_output = 1; UTXO on_chain_utxo = 2; } // The tx on this node is to spend the source's utxo. // The user's public key should already be registered with the SE for the root node. AddressRequestNode node = 3; bytes user_identity_public_key = 4; } message AddressNode { Address address = 1; repeated AddressNode children = 2; } message PrepareTreeAddressResponse { AddressNode node = 1; } message CreationNode { // This is the cpfp tx that spends the parent node's output. SigningJob node_tx_signing_job = 1; // The refund tx can only exist if there's no children. SigningJob refund_tx_signing_job = 2; // The children will spend the output of the node's tx. Vout is the index of the child. repeated CreationNode children = 3; // This is the direct tx that spends the parent node's output. SigningJob direct_node_tx_signing_job = 4; // The direct refund tx can only exist if there's no children. SigningJob direct_refund_tx_signing_job = 5; // The direct from cpfp refund tx can only exist if there's no children. SigningJob direct_from_cpfp_refund_tx_signing_job = 6; } message CreateTreeRequest { oneof source { NodeOutput parent_node_output = 1; UTXO on_chain_utxo = 2; } // The node should contain the tx that spends the source's utxo. CreationNode node = 3; // The owner of the tree. bytes user_identity_public_key = 4; } message CreationResponseNode { string node_id = 1; SigningResult node_tx_signing_result = 2; SigningResult refund_tx_signing_result = 3; repeated CreationResponseNode children = 4; SigningResult direct_node_tx_signing_result = 5; SigningResult direct_refund_tx_signing_result = 6; SigningResult direct_from_cpfp_refund_tx_signing_result = 7; } message CreateTreeResponse { CreationResponseNode node = 1; } message SigningOperatorInfo { uint64 index = 1; string identifier = 2; bytes public_key = 3; string address = 4; } message GetSigningOperatorListResponse { map signing_operators = 1; } message QueryUserSignedRefundsRequest { bytes payment_hash = 1; bytes identity_public_key = 2; } message QueryUserSignedRefundsResponse { repeated UserSignedRefund user_signed_refunds = 1; reserved 2; Transfer transfer = 3; } enum PreimageRequestStatus { PREIMAGE_REQUEST_STATUS_WAITING_FOR_PREIMAGE = 0; PREIMAGE_REQUEST_STATUS_PREIMAGE_SHARED = 1; PREIMAGE_REQUEST_STATUS_RETURNED = 2; } enum PreimageRequestRole { PREIMAGE_REQUEST_ROLE_RECEIVER = 0; PREIMAGE_REQUEST_ROLE_SENDER = 1; PREIMAGE_REQUEST_ROLE_RECEIVER_AND_SENDER = 2; } message PreimageRequestWithTransfer { // Preimage request data bytes payment_hash = 1 [(validate.rules).bytes.len = 32]; bytes receiver_identity_pubkey = 2 [(validate.rules).bytes.len = 33]; PreimageRequestStatus status = 3; google.protobuf.Timestamp created_time = 4; // Associated transfer (if exists) optional Transfer transfer = 5; // Preimage data (if available) optional bytes preimage = 6; // The identity public key of the sender can potentially be null for old preimage requests. bytes sender_identity_pubkey = 7; } message QueryHtlcRequest { repeated bytes payment_hashes = 1; bytes identity_public_key = 2 [(validate.rules).bytes.len = 33]; optional PreimageRequestStatus status = 3; int64 limit = 4; // defaults to 100 if not set. int64 offset = 5; // defaults to 0 if not set. repeated string transfer_ids = 6; PreimageRequestRole match_role = 7; // defaults to PREIMAGE_REQUEST_ROLE_RECEIVER if not set. } message QueryHtlcResponse { repeated PreimageRequestWithTransfer preimage_requests = 1; int64 offset = 2; // defaults to -1 if there are no more results } message ProvidePreimageRequest { bytes payment_hash = 1; bytes preimage = 2; bytes identity_public_key = 3; } message ProvidePreimageResponse { Transfer transfer = 1; } message QueryPreimageRequest { bytes payment_hash = 1 [(validate.rules).bytes.len = 32]; bytes receiver_identity_pubkey = 2 [(validate.rules).bytes.len = 33]; } message QueryPreimageResponse { optional bytes preimage = 1; } message TreeNodeIds { repeated string node_ids = 1; } message QueryNodesRequest { oneof source { bytes owner_identity_pubkey = 1; TreeNodeIds node_ids = 2; } bool include_parents = 3; int64 limit = 4; int64 offset = 5; Network network = 6; // Does not check network when querying by node_ids repeated TreeNodeStatus statuses = 7; } message QueryNodesResponse { map nodes = 1; int64 offset = 2; } message CancelTransferRequest { string transfer_id = 1; bytes sender_identity_public_key = 2; } message CancelTransferResponse { Transfer transfer = 1; } /** * Returns a list of addresses that can be used in express deposit flow. * Excludes static deposit addresses. **/ message QueryUnusedDepositAddressesRequest { bytes identity_public_key = 1; Network network = 2; int64 limit = 3; // defaults to 100 if not set. int64 offset = 4; // defaults to 0 if not set. } message QueryStaticDepositAddressesRequest { bytes identity_public_key = 1; Network network = 2; int64 limit = 4; int64 offset = 5; // Optional filter. When specified, only the DepositAddress with this address is returned. optional string deposit_address = 6; // The hash variant to use for computing the proof of possession message hash. HashVariant hash_variant = 7; } message DepositAddressQueryResult { string deposit_address = 1; bytes user_signing_public_key = 2; bytes verifying_public_key = 3; optional string leaf_id = 4 [(validate.rules).string.uuid = true]; optional DepositAddressProof proof_of_possession = 5; } message QueryUnusedDepositAddressesResponse { repeated DepositAddressQueryResult deposit_addresses = 1; int64 offset = 2; // defaults to -1 if there are no more results } message QueryStaticDepositAddressesResponse { repeated DepositAddressQueryResult deposit_addresses = 1; } message QueryBalanceRequest { bytes identity_public_key = 1; Network network = 2; } message QueryBalanceResponse { uint64 balance = 1; map node_balances = 2; } message SparkAddress { bytes identity_public_key = 1; SparkInvoiceFields spark_invoice_fields = 2; optional bytes signature = 3 [(validate.rules).bytes.len = 64]; } message SparkInvoiceFields { uint32 version = 1; bytes id = 2 [(validate.rules).bytes.len = 16]; oneof payment_type { TokensPayment tokens_payment = 3; SatsPayment sats_payment = 4; } optional string memo = 5 [(validate.rules).string.max_bytes = 120]; optional bytes sender_public_key = 6 [(validate.rules).bytes.len = 33]; optional google.protobuf.Timestamp expiry_time = 7; } message SatsPayment { optional uint64 amount = 1; } message TokensPayment { optional bytes token_identifier = 1 [(validate.rules).bytes.len = 32]; optional bytes amount = 2 [(validate.rules).bytes.max_len = 16]; // variable length uint128 } /** * Static deposit address flow messages * **/ enum UtxoSwapRequestType { Fixed = 0; MaxFee = 1; Refund = 2; Instant = 3; } enum UtxoSwapStatus { UTXO_SWAP_STATUS_UNSPECIFIED = 0; UTXO_SWAP_STATUS_CREATED = 1; UTXO_SWAP_STATUS_COMPLETED = 2; UTXO_SWAP_STATUS_CANCELLED = 3; } // Which hash variant to use in cryptographic operations. enum HashVariant { HASH_VARIANT_UNSPECIFIED = 0; // Legacy HASH_VARIANT_V2 = 1; // Structured hashing } message InitiateStaticDepositUtxoRefundRequest { UTXO on_chain_utxo = 1; // A package that is used for signing L1 Bitcoin transactions using FROST. // SE consumes it to return SigningResult structure, that is used by the user to // construct the final signature for the refund Bitcoin transaction. SigningJob refund_tx_signing_job = 3; // Signature of a user statement that authorises the SE to initiate a static // deposit utxo refund to the user. // // The user statement is constructed by concatenating the following fields in order: // 1. Action name: "claim_static_deposit" (UTF-8 string) // 2. Network: lowercase network name (e.g., "bitcoin", "testnet") (UTF-8 string) // 3. Transaction ID: hex-encoded UTXO transaction ID (UTF-8 string) // 4. Output index: UTXO output index (vout) as 4-byte unsigned integer (little-endian) // 5. Request type: 2 for refund (1-byte unsigned integer, little-endian) // 6. Credit amount: amount of satoshis to credit as 8-byte unsigned integer (little-endian) // 7. Signing payload: sighash of spend transaction (UTF-8 string) // // The concatenated payload is then hashed with SHA-256, and the resulting hash // is signed using ECDSA with the user's identity private key to produce this signature. bytes user_signature = 4; // Optional: which hash variant was used to create user_signature. HashVariant hash_variant = 5; } message InitiateStaticDepositUtxoRefundResponse { // The FROST signing results which must be aggregated by the user to complete signing SigningResult refund_tx_signing_result = 1; DepositAddressQueryResult deposit_address = 2; } message InitiateUtxoSwapRequest { UTXO on_chain_utxo = 1; UtxoSwapRequestType request_type = 2; oneof amount { uint64 credit_amount_sats = 3; uint64 max_fee_sats = 4; } bytes ssp_signature = 5; bytes user_signature = 6; StartTransferRequest transfer = 7; SigningJob spend_tx_signing_job = 8; } message InitiateUtxoSwapResponse { SigningResult spend_tx_signing_result = 1; Transfer transfer = 2; DepositAddressQueryResult deposit_address = 3; } message ExitingTree { string tree_id = 1; common.SigningCommitment user_signing_commitment = 2; uint32 vin = 3; } message ExitSingleNodeTreeSigningResult { string tree_id = 1; SigningResult signing_result = 2; bytes verifying_key = 3; } message BitcoinTransactionOutput { int64 value = 1; bytes pk_script = 2; } message ExitSingleNodeTreesRequest { bytes owner_identity_public_key = 1; repeated ExitingTree exiting_trees = 2; bytes raw_tx = 3; repeated BitcoinTransactionOutput previous_outputs = 4; } message ExitSingleNodeTreesResponse { repeated ExitSingleNodeTreeSigningResult signing_results = 1; } message QueryNodesDistributionRequest { bytes owner_identity_public_key = 1; } message QueryNodesDistributionResponse { map node_distribution = 1; } message QueryNodesByValueRequest { bytes owner_identity_public_key = 1; int64 value = 2; int64 offset = 3; int64 limit = 4; } message QueryNodesByValueResponse { map nodes = 1; int64 offset = 2; } message GetUtxosForAddressRequest { string address = 1; uint64 offset = 2; uint64 limit = 3; Network network = 4; bool exclude_claimed = 5; } message GetUtxosForAddressResponse { repeated UTXO utxos = 1; uint64 offset = 2; } message GetUtxosForIdentityRequest { bytes identity_public_key = 1 [(validate.rules).bytes.len = 33]; Network network = 2 [(validate.rules).enum = {not_in: [0]}]; bool exclude_claimed = 3; PageRequest page = 4; bool include_pending = 5; } message GetUtxosForIdentityResponse { repeated AddressedUtxo utxos = 1; PageResponse page = 2; } message QuerySparkInvoicesRequest { int64 limit = 1; int64 offset = 2; // returns the status for the provided list of spark invoices. repeated string invoice = 3; } message QuerySparkInvoicesResponse { int64 offset = 1; repeated InvoiceResponse invoice_statuses = 2; } message InvoiceResponse { string invoice = 1; InvoiceStatus status = 2; oneof transfer_type { SatsTransfer sats_transfer = 3; TokenTransfer token_transfer = 4; } } message SatsTransfer { bytes transfer_id = 1 [(validate.rules).bytes.len = 16]; } message TokenTransfer { bytes final_token_transaction_hash = 1 [(validate.rules).bytes.len = 32]; } enum InvoiceStatus { reserved 3; NOT_FOUND = 0; PENDING = 1; // Payment for this id is complete and the stored invoice's money fields // (receiver, payment kind, amount, token identifier) match the invoice // you queried. FINALIZED = 2; RETURNED = 4; // A payment exists for this invoice id, but the money fields (receiver, // payment kind, amount, token identifier) of the stored invoice may differ // from the invoice you queried. Compare response.invoice to the invoice // you queried and confirm it matches what you expect before relying on // this result. MISMATCHED_INVOICE_FINALIZED = 5; MISMATCHED_INVOICE_PENDING = 6; MISMATCHED_INVOICE_RETURNED = 7; } message InitiateSwapPrimaryTransferRequest { // Transfer with refunds and key tweaks signed StartTransferRequest transfer = 1; // Adaptor public keys to verify the signatures of refunds for the primary // transfer in the swap AdaptorPublicKeyPackage adaptor_public_keys = 2; } message InitiateSwapPrimaryTransferResponse { Transfer transfer = 1; repeated LeafRefundTxSigningResult signing_results = 2; } // Adaptor public key is derived from the secret `t` using formula: // ```text // T = t * G // ``` message AdaptorPublicKeyPackage { bytes adaptor_public_key = 1; bytes direct_adaptor_public_key = 2; bytes direct_from_cpfp_adaptor_public_key = 3; } enum TreeNodeStatus { TREE_NODE_STATUS_CREATING = 0; TREE_NODE_STATUS_AVAILABLE = 1; TREE_NODE_STATUS_FROZEN_BY_ISSUER = 2; TREE_NODE_STATUS_TRANSFER_LOCKED = 3; TREE_NODE_STATUS_SPLIT_LOCKED = 4; TREE_NODE_STATUS_SPLITTED = 5; TREE_NODE_STATUS_AGGREGATED = 6; TREE_NODE_STATUS_ON_CHAIN = 7; TREE_NODE_STATUS_AGGREGATE_LOCK = 8; TREE_NODE_STATUS_EXITED = 9; TREE_NODE_STATUS_RENEW_LOCKED = 10; TREE_NODE_STATUS_UNAVAILABLE = 11; TREE_NODE_STATUS_PARENT_EXITED = 12; } message WalletSetting { bytes owner_identity_public_key = 1 [(validate.rules).bytes.len = 33]; bool private_enabled = 2; optional bytes master_identity_public_key = 3 [(validate.rules).bytes.len = 33]; } message UpdateWalletSettingRequest { optional bool private_enabled = 1; oneof master_identity_public_key { bytes set_master_identity_public_key = 2; bool clear_master_identity_public_key = 3; } } message UpdateWalletSettingResponse { WalletSetting wallet_setting = 1; } message QueryWalletSettingRequest { } message QueryWalletSettingResponse { WalletSetting wallet_setting = 1; }