@@ -2,13 +2,15 @@ package bitcoin
22
33import (
44 "bytes"
5+ "encoding/hex"
56 "errors"
67 "fmt"
78
89 "crypto/sha256"
910
1011 "github.com/bitcoinsv/bsvd/bsvec"
1112 "github.com/bitcoinsv/bsvd/chaincfg"
13+ "github.com/bitcoinsv/bsvd/txscript"
1214 "github.com/bitcoinsv/bsvutil"
1315)
1416
@@ -72,6 +74,22 @@ func (a *A25) ComputeChecksum() (c [4]byte) {
7274 return
7375}
7476
77+ // ValidA58 validates a base58 encoded bitcoin address. An address is valid
78+ // if it can be decoded into a 25 byte address, the version number is 0,
79+ // and the checksum validates. Return value ok will be true for valid
80+ // addresses. If ok is false, the address is invalid and the error value
81+ // may indicate why.
82+ func ValidA58 (a58 []byte ) (bool , error ) {
83+ var a A25
84+ if err := a .Set58 (a58 ); err != nil {
85+ return false , err
86+ }
87+ if a .Version () != 0 {
88+ return false , errors .New ("not version 0" )
89+ }
90+ return a .EmbeddedChecksum () == a .ComputeChecksum (), nil
91+ }
92+
7593// AddressFromPrivateKey takes a private key string and returns a Bitcoin address
7694func AddressFromPrivateKey (privateKey string ) (string , error ) {
7795 rawKey , err := PrivateKeyFromString (privateKey )
@@ -95,18 +113,40 @@ func AddressFromPubKey(publicKey *bsvec.PublicKey) (*bsvutil.LegacyAddressPubKey
95113 return bsvutil .NewLegacyAddressPubKeyHash (bsvutil .Hash160 (publicKey .SerializeCompressed ()), & chaincfg .MainNetParams )
96114}
97115
98- // ValidA58 validates a base58 encoded bitcoin address. An address is valid
99- // if it can be decoded into a 25 byte address, the version number is 0,
100- // and the checksum validates. Return value ok will be true for valid
101- // addresses. If ok is false, the address is invalid and the error value
102- // may indicate why.
103- func ValidA58 (a58 []byte ) (bool , error ) {
104- var a A25
105- if err := a .Set58 (a58 ); err != nil {
106- return false , err
116+ // AddressFromScript will take an output script and extract a standard bitcoin address
117+ func AddressFromScript (script string ) (string , error ) {
118+
119+ // No script?
120+ if len (script ) == 0 {
121+ return "" , errors .New ("missing script" )
107122 }
108- if a .Version () != 0 {
109- return false , errors .New ("not version 0" )
123+
124+ // Decode the hex string into bytes
125+ scriptBytes , err := hex .DecodeString (script )
126+ if err != nil {
127+ return "" , err
110128 }
111- return a .EmbeddedChecksum () == a .ComputeChecksum (), nil
129+
130+ // Extract the components from the script
131+ var addresses []bsvutil.Address
132+ _ , addresses , _ , err = txscript .ExtractPkScriptAddrs (scriptBytes , & chaincfg .MainNetParams )
133+ if err != nil {
134+ return "" , err
135+ }
136+
137+ // Missing an address?
138+ if len (addresses ) == 0 {
139+ // This error case should not occur since the error above will occur when no address is found,
140+ // however we ensure that we have an address for the NewLegacyAddressPubKeyHash() below
141+ return "" , fmt .Errorf ("invalid output script, missing an address" )
142+ }
143+
144+ // Extract the address from the pubkey hash
145+ var address * bsvutil.LegacyAddressPubKeyHash
146+ if address , err = bsvutil .NewLegacyAddressPubKeyHash (addresses [0 ].ScriptAddress (), & chaincfg .MainNetParams ); err != nil {
147+ return "" , err
148+ }
149+
150+ // Use the encoded version of the address
151+ return address .EncodeAddress (), nil
112152}
0 commit comments