docs: re-organize docs into new Gitbook compatible structure

This commit is contained in:
Olaoluwa Osuntokun 2020-10-13 16:53:56 -07:00
parent 7744d9d4bf
commit d1a5c35949
12 changed files with 485 additions and 403 deletions

405
README.md
View file

@ -1,7 +1,7 @@
# Lightning Pool
Lightning Pool is a non-custodial batched uniform clearing-price auction for
Channel Liquidity Bonds (CLB). A CLB packages up inbound (or outbound!) channel
Lightning Channel Lease (LCL). A LCL packages up inbound (or outbound!) channel
liquidity (ability to send/receive funds) as a fixed incoming asset (earning
interest over time) with a maturity date expressed in blocks. The maturity date
of each of the channels is enforced by Bitcoin contracts, ensuring that the
@ -68,405 +68,7 @@ A non-exhaustive list of use cases includes:
eaxmple, they can pay 1000 satohis to have 1 million satoshis be alloacted
to a user.
## The Auction Lifecycle
In this section, we'll walk through the typical auction lifecycle, and in the
process explain some key components of the Pool, and also illustrate how to
drive your `poold` on the command line.
### Accounts
Like any exchange/auction, before you can start trading, you'll need an
account! Accounts in the Pool are actually special on-chain contracts. A user
deposits a certain amount of funds into an account which has a set expiry. By
having users commit funds to an account in order to place orders, we ensure
that they're unable to spoof orders (placing an order that they can't fulfill).
We also add a cost to attempting to sybil attack the venue as well.
The script for an account is very simple, funds can be moved from the account:
* With a joint 2-of-2 signature by the _auctioneer_ and the user.
* Unilaterally by the user after the expiration period has passed.
This script resembles certain two-factor wallets with a time-lock escape
clause. The second clause ensures that users are able to move their funds if
the auctioneer is unavailable.
Many interactions in CLM are based around accounts:
* Fees paid to the auctioneer are deducted from your account
* Fees gained by selling channels are credited to your account
* Funds used to open channels to others are deducted from your account
As an account is just a UTXO, anytime a batch is cleared in the auction (market
made, channels bought+sold), your account is spent, and re-created in the same
transaction.
#### Creating An Account
Creating an account has two parameters: the size of the account, and the expiry
of an account. As you'll see below, both values can be adjusted at any time.
We can create an account using `pool`, like so:
```
🏔 pool accounts new --amt=50000000 --expiry_height=1773394
{
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "c6f62c80095c98a57f2eef485a7ff06611f97dc856754cad330f4eeb538ff514:0",
"value": 50000000,
"expiration_height": 1773394,
"state": "PENDING_OPEN",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
}
```
It's also possible to specify a _relative_ account expiry based on the current
best block with the `--expiry_blocks` argument. As an example, if I wanted my
account to expiry in 2 weeks, I would pass: `--expiry_blocks=2016`.
Here I created an account with 0.5 BTC, that'll expire at height `1773394`. The
response shows that it's now pending open (unconfirmed), my `trader_key` (used
to sign orders), and the outpoint of my new account.
Once at least 3 blocks have passed (in the alpha), the account will be confirmed
and ready for use:
```
🏔 pool accounts list
{
"accounts": [
{
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "c6f62c80095c98a57f2eef485a7ff06611f97dc856754cad330f4eeb538ff514:0",
"value": 50000000,
"expiration_height": 1773394,
"state": "OPEN",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
}
]
}
```
#### Depositing To An Account
We can add more funds to an account using the `pool accounts deposit` command.
Under the hood, we can actually batch _other_ transactions with account
modifications (make other payments, etc), but for now we expose only the basic
functionality over the CLI.
**NOTE**: You should _never_ send coins directly to your account output as it
won't be picked up by the auctioneer.
Let's say I want to deposit an extra 1 million satoshis into my account, I can
do so with the following command:
```
🏔 pool accounts deposit --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --amt=1000000 --sat_per_vbyte=5
{
"account": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "fef5cc4936290c6d57cda83bc3e90e75270296da8f34951cd562ac4cd37d4eef:0",
"value": 50001714,
"expiration_height": 1773394,
"state": "PENDING_UPDATE",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
},
"deposit_txid": "fef5cc4936290c6d57cda83bc3e90e75270296da8f34951cd562ac4cd37d4eef"
}
```
I specify my `trader_key` explicitly, as it's possible for `poold` to manage
_multiple_ accounts. The response shows my modified account, alongside with
the `txid` that'll be used to service the deposit. Once this transaction has
confirmed, I'll be able to use my account again.
Note that these funds came from the backing `lnd` node that `poold` is connected
to. At a future time we also plan to support a traditional _deposit_ address as
well.
#### Withdrawing From An Account
Incrementally _withdrawing_ from an account is also supported. The command is
similar to the deposit command. If I wanted to extract that 1 million from that
account (let's say it's my profit for the past week) and send elsewhere, I can
do so with the following command:
```
🏔 pool accounts withdraw --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --amt=1000000 --sat_per_vbyte=5 --addr=tb1qe3ueyx8jhlj4h0s6mgywmtl8vlwxqkgkgp3m3s
{
"account": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "31664dcf5dd4e89a398e816afa55a36f7518560de08b3167d75bbc6804674cd1:1",
"value": 49000801,
"expiration_height": 1773394,
"state": "PENDING_UPDATE",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
},
"withdraw_txid": "31664dcf5dd4e89a398e816afa55a36f7518560de08b3167d75bbc6804674cd1"
}
```
#### Closing An Account
Finally, if you wish to send _all_ your funds elsewhere, it's possible to close
your account out before the main expiration period. We can close out the
account we created above with the following command:
```
🏔 pool accounts close --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732
```
### Orders
Now that we have our account set up and funded, it's time to trade some channels!
There're two types of orders in the current version of Pool: asks, and bids.
You submit an ask when you have some coins that you want to _lease out_ as
inbound liquidity for a maximum period of time (expressed in blocks), at a
fixed rate compounded per block. You submit a bid when you need to acquire
inbound liquidity (ability to receive), for a minimum amount of time (again
expressed in blocks), paying out a fixed rate that compounds per-block.
In the alpha version of Lightning Pool, a single lump sum premium is paid after
order execution. In future versions, we plan on introducing "coupon channels"
which allow for _streaming interest_ to be paid out.
One important aspect of the market is that rather than buy/sell satoshis, we
use _units_. A unit is simply 100,000 satoshis and represents the _smallest_
channel that can be bought or sold on the network.
With that said, let's place some orders to try to earn some yield from this 0.5
BTC that's been burning a hole in our SD card for the past year. We'll place a
single order for 10 million satoshis, wanting to receive 0.3% (30 bps)
over a 3000 block period (a bit under 3 weeks):
```
🏔 pool orders submit ask 10000000 0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --interest_rate_percent=0.3 --max_duration_blocks=3000
-- Order Details --
Ask Amount: 0.1 BTC
Ask Duration: 3000
Total Premium (yield from taker): 0.0003 BTC
Rate Fixed: 1000
Rate Per Block: 0.000001000 (0.0001000%)
Execution Fee: 0.00010001 BTC
Max batch fee rate: 25000 sat/kw
Max chain fee: 0.016325 BTC
Confirm order (yes/no): yes
{
"accepted_order_nonce": "f1bebca6047dee6657f82377ebac94d1dc6667097f2a4d463deb63eff6f0dbcf"
}
```
By leaving off the `--force` flag, we request the final break down to confirm
the details of our order before we put it through.
In this case, if this order is executed, then I'll gain 30k satoshis:
```
premium = (rate_fixed / billion) * amount * blocks
30,000 = (1,000/1,000,000,000)*1,000,000*3,000
```
It's important to note that although internally we use a fixed rate per block
to compute the final premium, on the command line, we accept the final
acceptable premium as a _percentage_. Therefore, when submitting orders, one
should place the value that they wish to receive or accept at the end of the
lease period. Internally, we'll then compute the _per block lease rate_ and
submit the order using _that_.
The duration and fixed rate (the percentage) are two important values to pay
attention to when placing orders. Given the same amount, and fixed rate, you
earn more by leasing out the funds for a _longer_ period of time. Conversely, a
taker will pay more if they need the funds for a longer period of time.
Also notice the +*max batch fee** break down, that regulates the _highest_
chain fee you're willing to pay to get into a batch. When traders are included
in a batch, they split the channel open fee with the party they're matched
with, then pay for their account to be spent and re-created. The auctioneer
then uses this value during match making to ensure that traders don't pay more
_chain fees_ than they intend to. If your desired chain fee is _below_ the
current proposed batch chain fee, then your order won't be eligible for
execution until chain fees come down somewhat.
Users can use the `--max_batch_fee_rate` value to regulate chain fees. Note
that the values is expressed in `sat/kw` on the command line. To convert from
`sat/vbyte` to `sat/kw`, simply _divide_ by `250`.
Take note of the `order_nonce`, it's used through the auction to identify
orders, and also for authentication purposes.
We can then check out the order we just placed with the following command:
```
🏔 pool orders list
{
"asks": [
{
"details": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"rate_fixed": 1,
"amt": "10000000",
"funding_fee_rate": "253",
"order_nonce": "f1bebca6047dee6657f82377ebac94d1dc6667097f2a4d463deb63eff6f0dbcf",
"state": "ORDER_SUBMITTED",
"units": 100,
"units_unfulfilled": 100
},
"max_duration_blocks": 3000,
"version": 0,
},
}
```
The order hasn't been cleared yet (state `ORDER_SUBMITTED`), and it shows up as
100 units, or 10 million satoshis.
If we instead wanted to _buy_ inbound bandwidth, we could submit a bid instead.
A trader can have multiple unfilled bids and asks. Partial matching is possible
as well, so someone could only purchase 10 of the 100 units we have for sale.
Over time the orders will gain additional constraints such as fill-or-kill, or
min partial match size.
### Channel Leases
Once an order has been matched in an auction, the `pool auction leases` command
can be used to examine your current set of purchased/sold channel leases. An
example output looks something like the following:
```
🏔 pool auction leases
{
"leases": [
{
"channel_point": "78cc6879c1dc1c00f22b29a06458f1335ed0fdb7d05c01b9077e3155e697bbb9:2",
"channel_amt_sat": 5000000,
"channel_duration_blocks": 144,
"premium_sat": 40000,
"execution_fee_sat": 5001,
"chain_fee_sat": 165,
"order_nonce": "eb972cd21cf1651e251c8b07d69e89c47294bae104fbdc9da26edf9aee335c9a",
"purchased": false
}
],
"total_amt_earned_sat": 40000,
"total_amt_paid_sat": 5166
}
```
Here we can see I sold a channel for 40k satoshis, and ended up paying 5k
satoshis in chain and execution fees, netting a cool 35k satoshi yield. Within
the actual auction, these numbers will vary based on the chain fee rate, the
market prices, and also the execution fees. Users can constraint how much chain
fees they'll pay by setting the `--max_batch_fee_rate` argument when submitting
orders.
### Batched Uniform-Price Clearing
Now that we have orders submitted, how does the rest of the auction actually
work? As mentioned above, Pool conducts a _discrete_ batch auction every 10
minutes. This is distinct from regular continuous exchanges in that orders are
only cleared every 10 minutes. Orders are also sealed-bid, meaning that other
traders in the venue are unable to see what others have bid. On top
of this, we utilize a uniform-clearing price algorithm to give all traders in
the batch the _same_ interest rate. This is the same mechanism used by the U.S
Treasury for its bonds, and is intended to promote fairness as your order will
only be matched with a price better than your initial ask/bid.
Note that it's possible that after the 10 minutes interval has passed a market
can't be made (supply and demand didn't cross). In this case, nothing happens,
and we just wait for the next batch to come across.
To illustrate how the uniform price clearing works consider the following
example. Let's say I want to buy 100 million satoshis (1 BTC, 1000 units), for
at least 10 days (1440 blocks) at a price of 5% (using high numbers to make it
easy to follow). However, the _market clearing price_ (where the supply+demand
curves cross) is actually 1%. In this case I bid _more_ than the market
clearing price, but end up paying that price, as it's the best price that was
possible in that market.
A simple rule of thumb for bids and asks is as follows:
* When I submit a bid, I'll either pay that amount or less.
* When I submit an ask, I'll either receive that amount or more.
All orders in a batch are executed in a _single_ on-chain transaction. This
allows for thousands of channels to be bought/sold atomically in a single
block. We call the transaction that executes the orders the Batch Execution
Transaction.
The `pool auction` sub-command houses a number of useful commands to explore the
past batches, and examine the current auction parameters.
One can browse the latest cleared batch using the `pool auction snapshot`
command:
```
🏔 pool auction snapshot
{
"version": 0,
"batch_id": "02824d0cbac65e01712124c50ff2cc74ce22851d7b444c1bf2ae66afefb8eaf27f",
"prev_batch_id": "03687baa3c7414e800ddba37edacb3281999739303b7290a69bd457f428ecd9b2c",
"clearing_price_rate": 976,
"matched_orders": [
{
"ask": {
"version": 0,
"max_duration_blocks": 4032,
"rate_fixed": 744,
"chan_type": 0
},
"bid": {
"version": 0,
"min_duration_blocks": 1024,
"rate_fixed": 976,
"chan_type": 0
},
"matching_rate": 976,
"total_sats_cleared": "1000000",
"units_matched": 10
}
],
"batch_tx_id": "4508169e371096ad85e57f251e7b0034910a5e4799f3e9714d7df98f85fd8b93",
"batch_tx": "0200000000010307368f8721608c58743c452562b4fb300f3a983e0ce32e16975236493de64b4a01000000000000000019947c40c19c14f3e0ba9795c80e878e5ac9d19513f95fb63204590603c78e7a000000000000000000c6bbf036ec29cc79efa15e4b779ae33286ddf3d0ff06fba720b58e9652f030bb010000000000
0000000440420f0000000000220020169c54346374ed74d0654d4fc6fa493c637cdd8ce7c76ad24a476e7d370b926697490f0000000000220020c13828d72d6a3fd12e939d46153ebcb2cc1c7bbb0958d53d92701ba1ba5930eb0bbbc901000000002200201ec50230e41f0f0978e1b0c475bfe8af1e032135b65233a86affd9d56b320f6e99adeb020
000000022002026e0d02777ed45059d70233dfdec0aa30abe40fdc26fad5aa780f9448a399118024730440220641ad6ef4d754ad7e6164c9743b549d194db1b0a1d4fd1c4c8f47b6e044203e402206db731b2b0eebd9244f27118aaeb85bd7679769eac57cba395837a3c8b4ff24101232103ba06cff976b410f9381f297d9693544a19c504527f5a4c
c0eb2966b3900343b6ac0347304402207b0344aa98878e5aa40dc0fb712beff9b11d7fba3671f847996d83b4f6a643f90220720aa47f0ac229e4d14eebe38cffbdb2a344241e56151a0ce057f9c4cc001a1201483045022100be8808e71b6867521ed16c7749d78fb809ea0fc72f33d3b2b752cb4a13bc4ad802202335fda42f030a058003437dc7e05
39a6d36f3ce94045e20f3e176f165bc5ef0014e2103d9ebf3cea856f88ee98801621b7ea837951c530f69bc26da94d58f13417a4993ad2103a6051079a5910dd7c8d055b6713bdc0370e4983ee048a7ae26d9c52f7321949fac7364038b341bb1680347304402202ed63c0225afc718169c081b33e1bb2049cee8126539275ad62afcdf17adf74a0220
04d6c18d9a98e60642e4665428cccd71ebbc2e30fe81aee5b2bf10d682875dc901483045022100ba598f8480ed6dcdbdda1e30166b43a86f72bbc23d20bfe8751553bc8ecc6a3f02203412399095fd1429b924bfe224b64f0840172686a8af9dd3b18dc4ed40de1e23014e21038be01624676bf63a9d7d829175a70193a7e8680452b9b192ec6cf6654
a7e3be1ad2103bc6202b694e62a4d890cbb83f3a4dddb964fc500b25f55a38501642a770e3f37ac7364038a341bb16800000000"
```
Here we see a batch where a single order was matched, at a clearing rate of
`976`, with a single channel being purchased with a lifetime of `1024` blocks,
or roughly one week.
Note that the `pool auction snapshot` command can be used to determine the past
marker clearing price, which can be useful when deciding what your bid/ask
should be. There's no explicit "market buy" function, but submitting a bid/ask
at a similar `clearing_price_rate` is equivalent.
The command also accept a target `batch_id` as well. Here we can use the
`prev_batch_id` to examine the _prior_ batch, similar to traversing a
link-listed/blockchain:
```
🏔 pool auction snapshot --batch_id=03687baa3c7414e800ddba37edacb3281999739303b7290a69bd457f428ecd9b2c
```
### Service Level Lifetime Enforcement
In the alpha version of Pool, _script level enforcement_ isn't yet implemented.
Script level enforcement would lock the maker's funds in the channel for the
lease period. This ensures that they can't just collect the premium (before
coupon channels) and close out the channel instantly. With script enforcement,
they would be able to close the channel (force close it), but their funds would
be unavailable until the maturity period has passed.
Instead, we've implemented a feature in `lnd` to prevent channels from being
_cooperatively closed_ by the maker until the expiry height (what we call the
`thaw_height`). Additionally, if we detect a force close by the maker of that
channel, then we'll ban them from the market for a set period of time.
# Prerequisites
To build and run LLM, the following tools/binaries must be installed on your
system:
* Go `1.13` or later
* `make`
* `lnd` version `v0.11.1-beta` or later with the build tags `signrpc`,
`walletrpc`, `chainrpc` and `invoicesrpc` enabled (or the current `master`
branch built with `make install tags="signrpc walletrpc chainrpc invoicesrpc"`
if version`v0.11.1-beta` is not yet released).
For more detailed information, please check out [docs folder](docs/).
# Installation
@ -484,9 +86,6 @@ following command (assuming you have a local testnet `lnd` running):
🏔 poold --network=testnet --debuglevel=trace
```
The current server is reachable at `clm.testnet.lightningcluster.com:12010`,
this may change as the alpha version progresses.
## Authentication and transport security
The gRPC and REST connections of `poold` are encrypted with TLS and secured with

4
book.json Normal file
View file

@ -0,0 +1,4 @@
{
"root": "./docs",
"structure.readme": "../README.md"
}

11
docs/SUMMARY.md Normal file
View file

@ -0,0 +1,11 @@
# Table of contents
* [Lightning Pool: A Non-Custodial Channel Lease Marketplace](README.md)
* [Overview](overview.md)
* [Installation](install.md)
* [Accounts](accounts.md)
* [Orders](orders.md)
* [Channel Leases](channel_leases.md)
* [Batch Execution](batch_execution.md)
* [Alpha Limitations](alpha_limitations.md)
* [FAQ](faq.md)

0
docs/account_recovery.md Normal file
View file

139
docs/accounts.md Normal file
View file

@ -0,0 +1,139 @@
Accounts
## Overview
Like any exchange/auction, before you can start trading, you'll need an
account! Accounts in the Pool are actually special on-chain contracts. A user
deposits a certain amount of funds into an account which has a set expiry. By
having users commit funds to an account in order to place orders, we ensure
that they're unable to spoof orders (placing an order that they can't fulfill).
We also add a cost to attempting to sybil attack the venue as well.
The script for an account is very simple, funds can be moved from the account:
* With a joint 2-of-2 signature by the _auctioneer_ and the user.
* Unilaterally by the user after the expiration period has passed.
This script resembles certain two-factor wallets with a time-lock escape
clause. The second clause ensures that users are able to move their funds if
the auctioneer is unavailable.
Many interactions in CLM are based around accounts:
* Fees paid to the auctioneer are deducted from your account
* Fees gained by selling channels are credited to your account
* Funds used to open channels to others are deducted from your account
As an account is just a UTXO, anytime a batch is cleared in the auction (market
made, channels bought+sold), your account is spent, and re-created in the same
transaction.
## Creating An Account
Creating an account has two parameters: the size of the account, and the expiry
of an account. As you'll see below, both values can be adjusted at any time.
We can create an account using `pool`, like so:
```
🏔 pool accounts new --amt=50000000 --expiry_height=1773394
{
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "c6f62c80095c98a57f2eef485a7ff06611f97dc856754cad330f4eeb538ff514:0",
"value": 50000000,
"expiration_height": 1773394,
"state": "PENDING_OPEN",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
}
```
It's also possible to specify a _relative_ account expiry based on the current
best block with the `--expiry_blocks` argument. As an example, if I wanted my
account to expiry in 2 weeks, I would pass: `--expiry_blocks=2016`.
Here I created an account with 0.5 BTC, that'll expire at height `1773394`. The
response shows that it's now pending open (unconfirmed), my `trader_key` (used
to sign orders), and the outpoint of my new account.
Once at least 3 blocks have passed (in the alpha), the account will be confirmed
and ready for use:
```
🏔 pool accounts list
{
"accounts": [
{
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "c6f62c80095c98a57f2eef485a7ff06611f97dc856754cad330f4eeb538ff514:0",
"value": 50000000,
"expiration_height": 1773394,
"state": "OPEN",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
}
]
}
```
## Depositing To An Account
We can add more funds to an account using the `pool accounts deposit` command.
Under the hood, we can actually batch _other_ transactions with account
modifications (make other payments, etc), but for now we expose only the basic
functionality over the CLI.
**NOTE**: You should _never_ send coins directly to your account output as it
won't be picked up by the auctioneer.
Let's say I want to deposit an extra 1 million satoshis into my account, I can
do so with the following command:
```
🏔 pool accounts deposit --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --amt=1000000 --sat_per_vbyte=5
{
"account": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "fef5cc4936290c6d57cda83bc3e90e75270296da8f34951cd562ac4cd37d4eef:0",
"value": 50001714,
"expiration_height": 1773394,
"state": "PENDING_UPDATE",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
},
"deposit_txid": "fef5cc4936290c6d57cda83bc3e90e75270296da8f34951cd562ac4cd37d4eef"
}
```
I specify my `trader_key` explicitly, as it's possible for `poold` to manage
_multiple_ accounts. The response shows my modified account, alongside with
the `txid` that'll be used to service the deposit. Once this transaction has
confirmed, I'll be able to use my account again.
Note that these funds came from the backing `lnd` node that `poold` is connected
to. At a future time we also plan to support a traditional _deposit_ address as
well.
## Withdrawing From An Account
Incrementally _withdrawing_ from an account is also supported. The command is
similar to the deposit command. If I wanted to extract that 1 million from that
account (let's say it's my profit for the past week) and send elsewhere, I can
do so with the following command:
```
🏔 pool accounts withdraw --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --amt=1000000 --sat_per_vbyte=5 --addr=tb1qe3ueyx8jhlj4h0s6mgywmtl8vlwxqkgkgp3m3s
{
"account": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"outpoint": "31664dcf5dd4e89a398e816afa55a36f7518560de08b3167d75bbc6804674cd1:1",
"value": 49000801,
"expiration_height": 1773394,
"state": "PENDING_UPDATE",
"close_txid": "0000000000000000000000000000000000000000000000000000000000000000"
},
"withdraw_txid": "31664dcf5dd4e89a398e816afa55a36f7518560de08b3167d75bbc6804674cd1"
}
```
## Closing An Account
Finally, if you wish to send _all_ your funds elsewhere, it's possible to close
your account out before the main expiration period. We can close out the
account we created above with the following command:
```
🏔 pool accounts close --trader_key=0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732
```

View file

93
docs/batch_execution.md Normal file
View file

@ -0,0 +1,93 @@
# Auction Batch Execution Lifecycle
## Batched Uniform-Price Clearing
Now that we have orders submitted, how does the rest of the auction actually
work? As mentioned above, Pool conducts a _discrete_ batch auction every 10
minutes. This is distinct from regular continuous exchanges in that orders are
only cleared every 10 minutes. Orders are also sealed-bid, meaning that other
traders in the venue are unable to see what others have bid. On top
of this, we utilize a uniform-clearing price algorithm to give all traders in
the batch the _same_ interest rate. This is the same mechanism used by the U.S
Treasury for its bonds, and is intended to promote fairness as your order will
only be matched with a price better than your initial ask/bid.
Note that it's possible that after the 10 minutes interval has passed a market
can't be made (supply and demand didn't cross). In this case, nothing happens,
and we just wait for the next batch to come across.
To illustrate how the uniform price clearing works consider the following
example. Let's say I want to buy 100 million satoshis (1 BTC, 1000 units), for
at least 10 days (1440 blocks) at a price of 5% (using high numbers to make it
easy to follow). However, the _market clearing price_ (where the supply+demand
curves cross) is actually 1%. In this case I bid _more_ than the market
clearing price, but end up paying that price, as it's the best price that was
possible in that market.
A simple rule of thumb for bids and asks is as follows:
* When I submit a bid, I'll either pay that amount or less.
* When I submit an ask, I'll either receive that amount or more.
All orders in a batch are executed in a _single_ on-chain transaction. This
allows for thousands of channels to be bought/sold atomically in a single
block. We call the transaction that executes the orders the Batch Execution
Transaction.
The `pool auction` sub-command houses a number of useful commands to explore the
past batches, and examine the current auction parameters.
One can browse the latest cleared batch using the `pool auction snapshot`
command:
```
🏔 pool auction snapshot
{
"version": 0,
"batch_id": "02824d0cbac65e01712124c50ff2cc74ce22851d7b444c1bf2ae66afefb8eaf27f",
"prev_batch_id": "03687baa3c7414e800ddba37edacb3281999739303b7290a69bd457f428ecd9b2c",
"clearing_price_rate": 976,
"matched_orders": [
{
"ask": {
"version": 0,
"max_duration_blocks": 4032,
"rate_fixed": 744,
"chan_type": 0
},
"bid": {
"version": 0,
"min_duration_blocks": 1024,
"rate_fixed": 976,
"chan_type": 0
},
"matching_rate": 976,
"total_sats_cleared": "1000000",
"units_matched": 10
}
],
"batch_tx_id": "4508169e371096ad85e57f251e7b0034910a5e4799f3e9714d7df98f85fd8b93",
"batch_tx": "0200000000010307368f8721608c58743c452562b4fb300f3a983e0ce32e16975236493de64b4a01000000000000000019947c40c19c14f3e0ba9795c80e878e5ac9d19513f95fb63204590603c78e7a000000000000000000c6bbf036ec29cc79efa15e4b779ae33286ddf3d0ff06fba720b58e9652f030bb010000000000
0000000440420f0000000000220020169c54346374ed74d0654d4fc6fa493c637cdd8ce7c76ad24a476e7d370b926697490f0000000000220020c13828d72d6a3fd12e939d46153ebcb2cc1c7bbb0958d53d92701ba1ba5930eb0bbbc901000000002200201ec50230e41f0f0978e1b0c475bfe8af1e032135b65233a86affd9d56b320f6e99adeb020
000000022002026e0d02777ed45059d70233dfdec0aa30abe40fdc26fad5aa780f9448a399118024730440220641ad6ef4d754ad7e6164c9743b549d194db1b0a1d4fd1c4c8f47b6e044203e402206db731b2b0eebd9244f27118aaeb85bd7679769eac57cba395837a3c8b4ff24101232103ba06cff976b410f9381f297d9693544a19c504527f5a4c
c0eb2966b3900343b6ac0347304402207b0344aa98878e5aa40dc0fb712beff9b11d7fba3671f847996d83b4f6a643f90220720aa47f0ac229e4d14eebe38cffbdb2a344241e56151a0ce057f9c4cc001a1201483045022100be8808e71b6867521ed16c7749d78fb809ea0fc72f33d3b2b752cb4a13bc4ad802202335fda42f030a058003437dc7e05
39a6d36f3ce94045e20f3e176f165bc5ef0014e2103d9ebf3cea856f88ee98801621b7ea837951c530f69bc26da94d58f13417a4993ad2103a6051079a5910dd7c8d055b6713bdc0370e4983ee048a7ae26d9c52f7321949fac7364038b341bb1680347304402202ed63c0225afc718169c081b33e1bb2049cee8126539275ad62afcdf17adf74a0220
04d6c18d9a98e60642e4665428cccd71ebbc2e30fe81aee5b2bf10d682875dc901483045022100ba598f8480ed6dcdbdda1e30166b43a86f72bbc23d20bfe8751553bc8ecc6a3f02203412399095fd1429b924bfe224b64f0840172686a8af9dd3b18dc4ed40de1e23014e21038be01624676bf63a9d7d829175a70193a7e8680452b9b192ec6cf6654
a7e3be1ad2103bc6202b694e62a4d890cbb83f3a4dddb964fc500b25f55a38501642a770e3f37ac7364038a341bb16800000000"
```
Here we see a batch where a single order was matched, at a clearing rate of
`976`, with a single channel being purchased with a lifetime of `1024` blocks,
or roughly one week.
Note that the `pool auction snapshot` command can be used to determine the past
marker clearing price, which can be useful when deciding what your bid/ask
should be. There's no explicit "market buy" function, but submitting a bid/ask
at a similar `clearing_price_rate` is equivalent.
The command also accept a target `batch_id` as well. Here we can use the
`prev_batch_id` to examine the _prior_ batch, similar to traversing a
link-listed/blockchain:
```
🏔 pool auction snapshot --batch_id=03687baa3c7414e800ddba37edacb3281999739303b7290a69bd457f428ecd9b2c
```

58
docs/channel_leases.md Normal file
View file

@ -0,0 +1,58 @@
# Channel Leases
## Overview
Once an order has been matched in an auction, the `pool auction leases` command
can be used to examine your current set of purchased/sold channel leases. An
example output looks something like the following:
```
🏔 pool auction leases
{
"leases": [
{
"channel_point": "78cc6879c1dc1c00f22b29a06458f1335ed0fdb7d05c01b9077e3155e697bbb9:2",
"channel_amt_sat": 5000000,
"channel_duration_blocks": 144,
"premium_sat": 40000,
"execution_fee_sat": 5001,
"chain_fee_sat": 165,
"order_nonce": "eb972cd21cf1651e251c8b07d69e89c47294bae104fbdc9da26edf9aee335c9a",
"purchased": false
}
],
"total_amt_earned_sat": 40000,
"total_amt_paid_sat": 5166
}
```
Here we can see I sold a channel for 40k satoshis, and ended up paying 5k
satoshis in chain and execution fees, netting a cool 35k satoshi yield. Within
the actual auction, these numbers will vary based on the chain fee rate, the
market prices, and also the execution fees. Users can constraint how much chain
fees they'll pay by setting the `--max_batch_fee_rate` argument when submitting
orders.
## Service Level Lifetime Enforcement
In the alpha version of Pool, _script level enforcement_ isn't yet implemented.
Script level enforcement would lock the maker's funds in the channel for the
lease period. This ensures that they can't just collect the premium (before
coupon channels) and close out the channel instantly. With script enforcement,
they would be able to close the channel (force close it), but their funds would
be unavailable until the maturity period has passed.
Instead, we've implemented a feature in `lnd` to prevent channels from being
_cooperatively closed_ by the maker until the expiry height (what we call the
`thaw_height`). Additionally, if we detect a force close by the maker of that
channel, then we'll ban them from the market for a set period of time.
# Prerequisites
To build and run LLM, the following tools/binaries must be installed on your
system:
* Go `1.13` or later
* `make`
* `lnd` version `v0.11.1-beta` or later with the build tags `signrpc`,
`walletrpc`, `chainrpc` and `invoicesrpc` enabled (or the current `master`
branch built with `make install tags="signrpc walletrpc chainrpc invoicesrpc"`
if version`v0.11.1-beta` is not yet released).

0
docs/faq.md Normal file
View file

0
docs/install.md Normal file
View file

109
docs/orders.md Normal file
View file

@ -0,0 +1,109 @@
# Orders
## Overview
Now that we have our account set up and funded, it's time to trade some channels!
There're two types of orders in the current version of Pool: asks, and bids.
You submit an ask when you have some coins that you want to _lease out_ as
inbound liquidity for a maximum period of time (expressed in blocks), at a
fixed rate compounded per block. You submit a bid when you need to acquire
inbound liquidity (ability to receive), for a minimum amount of time (again
expressed in blocks), paying out a fixed rate that compounds per-block.
In the alpha version of Lightning Pool, a single lump sum premium is paid after
order execution. In future versions, we plan on introducing "coupon channels"
which allow for _streaming interest_ to be paid out.
One important aspect of the market is that rather than buy/sell satoshis, we
use _units_. A unit is simply 100,000 satoshis and represents the _smallest_
channel that can be bought or sold on the network.
With that said, let's place some orders to try to earn some yield from this 0.5
BTC that's been burning a hole in our SD card for the past year. We'll place a
single order for 10 million satoshis, wanting to receive 0.3% (30 bps)
over a 3000 block period (a bit under 3 weeks):
```
🏔 pool orders submit ask 10000000 0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732 --interest_rate_percent=0.3 --max_duration_blocks=3000
-- Order Details --
Ask Amount: 0.1 BTC
Ask Duration: 3000
Total Premium (yield from taker): 0.0003 BTC
Rate Fixed: 1000
Rate Per Block: 0.000001000 (0.0001000%)
Execution Fee: 0.00010001 BTC
Max batch fee rate: 25000 sat/kw
Max chain fee: 0.016325 BTC
Confirm order (yes/no): yes
{
"accepted_order_nonce": "f1bebca6047dee6657f82377ebac94d1dc6667097f2a4d463deb63eff6f0dbcf"
}
```
By leaving off the `--force` flag, we request the final break down to confirm
the details of our order before we put it through.
In this case, if this order is executed, then I'll gain 30k satoshis:
```
premium = (rate_fixed / billion) * amount * blocks
30,000 = (1,000/1,000,000,000)*1,000,000*3,000
```
It's important to note that although internally we use a fixed rate per block
to compute the final premium, on the command line, we accept the final
acceptable premium as a _percentage_. Therefore, when submitting orders, one
should place the value that they wish to receive or accept at the end of the
lease period. Internally, we'll then compute the _per block lease rate_ and
submit the order using _that_.
The duration and fixed rate (the percentage) are two important values to pay
attention to when placing orders. Given the same amount, and fixed rate, you
earn more by leasing out the funds for a _longer_ period of time. Conversely, a
taker will pay more if they need the funds for a longer period of time.
Also notice the +*max batch fee** break down, that regulates the _highest_
chain fee you're willing to pay to get into a batch. When traders are included
in a batch, they split the channel open fee with the party they're matched
with, then pay for their account to be spent and re-created. The auctioneer
then uses this value during match making to ensure that traders don't pay more
_chain fees_ than they intend to. If your desired chain fee is _below_ the
current proposed batch chain fee, then your order won't be eligible for
execution until chain fees come down somewhat.
Users can use the `--max_batch_fee_rate` value to regulate chain fees. Note
that the values is expressed in `sat/kw` on the command line. To convert from
`sat/vbyte` to `sat/kw`, simply _divide_ by `250`.
Take note of the `order_nonce`, it's used through the auction to identify
orders, and also for authentication purposes.
We can then check out the order we just placed with the following command:
```
🏔 pool orders list
{
"asks": [
{
"details": {
"trader_key": "0288096be9917f8ebdfc6eb2701635fe658f4eae1e0274dcce41418b3fb5145732",
"rate_fixed": 1,
"amt": "10000000",
"funding_fee_rate": "253",
"order_nonce": "f1bebca6047dee6657f82377ebac94d1dc6667097f2a4d463deb63eff6f0dbcf",
"state": "ORDER_SUBMITTED",
"units": 100,
"units_unfulfilled": 100
},
"max_duration_blocks": 3000,
"version": 0,
},
}
```
The order hasn't been cleared yet (state `ORDER_SUBMITTED`), and it shows up as
100 units, or 10 million satoshis.
If we instead wanted to _buy_ inbound bandwidth, we could submit a bid instead.
A trader can have multiple unfilled bids and asks. Partial matching is possible
as well, so someone could only purchase 10 of the 100 units we have for sale.
Over time the orders will gain additional constraints such as fill-or-kill, or
min partial match size.

69
docs/overview.md Normal file
View file

@ -0,0 +1,69 @@
# Lightning Pool
Lightning Pool is a non-custodial batched uniform clearing-price auction for
Lightning Channel Lease (LCL). A LCL packages up inbound (or outbound!) channel
liquidity (ability to send/receive funds) as a fixed incoming asset (earning
interest over time) with a maturity date expressed in blocks. The maturity date
of each of the channels is enforced by Bitcoin contracts, ensuring that the
funds of the maker (the party that sold the channel) can't be swept until the
maturity height. All cleared orders (purchased channels) are cleared in a
single batched on-chain transaction.
The existence of an open auction to acquire/sell channel liquidity provides all
participants on the network with a more _stable_ income source in addition to
routing network fees. By selling liquidity within the marketplace, individuals
are able to price their channels to ensure that they're compensated for the
time-value of their coins within a channel, accounting for worst-case force
close CSV delays.
Pool critically allows participants on the network to exchange pricing
signals to determine where liquidity in the network is most _demanded_. A
channel opened to an area of the sub-graph that doesn't actually need that
liquidity will likely remain dormant and not earn any active routing fees.
Instead, if capital can be allocated within the network in an efficient manner,
being placed where it's most demanded, we can better utilize the allocated
capital on the network, and also allow new participants to easily identify
where their capital is most needed.
Amongst several other uses cases, the Pool allows a new participant in the
network to easily _boostrap_ their ability to receive funds by paying only a
percentage of the total amount of inbound funds acquired. As an example, a node
could acquire 100 million satoshis (1000 units, more on that below) for 100,000
satoshis, or 0.1%. Ultimately the prices will be determined by the open market
place.
A non-exhaustive list of use cases includes:
* **Bootstrapping new users with side car channels**: A common question
posted concerning the Lightning Network goes something like: Alice is new
to Bitcoin entirely, how can she join the Lightning Network without her,
herself, making any new on-chain Bitcoin transactions? Its desirable to a
solution to onboarding new users on to the network which is as as simple as
sending coins to a fresh address. The Pool solves this by allowing a third
party Carol, to purchase a channel _for_ Alice, which includes starting
_outbound_ liquidity.
* **Demand fueled routing node channel selection**: Another common question
with regards to the LN is: "where should I open my channels to , such that
they'll actually be routed through"?. Pool provides a new signal for
autopilot agents: a market demand signal. The node can offer up its
liquidity and have it automatically be allocated where it's most demanded.
* **Bootstrapping new services to Lightning**: Any new service launched on
the Lightning Network will likely need to figure out how to obtain inbound
channels so they can accept payments. For this Pool provides an elegant
solution in that a merchant can set up a series of "introduction points"
negotiated via the market place. The merchant can pay a small percentage of
the total amount of liquidity allocated towards it, and also ensure that
the funds will be committed for a set period of time.
* **Allowing users to instantly receive with a wallet**: A common UX
challenge that wallets face concerns ensuring a user can receive funds as
soon as they set up a wallet. Some wallet providers have chosen to open new
inbound channels to users themselves. This gives users the inbound
bandwidth they need to receive, but can come at a high capital cost to the
wallet provider as they need to commit funds with a 1:1 ratio. The
Lightning Pool allows them to achieve some leverage in a sense, as they can
pay only a percentage of the funds to be allocated to a new user. As an
eaxmple, they can pay 1000 satohis to have 1 million satoshis be alloacted
to a user.