-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fidelity bonds foundation - DCR only, no frontend, manual bond replacement #1480
Conversation
Even if we have the keys, we don't have the lock time, so we can't generate the scripts. We could maybe ask the server for their records, but that's not great.
Could we base the script on a time offset or a block height offset, rather than an absolute time? Isn't that what DCP0003 gave us? |
Broken up in to three pieces now:
|
Summary
This begins advancing the proof-of-concept from #1120 to a proper implementation in the product. This covers the first several steps outlined in https://github.com/orgs/decred/projects/2
This will likely come out of draft in the next few days. I have not tested it since the initial draft in #1120, which used different routes and has significant differences with the present work.
To make this transition smoother, the client and server retain all the legacy registration fee machinery, and the client's frontend continues to use the legacy
'register'
protocol, with the'postbond'
method only accessible via the rpcserver (dexcctl
).This PR replaces the registration fee, which was paid to an address provided by the server operator, with a time-locked fidelity bond, which is redeemable by the user who posted the bond after a certain time. This creates a time cost to use DCRDEX instead of a monetary cost.
The DEX considers a user's bond as active when the bond script's
lockTime
(when it can be redeemed by the user) is at leastbondExpiry
in the future. That is, the bond remains locked for a period even after it becomes inactive for DEX purposes.This also introduces an account tier system. Previously, paying the registration fee would mark the account paid, and it could be closed permanently if the user's violations exceed a certain score (binary and permanent). Now, posting a bond increases a user's tier, which offsets violations and in future work will also scale user order limits. When a bond expires, their tier is reduced. To trade, a user must have a tier > 0.
Bond Transaction Structure
There must be at least two outputs: the bond output (P2SH) and an account commitment (nulldata).
See:
dex/networks/dcr.ExtractBondDetails
client/asset/dcr.(*ExchangeWallet).{MakeBondTx,RefundBond}
server/assset/dcr.ParseBondTx
Time-locked Bond (output 0)
Output 0 of the fidelity bond transaction must be a P2SH output paying to the bond script.
The redeem script looks similar to the refund path of an atomic swap script:
<locktime[4]> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey[33]> OP_CHECKSIG
The above uses P2PK since nothing is gained from P2PKH on account of the need to reveal the script pubkey anyway for validation on the server. (The user must demonstrate ownership of the locked funds by signing a message with the private key corresponding to the pubkey in the TL redeemscript.)
Server validates that this P2SH output actually pays to the provided redeem script.
The pubkey referenced by the script need not be controlled by the user's wallet, but in this implementation it comes from their wallet. The client could even use their account pubkey in the script, but for security reasons it is best not to reuse pubkeys in this bond outputs, which are unspent on the blockchain for long periods. We may consider using a key pair from the client's HD keychain, but I'm leaning toward this being a wallet job.
The
lockTime
must be after a bond expiry time, thelockTimeThreshold
. A bond becomes expired for a DEX account when duration untillockTime
is less than abondExpiry
duration, which is on the order of a month. This, a user should create a bond with alockTime
at leastbondExpiry
in the future, but a practicallockTime
would be more like 2xbondExpiry
in the future so the account is active on the DEX forbondExpiry
.DEX Account commitment (output 1)
The account commitment OP_RETURN output should reference the account ID that corresponds to the account pubkey in the
postbond
request.Having it in the raw like this allows the txn alone to identify the account, and without requiring the bond output pay to the account's private keys.
Protocol
New
postbond
route replacesregister
, but with no fee address and instead a txn with time-locked output (P2SH) and a DEX account commitment output (OP_RETURN).postbond
need not be used only for new accounts. Existing accounts may top-up / supplement their bond.The
config
response should be consulted for bond requirements, including: expiry time, supported bond assets, amounts, and required confirmations.The user may submit an initial
postbond
prior to broadcasting the bond transaction request containing the raw unsigned transaction for validation. The bond script to which the P2SH bond output pays must also be provided in thepostbond
request for validation by the DEX (correct script structure and lock time). The payload:Server must use provided account pubkey to verify signed
postbond
request, otherwise the user could be spamming or putting up a bond for a bogus account or someone else's account.Further validation is described in subsequent sections of this PR description.
The response payload:
After validation of the provided data, the DEX attempts to locate the bond transaction on the asset network:
PostBondResult
is sent immediately withConfs=-1
set. The bond is NOT stored in the DB. This was a courtesy pre-validation. The user should then broadcast the transaction, wait for the required number of confirmations, and sendpostbond
again.bondconfirmed
notification is sent.When the client receives the initial successful response prior to broadcast, they should then broadcast the bond txn, wait for the required confirmations, and resubmit
postbond
.Server must record all known bond txns and their amounts and expiry times. There is no explicit invalidation of bonds due to conduct, and instead a user's tier is a balance between bond "strength" (a function of the active bond total amounts) and their conduct score.
TODOs
See the project board at https://github.com/orgs/decred/projects/2.
Main items:
Auto add bond in
client.Core
. There are comments in the code regarding an option to automatically postbond when previous bonds are about to expire on DEX. There are questions pertaining to timing, UI, and UX. Presently this PR requires using dexcctl to call thepostbond
RPC (or a direct http API call to the endpoint of the same name, which is created for said UI plans).Refining the bond amount. It's pretty clear the bond amount has to be at least an order of magnitude more than the previous registration fee since you get it back, and it's only an opportunity cost having it locked up. I'm thinking like 5 DCR per tier (the bond increment).
Related to bond amount, the violation weights can use rebalancing. Specifically, increase weight for "no swap as taker" (currently 11, increase to 18 or 20) and "no redeem as maker" (currently 7, increase to 12 to 14), the violations that lock counterparty funds (20hr / 8 hr, respectively). Maybe even higher.
Make the tier system scale up order size limits. This was planned outside of fidelity bond work, in terms of conduct score, but it's more intuitive in terms of tier, which is a function of both account bond level and score.
Scale penalty (score change) with amount locked due to violation (e.g. lots/10 * violation score). This was planned regardless of fidelity bonds, but it dovetails nicely with the tier system.
Open Questions
What change can we make to facilitate recovery/discovery of bonds if the client's DB is lost? What might be gained from deriving the private keys from the client's HD key chain instead of using keys from the wallet itself? Can the bond scripts be deterministic?
When and if accounts go away, would output 1 commit to a magic DEX network key instead of account ID?
Is this transaction structure and account commitment output sufficient to prevent txns from being dual purposed for other services with similar TL output structure?
What architectural and protocol changes might facilitate adding ETH support for time locking funds in some basic contract that server could recognize as a bond?