muun-recovery/libwallet/address_test.go
2025-05-13 17:49:44 -03:00

322 lines
7.4 KiB
Go
Executable File

package libwallet
import (
"encoding/hex"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
"google.golang.org/protobuf/proto"
)
const (
address = "2NDhvuRPCYXq4fB8SprminieZ2a1i3JFXyS"
amountURI = address + "?amount=1.2"
completeURI = amountURI + "&label=hola&message=mensaje%20con%20espacios"
uriWithSlashes = "bitcoin://" + amountURI
invalidAddress = "2NDhvuRPCYXq4fB8SprminieZ2a1i3JFXya"
randomText = "fooo"
bip70URL = "https://bitpay.com/i/KXCEAtJQssR9vG2BxdjFwx"
bip70NonRetroCompatAddress = bitcoinScheme + "?r=" + bip70URL
bip70RetroCompatAddress = bitcoinScheme + address + "?r=" + bip70URL
)
func TestGetPaymentURI(t *testing.T) {
const (
invoice = "lnbcrt1pwtpd4xpp55meuklpslk5jtxytyh7u2q490c2xhm68dm3a94486zntsg7ad4vsdqqcqzys763w70h39ze44ngzhdt2mag84wlkefqkphuy7ssg4la5gt9vcpmqts00fnapf8frs928mc5ujfutzyu8apkezhrfvydx82l40w0fckqqmerzjc"
invoiceHashHex = "a6f3cb7c30fda925988b25fdc502a57e146bef476ee3d2d6a7d0a6b823dd6d59"
invoiceDestinationHex = "028cfad4e092191a41f081bedfbe5a6e8f441603c78bf9001b8fb62ac0858f20edasd"
)
invoiceDestination, _ := hex.DecodeString(invoiceDestinationHex)
invoicePaymentHash := make([]byte, 32)
hex.Decode(invoicePaymentHash[:], []byte(invoiceHashHex))
type args struct {
address string
network Network
}
tests := []struct {
name string
args args
want *MuunPaymentURI
wantErr bool
}{
{
name: "validAddress",
args: args{
address: address,
network: *Regtest(),
},
want: &MuunPaymentURI{
Address: address,
Uri: bitcoinScheme + address,
},
},
{
name: "amountValidAddress",
args: args{
address: amountURI,
network: *Regtest(),
},
want: &MuunPaymentURI{
Address: address,
Amount: "1.2",
Uri: bitcoinScheme + amountURI,
},
},
{
name: "completeValidAddress",
args: args{
address: completeURI,
network: *Regtest(),
},
want: &MuunPaymentURI{
Address: address,
Amount: "1.2",
Label: "hola",
Message: "mensaje con espacios",
Uri: bitcoinScheme + completeURI,
},
},
{
name: "invalidAddress",
args: args{
address: invalidAddress,
network: *Regtest(),
},
wantErr: true,
},
{
name: "randomText",
args: args{
address: randomText,
network: *Regtest(),
},
wantErr: true,
},
{
name: "BIP70NonRetroCompatAddress",
args: args{
address: bip70NonRetroCompatAddress,
network: *Regtest(),
},
want: &MuunPaymentURI{
Uri: bip70NonRetroCompatAddress,
Bip70Url: bip70URL,
},
},
{
name: "BIP70RetroCompatAddress",
args: args{
address: bip70RetroCompatAddress,
network: *Regtest(),
},
want: &MuunPaymentURI{
Address: address,
Uri: bip70RetroCompatAddress,
Bip70Url: bip70URL,
},
},
{
name: "URL like address",
args: args{
address: uriWithSlashes,
network: *Regtest(),
},
want: &MuunPaymentURI{
Address: address,
Uri: uriWithSlashes,
Amount: "1.2",
},
},
{
name: "bad url",
args: args{
address: ":foo#%--",
network: *Regtest(),
},
wantErr: true,
},
{
name: "bad query",
args: args{
address: "bitcoin:123123?%&-=asd",
network: *Regtest(),
},
wantErr: true,
},
{
name: "network mismatch",
args: args{
address: amountURI,
network: *Mainnet(),
},
wantErr: true,
},
{
name: "BIP with lightning",
args: args{
address: "bitcoin:123123?lightning=" + invoice,
network: *network,
},
want: &MuunPaymentURI{Invoice: &Invoice{
RawInvoice: invoice,
FallbackAddress: nil,
Network: network,
MilliSat: "",
Destination: invoiceDestination,
PaymentHash: invoicePaymentHash,
Description: "",
}},
},
{
name: "ALL CAPS",
args: args{
address: "BITCOIN:BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2",
network: *Mainnet(),
},
want: &MuunPaymentURI{
Address: strings.ToLower("BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2"),
Uri: "BITCOIN:BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2",
},
},
{
name: "MiXeD Case",
args: args{
address: "BiTcOiN:BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2",
network: *Mainnet(),
},
want: &MuunPaymentURI{
Address: strings.ToLower("BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2"),
Uri: "BiTcOiN:BC1QSQP0D3TY8AAA8N9J8R0D2PF3G40VN4AS9TPWY3J9R3GK5K64VX6QWPAXH2",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetPaymentURI(tt.args.address, &tt.args.network)
if (err != nil) != tt.wantErr {
t.Errorf("GetPaymentURI() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != nil && got.Invoice != nil {
// expiry is relative to now, so ignore it
got.Invoice.Expiry = 0
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPaymentURI() = %+v, want %+v", got, tt.want)
}
})
}
}
func Test_normalizeAddress(t *testing.T) {
type args struct {
rawAddress string
targetScheme string
}
tests := []struct {
name string
args args
want string
}{
{
name: "normalAddress",
args: args{
rawAddress: address,
targetScheme: bitcoinScheme,
},
want: bitcoinScheme + address,
},
{
name: "bitcoinAddress",
args: args{
rawAddress: bitcoinScheme + address,
targetScheme: bitcoinScheme,
},
want: bitcoinScheme + address,
},
{
name: "muunAddress",
args: args{
rawAddress: muunScheme + address,
targetScheme: bitcoinScheme,
},
want: bitcoinScheme + address,
},
{
name: "muun to lightning",
args: args{
rawAddress: muunScheme + address,
targetScheme: lightningScheme,
},
want: lightningScheme + address,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := buildUriFromString(tt.args.rawAddress, tt.args.targetScheme); got != tt.want {
t.Errorf("buildUriFromString() = %v, want %v", got, tt.want)
}
})
}
}
func TestDoPaymentRequestCall(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("/payment-request/", func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Accept") != "application/bitcoin-paymentrequest" {
t.Fatal("expected Accept header to be application/bitcoin-paymentrequest")
}
script, _ := hex.DecodeString("76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac")
serializedPaymentDetails, _ := proto.Marshal(&PaymentDetails{
Network: "test",
Outputs: []*Output{
{
Script: script,
Amount: 2500,
},
},
Time: 100000,
Expires: 102000,
Memo: "Hello World",
PaymentUrl: "http://localhost:8000/pay",
MerchantData: []byte(""),
})
payReq, _ := proto.Marshal(&PaymentRequest{SerializedPaymentDetails: serializedPaymentDetails})
w.Write(payReq)
})
server := httptest.NewServer(mux)
defer server.Close()
url := server.URL + "/payment-request/"
paymentURI, err := DoPaymentRequestCall(url, Testnet())
if err != nil {
t.Fatal(err)
}
expected := &MuunPaymentURI{
Address: "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f",
Message: "Hello World",
Amount: "0.000025",
Bip70Url: url,
CreationTime: "100000",
ExpiresTime: "102000",
}
if !reflect.DeepEqual(paymentURI, expected) {
t.Fatalf("decoded URI struct does not match expected, %+v != %+v", paymentURI, expected)
}
}