shrub/lib/btc-wallet-store.hoon

208 lines
5.1 KiB
Plaintext
Raw Normal View History

2020-10-31 14:25:32 +03:00
::
::
2020-10-30 14:45:38 +03:00
/- *btc-wallet-store
/+ bip32, btc
=, secp:crypto
=+ ecc=secp256k1
|%
2020-11-22 17:49:55 +03:00
++ enjs
=, enjs:format
|%
::
++ txbu
|= =^txbu
^- json
2020-11-24 22:30:41 +03:00
%- pairs
2020-11-26 12:38:30 +03:00
:~ :: [%inputs [%a (turn txis.txbu txi)]]
['associatedKeysets' [%a (turn txis.txbu |=(=txi (key key.txi)))]]
2020-11-24 22:30:41 +03:00
['changePath' s+'hi']
['outputScriptHex' s+'hi']
['lockTime' s+'hi']
['sigHashType' s+'hi']
[%segwit s+'hi']
['initialTimestamp' s+'hi']
==
:: TODO inputs, keysets, changeppath, outputscripthex, locktime, sigHashType, segwit, initialTimestamp
:: , additionals ("bech32")
2020-11-26 12:38:30 +03:00
++ txi
|= =^txi ^- json
?> ?=(^ ur.txi)
:- %a
:~ s+(en:base16:mimes:html u.ur.txi)
n+pos.utxo.txi
==
++ key
|= =^key ^- json
:- %s
%^ cat 3 'm/'
%^ cat 3
?- bipt.key
%bip44 '44'
%bip49 '49'
%bip84 '84'
==
%^ cat 3 '/0\'/0\'/'
%^ cat 3 ?:(=(%0 chyg.key) '0/' '1/')
(crip ((d-co:co 0) idx.key))
2020-11-22 17:49:55 +03:00
--
::
2020-11-13 15:47:11 +03:00
++ defaults
|%
++ max-gap 20
++ confs 6
--
2020-11-02 10:21:48 +03:00
::
2020-11-11 15:30:22 +03:00
++ from-xpub
2020-11-13 15:47:11 +03:00
|= [=xpub:btc scan-to=(unit scon) max-gap=(unit @ud) confs=(unit @ud)]
2020-11-11 15:30:22 +03:00
^- walt
:* (from-extended:bip32 (trip xpub))
(xpub-type:btc xpub)
*wach
[0 0]
%.n
(fall scan-to *scon)
2020-11-13 15:47:11 +03:00
(fall max-gap max-gap:defaults)
(fall confs confs:defaults)
2020-11-11 15:30:22 +03:00
==
:: wad: door for processing walts (wallets)
:: parameterized on a walt and it's chyg account
::
++ wad
|_ [w=walt =chyg]
2020-10-31 14:25:32 +03:00
++ mk-address
2020-11-02 10:21:48 +03:00
|= =idx
2020-10-30 14:45:38 +03:00
^- address:btc
=/ pubkey=@ux
%- compress-point:ecc
2020-11-11 15:30:22 +03:00
pub:(derive-public:(derive-public:wilt.w (@ chyg)) idx)
?: ?=(%bip84 bipt.w)
2020-10-30 14:45:38 +03:00
(need (encode-pubkey:bech32:btc %main pubkey))
~|("legacy addresses not supported yet " !!)
:: generates and watches the next available address
::
++ gen-address
2020-11-11 15:30:22 +03:00
^- (pair address:btc walt)
=/ addr (mk-address nixt-idx)
:- addr
(update-address addr [chyg nixt-idx *(set utxo:btc)])
2020-10-31 14:25:32 +03:00
:: insert a new address; update "nixt" free address if this one was it
::
++ update-address
2020-10-31 14:25:32 +03:00
|= [a=address:btc =addi]
2020-11-11 15:30:22 +03:00
^- walt
2020-11-02 10:21:48 +03:00
?> =(chyg chyg.addi)
?> =(a (mk-address idx.addi))
2020-11-11 15:30:22 +03:00
=? nixt.w (is-nixt addi)
2020-11-02 10:21:48 +03:00
new:bump-nixt
2020-11-11 15:30:22 +03:00
w(wach (~(put by wach.w) a addi))
2020-10-31 14:25:32 +03:00
::
++ is-nixt
2020-11-02 10:21:48 +03:00
|= =addi ^- ?
?: ?=(%0 chyg.addi)
2020-11-11 15:30:22 +03:00
=(idx.addi p.nixt.w)
=(idx.addi q.nixt.w)
2020-11-02 13:37:55 +03:00
++ nixt-idx
2020-11-11 15:30:22 +03:00
?:(?=(%0 chyg) p.nixt.w q.nixt.w)
2020-11-02 10:21:48 +03:00
:: Returns: the prior idx in the account
:: nixt with account idx bumped
2020-11-02 13:37:55 +03:00
:: Increments idx until an unwatched address is found
2020-11-02 10:21:48 +03:00
:: Crashes if max-index is passed
2020-10-31 12:41:00 +03:00
::
2020-10-31 14:25:32 +03:00
++ bump-nixt
2020-11-02 10:21:48 +03:00
|^ ^- [old=idx new=nixt]
2020-11-02 13:37:55 +03:00
:- nixt-idx
=/ new-idx=idx +(nixt-idx)
2020-10-31 14:25:32 +03:00
|- ?> (lte new-idx max-index)
2020-11-11 15:30:22 +03:00
?. (~(has by wach.w) (mk-address new-idx))
2020-11-02 10:21:48 +03:00
(set-nixt new-idx)
2020-10-31 14:25:32 +03:00
$(new-idx +(new-idx))
2020-11-02 10:21:48 +03:00
::
++ set-nixt
|= idx=@ ^- nixt
2020-11-11 15:30:22 +03:00
?:(?=(%0 chyg) [idx q.nixt.w] [p.nixt.w idx])
2020-11-02 10:21:48 +03:00
--
2020-10-30 14:45:38 +03:00
--
2020-11-18 14:39:57 +03:00
:: sut: door to select utxos
::
++ sut
2020-11-22 15:57:25 +03:00
|_ [w=walt eny=@uvJ payee=(unit ship) =feyb txos=(list txo)]
2020-11-18 14:39:57 +03:00
++ meta-weight 10
++ output-weight 31
2020-11-19 14:44:12 +03:00
::
++ target-value
^- sats
%+ roll (turn txos |=(=txo value.txo))
|=([a=sats b=sats] (add a b))
::
2020-11-18 14:39:57 +03:00
++ base-weight
^- vbytes
%+ add meta-weight
2020-11-19 14:44:12 +03:00
(mul (lent txos) output-weight)
::
2020-11-18 14:39:57 +03:00
++ input-weight
^- vbytes
?. ?=(%bip84 bipt.w)
~|("Only bech32 wallets supported" !!)
102
::
++ total-vbytes
|= selected=(list input)
^- vbytes
%+ add base-weight
(mul input-weight (lent selected))
:: value of an input after fee
2020-11-19 12:11:02 +03:00
:: 0 if net is <= 0
2020-11-18 14:39:57 +03:00
::
++ net-value
|= val=sats ^- sats
=/ cost (mul input-weight feyb)
?: (lte val cost) 0
(sub val cost)
2020-11-22 15:57:25 +03:00
:: Uses naive random selection. Should switch to branch-and-bound later.
2020-11-19 14:44:12 +03:00
::
2020-11-18 14:39:57 +03:00
++ select-utxos
2020-11-19 18:54:01 +03:00
|^ ^- (unit =txbu)
2020-11-26 12:38:30 +03:00
=/ is=(unit (list input))
2020-11-19 14:44:12 +03:00
%- single-random-draw
%- zing
(turn ~(val by wach.w) to-inputs)
2020-11-26 12:38:30 +03:00
?~(is ~ `(inputs-to-txbu u.is))
2020-11-19 18:54:01 +03:00
::
2020-11-18 14:49:09 +03:00
++ to-inputs
|= =addi ^- (list input)
2020-11-18 14:39:57 +03:00
%+ turn ~(tap in utxos.addi)
2020-11-18 14:49:09 +03:00
|=(=utxo:btc [utxo chyg.addi idx.addi])
2020-11-19 18:54:01 +03:00
++ inputs-to-txbu
|= is=(list input) ^- txbu
2020-11-22 15:57:25 +03:00
:* payee
(total-vbytes is)
2020-11-19 18:54:01 +03:00
%+ turn is
|=(i=input [utxo.i ~ [bipt.w chyg.i idx.i]])
txos
==
2020-11-18 14:49:09 +03:00
--
2020-11-18 14:39:57 +03:00
:: single-random-draw
:: randomly choose utxos until target is hit
:: only use an input if its net-value > 0
::
++ single-random-draw
|= is=(list input)
2020-11-19 14:44:12 +03:00
^- (unit (list input))
2020-11-18 14:39:57 +03:00
=/ rng ~(. og eny)
2020-11-19 14:44:12 +03:00
=/ target (add target-value (mul feyb base-weight)) :: add base fees to target
2020-11-18 14:39:57 +03:00
=| [select=(list input) total=sats:btc]
2020-11-19 12:11:02 +03:00
|- ?: =(~ is) ~
2020-11-18 14:39:57 +03:00
=^ n rng (rads:rng (lent is))
2020-11-19 12:11:02 +03:00
=/ i=input (snag n is)
2020-11-18 14:39:57 +03:00
=/ net-val (net-value value.utxo.i)
2020-11-19 14:44:12 +03:00
=? select (gth net-val 0) [i select] :: select if net-value > 0
2020-11-18 14:39:57 +03:00
=/ new-total (add total net-val)
2020-11-19 14:44:12 +03:00
?: (gte new-total target) `select
2020-11-18 14:39:57 +03:00
%= $
2020-11-19 12:11:02 +03:00
is (oust [n 1] is)
2020-11-18 14:39:57 +03:00
total new-total
==
::
--
2020-10-30 14:45:38 +03:00
--