Skip to content

Commit

Permalink
add support for btc wallet
Browse files Browse the repository at this point in the history
Signed-off-by: Philemon Ukane <[email protected]>
  • Loading branch information
ukane-philemon committed Dec 22, 2023
1 parent 1c9221c commit 4319c0f
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 54 deletions.
7 changes: 4 additions & 3 deletions dexc/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ const (
// CustomDexWalletType is a keyword that identifies a custom Cryptopower
// wallet used by the DEX client.
CustomDexWalletType = "cryptopowerwallet"
// DexDcrWalletIDConfigKey is the key that holds the wallet ID value in the
// settings map used to connect an existing dcr wallet to the DEX client.
DexDcrWalletIDConfigKey = "walletid"
// DexWalletIDConfigKey is the key that holds the wallet ID value in the
// settings map used to connect an existing Cryptopower wallet to the DEX
// client.
DexWalletIDConfigKey = "walletid"
// DexDcrWalletAccountNameConfigKey is the key that holds the wallet account
// values in the settings map used to connect an existing dcr wallet to the
// DEX client.
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ require (
github.com/decred/dcrd/txscript/v3 v3.0.0 // indirect
github.com/decred/dcrtime v0.0.0-20191018193024-8d8b4ef0458e // indirect
github.com/decred/go-socks v1.1.0 // indirect
github.com/decred/vspd/client/v2 v2.0.0 // indirect
github.com/decred/vspd/client/v2 v2.1.0 // indirect
github.com/decred/vspd/types v1.1.0 // indirect
github.com/decred/vspd/types/v2 v2.0.0 // indirect
github.com/dgraph-io/ristretto v0.0.2 // indirect
github.com/dustin/go-humanize v1.0.1-0.20210705192016-249ff6c91207 // indirect
Expand Down Expand Up @@ -227,3 +228,5 @@ replace github.com/lib/pq => github.com/lib/pq v1.10.4
// neccessary to work with dcrdex which has latest version of
// github.com/btcsuite/btcwallet.
replace github.com/btcsuite/btcwallet v0.16.10-0.20230706223227-037580c66b74 => github.com/btcsuite/btcwallet v0.16.9

replace decred.org/dcrdex v0.6.3 => ../../decred/dcrdex
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcig
decred.org/cspp v0.3.0/go.mod h1:UygjYilC94dER3BEU65Zzyoqy9ngJfWCD2rdJqvUs2A=
decred.org/cspp/v2 v2.1.0 h1:HeHb9+BFqrBaAPc6CsPiUpPFmC1uyBM2mJZUAbUXkRw=
decred.org/cspp/v2 v2.1.0/go.mod h1:9nO3bfvCheOPIFZw5f6sRQ42CjBFB5RKSaJ9Iq6G4MA=
decred.org/dcrdex v0.6.3 h1:XrqbF5O+CFhQws+eugzqQoPgvjrFKgpYSkfKGAbD3NM=
decred.org/dcrdex v0.6.3/go.mod h1:zzHSNtu94lYxCBUwkuEmWGUL1wlO4pFzMoaPTGoqtBo=
decred.org/dcrwallet v1.7.0 h1:U/ew00YBdUlx3rJAynt2OdKDgGzBKK4O89FijBq8iVg=
decred.org/dcrwallet v1.7.0/go.mod h1:hNOGyvH53gWdgFB601/ubGRzCPfPtWnEVAi9Grs90y4=
decred.org/dcrwallet/v3 v3.0.1 h1:+OLi+u/MvKc3Ubcnf19oyG/a5hJ/qp4OtezdiQZnLIs=
Expand Down Expand Up @@ -557,8 +555,10 @@ github.com/decred/slog v1.0.0/go.mod h1:zR98rEZHSnbZ4WHZtO0iqmSZjDLKhkXfrPTZQKtA
github.com/decred/slog v1.1.0/go.mod h1:kVXlGnt6DHy2fV5OjSeuvCJ0OmlmTF6LFpEPMu/fOY0=
github.com/decred/slog v1.2.0 h1:soHAxV52B54Di3WtKLfPum9OFfWqwtf/ygf9njdfnPM=
github.com/decred/slog v1.2.0/go.mod h1:kVXlGnt6DHy2fV5OjSeuvCJ0OmlmTF6LFpEPMu/fOY0=
github.com/decred/vspd/client/v2 v2.0.0 h1:gaSF1Bm2/EvoAiSLxNR5fgStrObAO66xmanhedidYIM=
github.com/decred/vspd/client/v2 v2.0.0/go.mod h1:IDDviEe/6CuxxrW0PLOcg448enU3YmeElFHledYHw78=
github.com/decred/vspd/client/v2 v2.1.0 h1:RzwmM/FCvpJDskNMeqeJ8UNnlR7kLCl3JlG8iZiLbG0=
github.com/decred/vspd/client/v2 v2.1.0/go.mod h1:r/CtdQF7TmuoIaFuanHtUMYYlQxWgRBGapdn4b+Bouc=
github.com/decred/vspd/types v1.1.0 h1:hTeqQwgRUN2FGIbuCIdyzBejKV+jxKrmEIcLKxpsB1g=
github.com/decred/vspd/types v1.1.0/go.mod h1:THsO8aBSwWBq6ZsIG25cNqbkNb+EEASXzLhFvODVc0s=
github.com/decred/vspd/types/v2 v2.0.0 h1:FaPA+W4OOMRWK+Vk4fyyYdXoVLRMMRQsxzsnSjJjOnI=
github.com/decred/vspd/types/v2 v2.0.0/go.mod h1:2xnNqedkt9GuL+pK8uIzDxqYxFlwLRflYFJH64b76n0=
github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCFFnBUn4RN0nRcs1LJA=
Expand Down
198 changes: 198 additions & 0 deletions libwallet/assets/btc/dex-wallet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// This code is available on the terms of the project LICENSE.md file, and as
// terms of the BlueOak License. See: https://blueoakcouncil.org/license/1.0.0.

package btc

// Note: Most of the code here is a copy-pasta from:
// https://github.com/decred/dcrdex/blob/master/client/asset/btc/spv.go

import (
"context"
"errors"
"fmt"
"time"

"decred.org/dcrdex/client/asset"
dexbtc "decred.org/dcrdex/client/asset/btc"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet"
"github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wtxmgr"
)

// DEXWallet wraps *wallet.Wallet and implements dexbtc.BTCWallet.
type DEXWallet struct {
*wallet.Wallet // Implements most of dexbtc.BTCWallet
asset *Asset
}

var _ dexbtc.BTCWallet = (*DEXWallet)(nil)

// NewDEXWallet returns a new *DEXWallet.
func NewDEXWallet(asset *Asset) *DEXWallet {
return &DEXWallet{
Wallet: asset.Internal().BTC,
asset: asset,
}
}

// The below methods are not implemented by *wallet.Wallet, so must be
// implemented by the BTCWallet implementation.

func (dw *DEXWallet) WalletTransaction(txHash *chainhash.Hash) (*wtxmgr.TxDetails, error) {
details, err := wallet.UnstableAPI(dw.Wallet).TxDetails(txHash)
if err != nil {
return nil, err
}
if details == nil {
return nil, dexbtc.WalletTransactionNotFound
}

return details, nil
}

func (dw *DEXWallet) SyncedTo() waddrmgr.BlockStamp {
return dw.Wallet.Manager.SyncedTo()
}

func (dw *DEXWallet) SignTx(tx *wire.MsgTx) error {
var prevPkScripts [][]byte
var inputValues []btcutil.Amount
for _, txIn := range tx.TxIn {
_, txOut, _, _, err := dw.Wallet.FetchInputInfo(&txIn.PreviousOutPoint)
if err != nil {
return err
}
inputValues = append(inputValues, btcutil.Amount(txOut.Value))
prevPkScripts = append(prevPkScripts, txOut.PkScript)
// Zero the previous witness and signature script or else
// AddAllInputScripts does some weird stuff.
txIn.SignatureScript = nil
txIn.Witness = nil
}
return txauthor.AddAllInputScripts(tx, prevPkScripts, inputValues, &secretSource{dw, dw.ChainParams()})
}

func (dw *DEXWallet) BlockNotifications(ctx context.Context) <-chan *dexbtc.BlockNotification {
cl := dw.Wallet.NtfnServer.TransactionNotifications()
ch := make(chan *dexbtc.BlockNotification, 1)
go func() {
defer cl.Done()
for {
select {
case note := <-cl.C:
if len(note.AttachedBlocks) > 0 {
lastBlock := note.AttachedBlocks[len(note.AttachedBlocks)-1]
select {
case ch <- &dexbtc.BlockNotification{
Hash: *lastBlock.Hash,
Height: lastBlock.Height,
}:
default:
}
}
case <-ctx.Done():
return
}
}
}()
return ch
}

func (dw *DEXWallet) RescanAsync() error {
return dw.asset.rescanAsync()
}

func (dw *DEXWallet) ForceRescan() {
dw.asset.forceRescan()
}

func (dw *DEXWallet) Start() (dexbtc.SPVService, error) {
return dw.asset.chainClient, nil
}

func (dw *DEXWallet) Reconfigure(*asset.WalletConfig, string) (bool, error) {
return false, errors.New("Reconfigure not supported for Cyptopower btc wallet")
}

func (dw *DEXWallet) Birthday() time.Time {
return dw.Manager.Birthday()
}

func (dw *DEXWallet) Peers() ([]*asset.WalletPeer, error) {
peers := dw.asset.chainClient.CS.Peers()
var walletPeers []*asset.WalletPeer
for i := range peers {
p := peers[i]
walletPeers = append(walletPeers, &asset.WalletPeer{
Addr: p.Addr(),
Connected: p.Connected(),
Source: asset.WalletDefault,
})
}
return walletPeers, nil
}

func (dw *DEXWallet) AddPeer(address string) error {
dw.asset.SetSpecificPeer(address)
return nil
}

func (dw *DEXWallet) RemovePeer(address string) error {
dw.asset.RemoveSpecificPeer(address)
return nil
}

// secretSource is used to locate keys and redemption scripts while signing a
// transaction. secretSource satisfies the txauthor.SecretsSource interface.
type secretSource struct {
w *DEXWallet
chainParams *chaincfg.Params
}

// ChainParams returns the chain parameters.
func (s *secretSource) ChainParams() *chaincfg.Params {
return s.chainParams
}

// GetKey fetches a private key for the specified address.
func (s *secretSource) GetKey(addr btcutil.Address) (*btcec.PrivateKey, bool, error) {
ma, err := s.w.Wallet.AddressInfo(addr)
if err != nil {
return nil, false, err
}

mpka, ok := ma.(waddrmgr.ManagedPubKeyAddress)
if !ok {
e := fmt.Errorf("managed address type for %v is `%T` but "+
"want waddrmgr.ManagedPubKeyAddress", addr, ma)
return nil, false, e
}

privKey, err := mpka.PrivKey()
if err != nil {
return nil, false, err
}
return privKey, ma.Compressed(), nil
}

// GetScript fetches the redemption script for the specified p2sh/p2wsh address.
func (s *secretSource) GetScript(addr btcutil.Address) ([]byte, error) {
ma, err := s.w.Wallet.AddressInfo(addr)
if err != nil {
return nil, err
}

msa, ok := ma.(waddrmgr.ManagedScriptAddress)
if !ok {
e := fmt.Errorf("managed address type for %v is `%T` but "+
"want waddrmgr.ManagedScriptAddress", addr, ma)
return nil, e
}
return msa.Script()
}
4 changes: 2 additions & 2 deletions libwallet/assets/btc/rescan.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (asset *Asset) rescanAsync() error {
}

log.Infof("Synchronizing wallet (%s) with network...", asset.GetWalletName())
asset.Internal().BTC.SynchronizeRPC(asset.chainClient)
asset.Internal().BTC.SynchronizeRPC(asset.chainClient.NeutrinoClient)
return nil
}

Expand Down Expand Up @@ -379,7 +379,7 @@ func (asset *Asset) getblockStamp(height int32) (*waddrmgr.BlockStamp, error) {
return nil, fmt.Errorf("invalid block height provided: Error: %v", err)
}

block, err := asset.chainClient.GetBlock(startHash)
block, err := asset.chainClient.NeutrinoClient.GetBlock(startHash)
if err != nil {
return nil, fmt.Errorf("invalid block hash provided: Error: %v", err)
}
Expand Down
6 changes: 4 additions & 2 deletions libwallet/assets/btc/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ func (asset *Asset) prepareChain() error {
return err
}

asset.chainClient = chain.NewNeutrinoClient(asset.chainParams, chainService)
asset.chainClient = &btcChainService{
NeutrinoClient: chain.NewNeutrinoClient(asset.chainParams, chainService),
}

return nil
}
Expand Down Expand Up @@ -510,7 +512,7 @@ func (asset *Asset) startSync() error {

log.Infof("Synchronizing wallet (%s) with network...", asset.GetWalletName())
// Initializes the goroutines handling chain notifications, rescan progress and handlers.
asset.Internal().BTC.SynchronizeRPC(asset.chainClient)
asset.Internal().BTC.SynchronizeRPC(asset.chainClient.NeutrinoClient)

select {
// Wait for 5 seconds so that all goroutines initialized in SynchronizeRPC()
Expand Down
Loading

0 comments on commit 4319c0f

Please sign in to comment.