mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
Document the configurable maximum account payment size and optional channel balance reservation check, including their defaults, fee handling, and operational limitations.
197 lines
8.3 KiB
Markdown
197 lines
8.3 KiB
Markdown
# Custodial accounts
|
|
|
|
This document describes how the "accounts" feature of LiT can be used to create
|
|
custodial user accounts with their own balances on an existing `lnd` node.
|
|
|
|
## What is an account?
|
|
|
|
An account in the LiT context is a virtual construct that provides restricted
|
|
access to an existing `lnd`/LiT node. An account has a virtual (off-chain only)
|
|
balance in satoshis and an optional expiration. That allows a node operator to
|
|
give someone else (or some client application, see [Use cases](#use-cases))
|
|
restricted access to their node with the ability to only spend up to a certain
|
|
amount of the node's channel balance.
|
|
|
|
NOTE: An account's balance is purely virtual. If an account is created with an
|
|
initial balance higher than the node's actual overall channel balance, that is
|
|
equivalent to fractional reserve banking. Therefore, the user accepting an
|
|
account-restricted access enters a trust relationship with the node operator
|
|
that the promised balance of the account is actually spendable.
|
|
|
|
## How do accounts work?
|
|
|
|
The accounts system is made possible thanks to the power of
|
|
[macaroons](https://github.com/lightningnetwork/lnd/blob/master/docs/macaroons.md)
|
|
and the [RPC middleware
|
|
interceptor](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.proto#L558)
|
|
of `lnd`.
|
|
|
|
**What does that mean?**
|
|
|
|
It means a node operator can give another user or client application access to
|
|
their node through the default gRPC interface of `lnd`, which makes this access
|
|
mode fully compatible with any remote (or local) user interfaces or
|
|
apps/browser plugins, as well as any [LNC (Lightning Node
|
|
Connect)](https://github.com/lightninglabs/lightning-node-connect) connection.
|
|
|
|
What features and balance the restricted user has access to is **solely
|
|
controlled by the macaroon that is given to the user**. So a user that wants to
|
|
get restricted access to a node will receive a macaroon that is bound to an
|
|
account that is defined in LiT. Because of the cryptographic setup of macaroons,
|
|
that restriction cannot be removed from the macaroon by the user without
|
|
invalidating the macaroon itself. Therefore, any user/application using such a
|
|
restricted macaroon will trigger special rules in the RPC middleware interceptor
|
|
mentioned above. See [the features](#features) section below to find out what
|
|
those rules are.
|
|
|
|
## Features
|
|
|
|
When an account-restricted macaroon is used, the RPC middleware interceptor
|
|
enforces the following rules on the RPC interface:
|
|
|
|
* Any payment made by a custodial/restricted user account is deducted from an
|
|
account's virtual balance (the full amount, including off-chain routing fees).
|
|
* If a payment (or the sum of multiple in-flight payments) exceeds the account's
|
|
virtual balance, it is denied.
|
|
* The on-chain balance of any RPC responses such as the `WalletBalance` RPC is
|
|
always shown as `0`. A custodial/restricted user shouldn't be able to see what
|
|
on-chain balance is available to the node operator as an account can only
|
|
spend off-chain balances anyway.
|
|
* The off-chain balance (e.g. the response returned by the `ChannelBalance` RPC)
|
|
always reflects the account's virtual balance and not the node's overall
|
|
channel balance (and any remote balances are always shown as `0`).
|
|
* The list of active/pending/closed channels is always returned empty. The
|
|
custodial/restricted user should not need to care (or even know) about
|
|
channels and their internal workings.
|
|
* The list of payments and invoices is filtered to only return payments/invoices
|
|
created or paid by the account.
|
|
* Invoices created by an account are mapped to that account. If/when such a
|
|
mapped invoice is paid, the amount is credited to that account's virtual
|
|
balance.
|
|
|
|
## Operator controls
|
|
|
|
LiT provides optional account safeguards through its configuration:
|
|
|
|
* `accounts.max-payment-size-msat` limits the total amount a single account
|
|
payment may debit, including fees. For `SendPaymentV2`, the configured fee
|
|
limit is included; for `SendToRouteV2`, the route's stated fee is included.
|
|
The default value of `0` disables this limit.
|
|
* `accounts.check-channel-balance` rejects new accounts, administrative
|
|
credits and administrative balance increases that would make the sum of all
|
|
account balances exceed the node's current local channel balance. It is
|
|
disabled by default. When enabled, allocations fail if LiT cannot query the
|
|
Lightning client for the channel balance.
|
|
|
|
Note: The channel-balance check only applies when a balance is allocated. It
|
|
cannot prevent the node's local balance from subsequently falling below the
|
|
allocated account balance if the operator sends non-account Lightning
|
|
payments or other non-account activity.
|
|
|
|
## Use cases
|
|
|
|
The following (definitely non-exhaustive) list of use cases is made possible by
|
|
the accounts system:
|
|
- The "Uncle Jim" model: The tech-savvy person of the family (e.g. "Uncle Jim")
|
|
operates a Lightning node. He manages the liquidity of the node and provides
|
|
the capital for the channels. He can onboard his family members by creating
|
|
an account, locking a macaroon to that account and then scanning a QR code
|
|
with an app like [Zeus](https://github.com/ZeusLN/zeus) on the family
|
|
member's smartphone.
|
|
- The "spend up to a certain amount automatically" model: A web user has a
|
|
browser extension like [Alby](https://getalby.com/) installed and wants to
|
|
allow that extension to pay invoices for paywalls automatically up to a
|
|
certain amount per month. That amount could be enforced by the account so the
|
|
browser extension doesn't have to keep track of its spending actions. And an
|
|
account can be shared between extensions installed in different browsers.
|
|
- The "allowance" model: A parent wants to give their child their allowance in
|
|
Lightning satoshis. They create an account over the allowance amount and top
|
|
up the account each week/month.
|
|
|
|
## HOWTO
|
|
|
|
This section describes how an account can be created and used.
|
|
|
|
### Create the account
|
|
|
|
The first thing that needs to be done is to create the account with its initial
|
|
balance (and an optional expiry). This **needs to be done by the node
|
|
operator**, meaning access to the `lit.macaroon` is required.
|
|
|
|
Example:
|
|
```shell
|
|
$ litcli accounts create 50000 --save_to /tmp/accounts.macaroon
|
|
|
|
{
|
|
"account": {
|
|
"id": "d64dbc31b28edf66",
|
|
"initial_balance": "50000",
|
|
"current_balance": "50000",
|
|
"last_update": "1652353332",
|
|
"expiration_date": "0"
|
|
},
|
|
"macaroon": "020103........."
|
|
}
|
|
Account macaroon saved to /tmp/accounts.macaroon
|
|
```
|
|
|
|
This created a new account (ID `d64dbc31b28edf66`) with an initial balance of
|
|
50k satoshis and no expiration. A new macaroon was baked that contains the
|
|
correct permissions and is locked to that account. The macaroon file was stored
|
|
under `/tmp/accounts.macaroon` in this example.
|
|
|
|
### Use the macaroon
|
|
|
|
This step is done by the user/app that should be given the restricted access. An
|
|
example could be to create a QR code with a tool like
|
|
[`lndconnect`](https://github.com/LN-Zap/lndconnect) that can be scanned by
|
|
mobile apps to connect to the node. Or some browser extensions require the user
|
|
to upload the macaroon to the browser.
|
|
|
|
**It's absolutely crucial to use the macaroon generated in the previous step
|
|
here** to make sure the restrictions are applied.
|
|
|
|
The permissions and restrictions of a macaroon can always be inspected by:
|
|
```shell
|
|
$ lncli printmacaroon --macaroon_file /tmp/accounts.macaroon
|
|
|
|
{
|
|
"version": 2,
|
|
"location": "lnd",
|
|
"root_key_id": "0",
|
|
"permissions": [
|
|
"info:read",
|
|
"invoices:read",
|
|
"invoices:write",
|
|
"offchain:read",
|
|
"offchain:write",
|
|
"onchain:read"
|
|
],
|
|
"caveats": [
|
|
"lnd-custom account d64dbc31b28edf66"
|
|
]
|
|
}
|
|
```
|
|
|
|
The important part is the `lnd-custom account ...` part in the `caveats`
|
|
section.
|
|
|
|
Example of using `lncli` to check the account balance (assuming integrated `lnd`
|
|
mode, adjust RPC server/port and TLS cert for remote mode):
|
|
```shell
|
|
$ lncli --macaroonpath=/tmp/accounts.macaroon channelbalance
|
|
|
|
{
|
|
"balance": "5000",
|
|
"pending_open_balance": "0",
|
|
"local_balance": {
|
|
"sat": "5000",
|
|
"msat": "5000000"
|
|
},
|
|
"remote_balance": {
|
|
"sat": "0",
|
|
"msat": "0"
|
|
}
|
|
...
|
|
}
|
|
```
|