/
utils.go
141 lines (121 loc) · 3.81 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package btc
import (
"encoding/binary"
"fmt"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcwallet/waddrmgr"
sharedW "github.com/crypto-power/cryptopower/libwallet/assets/wallet"
"github.com/crypto-power/cryptopower/libwallet/utils"
)
const (
maxAmountSatoshi = btcutil.MaxSatoshi // MaxSatoshi is the maximum transaction amount allowed in satoshi.
// TestnetHDPath is the BIP 84 HD path used for deriving addresses on the
// test network.
TestnetHDPath = "m / 84' / 1' / "
// MainnetHDPath is the BIP 84 HD path used for deriving addresses on the
// main network.
MainnetHDPath = "m / 84' / 0' / "
)
var wAddrMgrBkt = []byte("waddrmgr")
// GetScope returns the key scope that will be used within the waddrmgr to
// create an HD chain for deriving all of our required keys. A different
// scope is used for each specific coin type.
func GetScope() waddrmgr.KeyScope {
// Construct the key scope that will be used within the waddrmgr to
// create an HD chain for deriving all of our required keys. A different
// scope is used for each specific coin type.
return waddrmgr.KeyScopeBIP0084
}
// AmountBTC converts a satoshi amount to a BTC amount.
func AmountBTC(amount int64) float64 {
return btcutil.Amount(amount).ToBTC()
}
// AmountSatoshi converts a BTC amount to a satoshi amount.
func AmountSatoshi(f float64) int64 {
amount, err := btcutil.NewAmount(f)
if err != nil {
log.Error(err)
return -1
}
return int64(amount)
}
// ToAmount returns a BTC amount that implements the asset amount interface.
func (asset *Asset) ToAmount(v int64) sharedW.AssetAmount {
return Amount(btcutil.Amount(v))
}
func hardenedKey(key uint32) uint32 {
return key + hdkeychain.HardenedKeyStart
}
// DeriveAccountXpub derives the xpub for the given account.
func (asset *Asset) DeriveAccountXpub(seedMnemonic string, account uint32, params *chaincfg.Params) (xpub string, err error) {
seed, err := sharedW.DecodeSeedMnemonic(seedMnemonic, asset.Type)
if err != nil {
return "", err
}
defer func() {
for i := range seed {
seed[i] = 0
}
}()
// Derive the master extended key from the provided seed.
masterNode, err := hdkeychain.NewMaster(seed, params)
if err != nil {
return "", err
}
defer masterNode.Zero()
path := []uint32{hardenedKey(GetScope().Purpose), hardenedKey(GetScope().Coin)}
path = append(path, hardenedKey(account))
currentKey := masterNode
for _, pathPart := range path {
currentKey, err = currentKey.Derive(pathPart)
if err != nil {
return "", err
}
}
pubVersionBytes := make([]byte, len(params.HDPublicKeyID))
copy(pubVersionBytes, params.HDPublicKeyID[:])
switch params.Name {
case chaincfg.TestNet3Params.Name:
binary.BigEndian.PutUint32(pubVersionBytes, uint32(
waddrmgr.HDVersionTestNetBIP0084,
))
case chaincfg.MainNetParams.Name:
binary.BigEndian.PutUint32(pubVersionBytes, uint32(
waddrmgr.HDVersionMainNetBIP0084,
))
case chaincfg.SimNetParams.Name:
binary.BigEndian.PutUint32(pubVersionBytes, uint32(
waddrmgr.HDVersionSimNetBIP0044,
))
default:
return "", utils.ErrInvalidNet
}
currentKey, err = currentKey.CloneWithVersion(
params.HDPrivateKeyID[:],
)
if err != nil {
return "", err
}
currentKey, err = currentKey.Neuter()
if err != nil {
return "", err
}
currentKey, err = currentKey.CloneWithVersion(pubVersionBytes)
if err != nil {
return "", err
}
return currentKey.String(), nil
}
func decodeAddress(s string, params *chaincfg.Params) (btcutil.Address, error) {
addr, err := btcutil.DecodeAddress(s, params)
if err != nil {
return nil, fmt.Errorf("invalid address %q: decode failed with %#q", s, err)
}
if !addr.IsForNet(params) {
return nil, fmt.Errorf("invalid address %q: not intended for use on %s",
addr, params.Name)
}
return addr, nil
}