Compare commits
153 commits
Author | SHA1 | Date | |
---|---|---|---|
|
39fc1d8863 | ||
|
91c5da4d9f | ||
|
dd7a26689d | ||
|
c8775c53be | ||
|
1e02050dcd | ||
|
3c5f73e42a | ||
|
ee9ec4cd45 | ||
|
f03f4ce7ab | ||
|
2a4c2b7e9a | ||
|
c454764eb0 | ||
|
6aa3df5ff1 | ||
|
79b73409da | ||
|
ed2ff08a5c | ||
|
3d4383bf93 | ||
|
5f64cb0877 | ||
|
2520e8d067 | ||
|
d14fad500b | ||
|
492851edfc | ||
|
9f36ae2ad0 | ||
|
1961fb9c00 | ||
|
b2dca44842 | ||
|
c2971903a3 | ||
|
a1d16d3cdd | ||
|
bbe731878c | ||
|
a650325c85 | ||
|
377cac0d8d | ||
|
e2649be31d | ||
|
dc97097f94 | ||
|
c3588c8984 | ||
|
85faf7dadc | ||
|
58eff4b633 | ||
|
dca7c12861 | ||
|
faf36ed2e3 | ||
|
f2b92776d5 | ||
|
de42eccd27 | ||
|
b4cb8ea07d | ||
|
611883a24a | ||
|
81efae4b75 | ||
|
b0dfaa54ad | ||
|
b5602911ad | ||
|
51d46dae43 | ||
|
e749319cac | ||
|
1d0a341e61 | ||
|
02bb9e521b | ||
|
64338a4340 | ||
|
982348ca5d | ||
|
0f2a433516 | ||
|
0c43bfd8ba | ||
|
bd2af374af | ||
|
f9c2df5d35 | ||
|
e9c8e9bc88 | ||
|
a1ce8ab255 | ||
|
78100ed43f | ||
|
0919eae319 | ||
|
f1f97550ff | ||
|
3ac2159691 | ||
|
5dcf316a63 | ||
|
6a00164534 | ||
|
552b5c4bfa | ||
|
40b7ae44d9 | ||
|
5ddc6cddf5 | ||
|
d9466f2ac4 | ||
|
7d1468e016 | ||
|
ecf22d4735 | ||
|
d036c8cf72 | ||
|
871b93dfe6 | ||
|
b8f269187e | ||
|
5d92967586 | ||
|
8893727844 | ||
|
651e00c5eb | ||
|
34d0086b63 | ||
|
8dce3724c5 | ||
|
03f24f0fb3 | ||
|
b1864f8a8a | ||
|
2222ceab61 | ||
|
12355d607a | ||
|
9b07069a8f | ||
|
b7282a531f | ||
|
63f6ddc6e3 | ||
|
f0d16bb517 | ||
|
cf72eaa2d7 | ||
|
41a2403875 | ||
|
6c7a90a097 | ||
|
d77a526aac | ||
|
15a0514894 | ||
|
d5e6f75ae9 | ||
|
e145ede26a | ||
|
0e8e9ad705 | ||
|
ab5500dfda | ||
|
07b6fa080d | ||
|
523ed86eab | ||
|
1d4aa4266b | ||
|
ba625b1cd3 | ||
|
6df4a3824b | ||
|
2051ff38f8 | ||
|
4349e8da45 | ||
|
2bcc40ae04 | ||
|
fccca20761 | ||
|
e2d902290a | ||
|
8207e24721 | ||
|
6c64b50d23 | ||
|
5da66a4c34 | ||
|
bcfa32f90c | ||
|
ef397f0be1 | ||
|
55aa5b04eb | ||
|
7ae9f94d73 | ||
|
5b5e550c28 | ||
|
75faa36dee | ||
|
e6cc5f1252 | ||
|
cb79a4fc13 | ||
|
189ceec7b1 | ||
|
1083311739 | ||
|
54d0ee678d | ||
|
71e57c5f6d | ||
|
824549eaaa | ||
|
859169559d | ||
|
815a50c802 | ||
|
10fa5ad679 | ||
|
28f96bafcc | ||
|
239b7a2957 | ||
|
a82530729e | ||
|
5ebcbb6f99 | ||
|
e8fabfd5cd | ||
|
e928c44cc8 | ||
|
aed7556df5 | ||
|
7a13f4de7c | ||
|
15fbf7fda5 | ||
|
529977580f | ||
|
0bb45ebd64 | ||
|
ff1133a108 | ||
|
10cb9b80bc | ||
|
28eb764536 | ||
|
961b7162f5 | ||
|
f817f1d886 | ||
|
a1e5901540 | ||
|
2a9e24f600 | ||
|
c7bc11e8e1 | ||
|
6b50260452 | ||
|
4012924209 | ||
|
44818ec0b6 | ||
|
4bd4e6febc | ||
|
555937cf2f | ||
|
37ca45b475 | ||
|
3006bc8022 | ||
|
17dd78b6c7 | ||
|
98d712ece6 | ||
|
daaad1f2da | ||
|
1153f5fb5d | ||
|
61f66b08a3 | ||
|
47edbd2e01 | ||
|
55b5808016 | ||
|
9031dfaf9f | ||
|
e70ab946af |
23 changed files with 1711 additions and 30 deletions
34
README.md
34
README.md
|
@ -33,15 +33,27 @@ Number | Title |
|
|||
[23](bsip-0023.md) | Sharedropping an UIA against an external cryptocurrency distribution snapshot | Customminer | Protocol | Draft
|
||||
[24](bsip-0024.md) | Locking Bitshares away as 'Bitshares Influence' for voting privileges on the BTS DEX | Customminer | Protocol | Draft
|
||||
[25](bsip-0025.md) | Transaction Flat-Rates with Weighted Rate-Limitation | Fabian Schuh | Protocol | Draft
|
||||
[26](bsip-0026.md) | Refund Order Creation Fee in Originally Paid Asset on Cancel | Abit More | Protocol | Accepted
|
||||
[27](bsip-0027.md) | Asset Issuer Reclaim Fee Pool Funds | Abit More | Protocol | Accepted
|
||||
[26](bsip-0026.md) | Refund Order Creation Fee in Originally Paid Asset on Cancel | Abit More | Protocol | Installed
|
||||
[27](bsip-0027.md) | Asset Issuer Reclaim Fee Pool Funds | Abit More | Protocol | Installed
|
||||
[28](bsip-0028.md) | Worker Proposal Improvements | Bill Butler | Protocol | Draft
|
||||
[29](bsip-0029.md) | Asset issue change to require owner authority | Fabian Schuh | Protocol | Accepted
|
||||
[30](bsip-0030.md) | Always Allow Increasing Collateral Ratio If Debt Not Increased | Abit More | Protocol | Accepted
|
||||
[31](bsip-0031.md) | Update Short Position's Margin Call Price After Partially Called Or Settled | Abit More | Protocol | Accepted
|
||||
[32](bsip-0032.md) | Always Match Orders At Maker Price | Abit More | Protocol | Accepted
|
||||
[33](bsip-0033.md) | Maker Orders With Better Prices Take Precedence | Abit More | Protocol | Accepted
|
||||
[34](bsip-0034.md) | Always Trigger Margin Call When Call Price Above Or At Price Feed | Abit More | Protocol | Accepted
|
||||
[35](bsip-0035.md) | Mitigate Rounding Issue On Order Matching | Abit More | Protocol | Accepted
|
||||
[36](bsip-0036.md) | Remove expired price feeds on maintenance interval | oxarbitrage | Protocol | Accepted
|
||||
[37](bsip-0037.md) | Allow new asset name to end with a number | oxarbitrage | Protocol | Accepted
|
||||
[29](bsip-0029.md) | Asset issue change to require owner authority | Fabian Schuh | Protocol | Installed
|
||||
[30](bsip-0030.md) | Always Allow Increasing Collateral Ratio If Debt Not Increased | Abit More | Protocol | Installed
|
||||
[31](bsip-0031.md) | Update Short Position's Margin Call Price After Partially Called Or Settled | Abit More | Protocol | Installed
|
||||
[32](bsip-0032.md) | Always Match Orders At Maker Price | Abit More | Protocol | Installed
|
||||
[33](bsip-0033.md) | Maker Orders With Better Prices Take Precedence | Abit More | Protocol | Installed
|
||||
[34](bsip-0034.md) | Always Trigger Margin Call When Call Price Above Or At Price Feed | Abit More | Protocol | Installed
|
||||
[35](bsip-0035.md) | Mitigate Rounding Issue On Order Matching | Abit More | Protocol | Installed
|
||||
[36](bsip-0036.md) | Remove expired price feeds on maintenance interval | oxarbitrage | Protocol | Installed
|
||||
[37](bsip-0037.md) | Allow new asset name to end with a number | oxarbitrage | Protocol | Installed
|
||||
[38](bsip-0038.md) | Add target collateral ratio option to short positions | Abit More | Protocol | Installed
|
||||
[39](bsip-0039.md) | Automatically approve proposals by the proposer | Fabian Schuh | Protocol | Draft
|
||||
[40](bsip-0040.md) | Custom active permission | Stefan Schießl | Protocol | Draft
|
||||
[42](bsip-0042.md) | Adjust price feed to influence trading price of SmartCoins | Abit More | Protocol | Draft
|
||||
[44](bsip-0044.md) | Hashed Time-Locked Contract | Ryan R. Fox | Protocol | Draft
|
||||
[45](bsip-0045.md) | Introduce 'allow use as bitasset backing collateral' flag/permission to assets | Customminer | Protocol | Draft
|
||||
50 | Stealth development, Phase II | Christopher Sanborn | Informational | Draft
|
||||
51 | New operations for Confidential Asset (CA) transactions | Christopher Sanborn | Protocol | Draft
|
||||
52 | Ring signatures for untraceability of Stealth transactions | Christopher Sanborn | Protocol | Draft
|
||||
[53](bsip-0053.md) | Blockchain scanning for inbound Stealth transactions | Christopher Sanborn | Protocol | Draft
|
||||
54 | Deterministic addresses for Stealth wallets | Christopher Sanborn | Informational | Draft
|
||||
55 | Metadata hiding via Garlic Routing and other means | Christopher Sanborn | Informational | Draft
|
||||
|
|
|
@ -107,7 +107,7 @@ for each asset_holder in coin_age_hashmap {
|
|||
|
||||
# Copyright
|
||||
|
||||
N/A - Consider this BSIP entirely open-source/MIT-licensed, I am not the originator of the concept of 'coin-age' (several proof-of-stake cryptocurrencies make use of coin-age for finding stakable coins).
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
* [List account balances - Graphene documentation](http://docs.bitshares.org/api/database.html#id8)
|
||||
|
|
|
@ -119,7 +119,7 @@ Please do raise your concerns, propose improvements and engage in the BSIP creat
|
|||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain, 100% open source & should be considered MIT licensed.
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
|
|
|
@ -651,7 +651,7 @@ The Bitshares starship drops out of hyperspace in planet Bitcoin's orbit, the cr
|
|||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain, 100% open source & should be considered MIT licensed.
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ Would there even be a difference in voting behaviour betwen the two? Perhaps it
|
|||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain, 100% open source & should be considered MIT licensed.
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0026
|
||||
Title: Refund Order Creation Fee in Originally Paid Asset on Cancel
|
||||
Authors: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2017-10-16
|
||||
Discussion: https://bitsharestalk.org/index.php/topic,25153.0.html
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Title: Asset Issuer Reclaim Fee Pool Funds
|
||||
Authors: Abit More <https://github.com/abitmore>
|
||||
Fabian Schuh <Fabian@BitShares.eu>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2017-11-02
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/188
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0029
|
||||
Title: Asset issue change to require owner authority
|
||||
Authors: Fabian Schuh <Fabian.Schuh@blockchainprojectsbv.com>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-01-28
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/199
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0030
|
||||
Title: Always Allow Increasing Collateral Ratio If Debt Not Increased
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-16
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/583,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0031
|
||||
Title: Update Short Position's Margin Call Price After Partially Called Or Settled
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-16
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/343,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0032
|
||||
Title: Always Match Orders At Maker Price
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-16
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/338
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0033
|
||||
Title: Maker Orders With Better Prices Take Precedence
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-17
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/625,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0034
|
||||
Title: Always Trigger Margin Call When Call Price Above Or At Price Feed
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-18
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/606
|
||||
|
|
11
bsip-0035.md
11
bsip-0035.md
|
@ -1,13 +1,13 @@
|
|||
BSIP: 0035
|
||||
Title: Mitigate Rounding Issue On Order Matching
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-19
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/132,
|
||||
https://github.com/bitshares/bitshares-core/issues/184,
|
||||
https://github.com/bitshares/bitshares-core/issues/342
|
||||
Replaces: -
|
||||
Superseded-By: 0038 (partly)
|
||||
Worker: 1.14.96
|
||||
|
||||
# Abstract
|
||||
|
@ -261,7 +261,8 @@ The detailed rules proposed by this BSIP with new rules highlighted:
|
|||
amount remaining), check the remaining amount, if the amount is too small
|
||||
so the order would receive nothing on next match, cancel the order.**
|
||||
|
||||
* When matching a limit order with a call order,
|
||||
* When matching a limit order with a call order (**note: this rule has changed
|
||||
in [BSIP 38](bsip-0038.md)**),
|
||||
* **if the call order is receiving the whole debt amount, which means it's
|
||||
smaller and the short position will be closed after the match, round up its
|
||||
paying amount; otherwise,** round down its paying amount.
|
||||
|
@ -371,12 +372,12 @@ Assuming both orders are limit orders, they'll be processed as follows:
|
|||
* If Alice's order is maker, use `$3 / 80` as match price; since Alice's order
|
||||
is smaller, round in favor of Bob's order, so Alice will get
|
||||
`round_down(50 CORE * $3 / 80 CORE) = round_down($1.6) = $1`,
|
||||
and Bob will get `round_up($1 * 80 CORE / $3) = round_up($26.67) = $27`,
|
||||
and Bob will get `round_up($1 * 80 CORE / $3) = round_up(26.67 CORE) = 27 CORE`,
|
||||
the effective price would be `$1 / 27 = $0.037`;
|
||||
* If Bob's order is maker, use `$19 / 500` as match price; since Alice's order
|
||||
is smaller, round in favor of Bob's order, so Alice will get
|
||||
`round_down(50 CORE * $19 / 500 CORE = round_down($1.9) = $1`,
|
||||
and Bob will get `round_up($1 * 500 CORE / $19) = round_up($26.3) = $27`,
|
||||
and Bob will get `round_up($1 * 500 CORE / $19) = round_up(26.3 CORE) = 27 CORE`,
|
||||
the effective price would also be `$1 / 27 = $0.037`.
|
||||
|
||||
# Specifications
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0036
|
||||
Title: Remove expired price feeds on maintenance interval
|
||||
Author: oxarbitrage <https://github.com/oxarbitrage>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-22
|
||||
Discussion: https://bitsharestalk.org/index.php?topic=25996.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
BSIP: 0037
|
||||
Title: Allow new asset name to end with a number
|
||||
Author: oxarbitrage <https://github.com/oxarbitrage>
|
||||
Status: Accepted
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-02-23
|
||||
Discussion: https://bitsharestalk.org/index.php?topic=25997.0
|
||||
|
|
348
bsip-0038.md
Normal file
348
bsip-0038.md
Normal file
|
@ -0,0 +1,348 @@
|
|||
BSIP: 0038
|
||||
Title: Add target collateral ratio option to short positions
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Installed
|
||||
Type: Protocol
|
||||
Created: 2018-03-05
|
||||
Discussion: https://bitsharestalk.org/index.php?topic=25924.0,
|
||||
https://github.com/bitshares/bsips/issues/51
|
||||
Replaces: 0035 (partly)
|
||||
Worker: 1.14.100
|
||||
|
||||
# Abstract
|
||||
|
||||
When a short position is margin called, some of its collateral will be sold
|
||||
and some or all of its debt will be covered accordingly.
|
||||
|
||||
However, usually more collateral will be sold, in comparison to the minimum
|
||||
amount required to be sold to maintain the maintenance collateral ratio (MCR)
|
||||
requirement.
|
||||
|
||||
This BSIP proposes a protocol change to let shortes (borrowers) have control
|
||||
over selling how much collateral when being margin called.
|
||||
|
||||
This BSIP depends on [BSIP 31](bsip-0031.md).
|
||||
|
||||
# Motivation
|
||||
|
||||
As discussed in [this forum
|
||||
post](https://bitsharestalk.org/index.php?topic=25924.0), current process gives
|
||||
manipulators big chance to short BTS and make money and increase the risk of
|
||||
black swan, thus hurts the BTS ecosystem. Many participants in the discussion
|
||||
agree that usually it's not really required to cover all debt (thus selling more
|
||||
collateral) when being margin called.
|
||||
|
||||
After [BSIP 31](bsip-0031.md) is
|
||||
in place, shorters will have more chance to not cover all debt on margin call,
|
||||
but it's not 100% guaranteed, and they can only accept the result passively.
|
||||
|
||||
# Rationale
|
||||
|
||||
Different shorters have different expectations when being margin called:
|
||||
* some want to close their short positions completely to cut losses;
|
||||
* some want to sell as little collateral as possible to keep remaining short
|
||||
positions as large as possible;
|
||||
* some want to sell more than minimum required collateral to reduce the
|
||||
possibility of being margin called again in the near future, but don't
|
||||
want to close their short positions completely.
|
||||
|
||||
With a new "target collateral ratio" option, all these expectations can be met.
|
||||
|
||||
In sections below, both a "margin call order" and a "call order" mean a short
|
||||
position in margin call territory.
|
||||
|
||||
## The Definition of Target Collateral Ratio
|
||||
|
||||
For reference purpose, the collateral ratio of any given debt/short position
|
||||
describes the ratio between the available collateral (e.g. core toke BTS) to
|
||||
the debt that is owed (e.g. CNY, etc.) by the original borrower to the
|
||||
blockchain. It is defined to be a dimensionless value as
|
||||
`CR = collateral / (debt / feed_price)` where the price is measured in units of
|
||||
the debt asset / units of the collateral asset (e.g. `CNY / BTS`).
|
||||
|
||||
"Target collateral ratio" is an optional value which can be set onto a short
|
||||
position, when the position being automatically liquidized (margin called),
|
||||
sell no more than required collateral until collateral ratio of the position
|
||||
is **higher than** this value.
|
||||
* Default value: not set, which means to sell as much collateral as possible,
|
||||
which is same to current behavior.
|
||||
* When the value is set but below MCR, use MCR.
|
||||
* When matching a margin call order with a force settle order, ignore this
|
||||
option.
|
||||
* When checking for black swan or globally settling, ignore this option.
|
||||
|
||||
Why to use "higher than" but not "equal to", is due to an existing rule:
|
||||
if a short position's collateral ratio is equal to MCR, it will still be
|
||||
margin called.
|
||||
|
||||
## The Math
|
||||
|
||||
Let prices described below be in terms of `debt / collateral`,
|
||||
e.g. how much CNY per BTS.
|
||||
|
||||
A margin call order can be matched with a limit order as either maker or taker,
|
||||
in any case, there would be a matching price. We can solve an equation as
|
||||
follows:
|
||||
|
||||
```
|
||||
target_CR = new_collateral / ( new_debt / feed_price )
|
||||
= ( collateral - max_amount_to_sell ) * feed_price
|
||||
/ ( debt - amount_to_get )
|
||||
= ( collateral - max_amount_to_sell ) * feed_price
|
||||
/ ( debt - max_amount_to_sell * match_price )
|
||||
=>
|
||||
max_amount_to_sell = (debt * target_CR - collateral * feed_price)
|
||||
/ (target_CR * match_price - feed_price)
|
||||
```
|
||||
|
||||
The result is a rational number.
|
||||
|
||||
Then, the maximum debt it wants to cover can be calculated as:
|
||||
|
||||
```
|
||||
max_debt_to_cover = max_amount_to_sell * match_price
|
||||
```
|
||||
|
||||
The result is a rational number as well.
|
||||
|
||||
## Rounding on Maximums Calculation
|
||||
|
||||
As described in [BSIP 35](bsip-0035.md), at last we need to convert the
|
||||
rational numbers to integers, so rounding is involved.
|
||||
|
||||
### The first round
|
||||
|
||||
When calculating maximum debt to cover, the goal is to go over the specified
|
||||
target but not go too far beyond.
|
||||
That said, if a short position got matched with a big limit order, after
|
||||
partially filled, its collateral ratio should be **just** higher than specified
|
||||
target collateral ratio.
|
||||
|
||||
We may calculate like this: if `max_debt_to_cover` has no fractional component
|
||||
(e.g. 5.00 as opposed to 5.23), plus it by one Satoshi; otherwise, round it up.
|
||||
An effectively same approach is to round down then add one Satoshi onto the
|
||||
result:
|
||||
|
||||
```
|
||||
max_debt_to_cover_int = round_down(max_debt_to_cover) + 1
|
||||
```
|
||||
|
||||
With `max_debt_to_cover_int` in integer, `max_amount_to_sell_int` in integer
|
||||
can be calculated as:
|
||||
|
||||
```
|
||||
max_amount_to_sell_int = round_up(max_debt_to_cover_int / match_price)
|
||||
```
|
||||
|
||||
It's worth noting that we need to make sure the 2 integers always pair
|
||||
perfectly, they're either the full collateral amount and full debt
|
||||
amount, or have:
|
||||
|
||||
```
|
||||
max_amount_to_sell_int == round_up(max_debt_to_cover_int / match_price)
|
||||
max_debt_to_cover_int == round_down(max_amount_to_sell_int * match_price)
|
||||
```
|
||||
|
||||
For `max_amount_to_sell_int` above, we can adjust `max_debt_to_cover_int` with:
|
||||
|
||||
```
|
||||
max_debt_to_cover_int = round_down(max_amount_to_sell_int * match_price)
|
||||
```
|
||||
|
||||
### Review the result
|
||||
|
||||
Due to rounding, it's not guaranteed that selling more collateral will
|
||||
always result in higher collateral ratio on remaining call order.
|
||||
|
||||
On one hand, it's not guaranteed that the pair of integers above will
|
||||
meet the requirements: after covered `max_debt_to_cover_int`, it's possible
|
||||
that collateral ratio of remaining order is still not higher than `MCR` or
|
||||
`target_CR`. In this case, the result is not acceptable. Generally, if we search
|
||||
upwards, we can find a new pair that meets the requirements, or hit the order's
|
||||
collateral or debt amount.
|
||||
|
||||
On the other hand, no matter if the pair above meets the collateral ratio
|
||||
requirement, it's possible that there exists a smaller pair which meets the
|
||||
requirement. However, it's not easy to find a perfect pair. If we search
|
||||
downwards, it's not easy to decide when to stop; if we start from a smaller
|
||||
pair then search upwards, it's not easy to decide where to start.
|
||||
|
||||
### Favor performance over accuracy
|
||||
|
||||
Due to the difficulty mentioned above, in this BSIP we allow imperfect results,
|
||||
and don't describe or enforce how exactly to find better results.
|
||||
|
||||
The first implementation should be made with efforts. It will become consensus
|
||||
after approved by stake holders via voting. It will then be in effect until
|
||||
changed or replaced with a new BSIP.
|
||||
|
||||
Here are some guidelines about implementation.
|
||||
|
||||
When searching upwards, usually the real working pair is not far away, but it's
|
||||
not guaranteed due to rounding. For better performance, it's not good to search
|
||||
by adding one Satoshi every time. Can use a divergence sequence or other
|
||||
sublinear-time algorithm, that means it's possible that some good data will be
|
||||
skipped which may result in impefect result.
|
||||
|
||||
|
||||
## Rounding on Order Matching, and Edge Cases
|
||||
|
||||
Rounding rules about order matching are defined in [BSIP 35](bsip-0035.md).
|
||||
|
||||
Generally, when two orders got matched, the order matching engine will favor
|
||||
the larger order while rounding.
|
||||
|
||||
When a call order got matched with a limit order, if the call order has no
|
||||
`target_CR` option set but its debt is more than the limit order offered,
|
||||
or the call order has `target_CR` option set but `max_debt_to_cover_int`
|
||||
is more than the limit order offered, both means the call order is larger,
|
||||
according to the rounding rule, the call order's paid collateral will be
|
||||
rounded down, so its collateral ratio will increase after partially filled.
|
||||
|
||||
If the call order has `target_CR` option set and is covering the whole "maximum
|
||||
debt to cover", to be fair, we should consider that part of call order to be
|
||||
smaller and favor the limit order while rounding, otherwise the limit order may
|
||||
suffer an overall loss.
|
||||
That means the call order will be partially filled and its paid
|
||||
collateral will be rounded up, in this case, if the call order's collateral
|
||||
ratio was not too low, usually, partially filling will still lead to an
|
||||
increase in collateral ratio.
|
||||
|
||||
However, there are edge cases: if the call order's collateral ratio is already
|
||||
low, or its debt or collateral amount is tiny, rounding up paid collateral on
|
||||
partially filling will probably lead to a decrease in collateral ratio,
|
||||
in an extreme case it may even lead to a black swan event. This is against the
|
||||
intention of this BSIP. To solve this issue, if detected a decrease in
|
||||
collateral ratio when matching, we propose to ignore the `target_CR` option of
|
||||
corresponding call order, and re-evaluate the match.
|
||||
|
||||
## The Revised Rounding Rules on Order Matching
|
||||
|
||||
So the rule for matching a limit order with a call order will be revised as
|
||||
follows with new rules **in bold**:
|
||||
* if the call order is receiving the whole debt amount, which means it's
|
||||
smaller and the short position will be closed after the match, round up its
|
||||
paying amount;
|
||||
* **otherwise,**
|
||||
* **if the call order has `target_collateral_ratio` set and is receiving the
|
||||
maximum debt amount calculated with `target_collateral_ratio`, see the call
|
||||
order as smaller, try to round up its paying amount;**
|
||||
* **for edge cases, if the call order's collateral ratio would not increase
|
||||
after being partially filled due to the round-up (which may even cause a
|
||||
black swan event in an extreme scenario), see its `target_collateral_ratio`
|
||||
as "not set" for this time, re-apply the filling rules for this match.**
|
||||
* otherwise, the call order is larger, round down its paying amount.
|
||||
* if the limit order would receive nothing, cancel it (it's smaller,
|
||||
so safe to cancel);
|
||||
* otherwise, calculate the amount that the limit order would pay as
|
||||
`round_up(receiving_amount * match_price)`. After filled both orders,
|
||||
if the limit order still exists, the remaining amount might be too small,
|
||||
so cancel it.
|
||||
|
||||
## When and How To Use the Option
|
||||
|
||||
The `target_collateral_ratio` option can to be set, updated or cleared when
|
||||
creating or updating a short position. When doing so, other rules still apply,
|
||||
E.G. can't update a short position to have too small collateral ratio.
|
||||
|
||||
For one account, different short positions (for different assets) can be set
|
||||
with different `target_collateral_ratio`.
|
||||
|
||||
For one short position,
|
||||
|
||||
* if want to close it completely to cut losses when being margin called,
|
||||
* don't set or clear `target_collateral_ratio` option, because the option is
|
||||
**optional** so can be unset or cleared;
|
||||
|
||||
* if want to sell as little collateral as possible when being margin called,
|
||||
to keep the remaining short position as large as possible,
|
||||
* set `target_collateral_ratio` to `MCR` or less;
|
||||
|
||||
* if want to sell more than minimum required collateral when being margin
|
||||
called, to reduce the possibility of being margin called again in the near
|
||||
future, but don't want to completely close the short position,
|
||||
* set `target_collateral_ratio` to a value higher than `MCR`, E.G. `300%`.
|
||||
The higher the value is, the more collateral will be listed for sale when
|
||||
it's margin called.
|
||||
|
||||
|
||||
# Specifications
|
||||
|
||||
## `call_order_object`
|
||||
|
||||
The `call_order_object` stores current status of a short position.
|
||||
|
||||
Need to add a new field into it:
|
||||
|
||||
* `optional<uint16_t> target_collateral_ratio;`
|
||||
|
||||
Same to other collateral ratios, the actual ratio is the value divided by
|
||||
`GRAPHENE_COLLATERAL_RATIO_DENOM` aka `1000`.
|
||||
|
||||
Due to the `uint16_t` data type, the new field's maximum value is `65535`,
|
||||
which means `6553.5%`.
|
||||
|
||||
## `call_order_update_operation`
|
||||
|
||||
The `call_order_update_operation` is used to open, update and close short
|
||||
positions. It contains an `extensions` field:
|
||||
|
||||
* `extensions_type extensions;`
|
||||
|
||||
Need to override data type of this field so it can include the new "target
|
||||
collateral ratio" option.
|
||||
|
||||
## `call_order_update_evaluator`
|
||||
|
||||
The `call_order_update_evaluator` is used to evaluate and apply the
|
||||
`call_order_udpate_operation`. Need to add logic:
|
||||
* only allow `target_collateral_ratio` to be set after the hard fork;
|
||||
* set/update/clear `target_collateral_ratio` field of `call_order_object`
|
||||
accordingly. Specifically,
|
||||
* set or update the field if it presents in the operation and is valid,
|
||||
* clear the field if it doesn't present in the operation or is not valid.
|
||||
|
||||
## `proposal_create_evaluator`
|
||||
|
||||
The `proposal_create_evaluator` is used to evaluate and apply the
|
||||
`proposal_create_operation`, which can contain zero or more
|
||||
`call_order_udpate_operation` objects. Need to add logic:
|
||||
* only allow `target_collateral_ratio` to be set after the hard fork.
|
||||
|
||||
## Call Order Matching and Filling
|
||||
|
||||
After a call order get matched with a limit order and about to fill,
|
||||
* if `target_collateral_ratio` is not set, process as before;
|
||||
* if `target_collateral_ratio` is set, compare it to `MCR`, use the bigger
|
||||
one (aka `max(target_collateral_ratio,MCR)`) to calculate maximum amount of
|
||||
debt to cover according to the equation described above, and apply the
|
||||
revised rounding rules, then process other logic as before.
|
||||
|
||||
## UI/UX
|
||||
|
||||
The new option need to be presented and can be used in UI after the hard fork.
|
||||
|
||||
When there are call orders to be filled, if `target_collateral_ratio` option
|
||||
is set, UI need to show exact amount of collateral that another trader is able
|
||||
to buy and exact amount of debt that need to pay according to the equation
|
||||
described above. Note that this calculation will need to use the current `feed_price`.
|
||||
|
||||
# Discussion
|
||||
|
||||
With this BSIP, we provided a tool that can be used by shorters to keep their
|
||||
positions, however, it's not always the best strategy to keep as large position
|
||||
as possible, sometimes it's even more risky than just cutting losses.
|
||||
Nevertheless, how to use the tool, is up to the traders to decide.
|
||||
|
||||
# Summary for Shareholders
|
||||
|
||||
"This is how it should work."
|
||||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
* https://bitsharestalk.org/index.php?topic=25924.0
|
||||
* https://github.com/bitshares/bsips/issues/51
|
71
bsip-0039.md
Normal file
71
bsip-0039.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
BSIP: 0039
|
||||
Title: Automatically approve proposals by the proposer
|
||||
Authors: Fabian Schuh <https://github.com/xeroc>
|
||||
Abit More <https://github.com/abitmore>
|
||||
Status: Draft
|
||||
Type: Protocol
|
||||
Created: 2018-03-20
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/138
|
||||
Worker: <Id of worker proposal>
|
||||
|
||||
# Abstract
|
||||
|
||||
On the BitShares Blockchain, proposals allow to gather signatures for a
|
||||
multisignature-setup by means of on-chain approvals. In contrast to
|
||||
other blockchains, these proposals are actually stored on the blockchain
|
||||
and automatically executed once the required amount of approvals has
|
||||
been reached. This allows participants of a multisignature-setup to
|
||||
exchange insufficiently signed transactions easily.
|
||||
|
||||
However, when creating a new proposal, the proposer needs to manually
|
||||
approve his operation afterwards. This is not only inconvenient, but
|
||||
also costs and additional operation and thus a fee.
|
||||
|
||||
This BSIP recommends to have the proposer of a proposal automatically
|
||||
added as approved.
|
||||
|
||||
# Motivation
|
||||
|
||||
In the case of a simple 2-of-3 multisig-scheme, today's implementation
|
||||
forces us to have 3 operations stored on the blockchain: a) the proposal
|
||||
itself, and two approvals.
|
||||
|
||||
The inconvenience and additional fee hinders adoption of this scheme and
|
||||
makes it unnecessary complicated.
|
||||
|
||||
# Rational
|
||||
|
||||
By proposing an action, the proposer can be considered as an agreeing
|
||||
party, otherwise the proposal wouldn't have been created in the first
|
||||
place.
|
||||
|
||||
If the proposer is not part of the multisig-setup, having him approve
|
||||
the proposal automatically does affect the validity of the proposal
|
||||
itself.
|
||||
|
||||
# Specifications
|
||||
|
||||
This BSIP comes with only minimal modifications that, however, change
|
||||
the behavior of the protocol and thus need a protocol upgrade.
|
||||
|
||||
The change is implemented in such a way that the `fee_paying_account`
|
||||
for the proposal is added to the `available_active_approvals` of the
|
||||
proposal after creation.
|
||||
|
||||
# Discussion
|
||||
|
||||
To be found in the forum - see link above.
|
||||
|
||||
# Summary for Shareholders
|
||||
|
||||
This BSIP proposes a minor modification that improves the process of
|
||||
using hierarchical account permissions and simplifies the use of
|
||||
multisig-setups with only minimal modifications.
|
||||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
* https://github.com/bitshares/bitshares-core/issues/138
|
422
bsip-0040.md
Normal file
422
bsip-0040.md
Normal file
|
@ -0,0 +1,422 @@
|
|||
BSIP: 0040
|
||||
Title: Custom active permissions
|
||||
Authors:
|
||||
Stefan Schießl <https://github.com/sschiessl-bcp>
|
||||
Contributors and Reviewers:
|
||||
Alex Megalokonomos <https://github.com/clockworkgr>
|
||||
Fabian Schuh <https://github.com/xeroc>
|
||||
Abit <https://github.com/abitmore>
|
||||
Peter Conrad <https://github.com/pmconrad>
|
||||
Status: Draft
|
||||
Type: Protocol
|
||||
Created: 2018-07-25
|
||||
Discussion: https://github.com/bitshares/bitshares-core/issues/1061
|
||||
Worker: <Id of worker proposal>
|
||||
|
||||
# Abstract
|
||||
|
||||
Strengthening user security is one of the main factors to elevate BitShares. In light of recent
|
||||
hacking and phishing attempts this becomes even more important. The need for a more sophisticated
|
||||
account security preceeded the idea for a finer-grained control of account permissions.
|
||||
We propose to add an additional authority to the account, called Custom Active (Permission). The
|
||||
permission contains a list of operationid-to-authority mappings that each grant access to the respective
|
||||
operation as if it were the active permission of the account. Additionally, the arguments of said operation
|
||||
can be restricted.
|
||||
|
||||
For the non-technical reader the section Specification can be skipped.
|
||||
|
||||
# Motivation
|
||||
|
||||
Any successfull hacking or phishing attempt on any of the web wallets that are powered by the
|
||||
BitShares Blockchain is bad publicity. The user needs to be educated in account security, and this BSIP
|
||||
aims to ensure all technical possibilities are met while being flexible to allow many use-cases.
|
||||
|
||||
With this BSIP any user can create additional keys with specific purpose (everything else is prohibited). We list some possibilities below:
|
||||
- Witness Key: Only allows update signing key and publish price feed
|
||||
- Trading Key: Only allows limit orders (arguments restricted to desired markets), update margin position and transfers (arguments restricted to certain accounts)
|
||||
- Proposal Update Key: Approve proposals (2FA comes to mind)
|
||||
- Faucet Key: Allow only to create accounts
|
||||
- Withdrawal Key: Allow another account to transfer funds to himself
|
||||
- Cold Storage Key: Only allow to move funds to the Hot Wallet
|
||||
|
||||
The above list of named keys is nothing that is known to the backend as the backend should have an abstract implementation.
|
||||
The UI could provide a button "Create Trading Key" that properly configures the respective custom active permission entry.
|
||||
|
||||
Note: The user can still use the active authority just like used to, no change in existing behavior. The named keys only give an additional possibility. For example: The user can login the UI using the private key of such a named key. Then he only as access to the operations that this named key grants. He can still login with the existing password to gain full access (similar a local wallet can be created that only contains the named key).
|
||||
|
||||
This BSIP will be split into parts that will be voted on separately (see Milestones section). All of the above keys are possible with Milestone 1. Milestone 2 allows stateful restrictions (e.g. allow market orders up to some amount for every month), Milestone 3 gives finer control of how to combine restrictions and Milestone 4 allows to set a number of allowed executions per authority (introduces an additional on-chain dependency). Milestone 2, 3 and 4 will be put up for voting if Milestone 1 proves successful.
|
||||
|
||||
# Rationale
|
||||
|
||||
Custom active permission is a list of `custom active authorities`. A `custom active authority` contains an `operation_id`,
|
||||
an `authority` (just like with active permission) and `restrictions` than can be used to restrict arguments.
|
||||
Furthermore, such a `custom active authority` is only valid in a specified time period (`valid_from` and `valid_to`).
|
||||
When handling incoming signed transactions, the backend checks
|
||||
for each operation if there is a `custom active authority` for any of its required accounts. Check for every required
|
||||
account of the transaction if all its belonging operations have at least one positively matched `custom active authority`
|
||||
(see Specifications for definition of "matching"), and if so behave as if the active authority of the corresponding account is present (recursive authorities are excluded, see Examples).
|
||||
|
||||
# Specification
|
||||
|
||||
All descriptions in this section are on a pseudo/prosa level and no recommendation how it can best be implemented or serialized. They are meant to facilitate the understanding. If anything in the looping process or order of evaluation is unsuitable for actual implementation, changes can be made accordingly as long the same functionality is achieved.
|
||||
|
||||
Note: The impact of Milestone 4 is explained in its own subsection to not hinder the reading flow
|
||||
|
||||
### Custom active permission and custom active authority
|
||||
|
||||
A `custom active permission` contains a list of `custom active authorities` and looks like follows (in JSON-like/pseudo for clarification):
|
||||
```
|
||||
custom_active_permission = {
|
||||
account_id, // account that is assigned to this permission
|
||||
authorities = list of custom_active_authority objects
|
||||
}
|
||||
custom_active_authority = {
|
||||
enabled, // status of this authority, true or false. true when created
|
||||
valid_from, // timestamp when this is active
|
||||
valid_to, // timestamp when this is invalid
|
||||
operation_id, // operation id of the target operation,
|
||||
authority, // same as for the existing authotities (multisig with weighted accounts or keys),
|
||||
restrictions // see below
|
||||
}
|
||||
```
|
||||
Note: This assumes `custom_active_permission` is stored in a separate index. Actual implementation details left to the implementer, as long as every `custom_active_permission` can be assigned to exactly one account.
|
||||
|
||||
A `custom active authority` is matched against operations of an incoming, signed transaction. The wording *matching* refers to:
|
||||
- `operation_id` is equal to the id of the incoming operation
|
||||
- `account_id` is in the required accounts of the operation
|
||||
- the `authority` of the `custom_active_authority` is given by the signatures of the transaction
|
||||
- timestamp `now` is within `valid_to` and `valid_from`
|
||||
- all `restrictions` assert positively
|
||||
|
||||
### Restrictions
|
||||
|
||||
The `restrictions` field is a list of restrictions consisting of argument to assert mappings.
|
||||
A dictionary-type object like
|
||||
```
|
||||
restriction = {
|
||||
function, // argument_identifier
|
||||
argument, // pointer to a dynamic value (argument of the operation, or attribute when nested)
|
||||
data, // data specific to the function
|
||||
}
|
||||
```
|
||||
is called a restriction, that can assert itself positively (passed) or negatively (violated). All restrictions are evaluated per default with `AND` logic to determine if the whole list has asserted positively.
|
||||
|
||||
List of possible restrictions are:
|
||||
|
||||
| function | data | state |
|
||||
| ------------- |:-------------:| -----:|
|
||||
| `any` | [`list`, `of`, `allowed`, `values`] | stateless |
|
||||
| `none` | [`none`, `of`, `these`, `values`] | stateless |
|
||||
| `lt, le, gt, ge, eq, neq` | `comparative` | stateless |
|
||||
| `contains_all, contains_none` | [`list`, `of`, `values`] | stateless |
|
||||
| `limit` | [`max_cumsum`, `interval_in_sec`] | [`current_cumsum`, `interval_began`] |
|
||||
| `limit_monthly` | [`max_cumsum`, `interval_in_months`] | [`current_cumsum`, `interval_began`] |
|
||||
| `attribute_assert` | list of restrictions | stateless |
|
||||
| `logical_or` | list of restrictions lists | stateless |
|
||||
|
||||
Following cases must hold for a restriction:
|
||||
- when the `custom_active_authority` is installed, the basic argument types (without nesting) are checked, and installing denying if not matching
|
||||
- if there is no value given (e.g. an optional argument, or nested value not given), the restrictions is passed (even if the underlying operation understands the absence of a key as instructions to delete it on-chain, see bitshares/bitshares-core#838)
|
||||
- if the expected type of the argument does not match the given type (no implicit type conversion), the restriction is violated (needed for nested `attribute_assert`)
|
||||
- if the function of the restriction asserts negatively, the restriction is violated
|
||||
|
||||
Note:
|
||||
- If required a field can be added that stores the assumed type of the argument
|
||||
- This list of restrictions may be redefined to improve clarity, performance or to reduce complexity of implementation while maintaining the intended functionality
|
||||
|
||||
In the following we list possible `restriction`s. Mentioning `argument value` in the text below refers to the value of
|
||||
the argument of the operation specified by `argument` of a restriction.
|
||||
|
||||
#### `any`
|
||||
Stateless assert, all argument types. `Argument value` must be equal to one of values in the data list.
|
||||
|
||||
Note
|
||||
- If beneficial for performance or complexity an additional operator `equal` can be implemented that only compares to one.
|
||||
|
||||
#### `none`
|
||||
Stateless assert, all argument types. `Argument value` must NOT be equal to any of the values in the list.
|
||||
|
||||
Note
|
||||
- If beneficial for performance or complexity an additional operator `not_equal` can be implemented that only compares to one.
|
||||
|
||||
#### `lt, le, gt, ge, eq, neq`
|
||||
Stateless assert. Allows explicit type conversion:
|
||||
- `int` type: use as is
|
||||
- `string` type: use `length` of string as `argument value`
|
||||
- `object` type: use `size` of object as `argument value`
|
||||
- `list` type: use `length` of the list as `argument value`
|
||||
|
||||
The different asserts read as:
|
||||
- `lt`: `Argument value` must be less than `comparative`
|
||||
- `le`: `Argument value` must be less than or equal to `comparative`
|
||||
- `gt`: `Argument value` must be greater than `comparative`
|
||||
- `ge`: `Argument value` must be greater than or equal to `comparative`
|
||||
- `eq`: `Argument value` must equal to `comparative`
|
||||
- `neq`: `Argument value` must NOT be equal to `comparative`
|
||||
|
||||
Note
|
||||
- `eq` and `neq` are implicit number comparators and not to be mistaken by a strict left must equal right operator, just like `lt, le, gt, ge` (for example, comparing `1 > list object` would have no sense)
|
||||
- If beneficial for performance or complexity the implicit type conversions can be removed and distinct operators introduced that do not have implicit type conversions
|
||||
|
||||
#### `contains_all, contains_none`
|
||||
Stateless assert, for `list` type arguments.
|
||||
- `contains_all`: The `argument value` must contain all items specified by `data`, but can contain more
|
||||
- `contains_none`: The `argument value` must NOT contain any of the items specified by `data`, but can contain others
|
||||
|
||||
#### `limit`
|
||||
Stateful assert, only `int` type arguments. When the authority is created, `interval_began` is set to `valid_from` from its custom active authority and `max_cumsum` to `0`. Incoming operations are first tried to match all stateless asserts,
|
||||
and if all passes continue with stateful asserts. If `now > interval_began + interval_in_sec`, then set `max_cumsum = 0` and set `interval_began = now`.
|
||||
The assert that needs to pass is now `current_cumsum + incoming value <= max_cumsum`. If all `asserts` of this `custom_active_authority` pass, update `current_cumsum = current_cumsum + incoming value`.
|
||||
|
||||
#### `limit_monthly`
|
||||
Stateful assert, only `int` type arguments. Analogue to `limit`, but `interval_began` is initially set to `month(valid_from)` and set to `month(now)` on update, additionally the time assert is `month(now) >= interval_began + interval_in_months` (include logic for month overflow when year changes). The `month(now)` call assumes zulu time to calculate month number.
|
||||
|
||||
#### `attribute_assert`
|
||||
Stateless assert, only for dictionary type objects. The data list contains restrictions that all must pass, the reference for the `argument` of the child restriction is nested into the attributes of the parent dictionary type object. Allows nesting of `attribute_assert`.
|
||||
|
||||
#### `logical_or`
|
||||
Stateless assert, only for dictionary type objects. The data is a list of restrictions lists, i.e.
|
||||
`data = [ [restriction 1, restriction 2], [restriction 3, restriction 4], ... ]`. If one of the restrictions sub-lists in data passes as whole, this restriction passes. In above miniexample that would mean if `restriction 1` and `restriction 2` pass, the whole `logical_or` restriction is considered to be passed as well.
|
||||
|
||||
### Outline of handling incoming transactions
|
||||
|
||||
When a signed transaction arrives and before the backend evaluates if all necessary authorities are present through the signatures, do the following:
|
||||
- iterate over `required accounts`
|
||||
- iterate over all `operations` (child operations of proposal are not included) within the transactions that require the active authority of this account
|
||||
- iterate the `custom_active_authorities` of this account, and if it matches, remember that and continue with next `operation`
|
||||
- if a `custom active authority` match was found for every operation in the loop, behave as if the `active authority` of this account is present for the corresponding operations.
|
||||
|
||||
Note:
|
||||
- A `custom_active_authority` can only grant the `active authority` of the required account of the corresponding operation, nothing more
|
||||
- The actual active authority of a required account can still be given as before, existing behavior is not to be changed
|
||||
- This for illustration, not actual implementation instructions
|
||||
|
||||
### Modification to the backend
|
||||
|
||||
* Add a new index or extend the account object to store custom active permission are assigned to an account and contain a list of custom active authorities. Multiple custom active authority entries are possible for one operation
|
||||
* Provide operations: `install_custom_active_authority`, `update_custom_active_authority`, `delete_custom_active_authority` to allow changing the custom active permission (3 operation to allow custom transaction fees and avoid having to send the complete list of all authorities for every update)
|
||||
* If the active authority of the account is updated, all custom active authorities are disabled and must be manually specified / re-enabled. User can either
|
||||
1. keep the authorities enabled by specifying them in a list of `custom_active_authorities` in `extensions` of `account_update_operation`
|
||||
2. enable them again afterwards by using `update_custom_active_authority`
|
||||
* Operation-specific authorities (if present) must be evaluated in incoming transactions
|
||||
* Remove expired custom_active_authorities on maintenance if they are expired for longer than one month
|
||||
* Additional committee parameters may be needed to limit the extend of usage of this feature
|
||||
|
||||
Notes: The implementation must not differentiate on which operation the custom active authority is applied, all operations are treated in same fashion
|
||||
|
||||
### Milestone 4: Number of executions
|
||||
|
||||
If Milestone 4 is implemented, a `custom active authority` receives an additional field `remaining_executions` to
|
||||
specify the allowed number of executions.
|
||||
The user can choose to restrict the valid time period and/or the number of executions, but the number of executions can only
|
||||
be unlimited (not set) if a time period is specified. A `custom active authority` then matches if the time period is
|
||||
valid or not set, and `remaining_executions` is either not set or > 0. When a `custom active authority` successfully grants
|
||||
the active authority for the corresponding operation and the whole transaction is executed, `remaining_executions` is
|
||||
decreased by one. If it becomes zero, the `custom active authority` becomes disabled.
|
||||
If the `custom active authority` does not get replenished by the user within one month, it will be deleted.
|
||||
|
||||
# Economics
|
||||
|
||||
Adding a custom active authority means increased effort for the backend, and with a stateful one also the need for more storage. Proposed transaction fees:
|
||||
- `install_custom_active_authority`: Normal accounts can only create custom active authoritites with a duration of maximum 1 year, LTM can do any duration. Two options come to mind:
|
||||
- A fixed high fee independent of authorities content
|
||||
- Tied to the duration and complexity of the custom active authority. Transaction fee is then `fee = flat_fee + basic_fee * duration` where `basic_fee` is calculated according to complexity (e.g. size of authority, number of restrictions and etc.). The period `duration` refers to the time that is still left, not the set duration
|
||||
(i.e. `date_to - max(now, date_from)`)
|
||||
- `update_custom_active_authority`: Base fee similar to `account_update` plus dynamic one for any duration increase, no payback if duration in decreased (increase/decrease is evaluated on both interval ends separately)
|
||||
- `delete_custom_active_authority`: Cheap similar to `limit_order_cancel`
|
||||
|
||||
This logic forces the user to think about the desired duration and enforces to put it rather too short than too long.
|
||||
If a custom active is expired, or considered to be too short, extending it is easily doable.
|
||||
After expired, the custom active becomes disabled and can still be enabled again with a new period, paying the fee for that new period.
|
||||
|
||||
Note:
|
||||
- For Milestone 4 the install fee would be dependent on the number of executions if no time period is set.
|
||||
|
||||
# Discussion
|
||||
|
||||
To be found in the [issue](https://github.com/bitshares/bitshares-core/issues/1061) and [pull request](https://github.com/bitshares/bsips/pull/86).
|
||||
|
||||
# Examples
|
||||
|
||||
These examples are for illustration and no specification of actual serialization.
|
||||
|
||||
|
||||
#### Example: Nested arguments like `options`
|
||||
Assume `asset_update_operation`. All attributes of its `options` must be filled on update call. This assert can not be used to realize a "may only change attribute xzy of `options`". This would require that the logic knows which of the arguments are reflected on-chain and it knows how to query it for every operation that contains `options`. If `options` are to be restricted with this assert, all values that should not change would need be fixated by defining an `any` assert for those attributes, while having e.g. a `lt` assert for the one attribute that is allowed to change.
|
||||
|
||||
#### Example: Simple transfer
|
||||
Assume account A and B and some unrelated key K.
|
||||
The custom active authority should be put such that a transfer transaction sending funds away from A can be signed with key K, as long as the receiver is B. More concrete, the authority would look like
|
||||
```
|
||||
custom active authority = {
|
||||
valid_from: 7.7.2018 00:00
|
||||
valid_to: 8.7.2018 00:00
|
||||
operation_id: transfer,
|
||||
authority: {
|
||||
threshold: 1
|
||||
key_auth: [key K, 1]
|
||||
account_auth: []
|
||||
},
|
||||
restrictions: [
|
||||
{
|
||||
function: any,
|
||||
argument: to,
|
||||
data: [account B]
|
||||
} // this restricts the argument identified with "to"
|
||||
]
|
||||
}
|
||||
```
|
||||
Exemplatory outcomes:
|
||||
- Transfer asset X with amount Y from account A to account B, signed with Key K: Accepted
|
||||
- Transfer asset X with amount Y from account B to account A, signed with Key K: Denied
|
||||
- Transfer asset X with amount Y from account A to account C, signed with Key K: Denied
|
||||
- Transfer asset X with amount Y from account A to account B, signed with active authority of B: Denied
|
||||
- Transfer asset X with amount Y from account A to account B, signed with active authority of A: Accepted
|
||||
- Create a proposal that includes operation 'transfer asset X with amount Y from account A to account B, signed with Key K: Accepted. Anyone can create a proposal.
|
||||
|
||||
Note:
|
||||
- This is included with the first Milestone
|
||||
- Normal permission logic is not altered. Account A can still sign the a transfer from account A to account B with its active authority
|
||||
|
||||
#### Involving multi-sig
|
||||
|
||||
Account A has multi-sig active authority of account B and C. Account A has a custom active authority that grants key K transfer priviliges (any asset to any account). Account B has a custom active authority that grants key L transfer priviliges (any asset to any account).
|
||||
|
||||
The transaction contains a transfer from A to account D. Required active authority of this operation is A.
|
||||
- Signed by B and C: Accepted
|
||||
- Signed by L and C: Denied. The custom active authority of B does not match, only applies for transfers with B as sender
|
||||
- Signed by K: Accepted, basically bypassing multisig. This is intended, as the multisig needs to approve the installment of the custom active authority in the first place
|
||||
|
||||
#### Recursive active authority
|
||||
|
||||
Suppose Alice has a custom active authority with key K for transfers to Charlie. Bob has Alice as his active authority account. Suppose a transaction containing two operations
|
||||
|
||||
1. transfer 1 BTS from Alice to Charlie
|
||||
2. transfer 1000 BTS from Bob to some other account
|
||||
|
||||
Cases:
|
||||
- Transaction is signed by K
|
||||
- Operation 1. requires Alice as active authority, and there is a matching custom active authority, thus this operation would be allowed to execute
|
||||
- Operation 2. requires Bob as active authority. Even though Bob has Alice as active authority, K can NOT grant recursively the active authority of Bob
|
||||
- The whole transaction is denied
|
||||
- Transaction is signed by K and A
|
||||
- Operation 1. requires Alice as active authority and is also directly present, is allowed
|
||||
- Operation 2. requires Bob as active authority, which is indirectly present through A, execution is allowed (existing logic)
|
||||
- The whole transaction is denied because too many signatures are present (existing logic)
|
||||
- Transaction is signed by K and B
|
||||
- Operation 1. requires Alice as active authority, and there is a matching custom active authority, thus this operation would be allowed to execute
|
||||
- Operation 2. requires Bob as active authority and is also directly present, is allowed
|
||||
- Transaction may execute
|
||||
|
||||
#### Example: Either or
|
||||
Assume account A, B and C and asset X and asset Y. The custom active authority should now achieve
|
||||
that a transfer transaction sending funds away from A can be signed with with active authority of account B if
|
||||
- it sends less than 10000 of asset X to account C
|
||||
- it sends less than or equal to 20000 of asset Y to account C
|
||||
|
||||
More concrete, the authority would look like
|
||||
```
|
||||
custom active authority = {
|
||||
valid_from: 7.7.2018 00:00
|
||||
valid_to: 8.7.2018 00:00
|
||||
operation_id: transfer,
|
||||
authority: {
|
||||
threshold: 1
|
||||
key_auth: []
|
||||
account_auth: [account B, 1]
|
||||
},
|
||||
restrictions: [
|
||||
{
|
||||
function: logical_or,
|
||||
data: [ either_list, or_list ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
either_list =
|
||||
[
|
||||
{
|
||||
function: attribute_assert,
|
||||
argument: amount,
|
||||
data: [
|
||||
{
|
||||
function: lt,
|
||||
argument: amount,
|
||||
data: 10000
|
||||
},
|
||||
{
|
||||
function: any,
|
||||
argument: asset_id,
|
||||
data: [ asset X ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
function: any,
|
||||
argument: to,
|
||||
data: [ account C ]
|
||||
}
|
||||
]
|
||||
|
||||
or_list =
|
||||
[
|
||||
{
|
||||
function: attribute_assert,
|
||||
argument: amount,
|
||||
data: [
|
||||
{
|
||||
function: le,
|
||||
argument: amount,
|
||||
data: 20000
|
||||
},
|
||||
{
|
||||
function: any,
|
||||
argument: asset_id,
|
||||
data: [ asset Y ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
function: any,
|
||||
argument: to,
|
||||
data: [ account C ]
|
||||
}
|
||||
]
|
||||
```
|
||||
Note: This is included with the third Milestone
|
||||
|
||||
|
||||
#### Example: Checking for custom active authorities
|
||||
|
||||
Assume Account A, B and C. Now A has two `custom active authorities`:
|
||||
|
||||
- `custom active authority 1`: Allow Account B to transfer asset X to D
|
||||
- `custom active authority 2`: Allow Account C to transfer asset X to D
|
||||
|
||||
The incoming transaction now contains `transfer 100 asset X from A to D, signed by all signatures required for active authority of C`.
|
||||
The required accounts (meaning required active authority) for the transaction is Account A.
|
||||
Backend would start considering `custom active authority 1` and check if active authority of account B is present through signatures.
|
||||
It is not, thus continue by checking if authority of `custom active authority 2` is present, which it is.
|
||||
Behave as if active authority of Account A is present for the matched operation and continue with normal authority checks.
|
||||
Since the required accounts is Account A, and the given accounts is also Account A through `custom active authority 2`,
|
||||
the transaction is executed.
|
||||
|
||||
# Milestones
|
||||
|
||||
We propose do split the implentation into multiple milestones. Each milestone will be voted on separately:
|
||||
|
||||
1. Implementation of basic functionaliy to allow custom active permissions and authorities, including `any`, `none` and `lt, le, gt, ge, eq, neq`, `contains_all, contains_none` and `attribute_assert` `asserts`. If deemed necessary by developpers, reduce to only allow one key or one account for every `custom active authority`
|
||||
2. Implement stateful asserts `limit` and `limit_monthly`
|
||||
3. Implement `logical_or`
|
||||
4. Implement `remaining_executions`
|
||||
|
||||
# Summary for Shareholders
|
||||
|
||||
Bad publicity in terms of security can have very negative effect on the BTS value. This BSIP allows that traders can e.g. use a trading key, witnesses can use their witness key and a faucet can use a faucet key. If then for some reason the key or witness/faucet server becomes compromised, such a key can do little harm to the account holders, minimizing the risk.
|
||||
|
||||
This BSIP opens up a lot of use-cases as presented in Motivation section. The intention is to not alter any existing logic of the permission system, which reduces the risk of malfunctioning.
|
||||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
186
bsip-0042.md
Normal file
186
bsip-0042.md
Normal file
|
@ -0,0 +1,186 @@
|
|||
BSIP: 0042
|
||||
Title: Adjust price feed to influence trading price of SmartCoins
|
||||
Author: Abit More <https://github.com/abitmore>
|
||||
Status: Up for voting
|
||||
Type: Protocol
|
||||
Created: 2018-08-22
|
||||
Workers: 1.14.118 (pro), 1.14.119 (con)
|
||||
|
||||
# Abstract
|
||||
|
||||
We here propose to dynamically adjust price feed in order to influence trading
|
||||
price of smart coins to achieve tighter peg.
|
||||
|
||||
This BSIP is constantly evaluated in terms of being accepted or rejected,see the last section *Constant voting evaluation* for details.
|
||||
|
||||
# Motivation
|
||||
|
||||
To get mass adoption, it's better that the SmartCoins can peg to targets more
|
||||
tightly. E.G. bitUSD pegs more tightly to Fiat USD.
|
||||
|
||||
# Rationale
|
||||
|
||||
When BTS is in a downtrend, the SmartCoins are always being traded at a
|
||||
premium; when BTS is in a uptrend, the SmartCoins tend to be traded with a
|
||||
discount. Here is a chart showing historical trading price of bitUSD:
|
||||
https://coinmarketcap.com/currencies/bitusd/
|
||||
|
||||
Typically a premium is around 10%, and a discount is around 5%. Although some
|
||||
people think the numbers are not very large, other people think they're too
|
||||
large. In this BSIP we aim to reduce the numbers.
|
||||
|
||||
Trading price of a SmartCoin is influenced by
|
||||
* underlying value guaranteed by collateral;
|
||||
* demand vs supply.
|
||||
|
||||
## Downtrend and premium
|
||||
|
||||
When BTS is in a downtrend, before a black swan event, supplies of SmartCoins
|
||||
are squeezed, while the underlying value is still guaranteed if price feeds are
|
||||
around real trading price, thus trading price of the SmartCoins will be pushed
|
||||
up.
|
||||
|
||||
If we slightly adjust the price feed, thus slightly loose the guarantee on the
|
||||
underlying value, hopefully we can push the trading price of SmartCoins towards
|
||||
par. Since adjusting price feed affects supply as well, ideally we don't need to
|
||||
adjust much to achieve the goal.
|
||||
|
||||
Other options include decreasing MCR to stimulate supply, or decreasing MSSR to
|
||||
suppress demand.
|
||||
|
||||
### Negative feedback
|
||||
|
||||
Actually we don't know what's the best offset to be applied to the inputs, but
|
||||
we can adopt a negative feedback approach. When adjusting the inputs, keep an
|
||||
eye on the result (trading price of SmartCoins). If the adjustment is in the
|
||||
correct direction, the price should move towards par. If the price moved too
|
||||
little, we adjust more; if the price moved too much, we adjust less. Finally
|
||||
this will lead to a stable result.
|
||||
|
||||
We may consider setting a hard limit on the offset which may make us feel safer.
|
||||
Actually, to be safe, we do need to start with a small offset, and adjust little
|
||||
by little. Since it's expected that the best offset will be figured out by the
|
||||
negative feedback mechanism, a preset limit may impact the mechanism negatively.
|
||||
A few witnesses publishing too far away offset doesn't harm much because
|
||||
they won't move the median much. In addition, stake holders may vote down
|
||||
perceived bad actors.
|
||||
|
||||
### Risks
|
||||
|
||||
All the adjustments (price feed, or MCR, or MSSR) in a downtrend actually looses
|
||||
requirement of collateral ratio, so it seems it will increase the possibility
|
||||
of black swan events. This is actually the most contraversial part of this BSIP.
|
||||
|
||||
The counter argument is about liquidity. As we can see, even without the
|
||||
adjustments, black swan events have occurred on bitHKD, bitSGD and some other
|
||||
SmartCoins due to poor liquidity. In contrast, bitCNY, bitUSD and etc have
|
||||
survived due to good liquidity. With the adjustments, hopefully we'll have
|
||||
better adoption, which means better liquidity in the markets, so possibility
|
||||
of black swan events would likely decrease.
|
||||
|
||||
### Guarantee of value
|
||||
|
||||
Adjusting price feeds impacts force settlements. Specifically, a user will
|
||||
likely get less by force settling when the price feed is adjusted. This lead
|
||||
to an argument says it breaks guarantee of SmartCoins' value.
|
||||
|
||||
The counter argument is also liquidity. With good liquidity, users should buy
|
||||
from market rather than force settling. It's up to UI to guide users for better
|
||||
experience. If a user has a large volume to trade, she has to be patient,
|
||||
since even go the force settlement approach she will likely encounter the
|
||||
volume limitation as well.
|
||||
|
||||
### Margin call price
|
||||
|
||||
Actual price (in FIAT) when buying into a margin call would be unchanged,
|
||||
because the adjustment will shift trading price of SmartCoins but not BTS.
|
||||
It's expected that margin calls will be less though.
|
||||
|
||||
### User experience changes
|
||||
|
||||
Currently, GUI shows median price feed on the market page. By looking at the
|
||||
price,
|
||||
people know what price BTS is trading around. Then people can check lastest
|
||||
trading price of BTS / SmartCoin pairs, to know how much premium or discount
|
||||
that the SmartCoins are trading at.
|
||||
|
||||
After applied the adjustments on price feeds, the median price feed showing
|
||||
on market page of GUI will no longer mean trading price of BTS, instead, it
|
||||
will mean a somewhat "guiding price" for SmartCoin production. People may get
|
||||
confused especially in the beginning of applying the adjustments.
|
||||
|
||||
On the other hand, after applied the adjustments, hopefully SmartCoins will
|
||||
be traded on par, so latest trading price of BTS / SmartCoin pairs will
|
||||
indicate trading price of BTS.
|
||||
|
||||
It's up to the GUI development team to optimize the GUI for better user
|
||||
experience.
|
||||
|
||||
|
||||
## Uptrend and discount
|
||||
|
||||
When BTS is in a uptrend, usually SmartCoins are oversupplied which results in
|
||||
devaluation. Ideally, to reduce supply, the best approach is to increase MCR.
|
||||
However, at this moment, there is a bug in BitShare-Core so we can't adjust MCR
|
||||
freely (more info is here:
|
||||
https://github.com/bitshares/bitshares-core/issues/1270). Before the bug is
|
||||
fixed, we can adjust price feed instead, similar to downtrend, with negative
|
||||
feedbacks, but in opposite direction.
|
||||
|
||||
Note: when adjusting price feed in a uptrend, we should set a fair force
|
||||
settlement offset at same time, see [BSIP 16](bsip-0016.md) for more info.
|
||||
|
||||
|
||||
# Specification
|
||||
|
||||
When witness publishing a price feed, after got price of BTS from exchanges
|
||||
(assuming it's `P`), check trading price of the publishing SmartCoin,
|
||||
adjust `P` with an algorithm.
|
||||
|
||||
To be safe, the algorithm should start with a small offset, or a value near
|
||||
the median, and adjust the offset little by little.
|
||||
|
||||
The algorithm should implement negative feedback,
|
||||
that said, it should track historical adjustments and historical differences
|
||||
on trading prices of SmartCoins, and make new adjustments accordingly.
|
||||
|
||||
We don't force all witnesses to use a same algorithm, instead, witnesses are
|
||||
encouraged to implement different algorithms for same goal.
|
||||
|
||||
We also don't set a hard limit about how much the offset should be within, in
|
||||
order to let the negative feed back mechasim find the best result by itself.
|
||||
Witnesses should make their own decisions on whether to set a hard limit and
|
||||
how much should it be if need to set one, generally, to reduce impacts caused
|
||||
by bugs.
|
||||
|
||||
It will be good to apply the change to bitCNY first, which has much better liquidity
|
||||
than other smartcoins. After witnesses and community learned enough in the process
|
||||
it can be also applied to bitUSD.
|
||||
|
||||
# Discussion
|
||||
|
||||
- https://bitsharestalk.org/index.php?topic=26948.0
|
||||
- https://bitsharestalk.org/index.php?topic=26315.0
|
||||
- https://bitsharestalk.org/index.php?topic=26966.0
|
||||
|
||||
# Summary for Shareholders
|
||||
|
||||
The peg of SmartCoin to the underlying asset is crucial to create trust for SmartCoin holders, in combination with a force settlement offset that is considered fair. This BSIP seeks to adress the issue of volatility with respect to the peg by allowing the witnesses to implement (within boundaries) their own price feed strategy that is targeted to uphold the peg and provide a fair force settlement offset.
|
||||
|
||||
This is a crucial intrusion into the open market mechanics and is thus not a strict directive to the witnesses, furthermore this BSIP is constantly evaluated, and if it becomes rejected (see the next section), witnesses are bound to return to the former price feed mechanisms.
|
||||
|
||||
# Constant voting evaluation
|
||||
|
||||
This BSIP has a pro and a con worker and has an ever evaluated state of accepted and rejected.
|
||||
|
||||
- **Accepted**:
|
||||
The pro worker is active in terms of receiving payout from the reserve pool AND its votes surpass the con worker.
|
||||
|
||||
- **Rejected**:
|
||||
The pro worker is NOT active (is not receiving funds from reserve pool) OR the votes of the con worker surpass the pro worker. If the pro worker expires, this BSIP is also considered rejected.
|
||||
|
||||
The earliest that this worker can become active is 7th September 2018.
|
||||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain.
|
292
bsip-0044.md
Normal file
292
bsip-0044.md
Normal file
|
@ -0,0 +1,292 @@
|
|||
BSIP: 0044\
|
||||
Title: Hashed Time-Locked Contract\
|
||||
Authors: Ryan R. Fox, John M. Jones, taconator\
|
||||
Status: Draft\
|
||||
Type: Protocol\
|
||||
Created: 2018-08-22\
|
||||
Discussion: https://github.com/bitshares/bsips/pull/104
|
||||
|
||||
# **Abstract**
|
||||
|
||||
This BSIP describes an implementation of a Hashed Time-Locked Contract (HTLC) operation.
|
||||
|
||||
# **Motivation**
|
||||
|
||||
The ability to securely hold tokenized assets within a hashed time-locked contract on the BitShares blockchain is a desirable feature that could be used by many persons, services, and businesses to mitigate risks between participants during asset transfer. HTLC implement conditional transfers, whereby a designated party (the "recipient") will reveal the preimage of a hash in order to execute the asset transfers from a second party (the "depositor"), else after time lock expiry "depositor" may retrieve their assets. No third-party escrow agent is required, rather the HTLC operation enforces conditions, evaluations and transfers through the BitShares consensus protocol.
|
||||
|
||||
# **Rational**
|
||||
|
||||
## **Elements of a Hashed Time-Locked Contract (HTLC)**
|
||||
|
||||
An HTLC is defined to have the following components:
|
||||
|
||||
* Parties to the HTLC
|
||||
|
||||
* The depositor
|
||||
|
||||
* The recipient
|
||||
|
||||
* Secured Asset
|
||||
|
||||
* Symbol
|
||||
|
||||
* Quantity
|
||||
|
||||
* Conditions
|
||||
|
||||
* Hash lock
|
||||
|
||||
* Preimage (the secret)
|
||||
|
||||
* Preimage hash (hash of the preimage)
|
||||
|
||||
* Preimage length
|
||||
|
||||
* Time lock
|
||||
|
||||
* Timeout threshold (expiry)
|
||||
|
||||
* Condition Evaluators
|
||||
|
||||
* Fees
|
||||
|
||||
* Prepare operation fee
|
||||
|
||||
* Prepare duration fee
|
||||
|
||||
* Redeem operation fee
|
||||
|
||||
### **Parties**
|
||||
|
||||
Two parties must be defined within each HTLC: the `depositor` and the `recipient`. The `depositor` will secure their assets within the HTLC and designate the `recipient` to receive them. Note that a proposal transaction may be used for tasks such as multi-signature, but the end result at approval remains a single `depositor` and a single `recipient`.
|
||||
|
||||
### **Secured Asset**
|
||||
|
||||
An HTLC involves a conditional transfer of the defined `asset symbol` in the amount of `assets quantity` from the `depositor` to the `recipient`. The HTLC holds these designated `secured assets` from `depositor` on the blockchain and will continue to enforce the specified `conditions` until one is satisfied.
|
||||
|
||||
### **Conditions**
|
||||
|
||||
There are two competing conditions within an HTLC, the `hash lock` and the `time lock`.
|
||||
|
||||
The HTLC contains a `hash lock` condition, which comprise both the `preimage hash` and `preimage length`, barring the transfer of held `secured assets` unless satisfied. If a `preimage` of requisite `length` is provided to the HTLC which generates a hash matching the `preimage hash`, the `preimage` is then stored within the blockchain, and the `secured assets` are transferred to the `recipient`.
|
||||
|
||||
If a satisfactory `preimage` is not provided to the HTLC before the stipulated `time lock` expires, the `depositor` may request the return of `secured assets`. The HTLC will only evaluate transfer request from `depositor` and after `timeout threshold`, then return `secured assets` to `depositor`.
|
||||
|
||||
**Note:** we recommend the Committee the set maximum allowable `preimage length` to ensure unreasonably large submissions are rejected.
|
||||
|
||||
### **Condition Evaluators**
|
||||
|
||||
The `preimage` can be thought of a secret key, that will eventually be shared with the `recipient`. This can be a word, a phrase, or even a random series of bytes. The `length` of the `preimage` must be specified within the HTLC at creation.
|
||||
|
||||
Upon presentation of a `preimage`, the HTLC `condition evaluator` validates:
|
||||
|
||||
1. That the `timeout threshold` has not yet occurred.
|
||||
|
||||
2. That the length of the `preimage` matches the specified `preimage length`.
|
||||
|
||||
3. That the hash of the `preimage` calculates to the specified `preimage hash`.
|
||||
|
||||
If all evaluations succeed, the `secured assets` are transferred to the `recipient`. If any evaluation fails, nothing happens; the HTLC remains ready to evaluate the next `preimage`.
|
||||
|
||||
### **Timing of Condition Evaluation**
|
||||
|
||||
The `timeout threshold` of the contract is defined by `depositor` within the HTLC at creation. It can be any time in the future and should allow enough time for `recipient` to review the HTLC and provide the `preimage`. Further, it should not be set too far into the future to mitigate against an unresponsive `recipient` impacting `depositor`, as their `secured assets` will be locked until `timeout threshold` expiry. The accuracy is based on when the `condition evaluator` runs, and should be considered accurate ± 15 seconds.
|
||||
|
||||
**Note:** we recommend the Committee set the maximum value for `timeout threshold` to limit the amount of time a contract may consume memory of validation nodes.
|
||||
|
||||
### **Early Termination of an HTLC**
|
||||
|
||||
To protect the `recipient`, early termination of an HTLC is not allowed by any party. Placing a `timeout threshold` far into the future is valid, up to the maximum defined by the Committee. User protection from locking up funds for an extremely long period could be provided by the UI used to create the HTLC.
|
||||
|
||||
### **Automatic Transfers Upon Expiry**
|
||||
|
||||
Upon expiry of the `timeout threshold`, the `secured assets` held within the HTLC will be queued for return to `depositor`. From this time, the HTLC will no longer evaluate the `hash lock`, preventing `recipient` from receiving the `secured assets`. No action is required by the `depositor` to receive their "locked" funds back from the contract after expiry.
|
||||
|
||||
### **Fees**
|
||||
|
||||
We propose three (3) operations (see Specification) to implement the HTLC feature, each requiring distinct fees. All fees will be set and maintained by the Committee.
|
||||
|
||||
The "prepare" operation will store in-memory data on validation nodes until redeemed or expiry. We recommend the `htlc_preparation_fee` be comprised of two (2) components: `GRAPHENE_HTLC_PREPARE_FEE` which is flat and `GRAPHENE_HTLC_DAILY_FEE` which is variable based on the number of days until `timeout threshold`.
|
||||
|
||||
The "redeem" operation frees most of the memory from the validation nodes and adds the `preimage` data into blockchain storage when the transaction is validated. We recommend the `htlc_redemption_fee` be comprised of two (2) components: `GRAPHEN_HTLC_REDEEM_FEE` which is may be quite low and `GRAPHENE_HTLC_KB_FEE` which is variable based on the total number of kilobytes of data committed to the blockchain.
|
||||
|
||||
The "extend expiry" operation will update the `timeout_threshold` to a future date, extending in-memory resources on validation nodes. We recommend the `htlc_extend_expiry_fee` be comprised of two (2) components: `GRAPHENE_HTLC_EXTEND_EXPIRY_FEE` which is flat and `GRAPHENE_HTLC_DAILY_FEE` which is variable based on the number of additional days added to extend the `timeout_threshold` of the contract.
|
||||
|
||||
## **Existing Escrow Proposals**
|
||||
|
||||
This section describes various escrow concepts that have been proposed either for BitShares or for other blockchains or services in terms of the elements that have been defined above. This is intended to provide some background and comparison to the concepts that follow.
|
||||
|
||||
### **BitShares Escrow**
|
||||
|
||||
A separate BSIP [cite] is currently being discussed that provides a more traditional escrow service. This involves parties, agents, and a more complex evaluation. HTLC shares some similarities, and could be considered a thin subset of BitShares Escrow.
|
||||
|
||||
The smaller, well-defined nature of HTLC provides a major advantage for applications that want to attempt tasks such as cross chain atomic swaps.
|
||||
|
||||
### **Scorum Atomic Swap**
|
||||
[cite]
|
||||
|
||||
### **BitShares Multi-Signature Account**
|
||||
|
||||
One of the existing features of BitShares is the ability to have an account that requires multiples signatures by differently authorized parties [cite] and even hierarchical authorizations. Using this mechanism as a form of escrow is possible. But there are many limitations. More information on escrow and multi-signatures can be found in the BitShares Escrow BSIP [cite].
|
||||
|
||||
### **BitShares Proposals**
|
||||
|
||||
One of the existing features of BitShares is the ability to have a proposal that is recorded on the blockchain and awaits the authorization of the requisite parties (e.g. M-of-N signatures) to execute. However, the proposal does not "lock" any assets, so the transfer will fail if the sending account lacks sufficient funds during validation. If the required authorizations are not given by proposal expiry, then no transfer will occur. This feature also contains many limitations when compared to HTLC.
|
||||
|
||||
## **Possible Concepts to Implement**
|
||||
|
||||
The following will describe possible concepts that could be implemented within the BitShares protocol.
|
||||
|
||||
### **Set-Price Swap**
|
||||
|
||||
Two parties may agree on a swap of two distinct `secured assets` at a set price (defined exchange ratio), without using an exchange such as the BitShares DEX. This will require two (2) HTLC contracts containing the identical `preimage hash` within each to "link" them together and facilitate the execution of an "atomic swap" of these "locked" `secured assets` between the party's accounts resulting in a trustless value exchange.
|
||||
|
||||
#### **Business Approach**
|
||||
|
||||
Alice begins by generating a distinct `preimage` of her choosing, notes the `preimage length` and calculates the `preimage hash`. She retains the `preimage` in secret, then creates a new HTLC stipulating that the `depositor` account "alice" will transfer `quantity` "100" "bitUSD" `asset` into the `recipient` account "bob" if a `preimage` is presented matching the `preimage hash` before the `timelock threshold` of 10AM tomorrow. Upon consensus validation of the HTLC, the 100 bitUSD `secured assets` are transferred from Alice's `depositor` account into the HTLC where they remain locked by the `preimage hash` and `timelock threshold`. She then shares the resulting `contract identifier` with Bob.
|
||||
|
||||
Bob queries the blockchain for the `contract identifier` Alice provided. He examines to ensure it contains his desired `recipient` account, `asset` symbol, asset `quantity`, `preimage length`, and `timelock threshold`. Bob now creates his own HTLC that will deposit `quantity` "10,000" "BTS" `symbol` into the `recipient` account "alice" from `depositor` account "bob", if a `preimage` that generates the `preimage hash` Bob copied from Alice's HTLC before the `timelock threshold` of 5pm today. Upon consensus validation of Bob's HTLC, his 10,000 BTS `secured assets` are transferred from his `depositor` account and "locked" into the contract. He then shares the resulting `contract identifier` with Alice. Notice Bob specified a `timelock threshold` much shorter than Alice defined in her contract. This ensures Bob will have enough time to observe and use the `preimage` Alice will publish to the blockchain next.
|
||||
|
||||
Alice now examines the HTLC Bob created, ensuring the `preimage hash` and `preimage length` both match the original values she used within her contract. She also verifies her desired `recipient` account "alice", the `quantity`, `symbol`, and the `timelock threshold` agree with her intentions. She now uses her `preimage` to "unlock" Bob's contract. Once consensus validation occurs, the HTLC will transfer the `secured assets` 10,000 BTS into her `recipient` account "alice". This reveals the `preimage` on the BitShares blockchain for Bob to use next. NOTE: She must do this before 5PM. Otherwise, Bob may (and should) reclaim the funds in the contract he created.
|
||||
|
||||
Bob can now observe the `preimage` Alice used to "unlock" his HTLC, and he will use it to "unlock" her HTLC to receive the 100 bitUSD `secured assets` into his `recipient` account "bob". NOTE: He must do this before 10AM tomorrow. Otherwise, Alice may (and should) reclaim the funds in the contract she created.
|
||||
|
||||
### **Cross-Chain Swap**
|
||||
|
||||
Similar to the set-price swap mentioned above, two parties may exchange tokens between distinct blockchains when both implement HTLC support. Bitcoin, Litecoin and many others support HTLC [cite].
|
||||
|
||||
#### **Business Approach**
|
||||
|
||||
Alice and Bob intend to swap BTC (bitcoin token) and BTS (BitShares token). This will require both parties to define both a BTC deposit address and BTS deposit account. These addresses/accounts will be exchanged between the parties.
|
||||
|
||||
Alice will initiate the first leg of the swap on the BitShares Network with her HTLC and Bob will follow up on the Bitcoin Network with his HTLC. Allice generates a distinct `preimage` of her choosing, notes the `preimage length` and calculates the `preimage hash`. She retains the `preimage` in secret, then creates a new HTLC stipulating that the `depositor` account "alice" will transfer `quantity` "10,000" "bitUSD" `asset` into the `recipient` account "bob" if a `preimage` is presented matching the `preimage hash` before the `timelock threshold` of 10AM tomorrow. Upon consensus validation of the HTLC on the BitShares Network, the 10,000 bitUSD `secured assets` are transferred from Alice's `depositor` account into the HTLC where they remain locked by the `preimage hash` and `timelock threshold`. She then shares the resulting `contract identifier` with Bob.
|
||||
|
||||
Bob queries the BitShares Network for the `contract identifier` Alice provided. He examines to ensure it contains his desired `recipient` account, `asset` symbol, asset `quantity`, `preimage length`, and `timelock threshold`. Bob now creates and funds his own HTLC on the Bitcoin Network that will spend the `UTXO` of this contract to the `recipient address` Alice provided during their setup phase, of `amount` 1 BTC if a `preimage` that generates the `preimage hash` Bob copied from Alice's HTLC before the `timelock threshold` of 5pm today. Upon consensus validation of Bob's HTLC on the Bitcoin Network, 1 BTC he controlled are spent into the contract and "locked". He then shares the resulting `contract identifier` with Alice. Notice Bob specified a `timelock threshold` much shorter than Alice defined in her contract. This ensures Bob will have enough time to observe and use the `preimage` Alice will publish to the blockchain next.
|
||||
|
||||
Alice now examines the HTLC Bob created on the Bitcoin Network, ensuring the `preimage hash` and `preimage length` both match the original values she used within her contract. She also verifies her desired `recipient address`, `quantity`, and `timelock threshold` agree with her intentions. She now uses her `preimage` to "unlock" Bob's contract. Once consensus validation occurs on the Bitcoin Network, the HTLC will spend 1 BTC to Alice's `recipient address`. This reveals the `preimage` on the Bitcoin Network for Bob to use next. NOTE: She must do this before 5PM. Otherwise, Bob may (and should) reclaim the funds in the contract he created.
|
||||
|
||||
Bob has now observed the `preimage` Alice used to "unlock" his HTLC, and he will use it to "unlock" her HTLC to receive the 10,000 bitUSD `secured assets` into his `recipient` account "bob". NOTE: He must do this before 10AM tomorrow. Otherwise, Alice may (and should) reclaim the funds in the contract she created.
|
||||
|
||||
# **Specifications**
|
||||
|
||||
## **Objects**
|
||||
|
||||
```
|
||||
class htlc_object : public graphene::db::abstract_object<htlc_object> {
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_htlc_object_type;
|
||||
|
||||
account_id_type depositor;
|
||||
account_id_type recipient;
|
||||
asset amount;
|
||||
fc::time_point_sec expiration;
|
||||
asset pending_fee;
|
||||
vector<unsigned char> preimage_hash;
|
||||
uint16_t preimage_size;
|
||||
transaction_id_type preimage_tx_id;
|
||||
};
|
||||
```
|
||||
|
||||
## **Operations**
|
||||
|
||||
### **Prepare**
|
||||
|
||||
```
|
||||
transaction_obj htlc_prepare(depositor, quantity, symbol, recipient, hash_algorithm, preimage_hash, preimage_length, timeout_threshold, htlc_preparation_fee)
|
||||
Validate: HTLC signed by requisite `authority` for `depositor` account
|
||||
Validate: `depositor` account has requisite `quantity` of `symbol` asset for the `guarantee`
|
||||
Validate: `timeout_threshold` < now() + GRAPHENE_HTLC_MAXIMUM_DURRATION
|
||||
Calculate: `required_fee` = GRAPHENE_HTLC_OPERATION_FEE + GRAPHENE_HTLC_DAILY_FEE * count((`timeout_threshold` - now()), days)
|
||||
Validate: `depositor` account has requisite `quantity` of BTS for `required_fee`
|
||||
Validate: `recipient` account exists
|
||||
Validate: `preimage_length` does not exceed GRAPHENE_HTLC_MAXIMUM_PREIMAGE_LENGTH
|
||||
Validate: `preimage_hash` well formed
|
||||
Update: BTS balance of `depositor` based on `required_fee`)
|
||||
contract = new htlc_obj
|
||||
Set: `contract.depositor` = `depositor`
|
||||
Set: `contract.recipient` = `recipient`
|
||||
Set: `contract.hash_algorithm` = `hash_algorithm`
|
||||
Set: `contract.preimage_hash` = `preimage_hash`
|
||||
Set: `contract.preimage_length` = `preimage_length`
|
||||
Set: `contract.timeout_treshold` = `timeout_threshold`
|
||||
Transfer: from `depositor` account to `contract.quantity` of `contract.symbol`
|
||||
return results
|
||||
```
|
||||
|
||||
### **Redeem**
|
||||
|
||||
```
|
||||
transaction_obj htlc_redeem(fee_paying_account, id, preimage, htlc_redemption_fee)
|
||||
Validate: transaction signed by requisite `authority` for `fee_paying_account` // any account may attempt to redeem
|
||||
Get: get_htlc(id)
|
||||
Validate: `fee_paying_account` account has requisite `quantity` of BTS for `htlc_redeem_fee` and `htlc_kb_fee`
|
||||
Update: balance of `fee_paying_account` based on total fees
|
||||
// Evaluate: timelock
|
||||
if now() < `timeout_threshold` then return error // "timeout exceeded"
|
||||
// Evaluate: hashlock
|
||||
if length(preimage) != `id.preimage_length` then return error // "preimage length mismatch"
|
||||
Calculate: `preimage_hash` = hash(preimage)
|
||||
if `preimage_hash` != `id.preimage_hash` then return error // "invalid preimage submitted"
|
||||
Update: balance of `id.recipient` add asset `id.symbol` of quantity `id.quantity`
|
||||
Add: transaction to mempool
|
||||
Set: `id.preimage_tx_id` = `transaction_id`
|
||||
Cleanup: memory allocated to this htlc
|
||||
Virtual Operation: Update account history for `depositor` to reflect redemption as by default the above operation will only appear for `redeemer`
|
||||
|
||||
return: results
|
||||
```
|
||||
|
||||
### **Extend Expiry**
|
||||
|
||||
```
|
||||
transaction_obj htlc_extend_expiry(depositor, id, timeout_threshold, htlc_extention_fee)
|
||||
Validate: 'depositor' = get_htlc(id).depositor
|
||||
Validate: `timeout_threshold` < now() + GRAPHENE_HTLC_MAXIMUM_DURRATION
|
||||
Calculate: `required_fee` = GRAPHENE_HTLC_DAILY_FEE * count((`timeout_threshold` - now()), days)
|
||||
Validate: `depositor` account has requisite `quantity` of BTS for `required_fee`
|
||||
Update: BTS balance of `depositor` based on `required_fee`)
|
||||
Set: `contract.timeout_treshold` = `timeout_threshold`
|
||||
return results
|
||||
```
|
||||
|
||||
### **At Expiry** (evaluated at each block commit)
|
||||
|
||||
```
|
||||
Get: get_htlc(id)
|
||||
Update: balance of `depositor` add asset `id.symbol` of quantity `id.quantity`
|
||||
Cleanup: memory allocated to this htlc
|
||||
Virtual Operation: Update account history for `depositor` to reflect expiry without redemption.
|
||||
```
|
||||
|
||||
## **cli_wallet APIs**
|
||||
|
||||
### **htlc_prepare**
|
||||
|
||||
### **htlc_redeem**
|
||||
|
||||
### **htlc_extend_expiry**
|
||||
|
||||
## **witness_node APIs**
|
||||
|
||||
### **get_htlc**
|
||||
|
||||
### **get_htlcs_for_account**
|
||||
|
||||
# **Discussion**
|
||||
|
||||
https://github.com/bitshares/bsips/pull/104
|
||||
|
||||
# **Summary for Tokenholders**
|
||||
|
||||
Hashed Timelock Contracts (HTLCs) enable conditional transfers, whereby distinct account holders may transfer tokens from one account (`sender`) to a second account (`receiver`) before a defined expiry (`timelock`), only if the `preimage` (a.k.a. password) is revealed (`hashlock`) on the blockchain. If the `hashlock` condition is not satisfied prior to the `timelock` the tokens are return to the `sender`.
|
||||
|
||||
A typical scenario involves “Alice” and “Bob” each having accounts on the BitShares Network and addresses on the Bitcoin Network willing to trade their tokens. Alice will begin by creating an HTLC on BitShares to transfer BTS tokens from account `alice` to account `bob` with conditions set for hash of preimage (`hashlock`) and contract expiry (`timelock`). Bob will review her HTLC, if acceptable he will create an HTLC on the Bitcoin Network to transfer BTC from `his address` to `her address` with conditions set to the same `hashlock` value and a `timelock` value approximately half that specified by Alice. Next, Alice will review Bob’s HTLC for correctness and if acceptable, will redeem the BTC therein by publishing her `preimage` to satisfy the `hashlock` prior to the `timelock` expiry. Finally, Bob will observe the revealed `preimage` and use it to redeem Alice’s HTLC on the BitShares Network resulting in the BTS transferring to his account. Alice and Bob successfully exchanged native BTS and BTC at their agreed to ratio without any intermediaries.
|
||||
|
||||
# **Copyright**
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
||||
# **See Also**
|
||||
|
||||
A description of [Hashed Timelock Contracts](https://en.bitcoinwiki.org/wiki/Hashed_Timelock_Contracts)
|
85
bsip-0045.md
Normal file
85
bsip-0045.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
```
|
||||
BSIP: 45
|
||||
Title: Introduce 'allow use as bitasset backing collateral' flag/permission to assets
|
||||
Authors: @grctest
|
||||
Status: Draft
|
||||
Type: Protocol
|
||||
Created: 07/10/2018
|
||||
Discussion: https://github.com/bitshares/bsips/issues/80
|
||||
Replaces: N/A
|
||||
Superseded-By: N/A
|
||||
Worker: N/A
|
||||
```
|
||||
---
|
||||
|
||||
# Abstract
|
||||
|
||||
It's currently possible to impose new asset settings through MPA encapsulation without the permission of the backing asset's 'asset owner'.
|
||||
|
||||
This BSIP proposes to introduce a new asset permission/flag which enables the asset owner to enable|prevent MPA encapsulation.
|
||||
|
||||
# Motivation
|
||||
|
||||
By encapsulating an asset (UIA/EBA|MPA) within a new MPA, you can impose new asset settings upon the underlying asset, to the possible detriment of the backing asset's 'asset owner'.
|
||||
|
||||
# Rational
|
||||
|
||||
By providing asset owners this functionality, we can improve asset owner confidence in the finality of their configured asset settings.
|
||||
|
||||
# Specifications
|
||||
|
||||
## Create new 'allow use as backing collateral' flag/permission
|
||||
|
||||
Rather than create a system of inheriting permissions from backing collateral, a new flag/permission for 'allow use as MPA backing collateral' could simply prevent MPA encapsulation entirely at the discretion of the asset owner.
|
||||
|
||||
Existing assets which are currently configured as an bitasset's backing collateral would require this flag to be set default enabled (allowed). This couldn't be changed unless the bitasset reconfigured to an alternative backing collateral - impossible if supply is greater than 0.
|
||||
|
||||
Non applicable assets (PM & twice nested MPA) would prevent the flag from being enabled.
|
||||
|
||||
Existing assets currently not used as backing collateral could be set to disabled by default.
|
||||
|
||||
# Discussion
|
||||
|
||||
## Consequences of MPA encapsulation
|
||||
|
||||
* Removal/Bypassing of market fees (if enabled)
|
||||
* Re-implementation of confidential transfers (if disabled)
|
||||
* Evasion of whitelist/blacklist (both user & market lists)
|
||||
* Preventing the issuer from transfering the asset back to themselves (Can't transfer backing collateral back to yourself)
|
||||
* Remove backing asset issuer from transfer approval provess.
|
||||
|
||||
## Committee configuration
|
||||
|
||||
Should all smartcoins be allowed as bitasset backing collateral? Given that XCD already does this with bitUSD, I think it's appropriate. That said, not all committee owned bitassets are in a stable state (bitGOLD for example is in global settlement state right now).
|
||||
|
||||
## Enabling the flag grants permisson for all
|
||||
|
||||
Currently you can perform MPA encapsulation without involving the asset owner, this could introduce conflict between the two asset owners.
|
||||
|
||||
If the flag is enabled, that's an indication that the asset owner accepts any bitasset use case - you wouldn't need to seek explicit permission prior to creating experimental bitassets on the BTS DEX.
|
||||
|
||||
If it's disabled, that's a clear indication that the asset owner doesn't want it used as backing collateral.
|
||||
|
||||
## How to configure assets held by null-account?
|
||||
|
||||
It's possible that bitassets may be owned by null-account but remain operational, configuring default disabled would burn the possibility of encapsulation - if these assets exist then if possible should be set to enabled?
|
||||
|
||||
## Proposed UI changes
|
||||
|
||||
This flag could only work as long as no MPA has already selected the asset as its backing collateral; setting this as default disabled (not allowed) for newly created assets in the asset creation form could help prevent the asset being used as backing collateral without the user's knowledge.
|
||||
|
||||
---
|
||||
|
||||
# Summary for Shareholders
|
||||
|
||||
* Introduces new asset owner permissions.
|
||||
* Helps mitigate negative MPA encapsulation consequences, improving gateway regulatory compliance capability?
|
||||
* Given enabled flags could constitute advanced permission for MPA use case, there may be UIA backed MPA created which would contribute BTS fees to the reserve pool.
|
||||
|
||||
# Copyright
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
||||
# See Also
|
||||
|
||||
N/A
|
264
bsip-0053.md
Normal file
264
bsip-0053.md
Normal file
|
@ -0,0 +1,264 @@
|
|||
BSIP: 0053
|
||||
Title: Blockchain scanning for inbound Stealth transactions
|
||||
Authors: Christopher J. Sanborn
|
||||
Status: Draft
|
||||
Type: Protocol
|
||||
Created: 2018-01-29
|
||||
Discussion: https://github.com/bitshares/bsips/issues/91
|
||||
|
||||
|
||||
## Abstract
|
||||
|
||||
The existing Stealth implementation ([BSIP-0008](bsip-0008.md)) requires the sender to manually communicate *transaction receipts* to the recipients of each transaction to alert them to the presence of an inbound balance transfer, creating a danger of lost funds due to miscommunicated or lost receipts. This BSIP explores options for automated discovery of inbound transactions while still preserving fundamental privacy features of unlinkability and anonymity.
|
||||
|
||||
## Motivation
|
||||
|
||||
"Stealth addresses" are a method of providing _unlinkability_ to blockchain transactions. Unlinkability is a major component of the Privacy Triad: _unlinkability_, _confidentiality_, and _untraceability_. Using a stealth address, a sending wallet is able to compute a child public key that derives from a public key encoded in the address, but which cannot be correlated, or "linked", to the address public key, unless you are either the sender or the receiver. This child key becomes the authorization key for transaction outputs (TXOs) intended for the receiver. As such, third party observers cannot link TXOs to addresses, nor even link together independent TXOs which are destined to the same address.
|
||||
|
||||
Although this is a great benefit to privacy, it complicates the matter of detecting inbound transactions, since a wallet cannot simply scan for transactions which explicitly identify the destination address.
|
||||
|
||||
Existing [Stealth Phase I](bsip-0008.md) functionality already includes the use of stealth addresses, but does not include a solution for detection of inbound transactions. As a result of which, user adoption of the Stealth feature has been very minimal. We propose below a solution to inbound transaction detection as well as some additional enhancements to the stealth addressing scheme, including a proposed new address format that allows for watch-only wallets.
|
||||
|
||||
## Rationale
|
||||
|
||||
A confidential transaction (cTX) does not identify the recipient. As such, there is no direct way for a wallet to use only its Stealth address to query the p2p network for inbound transactions. In the current "phase one" implementation of Stealth ([BSIP-0008](bsip-0008.md)), inbound discovery is a manual process requiring the sender to communicate "transaction receipts" to the intended recipients of each transaction output in order to alert each recipient of their incoming balance. Transaction receipts are encrypted data structures that embed the Pedersen commitment of the transaction output and the value and blinding factor that the recipient needs to "open" the commitment. Additionally, the receipt records the one-time public key which the recipient must use to derive the private key offset needed to spend the incoming coin, via a shared-secret procedure between the one-time key and the recipient's address key. The need to communicate transaction receipts is burdensome and introduces substantial risk of lost funds due to failure to communicate or retain receipts.
|
||||
|
||||
_Keys involved in a cTX output (cTXO):_
|
||||
* **One-Time Key (OTK)** — The sender generates this key (public and private) from randomness and uses it to generate a shared-secret between the OTK and the recipient's Address ViewKey. The OTK PubKey will be clear-text encoded in the Tx receipt, and optionally also recorded in the transaction output to enable automated discovery.
|
||||
* **Address Keys (ViewKey and SpendKey)** — These are public keys encoded in the recipient's stealth address. The goal of a stealth address scheme is to _not_ identify these public keys in any transaction output. A long-form address encodes _two_ public keys, referred to as ViewKey and SpendKey. The SpendKey serves as a base point from which individual Tx output AuthKeys are computed as an offset, and the ViewKey is used with the OTK to compute that offset. A short-form address encodes only a single public key, which serves as both the ViewKey and SpendKey.
|
||||
* **Tx Output Authorization Key (AuthKey)** — This public key will be recorded in the confidential transaction output (cTXO) as the key which is authorized to spend the commitment. This key is offset from the address SpendKey by a secret offset that only the sender and recipient can calculate (from the shared secret between OTK and ViewKey). The sender can only know the offset, but not the full secret key to the AuthKey. The recipient, knowing the private key behind the SpendKey, can compute the private key to AuthKey and therefore can spend the commitment.
|
||||
|
||||
Automated discovery could be enabled if the receipt were embedded within the transaction data structure and if an aspect of that data structure supported a challenge condition which the recipient could recognize.
|
||||
|
||||
Current network rules allow for a receipt to be embedded in each Tx output via a `stealth_memo` field which is formatted in a similar way as the encrypted memos that may accompany regular (non-Stealth) transfer operations. These memos are composed of a header specifying the OTK PubKey and the "message PubKey" for which the recipient holds the corresponding private key, followed by cipher text which is AES encrypted with a shared-secret key between the OTK and the message PubKey. For this `stealth_memo` field, the current behavior of the CLI reference wallet is to use the recipient's Address PubKey as the message PubKey. Although this is a reasonable choice for encrypting message text generally, it has the severe downside of identifying the recipient's Address PubKey in the memo header, and therefore breaks anonymity and negates the unlinkability provided by using a stealth address scheme. For this reason, the CLI reference wallet currently does _NOT_ actually embed the memo in the Tx ouput but instead Base58 encodes it and prints it to the screen, calling it a "transaction receipt." The sender must manually, and secretly, transmit this to the recipient via a side channel.
|
||||
|
||||
**Stealth Memo structure: (Stealth I)**
|
||||
|
||||
<span></span> | <span></span>
|
||||
-----: | :---
|
||||
**One-time PubKey:** | Chosen from randomness by sender **_(33 bytes)_**
|
||||
**Message PubKey:** | Public key controlled by recipient. **_(33 bytes)_**<br>
|
||||
**Cipher Text:** | AES encrypted message, using _key ← Shared(OTK,MPK)_
|
||||
|
||||
_Current Stealth I behavior is to use the Address PubKey as the message PubKey, which reveals intended recipient!!_
|
||||
|
||||
A very simple solution would be to change the behavior of embedding the Address PubKey in the message PubKey field, and to instead record the Tx output AuthKey in this slot. Because the recipient is also able to derive this AuthKey through knowledge of her own address private keys (in combination with the OTK recorded in the header), the recipient would simply need to test the OTK against each of their own Address Keys to see if the resulting AuthKey matches the one in the header. If it does, then the output is recognized as destined to the recipient, even though the recipient's Address PubKeys are not identified in the memo header. The computational cost of this is one Diffie Hellman round, a hash operation, and a child key derivation. It should be noted that the AES encryption key should still be computed from the shared secret between the OTK and the address ViewKey, however, as this will allow view-only wallets which cannot compute the private key behind the AuthKey to decrypt the memo and tally the incoming transaction.
|
||||
|
||||
**Stealth Memo structure: (Proposed: Stealth II)**
|
||||
|
||||
<span></span> | <span></span>
|
||||
-----: | :---
|
||||
**One-time PubKey:** | Chosen from randomness by sender **_(33 bytes)_**
|
||||
**cTXO AuthKey:** | Child public key of the stealth address and the OTK. **_(33 bytes)_**<br>
|
||||
**Cipher Text:** | AES encrypted message, using _key ← Shared(OTK,ViewKey)_
|
||||
|
||||
_Proposed Stealth II behavior is to embed the AuthKey in the second slot, while still encrypting the message data with a shared key between the OTK and the Address key (specifically, the ViewKey so that watch-only wallets can read the commitment data)._
|
||||
|
||||
To support this strategy, a wallet will need to inspect all cTX activity on the network and test the challenge conditions on each transaction. This could be achieved if API nodes are extended to provide an API call to retrieve `stealth_memo` fields from all cTXOs appearing in a specified block range. The wallet could simply download the memos, test the challenge on each one, and identify and decrypt the ones that are destined to the wallet. No need would remain to manually transmit transaction receipts. The receipts would be embedded, compactly and unlinkably, in the Tx outputs.
|
||||
|
||||
## Specifications
|
||||
|
||||
We specify two protocols. In the first subsection, [_Wallet procedure..._](#wallet-procedure-for-recognizing-own-commitments), we specify the recognition protocol by detailing wallet behaviors for:
|
||||
* Creating transaction outputs that can be recognized by their recipients, and,
|
||||
* Recognizing transaction outputs that are destined to the wallet.
|
||||
|
||||
And in the second subsection, [_API requirements..._](#api-requirements-to-allow-detection-of-inbound-commitments), we propose a new API call for querying nodes for transaction outputs to be scanned for recognizable markers. This is an added feature for API nodes and does not involve any consensus changes.
|
||||
|
||||
### Wallet procedure for recognizing own commitments
|
||||
|
||||
Assumptions:
|
||||
|
||||
1. Wallet has access to a set of private keys corresponding to stealth addresses which may own commitments on the blockchain. These private keys are needed to "recognize" incoming transactions. If the wallet is a watch-only wallet for a particular address, then it is assumed to have the private and public ViewKey, but only the public SpendKey.
|
||||
2. Wallet can query an API node for commitments occurring between specified block heights, to obtain sets of embedded receipts to scan for owned commitments. ([See below](#api-requirements-to-allow-detection-of-inbound-commitments) for this process.)
|
||||
|
||||
We detail procedures for stealth address formats which encode either a single public key, or two distinct public keys in which one key is the ViewKey and the other the SpendKey. The single-key format is already in use on the BitShares network and is borrowed from the original Confidential Transactions specification. The dual-key format allows for additional wallet features and is borrowed from CryptoNote-based coins such as Monero. No changes to the network nodes are required for wallets to support dual-key address formats. In fact, the single-key format can be thought of as a special case of the dual-key format in which the same key is used as the ViewKey and the SpendKey.
|
||||
|
||||
**Address Formats:**
|
||||
|
||||
| Format:
|
||||
:------:|--------
|
||||
**CT-style:** | Single public key and checksum. Public key _A_ serves both viewing and spending roles.<br><br> Format: `BTSaaaaaaaaaaaaaaaaaaaacccc`
|
||||
**CryptoNote-style:** | Two public keys plus a checksum. Public key _A_ serves the viewing role and public key _B_ serves the spending role.<br><br> Format: `BTSaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbcccc`
|
||||
**Invoice Nonce:** | This one encodes a single PubKey serving both the viewing and spending role, but also includes a 64-bit "nonce" or "tag" that the spending wallet is to include in the encrypted memo part of the cTXO, allowing the receiver to interpret payment as being applied to a specific invoice. <br><br> Format: `BTSaaaaaaaaaaaaaaaaaaaannnnnnnncccc`
|
||||
|
||||
_(In the address formats above we consider the part following the "BTS" identifier to be Base58 encodings of the concatenated byte buffer representations of public keys and checksum bytes. C.f. [Base58Check](https://en.bitcoin.it/wiki/Base58Check_encoding) encoding.)_
|
||||
|
||||
|
||||
The dual-key format separates the duties of spending a commitment from those of reading the commitment, such that a person in possession of only the "viewing key" (the private key corresponding to the additional pubkey in the address) can discover, interpret, and tally incoming transactions, but _cannot_ spend them. The "spending key" (private key corresponding to the primary pubkey in the address) is needed to authorize the spending of a commitment. The dual-key address format and signing procedures are described in detail in [[vS13]](#references) and reviewed below.
|
||||
|
||||
#### Procedure for single-key stealth addresses (CT-style)
|
||||
|
||||
Recognizability depends on there being a deterministic relationship between the AuthKey that authorizes expenditure of a particular cTXO, the one-time key (OTK) that the sender generated randomly for the cTXO, and the recipient's Address key (or keys).
|
||||
|
||||
We assume that the stealth address encodes public keys corresponding to two purposes: discovery, and expenditure. When an address encodes only one public key, that key is used for both purposes. We refer to the key for discovery as the "view" key, and denote the private, public pair as _(v, ViewKey)_. For spending, we denote the key pair as _(s, SpendKey)_.
|
||||
|
||||
The AuthKey for a cTXO is an EC point summation of the address's SpendKey and an EC point "offset," which, for present purposes we will denote by the private, public pair _(o, Offset)_, with _Offset = o*G_, where _G_ is the generator point for the curve.
|
||||
|
||||
_AuthKey = SpendKey + Offset_
|
||||
|
||||
Anonymity is preserved so long as only the sender and the receiver are able to compute _o_ and _Offset_. The algorithm for computing _Offset_ is a deterministic function of the OTK and ViewKey only, (and not the SpendKey). This allows the the recipient to recover the SpendKey by simple subtraction of _Offset_ from the AuthKey. The recipient's wallet then compares the computed SpendKey against the address SpendKey. The wallet may even compare against a whole list of SpendKeys that the wallet may have used to generate an address family with a common ViewKey, allowing for differentiable invoices, without sacrificing efficiency of scanning. (See _[address-per-invoice](#utility-of-dual-key-addresses)_ below.)
|
||||
|
||||
Algorithm | Description / Specification
|
||||
:---:|:---------------------------
|
||||
_Shared(a,B) → secret <br> Shared(A,b) → secret_ | This yields a "shared secret" between public keys _A_ and _B_ computable only by parties possessing at least one of the private keys _a_ and _b_.<br><br> _secret = SHA512(P<sub>X</sub>)_; _P = aB = Ab_<br><br>For BitShares Stealth, the secret is a byte buffer (64 bytes) computed from the SHA512 hash of the encoded _X_ coordinate (32 bytes) of EC point _P_. (c.f. [EC Diffie-Hellman](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie–Hellman).)
|
||||
_ChildOffset(B,index) → offset_ | This yields an integer-valued private key _offset_ that generates the keypair _(offset, Offset = offset*G)_. The offset is considered to be a "child" of key _B_, and the parameter _index_ is a byte buffer.<br><br> _child = BigInteger(SHA256(Compressed(B)_ || _index))_<br><br>_Compressed(B)_ refers to the SEC1 "compressed" representation of public key _B_. The || symbol refers to concatenation.
|
||||
|
||||
**Sending:**
|
||||
|
||||
The sender's procedure for computing the offset and generating the AuthKey for the cTXO is detailed as follows:
|
||||
|
||||
<ol>
|
||||
<li> Compute a "shared secret" between between the sender and receiver:
|
||||
|
||||
_secret = Shared(otk, ViewKey)_
|
||||
|
||||
The sender must be careful to leak neither the shared shared secret nor the private _otk_ key.
|
||||
</li>
|
||||
<li> Compute the OffsetKey as a child of the ViewKey, using a SHA256 hash of the shared secret as a child index:
|
||||
|
||||
_childindex = SHA256(secret)_<br>
|
||||
_offset = ChildOffset(ViewKey,childindex)_<br>
|
||||
_OffsetKey = offset*G_
|
||||
</li>
|
||||
<li> Compute the AuthKey by summing SpendKey and OffsetKey:
|
||||
|
||||
_AuthKey = SpendKey + OffsetKey_
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
**Receiving:**
|
||||
|
||||
The receiver, having acquired a list of cTXO metadata that includes _OTK_ and _AuthKey_, goes through the following process to test for ownership:
|
||||
|
||||
<ol>
|
||||
<li> Compute a "shared secret" between between the sender and receiver:
|
||||
|
||||
_secret = Shared(OTK, viewpriv)_
|
||||
</li>
|
||||
<li> Compute the OffsetKey as a child of the ViewKey, using a SHA256 hash of the shared secret as a child index:
|
||||
|
||||
_childindex = SHA256(secret)_<br>
|
||||
_offset = ChildOffset(ViewKey,childindex)_<br>
|
||||
_OffsetKey = offset*G_
|
||||
</li>
|
||||
<li> Recover the public SpendKey by subtracting OffsetKey from AuthKey:
|
||||
|
||||
_SpendKey = AuthKey - OffsetKey_
|
||||
|
||||
</li>
|
||||
<li> Compare the recovered SpendKey against all wallet SpendKeys that may have been used with the ViewKey to generate an address. If one matches, then the cTXO is "recognized." To later spend the cTXO, the wallet computes the private authorization key as:
|
||||
|
||||
_authpriv = spendpriv + offset_
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
Thus, a wallet may undertake to periodically download and scan the metadata for Stealth transactions and test for outputs that can recover a wallet's public SpendKey from knowledge of the private ViewKey.
|
||||
|
||||
##### Embedding recognizability data in the transaction
|
||||
|
||||
For the recipient to have the practical ability to recognize a cTXO as their own, the cTXO, as recorded on the blockchain, must include the following two items: 1.) The one-time PubKey (OTK) that the sender generated for shared-secret generation, and, 2.) the authorization PubKey (AuthKey) of the cTXO. Because the AuthKey is computed deterministically from _Shared(OTK,AddrKey)_, it stands that if the recipient can generate the same AuthKey, then the cTXO belongs to them.
|
||||
|
||||
The structure of a cTXO is as follows:
|
||||
|
||||
_Field_ | _Purpose_
|
||||
-------:|:-------
|
||||
**`commitment`:** | Blinded value commitment _(EC curve point, 33 bytes)_
|
||||
**`range_proof`:** | Proof data supporting transaction validity _(0 to ~5 KiB)_
|
||||
**`owner`:** | BitShares owner structure specifying weighted list of keys or accounts that may spend this commitment. (Typically lists just one public key, the "AuthKey" for the cTXO.)
|
||||
**`stealth_memo`:** | Also known as the "transaction receipt" when transmitted off-chain.<br><br> **`one_time_key`:** _(EC curve point, 33 bytes)_<br> **`to`:** Use the AuthKey here! _(EC curve point, 33 bytes)_<br> **`encrypted_memo`:** Data that recipient needs to "open" the commitment.<br><br> _The stealth memo is optional as far as the network is concerned, but essential if you want the recipient to be able to detect the incoming transaction without sending a "receipt."_
|
||||
|
||||
_(An example transaction showing all these fields can be seen in [block 22157273](https://cryptofresh.com/tx/8182e9d78cbce7df281bc252a9e6d87566ca0622). In this Tx, the stealth_memo '`to`' field unwisely names the recipient's address key, rather than the cTXO Auth key, and thus breaks unlinkability.)_
|
||||
|
||||
Since the `stealth_memo` field can be used to record both the OTK and the AuthKey, all the wallet needs to do to scan for incoming transactions is to download batches of stealth memos and, for each one, test whether the combination of the OTK and the wallet's Address key yields the AuthKey. If it does, then derive the AES decryption key from _Shared(OTK,ViewKey)_ and use that to read the additional data in `encrypted_memo`.
|
||||
|
||||
Structure of `encrypted_memo`:
|
||||
|
||||
_Field_ | _Purpose_
|
||||
-------:|:-------
|
||||
**`from_key`:** | Original use:<br><br><ul>Identifies address key of sender **(optional)**. _(EC curve point, 33 bytes)_</ul>Alternate possible uses:<br><br> <ul><li>Instead of ID'ing the 'from' address, could use this field to embed an _invoice nonce_ to allow receiver to correlate payment to an invoice.</li></ul>
|
||||
**`amount`:** | Value of commitment. _(Integer, 32 bytes)_
|
||||
**`blinding_factor`:** | Blinding factor. _(Integer, 32 bytes)_<br><br>_Note: Except when a blind_sum is needed, the blinding factor is deterministic from a hash of the shared secret, meaning this field can potentially be repurposed or omitted. To guarantee that the blinding factor can always be deterministic, transactions can be padded with a commitment to zero to absorb the blind_sum._
|
||||
**`commitment`:** | The Pedersen commitment. _(EC curve point, 33 bytes)_<br><br> _Note: This field is redundant, since the commitment is determined by_ C = amnt * H + blind * G, _and could potentially be omitted._
|
||||
**`check`:** | Checksum to confirm correct decryption. _(4 bytes)_
|
||||
|
||||
_(TODO: How is this serialized? Do omitted fields "take up space"? Can fields be chosen a la carte? How hard will it be to extend this memo format, for, say, multiple assets in the case of CA? See fc::raw::pack.)_
|
||||
|
||||
|
||||
### API Requirements to Allow Detection of Inbound Commitments
|
||||
|
||||
To monitor for incoming transactions to a particular wallet, a wallet need only download sets of `stealth_memo` structures to test for recognition. The full cTXO (including Pedersen commitment, owner structure, range proof, etc.) need not be downloaded. Because the encrypted data inside the memo indicates the Pedersen commitment, the wallet will know which cTXO it has recognized. (Witness nodes index cTXO's by Pedersen commitment.)
|
||||
|
||||
(Discuss here a proposed API call for retrieving stealth_memos by block height range)
|
||||
|
||||
To know whether a cTXO is still unspent (e.g. by another instance of the wallet), a wallet could attempt to retrieve the corresponding commitment object from an API node. An empty result indicates the commitment has been spent. However, this procedure indicates our interest in a specific set of commitments, and the network traffic generated runs the risk of revealing that those commitments are "linked".
|
||||
|
||||
To prevent this, we propose instead that, in like manner to the downloading of bulk `stealth_memo` structures, that an API call for downloading bulk lists of consumed commitments be implemented, with the download again being over specified block height ranges. A wallet then needs only to test that its own commitments are not on the list of spent commitments.
|
||||
|
||||
In the event that ring signatures are implemented for transaction inputs (see [BSIP-0052](bsip-0052.md)), then instead of downloading a list of consumed commitments, we would instead download a list of used key images, which would serve the same purpose.
|
||||
|
||||
Because a wallet downloads `stealth_memo` structures in bulk over block height ranges, the wallet never reveals to the network its interest in any specific cTXOs. Thus network interaction for monitoring purposes does not undermine privacy.
|
||||
|
||||
NOTE: It is currently possible to retrieve all needed info to support recognition of incoming transactions via Elastic Search queries. This implies: (1) functional wallet behavior can be implemented right away, even if new API calls take longer to implement, and (2) it may be possible to avoid adding new API calls altogether, if the Elastic Search infrastructure is deemed performant enough to support queries from Stealth wallets. (Although intuitively it seems to me an API method would result in a better user experience).
|
||||
|
||||
## Discussion
|
||||
|
||||
### Utility of dual-key addresses
|
||||
|
||||
Utilization of the dual-key address format has numerous interesting use cases, including:
|
||||
|
||||
* The ability to maintain **watch-only wallets**. By entrusting only the View Key to a view-only node, it is possible for this node to monitor for activity to an address without granting spending access to the same node. This allows for such things as: opt-in transparency; cash register monitoring; organizational internal auditing, etc.
|
||||
|
||||
* The ability to use **address-per-invoice** without introducing substantial additional scanning overhead. To use this, one keeps the same viewing PubKey and iterates the Spending PubKey part of the address, generating a distinct address per invoice. When scanning the blockchain, the _Child Offset_ is a function of the shared-secret between OTK and ViewKey, such that _AuthKey = SpendKey + Offset_. To obtain the public SpendKey, a watching wallet can subtract the Offset from the AuthKey to obtain the SpendKey, and simply compare against a list of per-invoice SpendKeys that were used to generate addresses. Adding additional SpendKeys to scan for does not incur any additional EC group operations, merely additional byte-wise comparisons, which are trivial. _(Note that while the invoice addresses generated in this manner are distinct, they are not unlinkably distinct, since they share the viewing component. If a business wants individual invoices to be mutually unlinkable, then this scheme will not be sufficient. However, this is a consideration for a business's off-chain security practices, as the addresses themselves never appear on-chain or in a transaction. An alternate solution which allows even the ViewKey to vary, while still allowing for efficient scanning, is presented in [MRL-0006](https://lab.getmonero.org/pubs/MRL-0006.pdf), however this introduces a change in how the deterministic offsets are generated, which would need to be signaled by a flag in the address format and supported by wallets.)_
|
||||
|
||||
### Possible future extensions
|
||||
|
||||
#### Additional address formats
|
||||
|
||||
The two stealth address formats described above provide for single key and dual key addresses, where the latter allows for separation of transaction monitoring from the ability to spend, allowing for view-only wallets.
|
||||
|
||||
There may be use cases for additional address formats allowing for more complex situations.
|
||||
|
||||
One would be a multi-sig situation in which the address format encodes multiple spending keys and a weighting requirement. Although, this would make the resulting address very lengthy, it would also add an interesting use-case. And, since BitShares authority structures already allow for a vector of authorizing keys and weights, it should be possible to implement the feature on the wallet side, without needing any changes to consensus or API. This idea is not explored further here but merely suggested for future exploration if there is a desire for the feature.
|
||||
|
||||
Another use case for an extended address format would be... (TODO: Discuss including an "invoice nonce" in the address format for correlating incoming transactions to a particular invoice. C.f. Bitcoin where using an address-per-transaction serves both unlinkability as well as invoicing. With Stealth addresses, there is no need to increment addresses for unlinkability, and doing so to facilitate invoicing only increases the scanning overhead by introducing the need to test against additional private keys. But by including an invoice nonce in the address format, which the spending wallet would carry over into the encrypted part of the `stealth_memo`, the recipient can correlate payments to invoices while using only a single address key. This strategy would be similar to the "Integrated addresses" that can be used on the Monero platform. Note, however, that this scheme is largely obsoleted by the simple ability to iterate the SpendKey through a HD address family while keeping the same ViewKey in a dual-key address format.)
|
||||
|
||||
### Pitfalls and Cautions
|
||||
|
||||
#### Specific risks and remedies
|
||||
|
||||
##### Sender leaks private _otk_ or private _shared secret_:
|
||||
|
||||
TODO: analyze
|
||||
|
||||
#### An attack on address key from leak of a transaction private key
|
||||
|
||||
A confidential output will have associated with it an "Output PubKey," or AuthKey. He who can provide a signature from the AuthKey is authorized to spend the commitment. Automated detection of inbound commitments depends on the deterministic computation of an offset between the One-time PubKey (OTK) and the Address SpendKey, which is computed from the shared secret between the sender and receiver. Because only the offset is deterministic, the sender cannot compute the private key to the AuthKey. Only the receiver can do this (by knowing both the offset and the address's private spending key).
|
||||
|
||||
Because AuthKeys are only used once, wallet software designers may be led to believe that the security of the AuthKey private keys are only important up until the commitment is spent. (What would it matter, to leak that private key, when the commitment it authorizes is no longer spendable?) This would be a mistake, however, because anyone who can compute the additive offset can subtract it from the private AuthKey to reveal the address's private spending key. Although the general public is not expected to be privy to that offset, the _sender_ of the output is in possession of the offset (and the ability to compute it due to knowing the random _k_ behind the One-time PubKey). This means the sender would be enabled to compute the address's private key, in the event that the recipient leaks the private AuthKey.
|
||||
|
||||
Thus, wallet designers should be advised to treat the private TXO AuthKeys handled by their wallets with at least as much care as the address private keys, even long after the commitments they authorize have been spent. A leak of a single commitment's PrivKey is tantamount to a leak of the PrivKey for the entire wallet.
|
||||
|
||||
(A similar risk of revealing a parent PrivKey from leak of a child PrivKey and parent XPUB when using non-hardened derivation is noted in the Bitcoin BIP-32 protocol for Hierarchical Deterministic Wallets.)
|
||||
|
||||
## Summary for Shareholders
|
||||
|
||||
Although the goal of this BSIP is to support the long-range vision of [Stealth Phase II](bsip-0050.md), the implementation of this BSIP would provide value _right now_, as it would enable the utilization of even the Phase I _Confidential Transactions_ operations without the reliance on burdensome transaction receipts, which are the primary end-user stumbling block to routine Stealth use.
|
||||
|
||||
We have detailed in this document procedures for producing recipient-recognizable transaction outputs from stealth addresses. Specifically, we have detailed the procedure for _two_ distinct stealth address formats: a single-key address format which is identical to that which is already in use, and a new dual-key address format which separates the duties of monitoring from spending, and thus allows for watch-only Stealth wallets. Support for the dual-key address format would require no network or consensus changes. It requires only wallet support.
|
||||
|
||||
Most of the work needed to implement this BSIP is in the wallet, namely the correct production of recognizable cTXOs and the process of scanning for owned cTXOs. The only network-level change is the addition of two API calls: one to return batches of `stealth_memo` fields included in a block range, and one to return batches of consumed commitments (in the case of CT transactions) or used key-images (in the case of RingCT transactions). These API calls would need to be available on wallet-serving API nodes, but would not be needed on block-producing witness nodes. There are no consensus changes proposed in this document.
|
||||
|
||||
## Copyright
|
||||
|
||||
This document is placed in the public domain.
|
||||
|
||||
## References
|
||||
|
||||
[vS13] - Nicolas van Saberhagen, _Cryptonote v 2.0_, 2013 - https://cryptonote.org/whitepaper.pdf
|
||||
|
||||
[NG17] - Sarang Noether and Brandon Goodell, _An efficient implementation of Monero subaddresses_, 2017 - https://lab.getmonero.org/pubs/MRL-0006.pdf
|
||||
|
||||
## See Also
|
||||
|
||||
* Overview of _Stealth Phase II_ - [BSIP-0052](bsip-0052.md)
|
||||
* [bitshares-stealth-k](https://github.com/Agorise/bitshares-stealth-k) - A Kotlin library for Stealth support in BitShares (in _very_ early development stage)
|
Loading…
Reference in a new issue