mirror of
https://github.com/muun/recovery.git
synced 2025-11-11 14:30:19 -05:00
Release v0.1.0
This commit is contained in:
252
vendor/github.com/muun/libwallet/address.go
generated
vendored
Normal file
252
vendor/github.com/muun/libwallet/address.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
package libwallet
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type AddressVersion int
|
||||
|
||||
const (
|
||||
addressV1 AddressVersion = 1
|
||||
addressV2 AddressVersion = 2
|
||||
addressV3 AddressVersion = 3
|
||||
addressSubmarineSwap AddressVersion = 101
|
||||
)
|
||||
|
||||
type muunAddress struct {
|
||||
version AddressVersion
|
||||
derivationPath string
|
||||
address string
|
||||
redeemScript []byte
|
||||
}
|
||||
|
||||
func newMuunAddress(version AddressVersion, userPublicKey, muunPublicKey *HDPublicKey) (MuunAddress, error) {
|
||||
if userPublicKey.Path != muunPublicKey.Path {
|
||||
return nil, errors.Errorf("paths must match for address generation (%v != %v)", userPublicKey.Path, muunPublicKey.Path)
|
||||
}
|
||||
|
||||
switch version {
|
||||
case addressV1:
|
||||
return CreateAddressV1(userPublicKey)
|
||||
case addressV2:
|
||||
return CreateAddressV2(userPublicKey, muunPublicKey)
|
||||
case addressV3:
|
||||
return CreateAddressV3(userPublicKey, muunPublicKey)
|
||||
case addressSubmarineSwap:
|
||||
return CreateAddressSubmarineSwap(userPublicKey)
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("unknown version %v", version)
|
||||
}
|
||||
|
||||
func (a *muunAddress) Version() int {
|
||||
return int(a.version)
|
||||
}
|
||||
|
||||
func (a *muunAddress) DerivationPath() string {
|
||||
return a.derivationPath
|
||||
}
|
||||
|
||||
func (a *muunAddress) Address() string {
|
||||
return a.address
|
||||
}
|
||||
|
||||
func (a *muunAddress) RedeemScript() []byte {
|
||||
return a.redeemScript
|
||||
}
|
||||
|
||||
// MuunPaymentURI is muun's uri struct
|
||||
type MuunPaymentURI struct {
|
||||
Address string
|
||||
Label string
|
||||
Message string
|
||||
Amount string
|
||||
URI string
|
||||
BIP70Url string
|
||||
CreationTime string
|
||||
ExpiresTime string
|
||||
Invoice *Invoice
|
||||
}
|
||||
|
||||
const (
|
||||
bitcoinScheme = "bitcoin:"
|
||||
muunScheme = "muun:"
|
||||
)
|
||||
|
||||
// GetPaymentURI builds a MuunPaymentURI from an address and a network
|
||||
func GetPaymentURI(address string, network *Network) (*MuunPaymentURI, error) {
|
||||
|
||||
uriAddress := normalizeAddress(address)
|
||||
|
||||
components, err := url.Parse(uriAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if components.Scheme != "bitcoin" {
|
||||
return nil, errors.New("Invalid scheme")
|
||||
}
|
||||
|
||||
base58Address := components.Opaque
|
||||
|
||||
// When URIs are bitcoin:// the address comes in host
|
||||
// this happens in iOS that mostly ignores bitcoin: format
|
||||
if len(base58Address) == 0 {
|
||||
base58Address = components.Host
|
||||
}
|
||||
|
||||
queryValues, err := url.ParseQuery(components.RawQuery)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Couldnt parse query")
|
||||
}
|
||||
|
||||
var label, message, amount string
|
||||
|
||||
if len(queryValues["label"]) != 0 {
|
||||
label = queryValues["label"][0]
|
||||
}
|
||||
|
||||
if len(queryValues["message"]) != 0 {
|
||||
message = queryValues["message"][0]
|
||||
}
|
||||
|
||||
if len(queryValues["amount"]) != 0 {
|
||||
amount = queryValues["amount"][0]
|
||||
}
|
||||
|
||||
if len(queryValues["lightning"]) != 0 {
|
||||
invoice, err := ParseInvoice(queryValues["lightning"][0], network)
|
||||
|
||||
if err == nil {
|
||||
return &MuunPaymentURI{Invoice:invoice}, nil
|
||||
}
|
||||
}
|
||||
|
||||
//BIP70 check
|
||||
if len(queryValues["r"]) != 0 {
|
||||
if len(base58Address) > 0 {
|
||||
return &MuunPaymentURI{
|
||||
Address: base58Address,
|
||||
Label: label,
|
||||
Message: message,
|
||||
Amount: amount,
|
||||
URI: uriAddress,
|
||||
BIP70Url: queryValues["r"][0],
|
||||
}, nil
|
||||
}
|
||||
return &MuunPaymentURI{
|
||||
Label: label,
|
||||
Message: message,
|
||||
Amount: amount,
|
||||
URI: uriAddress,
|
||||
BIP70Url: queryValues["r"][0],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Bech32 check
|
||||
validatedBase58Address, err := btcutil.DecodeAddress(base58Address, network.network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !validatedBase58Address.IsForNet(network.network) {
|
||||
return nil, errors.Errorf("Network mismatch")
|
||||
}
|
||||
|
||||
return &MuunPaymentURI{
|
||||
Address: validatedBase58Address.String(),
|
||||
Label: label,
|
||||
Message: message,
|
||||
Amount: amount,
|
||||
URI: uriAddress,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// DoPaymentRequestCall builds a MuunPaymentUri from a url and a network. Handling BIP70 to 72
|
||||
func DoPaymentRequestCall(url string, network *Network) (*MuunPaymentURI, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to create request to: %s", url)
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/bitcoin-paymentrequest")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to make request to: %s", url)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to read body response")
|
||||
}
|
||||
|
||||
payReq := &PaymentRequest{}
|
||||
err = proto.Unmarshal(body, payReq)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to Unmarshall paymentRequest")
|
||||
}
|
||||
|
||||
payDetails := &PaymentDetails{}
|
||||
|
||||
err = proto.Unmarshal(payReq.SerializedPaymentDetails, payDetails)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to Unmarshall paymentDetails")
|
||||
}
|
||||
|
||||
if len(payDetails.Outputs) == 0 {
|
||||
return nil, errors.New("No outputs provided")
|
||||
}
|
||||
|
||||
address, err := getAddressFromScript(payDetails.Outputs[0].Script, network)
|
||||
if err != nil {
|
||||
errors.Wrapf(err, "Failed to get address")
|
||||
}
|
||||
|
||||
return &MuunPaymentURI{
|
||||
Address: address,
|
||||
Message: *payDetails.Memo,
|
||||
Amount: strconv.FormatUint(*payDetails.Outputs[0].Amount, 10),
|
||||
BIP70Url: url,
|
||||
CreationTime: strconv.FormatUint(*payDetails.Time, 10),
|
||||
ExpiresTime: strconv.FormatUint(*payDetails.Expires, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getAddressFromScript(script []byte, network *Network) (string, error) {
|
||||
pkScript, err := txscript.ParsePkScript(script)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
address, err := pkScript.Address(network.network)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return address.String(), nil
|
||||
}
|
||||
|
||||
func normalizeAddress(rawAddress string) string {
|
||||
newAddress := rawAddress
|
||||
|
||||
if strings.Contains(newAddress, muunScheme) {
|
||||
newAddress = strings.Replace(newAddress, muunScheme, bitcoinScheme, 1)
|
||||
}
|
||||
|
||||
if !strings.Contains(newAddress, bitcoinScheme) {
|
||||
newAddress = bitcoinScheme + rawAddress
|
||||
}
|
||||
|
||||
return newAddress
|
||||
}
|
||||
Reference in New Issue
Block a user