syntax = "proto3";

package hydra_app;

import "primitives.proto";
import "fee.proto";
import "balance.proto";
import "channel.proto";
import "payment.proto";

// Off-chain node management service.
//
// Provides full control over the off-chain node: peer connections, channel
// lifecycle (open, deposit, withdraw, close, force-close, redeem),
// payments (channel payments, routed payments, invoices, hashlocks),
// and dual-funding.
//
// JSON-RPC namespace: `node`
service NodeService {
  // Connect to a peer on a specific network.
  // This allows the node to establish a connection with another node
  // for communication and channel management.
  rpc ConnectToPeer(ConnectToPeerRequest) returns (ConnectToPeerResponse) {}
  // Disconnect from a peer on a specific network.
  // This allows the node to terminate the connection with another node.
  rpc DisconnectFromPeer(DisconnectFromPeerRequest)
      returns (DisconnectFromPeerResponse) {}
  // Get the list of connected peers on a specific network.
  rpc GetConnectedPeers(GetConnectedPeersRequest)
      returns (GetConnectedPeersResponse) {}
  // Check if a peer is connected on a specific network.
  rpc IsPeerConnected(IsPeerConnectedRequest)
      returns (IsPeerConnectedResponse) {}
  // Attach this node to a watchtower on a specific network.
  //
  // A watchtower holds the states and revocations this node signs, so
  // that a node which loses its local history can be handed back the
  // coverage it gave away, and so that a channel stays defended while
  // this node is offline. The session is separate from the ordinary
  // peer session: the same remote node may be both a channel peer and
  // a watchtower, and the two connections are independent.
  rpc ConnectToWatchtower(ConnectToWatchtowerRequest)
      returns (ConnectToWatchtowerResponse) {}
  // List the watchtowers this node currently has a session with.
  rpc GetConnectedWatchtowers(GetConnectedWatchtowersRequest)
      returns (GetConnectedWatchtowersResponse) {}
  // Read this node's policy configuration for the given asset.
  //
  // A "node policy" aggregates every parameter another party needs to
  // know before negotiating a channel with this node: reserve rules,
  // routing rules, channel timing rules, etc. Sub-messages are added
  // in a backwards-compatible way as new policy categories are
  // exposed by `NodeConfig` / per-protocol config traits.
  //
  // Used by liquidity providers (and any third party that wants to
  // size on-chain deposits accurately) to predict the exact runtime
  // reserve, routing fees, and payment ceilings the channel will be
  // subject to.
  rpc GetNodePolicy(GetNodePolicyRequest)
      returns (GetNodePolicyResponse) {}
  // Returns the zero-confirmation whitelist for the selected network.
  rpc GetZeroConfWhitelist(GetZeroConfWhitelistRequest)
      returns (GetZeroConfWhitelistResponse) {}
  // Adds a peer to the zero-confirmation whitelist.
  rpc AddPeerToZeroConfWhitelist(AddPeerToZeroConfWhitelistRequest)
      returns (AddPeerToZeroConfWhitelistResponse) {}
  // Removes a peer from the zero-confirmation whitelist.
  rpc RemovePeerFromZeroConfWhitelist(RemovePeerFromZeroConfWhitelistRequest)
      returns (RemovePeerFromZeroConfWhitelistResponse) {}
  // Returns the peer connection blacklist for the selected network.
  rpc GetBlacklist(GetBlacklistRequest) returns (GetBlacklistResponse) {}
  // Adds a peer to the connection blacklist.
  rpc AddPeerToBlacklist(AddPeerToBlacklistRequest)
      returns (AddPeerToBlacklistResponse) {}
  // Removes a peer from the connection blacklist.
  rpc RemovePeerFromBlacklist(RemovePeerFromBlacklistRequest)
      returns (RemovePeerFromBlacklistResponse) {}
  // Estimate the onchain fee for opening a channel with a specific peer.
  rpc EstimateOpenChannelFee(EstimateOpenChannelFeeRequest)
      returns (EstimateOpenChannelFeeResponse) {}
  // Open a channel with a specific peer on a specific network.
  // This operation will create a channel and allocate assets to it.
  // The channel will be funded with the specified asset amounts.
  rpc OpenChannel(OpenChannelRequest) returns (OpenChannelResponse) {}
  // Estimate the onchain fee for depositing assets into an existing channel.
  rpc EstimateDepositChannelFee(EstimateDepositChannelFeeRequest)
      returns (EstimateDepositChannelFeeResponse) {}
  // Deposit assets into an existing channel on a specific network.
  // This operation will add more assets to the channel, increasing its
  // capacity for future transactions.
  rpc DepositChannel(DepositChannelRequest) returns (DepositChannelResponse) {}
  // Estimate the onchain fee for withdrawing assets from an existing channel.
  rpc EstimateWithdrawChannelFee(EstimateWithdrawChannelFeeRequest)
      returns (EstimateWithdrawChannelFeeResponse) {}
  // Withdraw assets from an existing channel on a specific network.
  // This operation will remove assets from the channel, reducing its
  // capacity for future transactions.
  // The assets will be sent back to the respective parties.
  rpc WithdrawChannel(WithdrawChannelRequest)
      returns (WithdrawChannelResponse) {}
  // Estimate the onchain fee for a generic update of an existing channel.
  rpc EstimateUpdateChannelFee(EstimateUpdateChannelFeeRequest)
      returns (EstimateUpdateChannelFeeResponse) {}
  // Update an existing channel on a specific network.
  // Each side's wallet may deposit or withdraw independently, and part of
  // the resulting balance may be credited across in the state co-signed
  // alongside the update. A deposit and a withdrawal are the two shapes of
  // this that have their own calls; every other combination needs this one.
  rpc UpdateChannel(UpdateChannelRequest) returns (UpdateChannelResponse) {}
  // Estimate the onchain fee for closing a channel.
  rpc EstimateCloseChannelFee(EstimateCloseChannelFeeRequest)
      returns (EstimateCloseChannelFeeResponse) {}
  // Close a channel on a specific network.
  // This operation will settle the channel and return the assets to
  // the respective parties.
  rpc CloseChannel(CloseChannelRequest) returns (CloseChannelResponse) {}
  // Estimate the onchain fee for force-closing a channel.
  rpc EstimateForceCloseChannelFee(EstimateForceCloseChannelFeeRequest)
      returns (EstimateForceCloseChannelFeeResponse) {}
  // Force-close a channel on a specific network.
  // This operation will close the channel without waiting for the
  // normal settlement process. It is typically used in cases where
  // the channel is stuck or one party is unresponsive.
  // The assets will be spendable only after a dispute period.
  // Depending on the protocol, this may require an additional
  // transaction to redeem the assets after the dispute period expires.
  // This operation may incur higher fees than a normal close.
  rpc ForceCloseChannel(ForceCloseChannelRequest)
      returns (ForceCloseChannelResponse) {}
  // Estimate the onchain fee for redeeming a closed channel.
  rpc EstimateRedeemClosedChannelFee(EstimateRedeemClosedChannelFeeRequest)
      returns (EstimateRedeemClosedChannelFeeResponse) {}
  // Redeem a closed channel on a specific network.
  // This operation will settle the channel and return the assets to
  // the respective parties. It is used after a force-close
  // operation to finalize the settlement process and withdraw the
  // assets from the channel.
  rpc RedeemClosedChannel(RedeemClosedChannelRequest)
      returns (RedeemClosedChannelResponse) {}
  // Send a payment through a specific channel on a specific network.
  rpc SendChannelPayment(SendChannelPaymentRequest)
      returns (SendChannelPaymentResponse) {}
  // Estimate the offchain fee for sending a payment on a
  // network. This operation will find the best route for the payment
  // and calculate the fee for sending the payment through the
  // network.
  rpc EstimateSendPaymentFee(EstimateSendPaymentFeeRequest)
      returns (EstimateSendPaymentFeeResponse) {}
  // Send a payment on a specific network. This operation will find the
  // best route for the payment and send the payment through the
  // network. The payment will be routed through the channels and
  // nodes in the network to reach the recipient.
  rpc SendPayment(SendPaymentRequest) returns (SendPaymentResponse) {}
  // Create an invoice for a specific asset on a network.
  // This operation will generate a payment request that can be
  // shared with the payer.
  rpc CreateInvoice(CreateInvoiceRequest) returns (CreateInvoiceResponse) {}
  // Decode an invoice to retrieve its details.
  rpc DecodeInvoice(DecodeInvoiceRequest) returns (DecodeInvoiceResponse) {}
  // Estimate the offchain fee for paying an invoice.
  rpc EstimatePayInvoiceFee(EstimatePayInvoiceFeeRequest)
      returns (EstimatePayInvoiceFeeResponse) {}
  // Pay an invoice on a specific network.
  rpc PayInvoice(PayInvoiceRequest) returns (PayInvoiceResponse) {}
  // Estimate the offchain fee for paying an empty invoice by providing the
  // amount to pay.
  rpc EstimatePayEmptyInvoiceFee(EstimatePayEmptyInvoiceFeeRequest)
      returns (EstimatePayEmptyInvoiceFeeResponse) {}
  // Pay an empty invoice on a specific network by providing the
  // amount to pay.
  rpc PayEmptyInvoice(PayEmptyInvoiceRequest)
      returns (PayEmptyInvoiceResponse) {}
  // Resolve a hashlock payment by providing the payment preimage.
  // This operation will finalize the offchain payment and allow the recipient
  // to claim the funds.
  rpc ResolveHashlockPayment(ResolveHashlockPaymentRequest)
      returns (ResolveHashlockPaymentResponse) {}
  // Reject a hashlock payment on a specific network.
  // This operation will cancel the payment and unlock the funds for
  // the sender.
  rpc RejectPayment(RejectPaymentRequest) returns (RejectPaymentResponse) {}
  // Set the funding allowance for a specific peer on a network.
  // This replaces any existing allowance. The allowance controls the maximum
  // deposit and payment amounts that the counterparty is permitted to initiate
  // on our behalf.
  rpc SetFundingAllowance(SetFundingAllowanceRequest)
      returns (SetFundingAllowanceResponse) {}
  // Get the current funding allowance for a specific peer on a network.
  rpc GetFundingAllowance(GetFundingAllowanceRequest)
      returns (GetFundingAllowanceResponse) {}
  // Increase the funding allowance for a specific peer on a network.
  rpc IncreaseFundingAllowance(IncreaseFundingAllowanceRequest)
      returns (IncreaseFundingAllowanceResponse) {}
  // Decrease the funding allowance for a specific peer on a network.
  rpc DecreaseFundingAllowance(DecreaseFundingAllowanceRequest)
      returns (DecreaseFundingAllowanceResponse) {}
  // Revoke all funding allowances for a specific peer on a network.
  rpc RevokeFundingAllowance(RevokeFundingAllowanceRequest)
      returns (RevokeFundingAllowanceResponse) {}
  // Atomically execute a batch of on-chain channel operations in a single
  // transaction. Supported operations: open, deposit, withdraw, close,
  // force-close and redeem.
  rpc BatchChannelOperations(BatchChannelOperationsRequest)
      returns (BatchChannelOperationsResponse) {}
  // Estimate the total on-chain fee for a batch of channel operations.
  rpc EstimateBatchChannelOperationsFee(
      EstimateBatchChannelOperationsFeeRequest)
      returns (EstimateBatchChannelOperationsFeeResponse) {}
  // Estimate the on-chain fee of a single operation over a simulated channel
  // snapshot.
  rpc EstimateSimulatedChannelOperationFee(
      EstimateSimulatedChannelOperationFeeRequest)
      returns (EstimateSimulatedChannelOperationFeeResponse) {}
  // Estimate the total fee of multiple simulated channel-operation requests.
  rpc EstimateSimulatedChannelOperationsFee(
      EstimateSimulatedChannelOperationsFeeRequest)
      returns (EstimateSimulatedChannelOperationsFeeResponse) {}
}

// Request to connect to a remote peer.
message ConnectToPeerRequest {
  // The target network.
  Network network = 1;
  // The peer address in `<node_id>@<host>:<port>` format.
  string peer_url = 2;
}

message ConnectToPeerResponse {}

// Request to attach this node to a watchtower.
message ConnectToWatchtowerRequest {
  // The target network.
  Network network = 1;
  // The watchtower's address in `<node_id>@<host>:<port>` format — the
  // same form `ConnectToPeer` takes, since a watchtower is reached over
  // the same transport.
  string watchtower_url = 2;
}

message ConnectToWatchtowerResponse {}

// Request to list the watchtowers this node is attached to.
message GetConnectedWatchtowersRequest {
  // The target network.
  Network network = 1;
}

// Response containing the watchtowers this node has a session with.
message GetConnectedWatchtowersResponse {
  // Node ids of the attached watchtowers.
  repeated string node_ids = 1;
}

// Request to disconnect from a peer.
message DisconnectFromPeerRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

message DisconnectFromPeerResponse {}

// Request to list connected peers.
message GetConnectedPeersRequest {
  // The target network.
  Network network = 1;
}

// Response containing the list of connected peer node IDs.
message GetConnectedPeersResponse {
  // Hex-encoded public keys of connected peers.
  repeated string node_ids = 1;
}

// Request to check if a specific peer is connected.
message IsPeerConnectedRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

// Response indicating whether the peer is connected.
message IsPeerConnectedResponse {
  // True if the peer is currently connected.
  bool is_connected = 1;
}

// Request to read this node's policy configuration for an asset on a
// specific network. The asset is required because several policy
// values (`min_channel_reserve`, per-asset routing limits, etc.) are
// denominated in the asset's smallest unit.
message GetNodePolicyRequest {
  // The target network.
  Network network = 1;
  // The asset whose policy is being queried.
  string asset_id = 2;
}

// Aggregated node policy. Every sub-message describes one category of
// policy this node enforces. New categories can be added without
// breaking existing clients.
message GetNodePolicyResponse {
  // Channel-reserve parameters. Drives the deposit sizing algebra
  // `deposit = (free + fixed) / (1 − rate)` on the counterparty side.
  ReservePolicy reserve = 1;
}

// Channel reserve policy for a single (network, asset) pair. All
// `Decimal` amounts are in the asset's display denomination.
message ReservePolicy {
  // The reserve ratio (in millionths) the node imposes on its
  // counterparty when opening or accepting a channel. The runtime
  // reserve locked on the counterparty side equals
  // `(free + fixed) × counterparty_proportional_millionths / 1_000_000`.
  // Range: `[0, 1_000_000)`.
  uint64 counterparty_proportional_millionths = 1;
  // The maximum reserve ratio (in millionths) the node will accept on
  // its own side. Used by callers as an upper-bound clamp on the rate
  // they expect to see at runtime. Range: `[0, 1_000_000)`.
  uint64 max_self_proportional_millionths = 2;
  // Absolute minimum reserve in the asset's display denomination.
  // The runtime reserve is at least this value regardless of the
  // proportional rule.
  DecimalString min_absolute = 3;
  // Fixed-fee reserve (in the asset's display denomination) added on
  // top of the proportional reserve as a gas / dust buffer. Applies
  // once per channel, regardless of how many assets the channel holds.
  DecimalString fee_channel_reserve = 4;
}

// Request to retrieve the zero-confirmation whitelist.
message GetZeroConfWhitelistRequest {
  // The target network.
  Network network = 1;
}

// Response containing the zero-confirmation whitelist.
message GetZeroConfWhitelistResponse {
  // Hex-encoded public keys of whitelisted peers.
  repeated string node_ids = 1;
}

// Request to add a peer to the zero-confirmation whitelist.
message AddPeerToZeroConfWhitelistRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

message AddPeerToZeroConfWhitelistResponse {}

// Request to remove a peer from the zero-confirmation whitelist.
message RemovePeerFromZeroConfWhitelistRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

message RemovePeerFromZeroConfWhitelistResponse {}

// Request to retrieve the connection blacklist.
message GetBlacklistRequest {
  // The target network.
  Network network = 1;
}

// Response containing the connection blacklist.
message GetBlacklistResponse {
  // Hex-encoded public keys of blacklisted peers.
  repeated string node_ids = 1;
}

// Request to add a peer to the connection blacklist.
message AddPeerToBlacklistRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

message AddPeerToBlacklistResponse {}

// Request to remove a peer from the connection blacklist.
message RemovePeerFromBlacklistRequest {
  // The target network.
  Network network = 1;
  // The peer's public key in hex-encoded format.
  string node_id = 2;
}

message RemovePeerFromBlacklistResponse {}

// Request to estimate the on-chain fee for opening a channel.
message EstimateOpenChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The counterparty's public key.
  string node_id = 2;
  // Map of asset IDs to deposit amounts to allocate to the channel.
  map<string, DepositAmount> asset_amounts = 3;
  // The fee priority for the funding transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateOpenChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to open a channel with a peer.
message OpenChannelRequest {
  // The target network.
  Network network = 1;
  // The counterparty's public key.
  string node_id = 2;
  // Map of asset IDs to deposit amounts to allocate to the channel.
  map<string, DepositAmount> asset_amounts = 3;
  // The fee priority for the funding transaction.
  FeeOption fee_option = 4;
}

// Response containing the funding transaction and channel details.
message OpenChannelResponse {
  // The funding transaction ID.
  string txid = 1;
  // The newly created channel ID.
  string channel_id = 2;
}

// Request to estimate the on-chain fee for depositing into a channel.
message EstimateDepositChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The channel to deposit into.
  string channel_id = 2;
  // Map of asset IDs to deposit amounts.
  map<string, DepositAmount> asset_amounts = 3;
  // The fee priority for the deposit transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateDepositChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to deposit assets into an existing channel.
message DepositChannelRequest {
  // The target network.
  Network network = 1;
  // The channel to deposit into.
  string channel_id = 2;
  // Map of asset IDs to deposit amounts.
  map<string, DepositAmount> asset_amounts = 3;
  // The fee priority for the deposit transaction.
  FeeOption fee_option = 4;
}

// Response containing the deposit transaction details.
message DepositChannelResponse {
  // The deposit transaction ID.
  string txid = 1;
}

// Amount specification for a cooperative withdrawal from a channel.
// Both parties can withdraw assets in the same on-chain transaction.
message WithdrawAmount {
  // The amount to withdraw to the local wallet.
  Amount self_withdrawal = 1;
  // The amount to withdraw to the counterparty's wallet.
  Amount counterparty_withdrawal = 2;
}

// Request to estimate the on-chain fee for withdrawing from a channel.
message EstimateWithdrawChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The channel to withdraw from.
  string channel_id = 2;
  // Map of asset IDs to withdrawal amounts for each party.
  map<string, WithdrawAmount> asset_amounts = 3;
  // The fee priority for the withdrawal transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateWithdrawChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to withdraw assets from an existing channel.
message WithdrawChannelRequest {
  // The target network.
  Network network = 1;
  // The channel to withdraw from.
  string channel_id = 2;
  // Map of asset IDs to withdrawal amounts for each party.
  map<string, WithdrawAmount> asset_amounts = 3;
  // The fee priority for the withdrawal transaction.
  FeeOption fee_option = 4;
}

// Response containing the withdrawal transaction details.
message WithdrawChannelResponse {
  // The withdrawal transaction ID.
  string txid = 1;
}

// Request to estimate the on-chain fee for updating a channel.
message EstimateUpdateChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The channel to update.
  string channel_id = 2;
  // Map of asset IDs to the update each one asks for.
  map<string, ChannelUpdateAmount> asset_updates = 3;
  // The fee priority for the update transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateUpdateChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to update an existing channel.
message UpdateChannelRequest {
  // The target network.
  Network network = 1;
  // The channel to update.
  string channel_id = 2;
  // Map of asset IDs to the update each one asks for.
  map<string, ChannelUpdateAmount> asset_updates = 3;
  // The fee priority for the update transaction.
  FeeOption fee_option = 4;
}

// Response containing the update transaction details.
message UpdateChannelResponse {
  // The update transaction ID.
  string txid = 1;
}

// Request to estimate the on-chain fee for closing a channel.
message EstimateCloseChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The channel to close.
  string channel_id = 2;
  // The asset IDs to settle in the closing transaction.
  repeated string asset_ids = 3;
  // The fee priority for the closing transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateCloseChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to cooperatively close a channel.
message CloseChannelRequest {
  // The target network.
  Network network = 1;
  // The channel to close.
  string channel_id = 2;
  // The asset IDs to settle in the closing transaction.
  repeated string asset_ids = 3;
  // The fee priority for the closing transaction.
  FeeOption fee_option = 4;
}

// Response containing the closing transaction details.
message CloseChannelResponse {
  // The closing transaction ID.
  string txid = 1;
}

// Request to estimate the on-chain fee for force-closing a channel.
message EstimateForceCloseChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The channel to force-close.
  string channel_id = 2;
  // The asset IDs to settle.
  repeated string asset_ids = 3;
  // The fee priority for the force-close transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateForceCloseChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to unilaterally force-close a channel.
message ForceCloseChannelRequest {
  // The target network.
  Network network = 1;
  // The channel to force-close.
  string channel_id = 2;
  // The asset IDs to settle.
  repeated string asset_ids = 3;
  // The fee priority for the force-close transaction.
  FeeOption fee_option = 4;
}

// Response containing the force-close transaction details.
message ForceCloseChannelResponse {
  // The force-close transaction ID.
  string txid = 1;
}

// Request to estimate the on-chain fee for redeeming a force-closed channel.
message EstimateRedeemClosedChannelFeeRequest {
  // The target network.
  Network network = 1;
  // The force-closed channel to redeem.
  string channel_id = 2;
  // The asset IDs to redeem.
  repeated string asset_ids = 3;
  // The fee priority for the redeem transaction.
  FeeOption fee_option = 4;
}

// Response containing the estimated on-chain fee.
message EstimateRedeemClosedChannelFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to redeem assets from a force-closed channel after the dispute
// period has expired.
message RedeemClosedChannelRequest {
  // The target network.
  Network network = 1;
  // The force-closed channel to redeem.
  string channel_id = 2;
  // The asset IDs to redeem.
  repeated string asset_ids = 3;
  // The fee priority for the redeem transaction.
  FeeOption fee_option = 4;
}

// Response containing the redeem transaction details.
message RedeemClosedChannelResponse {
  // The redeem transaction ID.
  string txid = 1;
}

// Request to send a direct KeySend payment through a specific channel.
message SendChannelPaymentRequest {
  // The target network.
  Network network = 1;
  // The channel to send the payment through.
  string channel_id = 2;
  // Map of asset IDs to amounts to send.
  map<string, Amount> asset_amounts = 3;
  // Optional hashlock to create a conditional (HTLC) payment.
  optional Hashlock hashlock = 4;
  // Optional HTLC effective lifetime (BOLT-11 tag `c` semantic in seconds).
  // KeySend has no separate "invoice validity" knob — `cltv_buffer_secs`
  // alone is sufficient to bound the HTLC.
  optional uint64 cltv_buffer_secs = 5;
}

// Response containing the payment details.
message SendChannelPaymentResponse {
  // The unique identifier of the payment that was sent.
  string payment_id = 1;
}

// Request to estimate the off-chain fee for sending a routed KeySend payment.
message EstimateSendPaymentFeeRequest {
  // The target network.
  Network network = 1;
  // The recipient's public key.
  string recipient_node_id = 2;
  // Map of asset IDs to amounts to send.
  map<string, Amount> asset_amounts = 3;
  // Optional hashlock to create a conditional (HTLC) payment.
  optional Hashlock hashlock = 4;
  // Optional HTLC effective lifetime (BOLT-11 tag `c` semantic in seconds).
  optional uint64 cltv_buffer_secs = 5;
  // Optional clamp on the route's max-total-cltv (in seconds).  For
  // atomic-swap-correct timing pass a value matching the invoice's
  // `cltv_buffer_secs`; for permissive multi-hop routing omit.
  optional uint64 max_total_cltv_secs = 6;
}

// Response containing the estimated off-chain routing fees.
message EstimateSendPaymentFeeResponse {
  // Map of asset IDs to their estimated routing fees.
  map<string, DecimalString> fees = 1;
}

// Request to send a routed KeySend payment to a recipient node.
message SendPaymentRequest {
  // The target network.
  Network network = 1;
  // The recipient's public key.
  string recipient_node_id = 2;
  // Map of asset IDs to amounts to send.
  map<string, Amount> asset_amounts = 3;
  // Optional hashlock to create a conditional (HTLC) payment.
  optional Hashlock hashlock = 4;
  // Optional HTLC effective lifetime (BOLT-11 tag `c` semantic in seconds).
  optional uint64 cltv_buffer_secs = 5;
  // Optional clamp on the route's max-total-cltv (in seconds).
  optional uint64 max_total_cltv_secs = 6;
}

// Response containing the payment details.
message SendPaymentResponse {
  // The unique identifier of the payment that was sent.
  string payment_id = 1;
}

// Request to create a payment invoice.
message CreateInvoiceRequest {
  // The target network.
  Network network = 1;
  // The asset to receive payment in.
  string asset_id = 2;
  // The requested amount (omit for "empty" invoices where the payer decides).
  optional DecimalString amount = 3;
  // Optional custom hashlock for conditional payments.
  optional Hashlock hashlock = 4;
  // Optional invoice validity window in seconds (BOLT-11 `x` semantic).
  optional uint64 expiry_timeout_secs = 5;
  // Optional extra HTLC lifetime past invoice expiry the receiver
  // requires for safe settlement (BOLT-11 `c` semantic in seconds).
  optional uint64 cltv_buffer_secs = 6;
}

// Response containing the created invoice.
message CreateInvoiceResponse {
  // The created invoice with its payment request string.
  Invoice invoice = 1;
}

// Request to decode an invoice's payment request string.
message DecodeInvoiceRequest {
  // The target network.
  Network network = 1;
  // The encoded payment request string to decode.
  string payment_request = 2;
}

// Response containing the decoded invoice details.
message DecodeInvoiceResponse {
  // The decoded invoice.
  Invoice invoice = 1;
}

// Request to estimate the off-chain fee for paying an invoice.
message EstimatePayInvoiceFeeRequest {
  // The target network.
  Network network = 1;
  // The payment request string of the invoice to pay.
  string payment_request = 2;
  // Optional clamp on the route's max-total-cltv (in seconds).  For
  // atomic-swap-correct timing pass a value matching the invoice's
  // `cltv_buffer_secs`; for permissive multi-hop routing omit.
  optional uint64 max_total_cltv_secs = 3;
}

// Response containing the estimated routing fee.
message EstimatePayInvoiceFeeResponse {
  // The estimated routing fee.
  DecimalString fee = 1;
}

// Request to estimate the fee for paying an empty (amount-less) invoice.
message EstimatePayEmptyInvoiceFeeRequest {
  // The target network.
  Network network = 1;
  // The payment request string of the empty invoice.
  string payment_request = 2;
  // The amount to pay.
  Amount amount = 3;
  // Optional clamp on the route's max-total-cltv (in seconds).
  optional uint64 max_total_cltv_secs = 4;
}

// Response containing the estimated routing fee.
message EstimatePayEmptyInvoiceFeeResponse {
  // The estimated routing fee.
  DecimalString fee = 1;
}

// Request to pay an empty (amount-less) invoice with a specified amount.
message PayEmptyInvoiceRequest {
  // The target network.
  Network network = 1;
  // The payment request string of the empty invoice.
  string payment_request = 2;
  // The amount to pay.
  Amount amount = 3;
  // Optional clamp on the route's max-total-cltv (in seconds).
  optional uint64 max_total_cltv_secs = 4;
}

// Response containing the payment details.
message PayEmptyInvoiceResponse {
  // The unique identifier of the payment.
  string payment_id = 1;
}

// Request to pay an invoice.
message PayInvoiceRequest {
  // The target network.
  Network network = 1;
  // The payment request string of the invoice to pay.
  string payment_request = 2;
  // Optional clamp on the route's max-total-cltv (in seconds).  For
  // atomic-swap-correct timing pass a value matching the invoice's
  // `cltv_buffer_secs`; for permissive multi-hop routing omit.
  optional uint64 max_total_cltv_secs = 3;
}

// Response containing the payment details.
message PayInvoiceResponse {
  // The unique identifier of the payment.
  string payment_id = 1;
}

// Request to resolve a hashlock (HTLC) payment by providing the preimage.
message ResolveHashlockPaymentRequest {
  // The target network.
  Network network = 1;
  // The payment ID to resolve.
  string payment_id = 2;
  // The hex-encoded payment preimage that satisfies the hashlock.
  string payment_preimage = 3;
}

message ResolveHashlockPaymentResponse {}

// Request to reject a pending incoming payment.
message RejectPaymentRequest {
  // The target network.
  Network network = 1;
  // The payment ID to reject.
  string payment_id = 2;
}

message RejectPaymentResponse {}


// Funding allowance for a single asset.
// Controls what a peer may fund and what it may be credited.
message FundingAllowance {
  // Maximum deposit amount the peer may initiate (human-readable decimal).
  DecimalString allowed_deposit = 1;
  // Maximum balance the peer may be credited out of this side, whatever
  // moved it (human-readable decimal).
  DecimalString allowed_payment = 2;
}

// Request to set the funding allowance for a peer.
// This replaces any existing allowance for the specified assets.
message SetFundingAllowanceRequest {
  // The target network.
  Network network = 1;
  // The peer's public key.
  string node_id = 2;
  // Map of asset IDs to funding allowances.
  map<string, FundingAllowance> asset_allowances = 3;
}

message SetFundingAllowanceResponse {}

// Request to get the current funding allowance for a peer.
message GetFundingAllowanceRequest {
  // The target network.
  Network network = 1;
  // The peer's public key.
  string node_id = 2;
}

// Response with the current funding allowance for a peer.
message GetFundingAllowanceResponse {
  // Map of asset IDs to remaining funding allowances.
  map<string, FundingAllowance> asset_allowances = 1;
}

// Request to increase the funding allowance for a peer.
message IncreaseFundingAllowanceRequest {
  // The target network.
  Network network = 1;
  // The peer's public key.
  string node_id = 2;
  // Map of asset IDs to amounts to add to the current allowance.
  map<string, FundingAllowance> asset_allowances = 3;
}

message IncreaseFundingAllowanceResponse {
  // Map of asset IDs to updated funding allowances.
  map<string, FundingAllowance> asset_allowances = 1;
}

// Request to decrease the funding allowance for a peer.
message DecreaseFundingAllowanceRequest {
  // The target network.
  Network network = 1;
  // The peer's public key.
  string node_id = 2;
  // Map of asset IDs to amounts to subtract from the current allowance.
  map<string, FundingAllowance> asset_allowances = 3;
}

message DecreaseFundingAllowanceResponse {
  // Map of asset IDs to updated funding allowances.
  map<string, FundingAllowance> asset_allowances = 1;
}

// Request to revoke all funding allowances for a peer.
message RevokeFundingAllowanceRequest {
  // The target network.
  Network network = 1;
  // The peer's public key.
  string node_id = 2;
}

message RevokeFundingAllowanceResponse {}

// ── Batch channel operations ────────────────────────────────────────

// Open a new channel as part of a batch.
message BatchOpenChannel {
  // The peer's public key.
  string peer_pubkey = 1;
  // Map of asset IDs to deposit amounts for the new channel.
  map<string, DepositAmount> asset_amounts = 2;
}

// Deposit into an existing channel as part of a batch.
message BatchDepositChannel {
  // The channel to deposit into.
  string channel_id = 1;
  // Map of asset IDs to deposit amounts.
  map<string, DepositAmount> asset_amounts = 2;
}

// Withdraw from a channel as part of a batch.
message BatchWithdrawChannel {
  // The channel to withdraw from.
  string channel_id = 1;
  // Map of asset IDs to withdrawal amounts for each party.
  map<string, WithdrawAmount> asset_amounts = 2;
}

// Update a channel as part of a batch.
message BatchUpdateChannel {
  // The channel to update.
  string channel_id = 1;
  // Map of asset IDs to the update each one asks for.
  map<string, ChannelUpdateAmount> asset_updates = 2;
}

// Cooperatively close a channel as part of a batch.
message BatchCloseChannel {
  // The channel to close.
  string channel_id = 1;
  // The asset IDs to settle.
  repeated string asset_ids = 2;
}

// Force-close a channel as part of a batch.
message BatchForceCloseChannel {
  // The channel to force-close.
  string channel_id = 1;
  // The asset IDs to settle.
  repeated string asset_ids = 2;
}

// Redeem a force-closed channel as part of a batch.
message BatchRedeemChannel {
  // The channel to redeem.
  string channel_id = 1;
  // The asset IDs to redeem.
  repeated string asset_ids = 2;
}

// A single operation within a batch of channel operations.
message BatchChannelOperation {
  oneof operation {
    BatchOpenChannel open = 1;
    BatchDepositChannel deposit = 2;
    BatchWithdrawChannel withdraw = 3;
    BatchCloseChannel close = 4;
    BatchForceCloseChannel force_close = 5;
    BatchRedeemChannel redeem = 6;
    BatchUpdateChannel update = 7;
  }
}

// Request to atomically execute a batch of on-chain channel operations
// in a single transaction.
message BatchChannelOperationsRequest {
  // The target network.
  Network network = 1;
  // The list of operations to execute atomically.
  repeated BatchChannelOperation operations = 2;
  // The fee priority for the batched transaction.
  FeeOption fee_option = 3;
}

// Channel id produced by an Open operation within a batch, paired with
// the 0-based index of the originating operation in the request's
// `operations` list.
message BatchOpenedChannel {
  // 0-based index of the Open operation within the request's
  // `operations` list.
  uint32 input_index = 1;
  // Channel id assigned to that operation.
  string channel_id = 2;
}

// Response containing the batch transaction result.
message BatchChannelOperationsResponse {
  // The single transaction ID for the entire batch.
  string txid = 1;
  // Channel IDs created by Open operations. Each entry carries the
  // input index of the Open operation it originated from so callers do
  // not have to rely on any particular returned order.
  repeated BatchOpenedChannel opened_channels = 2;
}

// Request to estimate the total on-chain fee for a batch of channel operations.
message EstimateBatchChannelOperationsFeeRequest {
  // The target network.
  Network network = 1;
  // The list of operations to estimate fees for.
  repeated BatchChannelOperation operations = 2;
  // The fee priority for the estimation.
  FeeOption fee_option = 3;
}

// Response containing the estimated total fee for the batch.
message EstimateBatchChannelOperationsFeeResponse {
  // The estimated total fee in the network's native currency.
  DecimalString fee = 1;
}

// Simulated channel asset snapshot used for fee estimation.
message SimulatedAssetChannel {
  // The asset identifier.
  string asset_id = 1;
  // Our currently committed on-chain balance.
  DecimalString onchain_self_balance = 2;
  // Counterparty currently committed on-chain balance.
  DecimalString onchain_counterparty_balance = 3;
  // Our latest off-chain balance.
  DecimalString latest_self_balance = 4;
  // Counterparty latest off-chain balance.
  DecimalString latest_counterparty_balance = 5;
  // Number of pending HTLCs.
  uint64 num_htlcs = 6;
}

// Simulated channel snapshot used for fee estimation.
message SimulatedChannel {
  repeated SimulatedAssetChannel assets = 1;
}

// Operation kind to estimate on a simulated channel snapshot.
enum SimulatedChannelOperation {
  SIMULATED_CHANNEL_OPERATION_UNSPECIFIED = 0;
  SIMULATED_CHANNEL_OPERATION_OPEN = 1;
  SIMULATED_CHANNEL_OPERATION_DEPOSIT = 2;
  SIMULATED_CHANNEL_OPERATION_WITHDRAW = 3;
  SIMULATED_CHANNEL_OPERATION_COOPERATIVE_CLOSE = 4;
  SIMULATED_CHANNEL_OPERATION_FORCE_CLOSE = 5;
  SIMULATED_CHANNEL_OPERATION_CONFIRM_SETTLEMENT = 6;
}

// A simulated channel estimation request.
message SimulatedChannelOp {
  SimulatedChannel channel = 1;
  SimulatedChannelOperation operation = 2;
}

// Request to estimate the fee for a single simulated channel operation.
message EstimateSimulatedChannelOperationFeeRequest {
  // The target network.
  Network network = 1;
  // The simulated channel snapshot.
  SimulatedChannel channel = 2;
  // The operation to estimate.
  SimulatedChannelOperation operation = 3;
  // The fee priority for the estimation.
  FeeOption fee_option = 4;
}

// Response containing the estimated fee for a single simulated channel
// operation.
message EstimateSimulatedChannelOperationFeeResponse {
  // The estimated fee in the network's native currency.
  DecimalString fee = 1;
}

// Request to estimate the total fee for multiple simulated channel operations.
message EstimateSimulatedChannelOperationsFeeRequest {
  // The target network.
  Network network = 1;
  // The simulated operations to estimate.
  repeated SimulatedChannelOp operations = 2;
  // The fee priority for the estimation.
  FeeOption fee_option = 3;
}

// Response containing the estimated fee for multiple simulated channel
// operations.
message EstimateSimulatedChannelOperationsFeeResponse {
  // The estimated total fee in the network's native currency.
  DecimalString fee = 1;
}
