Skip to content

Commit

Permalink
Fixed change address (#22)
Browse files Browse the repository at this point in the history
* implements change address

* fix

* fix

* test double call

* "already have address" ignored

* eth address as a constant

* btc address as a constant

---------

Co-authored-by: dpiatkivskyi <dmytro.piatkikvskyi@gmailcom>
  • Loading branch information
dmytropiatkivskyi and dpiatkivskyi authored Aug 29, 2024
1 parent 80c481f commit 0f0ba15
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 28 deletions.
9 changes: 9 additions & 0 deletions run/btcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
_ "net/http/pprof" // nolint:gosec
"os"
"path/filepath"
"strings"
"sync"

"github.com/btcsuite/btcwallet/walletdb"
Expand All @@ -22,6 +23,8 @@ import (
"github.com/stroomnetwork/btcwallet/wallet"
)

const ethChangeAddr = "0x7b3f4f4b3cCf7f3fDf3f3f3f3f3f3f3f3f3f3f3f"

var (
cfg *Config
)
Expand Down Expand Up @@ -146,6 +149,12 @@ func doInit(signer frost.Signer, pk1, pk2 *btcec.PublicKey, bitcoindConfig *chai
return nil, err
}
w.AddressMapStorage = storage

changeAddressKey, err := w.GenerateKeyFromEthAddressAndImport(ethChangeAddr)
if err != nil && !strings.Contains(err.Error(), "already have address") {
return nil, fmt.Errorf("cannot import change address: %w", err)
}
w.ChangeAddressKey = changeAddressKey
}

// Add interrupt handlers to shut down the various process components
Expand Down
4 changes: 3 additions & 1 deletion run/signer_with_wallet_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"time"
)

const btcAddr = "sb1pgdyx9mulkelunyg9rkj384sajls7xx2y3jlagdpup2l2wl6tppasvgf8z0"

func Example() {
// Use all processor cores.
runtime.GOMAXPROCS(runtime.NumCPU())
Expand All @@ -39,7 +41,7 @@ func Example() {
time.Sleep(2 * time.Second)

w.Unlock([]byte("passphrase"), time.After(10*time.Minute))
_, err = w.ImportBtcAddressWithEthAddr("sb1pgdyx9mulkelunyg9rkj384sajls7xx2y3jlagdpup2l2wl6tppasvgf8z0", "0x7b3f4f4b3cCf7f3fDf3f3f3f3f3f3f3f3f3f3f3f")
_, err = w.GenerateAndImportKeyWithCheck(btcAddr, ethChangeAddr)

f := false
if f {
Expand Down
12 changes: 7 additions & 5 deletions wallet/createtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (w *Wallet) txToOutputsWithRedemptionId(outputs []*wire.TxOut,
var tx *txauthor.AuthoredTx
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
addrmgrNs, changeSource, err := w.addrMgrWithChangeSource(
dbtx, changeKeyScope, account,
dbtx, changeKeyScope, account, w.ChangeAddressKey,
)
if err != nil {
return err
Expand Down Expand Up @@ -471,13 +471,12 @@ func inputYieldsPositively(credit *wire.TxOut,
// addresses will come from the specified key scope and account, unless a key
// scope is not specified. In that case, change addresses will always come from
// the P2WKH key scope.
func (w *Wallet) addrMgrWithChangeSource(dbtx walletdb.ReadWriteTx,
changeKeyScope *waddrmgr.KeyScope, account uint32) (
walletdb.ReadWriteBucket, *txauthor.ChangeSource, error) {
func (w *Wallet) addrMgrWithChangeSource(dbtx walletdb.ReadWriteTx, changeKeyScope *waddrmgr.KeyScope, account uint32,
changeAddress *btcec.PublicKey) (walletdb.ReadWriteBucket, *txauthor.ChangeSource, error) {

// Determine the address type for change addresses of the given
// account.
if changeKeyScope == nil {
if changeKeyScope == nil || changeAddress != nil {
changeKeyScope = &waddrmgr.KeyScopeBIP0086
}
addrType := waddrmgr.ScopeAddrMap[*changeKeyScope].InternalAddrType
Expand Down Expand Up @@ -521,6 +520,9 @@ func (w *Wallet) addrMgrWithChangeSource(dbtx walletdb.ReadWriteTx,
changeAddr btcutil.Address
err error
)
if changeAddress != nil {
return txscript.PayToTaprootScript(changeAddress)
}
if account == waddrmgr.ImportedAddrAccount {
changeAddr, err = w.newChangeAddress(
addrmgrNs, 0, *changeKeyScope,
Expand Down
2 changes: 1 addition & 1 deletion wallet/frost_signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestFrostSigning(t *testing.T) {
err = w.Unlock([]byte("world"), time.After(10*time.Minute))
require.NoError(t, err)

pubKey, err := w.ImportBtcAddressWithEthAddr("", "0x7b3f4f4b3cCf7f3fDf3f3f3f3f3f3f3f3f3f3f3f")
pubKey, err := w.GenerateKeyFromEthAddressAndImport("0x7b3f4f4b3cCf7f3fDf3f3f3f3f3f3f3f3f3f3f3f")
require.NoError(t, err)

p2shAddr, err := txscript.PayToTaprootScript(pubKey)
Expand Down
48 changes: 34 additions & 14 deletions wallet/import_btc_addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,52 @@ import (
"github.com/stroomnetwork/frost/crypto"
)

func (w *Wallet) ImportBtcAddressWithEthAddr(btcAddr, ethAddr string) (*btcec.PublicKey, error) {
func (w *Wallet) GenerateAndImportKeyWithCheck(btcAddr, ethAddr string) (*btcec.PublicKey, error) {

lc, err := w.lcFromEthAddr(ethAddr)
key, importedAddress, err := w.generateKeyFromEthAddressAndImport(ethAddr)
if err != nil {
return nil, err
}

if importedAddress != nil {
if btcAddr != "" && importedAddress.Address().EncodeAddress() != btcAddr {
return nil, fmt.Errorf("address mismatch: %s != %s",
importedAddress.Address().EncodeAddress(), btcAddr)
}

}

return key, nil
}

func (w *Wallet) GenerateKeyFromEthAddressAndImport(ethAddr string) (*btcec.PublicKey, error) {
key, _, err := w.generateKeyFromEthAddressAndImport(ethAddr)
return key, err
}

func (w *Wallet) generateKeyFromEthAddressAndImport(ethAddr string) (*btcec.PublicKey, waddrmgr.ManagedAddress, error) {

lc, err := w.lcFromEthAddr(ethAddr)
if err != nil {
return nil, nil, err
}

pubKey := lc.GetCombinedPubKey()
importedAddress, err := w.ImportPublicKeyReturnAddress(pubKey, waddrmgr.TaprootPubKey)
if err != nil {
return nil, err
return nil, nil, err
}

if importedAddress != nil {
address := importedAddress.Address().EncodeAddress()
if btcAddr != "" && address != btcAddr {
return nil, fmt.Errorf("address mismatch: %s != %s",
importedAddress.Address().EncodeAddress(), btcAddr)
}
err := w.AddressMapStorage.SetEthAddress(address, ethAddr)
if err != nil {
return nil, err
}
if importedAddress == nil {
return nil, nil, fmt.Errorf("imported address is nil")
}

err = w.AddressMapStorage.SetEthAddress(importedAddress.Address().EncodeAddress(), ethAddr)
if err != nil {
return nil, nil, err
}

return pubKey, nil
return pubKey, importedAddress, nil
}

func (w *Wallet) lcFromEthAddr(ethAddrStr string) (*crypto.LinearCombination, error) {
Expand Down
4 changes: 1 addition & 3 deletions wallet/psbt.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,7 @@ func (w *Wallet) FundPsbt(packet *psbt.Packet, keyScope *waddrmgr.KeyScope,
// We also need a change source which needs to be able to insert
// a new change address into the database.
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
_, changeSource, err := w.addrMgrWithChangeSource(
dbtx, opts.changeKeyScope, account,
)
_, changeSource, err := w.addrMgrWithChangeSource(dbtx, opts.changeKeyScope, account, nil)
if err != nil {
return err
}
Expand Down
9 changes: 5 additions & 4 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,11 @@ type Wallet struct {
publicPassphrase []byte

// Data stores
db walletdb.DB
Manager *waddrmgr.Manager
TxStore *wtxmgr.Store
FrostSigner frost.Signer
db walletdb.DB
Manager *waddrmgr.Manager
TxStore *wtxmgr.Store
FrostSigner frost.Signer
ChangeAddressKey *btcec.PublicKey

AddressMapStorage *AddressMapStorage
Pk1, Pk2 *btcec.PublicKey
Expand Down

0 comments on commit 0f0ba15

Please sign in to comment.