github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/btc/bitcoinparser_test.go (about)

     1  //go:build unittest
     2  
     3  package btc
     4  
     5  import (
     6  	"encoding/hex"
     7  	"math/big"
     8  	"os"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"github.com/martinboehm/btcutil/chaincfg"
    13  	"github.com/trezor/blockbook/bchain"
    14  )
    15  
    16  func TestMain(m *testing.M) {
    17  	c := m.Run()
    18  	chaincfg.ResetParams()
    19  	os.Exit(c)
    20  }
    21  
    22  func TestGetAddrDescFromAddress(t *testing.T) {
    23  	type args struct {
    24  		address string
    25  	}
    26  	tests := []struct {
    27  		name    string
    28  		args    args
    29  		want    string
    30  		wantErr bool
    31  	}{
    32  		{
    33  			name:    "P2PKH",
    34  			args:    args{address: "1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"},
    35  			want:    "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac",
    36  			wantErr: false,
    37  		},
    38  		{
    39  			name:    "P2PKH from P2PK",
    40  			args:    args{address: "1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"},
    41  			want:    "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac",
    42  			wantErr: false,
    43  		},
    44  		{
    45  			name:    "P2SH",
    46  			args:    args{address: "321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"},
    47  			want:    "a9140394b3cf9a44782c10105b93962daa8dba304d7f87",
    48  			wantErr: false,
    49  		},
    50  		{
    51  			name:    "P2WPKH",
    52  			args:    args{address: "bc1qrsf2l34jvqnq0lduyz0j5pfu2nkd93nnq0qggn"},
    53  			want:    "00141c12afc6b2602607fdbc209f2a053c54ecd2c673",
    54  			wantErr: false,
    55  		},
    56  		{
    57  			name:    "P2WSH",
    58  			args:    args{address: "bc1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355sw5exgr"},
    59  			want:    "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
    60  			wantErr: false,
    61  		},
    62  		{
    63  			name:    " witness_unknown v1",
    64  			args:    args{address: "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y"},
    65  			want:    "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
    66  			wantErr: false,
    67  		},
    68  		{
    69  			name:    " witness_unknown v16",
    70  			args:    args{address: "bc1sw50qgdz25j"},
    71  			want:    "6002751e",
    72  			wantErr: false,
    73  		},
    74  	}
    75  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
    76  
    77  	for _, tt := range tests {
    78  		t.Run(tt.name, func(t *testing.T) {
    79  			got, err := parser.GetAddrDescFromAddress(tt.args.address)
    80  			if (err != nil) != tt.wantErr {
    81  				t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
    82  				return
    83  			}
    84  			h := hex.EncodeToString(got)
    85  			if !reflect.DeepEqual(h, tt.want) {
    86  				t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
    87  			}
    88  		})
    89  	}
    90  }
    91  
    92  func TestGetAddrDescFromAddressTestnet(t *testing.T) {
    93  	type args struct {
    94  		address string
    95  	}
    96  	tests := []struct {
    97  		name    string
    98  		args    args
    99  		want    string
   100  		wantErr bool
   101  	}{
   102  		{
   103  			name:    "pubkeyhash",
   104  			args:    args{address: "mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"},
   105  			want:    "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac",
   106  			wantErr: false,
   107  		},
   108  		{
   109  			name:    "scripthash",
   110  			args:    args{address: "2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"},
   111  			want:    "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487",
   112  			wantErr: false,
   113  		},
   114  		{
   115  			name:    "witness_v0_keyhash",
   116  			args:    args{address: "tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"},
   117  			want:    "0014e064dc594fec224afcb4c368ec86cc7a07813c3e",
   118  			wantErr: false,
   119  		},
   120  		{
   121  			name:    "witness_v0_scripthash",
   122  			args:    args{address: "tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"},
   123  			want:    "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
   124  			wantErr: false,
   125  		},
   126  		{
   127  			name:    "witness_v1_taproot",
   128  			args:    args{address: "tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"},
   129  			want:    "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603",
   130  			wantErr: false,
   131  		},
   132  	}
   133  	parser := NewBitcoinParser(GetChainParams("test"), &Configuration{})
   134  
   135  	for _, tt := range tests {
   136  		t.Run(tt.name, func(t *testing.T) {
   137  			got, err := parser.GetAddrDescFromAddress(tt.args.address)
   138  			if (err != nil) != tt.wantErr {
   139  				t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
   140  				return
   141  			}
   142  			h := hex.EncodeToString(got)
   143  			if !reflect.DeepEqual(h, tt.want) {
   144  				t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
   145  			}
   146  		})
   147  	}
   148  }
   149  
   150  func TestGetAddrDescFromVout(t *testing.T) {
   151  	type args struct {
   152  		vout bchain.Vout
   153  	}
   154  	tests := []struct {
   155  		name    string
   156  		args    args
   157  		want    string
   158  		wantErr bool
   159  	}{
   160  		{
   161  			name:    "P2PKH",
   162  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"}}},
   163  			want:    "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac",
   164  			wantErr: false,
   165  		},
   166  		{
   167  			name:    "P2PK compressed 1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg",
   168  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}}},
   169  			want:    "76a914f1dce4182fce875748c4986b240ff7d7bc3fffb088ac",
   170  			wantErr: false,
   171  		},
   172  		{
   173  			name:    "P2PK uncompressed 1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE",
   174  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}}},
   175  			want:    "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac",
   176  			wantErr: false,
   177  		},
   178  		{
   179  			name:    "P2SH",
   180  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"}}},
   181  			want:    "a9140394b3cf9a44782c10105b93962daa8dba304d7f87",
   182  			wantErr: false,
   183  		},
   184  		{
   185  			name:    "P2WPKH",
   186  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"}}},
   187  			want:    "00141c12afc6b2602607fdbc209f2a053c54ecd2c673",
   188  			wantErr: false,
   189  		},
   190  		{
   191  			name:    "P2WSH",
   192  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}}},
   193  			want:    "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
   194  			wantErr: false,
   195  		},
   196  	}
   197  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
   198  
   199  	for _, tt := range tests {
   200  		t.Run(tt.name, func(t *testing.T) {
   201  			got, err := parser.GetAddrDescFromVout(&tt.args.vout)
   202  			if (err != nil) != tt.wantErr {
   203  				t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr)
   204  				return
   205  			}
   206  			h := hex.EncodeToString(got)
   207  			if !reflect.DeepEqual(h, tt.want) {
   208  				t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want)
   209  			}
   210  		})
   211  	}
   212  }
   213  
   214  func TestGetAddressesFromAddrDesc(t *testing.T) {
   215  	type args struct {
   216  		script string
   217  	}
   218  	tests := []struct {
   219  		name    string
   220  		args    args
   221  		want    []string
   222  		want2   bool
   223  		wantErr bool
   224  	}{
   225  		{
   226  			name:    "P2PKH",
   227  			args:    args{script: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"},
   228  			want:    []string{"1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"},
   229  			want2:   true,
   230  			wantErr: false,
   231  		},
   232  		{
   233  			name:    "P2PK compressed",
   234  			args:    args{script: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"},
   235  			want:    []string{"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg"},
   236  			want2:   false,
   237  			wantErr: false,
   238  		},
   239  		{
   240  			name:    "P2PK uncompressed",
   241  			args:    args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"},
   242  			want:    []string{"1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"},
   243  			want2:   false,
   244  			wantErr: false,
   245  		},
   246  		{
   247  			name:    "P2SH",
   248  			args:    args{script: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"},
   249  			want:    []string{"321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"},
   250  			want2:   true,
   251  			wantErr: false,
   252  		},
   253  		{
   254  			name:    "P2WPKH",
   255  			args:    args{script: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"},
   256  			want:    []string{"bc1qrsf2l34jvqnq0lduyz0j5pfu2nkd93nnq0qggn"},
   257  			want2:   true,
   258  			wantErr: false,
   259  		},
   260  		{
   261  			name:    "P2WSH",
   262  			args:    args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"},
   263  			want:    []string{"bc1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355sw5exgr"},
   264  			want2:   true,
   265  			wantErr: false,
   266  		},
   267  		{
   268  			name:    "OP_RETURN ascii",
   269  			args:    args{script: "6a0461686f6a"},
   270  			want:    []string{"OP_RETURN (ahoj)"},
   271  			want2:   false,
   272  			wantErr: false,
   273  		},
   274  		{
   275  			name:    "OP_RETURN OP_PUSHDATA1 ascii",
   276  			args:    args{script: "6a4c0b446c6f7568792074657874"},
   277  			want:    []string{"OP_RETURN (Dlouhy text)"},
   278  			want2:   false,
   279  			wantErr: false,
   280  		},
   281  		{
   282  			name:    "OP_RETURN OP_PUSHDATA1 utf8",
   283  			args:    args{script: "6a31e5bfabe981a9e381ab4254434658e58f96e5bc95e3818ce381a7e3818de3828b5043e3818ce6acb2e38197e38184e38082"},
   284  			want:    []string{"OP_RETURN (快適にBTCFX取引ができるPCが欲しい。)"},
   285  			want2:   false,
   286  			wantErr: false,
   287  		},
   288  		{
   289  			name: "OP_RETURN OP_PUSHDATA2 ascii",
   290  			args: args{script: "6a4dd7035765277265206e6f20737472616e6765727320746f206c6f76650a596f75206b6e6f77207468652072756c657320616e6420736f20646f20490a412066756c6c20636f6d6d69746d656e74277320776861742049276d207468696e6b696e67206f660a596f7520776f756c646e27742067657420746869732066726f6d20616e79206f74686572206775790a49206a7573742077616e6e612074656c6c20796f7520686f772049276d206665656c696e670a476f747461206d616b6520796f7520756e6465727374616e640a0a43484f5255530a4e6576657220676f6e6e61206769766520796f752075702c0a4e6576657220676f6e6e61206c657420796f7520646f776e0a4e6576657220676f6e6e612072756e2061726f756e6420616e642064657365727420796f750a4e6576657220676f6e6e61206d616b6520796f75206372792c0a4e6576657220676f6e6e612073617920676f6f646279650a4e6576657220676f6e6e612074656c6c2061206c696520616e64206875727420796f750a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069740a416e6420696620796f752061736b206d6520686f772049276d206665656c696e670a446f6e27742074656c6c206d6520796f7527726520746f6f20626c696e6420746f20736565202843484f525553290a0a43484f52555343484f5255530a284f6f68206769766520796f75207570290a284f6f68206769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069742028544f2046524f4e54290a0a"},
   291  			want: []string{`OP_RETURN (We're no strangers to love
   292  You know the rules and so do I
   293  A full commitment's what I'm thinking of
   294  You wouldn't get this from any other guy
   295  I just wanna tell you how I'm feeling
   296  Gotta make you understand
   297  
   298  CHORUS
   299  Never gonna give you up,
   300  Never gonna let you down
   301  Never gonna run around and desert you
   302  Never gonna make you cry,
   303  Never gonna say goodbye
   304  Never gonna tell a lie and hurt you
   305  
   306  We've known each other for so long
   307  Your heart's been aching but you're too shy to say it
   308  Inside we both know what's been going on
   309  We know the game and we're gonna play it
   310  And if you ask me how I'm feeling
   311  Don't tell me you're too blind to see (CHORUS)
   312  
   313  CHORUSCHORUS
   314  (Ooh give you up)
   315  (Ooh give you up)
   316  (Ooh) never gonna give, never gonna give
   317  (give you up)
   318  (Ooh) never gonna give, never gonna give
   319  (give you up)
   320  
   321  We've known each other for so long
   322  Your heart's been aching but you're too shy to say it
   323  Inside we both know what's been going on
   324  We know the game and we're gonna play it (TO FRONT)
   325  
   326  )`},
   327  			want2:   false,
   328  			wantErr: false,
   329  		},
   330  		{
   331  			name:    "OP_RETURN hex",
   332  			args:    args{script: "6a072020f1686f6a20"},
   333  			want:    []string{"OP_RETURN 2020f1686f6a20"},
   334  			want2:   false,
   335  			wantErr: false,
   336  		},
   337  		{
   338  			name:    "OP_RETURN omni simple send tether",
   339  			args:    args{script: "6a146f6d6e69000000000000001f00000709bb647351"},
   340  			want:    []string{"OMNI Simple Send: 77383.80022609 TetherUS (#31)"},
   341  			want2:   false,
   342  			wantErr: false,
   343  		},
   344  		{
   345  			name:    "OP_RETURN omni simple send not supported coin",
   346  			args:    args{script: "6a146f6d6e69000000000000000300000709bb647351"},
   347  			want:    []string{"OP_RETURN 6f6d6e69000000000000000300000709bb647351"},
   348  			want2:   false,
   349  			wantErr: false,
   350  		},
   351  		{
   352  			name:    "OP_RETURN omni not supported version",
   353  			args:    args{script: "6a146f6d6e69010000000000000300000709bb647351"},
   354  			want:    []string{"OP_RETURN 6f6d6e69010000000000000300000709bb647351"},
   355  			want2:   false,
   356  			wantErr: false,
   357  		},
   358  	}
   359  
   360  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
   361  
   362  	for _, tt := range tests {
   363  		t.Run(tt.name, func(t *testing.T) {
   364  			b, _ := hex.DecodeString(tt.args.script)
   365  			got, got2, err := parser.GetAddressesFromAddrDesc(b)
   366  			if (err != nil) != tt.wantErr {
   367  				t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
   368  				return
   369  			}
   370  			if !reflect.DeepEqual(got, tt.want) {
   371  				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want)
   372  			}
   373  			if !reflect.DeepEqual(got2, tt.want2) {
   374  				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2)
   375  			}
   376  		})
   377  	}
   378  }
   379  
   380  func TestGetAddressesFromAddrDescTestnet(t *testing.T) {
   381  	type args struct {
   382  		script string
   383  	}
   384  	tests := []struct {
   385  		name    string
   386  		args    args
   387  		want    []string
   388  		want2   bool
   389  		wantErr bool
   390  	}{
   391  		{
   392  			name:    "pubkeyhash",
   393  			args:    args{script: "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac"},
   394  			want:    []string{"mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"},
   395  			want2:   true,
   396  			wantErr: false,
   397  		},
   398  		{
   399  			name:    "pubkey compressed",
   400  			args:    args{script: "2102a741071164b40b01c4ad28913c4aa2a1015cc5b064f0c802272552f17ae08750ac"},
   401  			want:    []string{"mkMe1fsfCWFext2qxf4bk3yiruBTvnici4"},
   402  			want2:   false,
   403  			wantErr: false,
   404  		},
   405  		{
   406  			name:    "pubkey uncompressed",
   407  			args:    args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"},
   408  			want:    []string{"mx43tNdg4JYY29ifrHjJpdbcCqqDGVSng5"},
   409  			want2:   false,
   410  			wantErr: false,
   411  		},
   412  		{
   413  			name:    "scripthash",
   414  			args:    args{script: "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487"},
   415  			want:    []string{"2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"},
   416  			want2:   true,
   417  			wantErr: false,
   418  		},
   419  		{
   420  			name:    "witness_v0_keyhash",
   421  			args:    args{script: "0014e064dc594fec224afcb4c368ec86cc7a07813c3e"},
   422  			want:    []string{"tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"},
   423  			want2:   true,
   424  			wantErr: false,
   425  		},
   426  		{
   427  			name:    "witness_v0_scripthash",
   428  			args:    args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"},
   429  			want:    []string{"tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"},
   430  			want2:   true,
   431  			wantErr: false,
   432  		},
   433  		{
   434  			name:    "witness_v1_taproot",
   435  			args:    args{script: "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603"},
   436  			want:    []string{"tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"},
   437  			want2:   true,
   438  			wantErr: false,
   439  		},
   440  		{
   441  			name:    "OP_RETURN ascii",
   442  			args:    args{script: "6a0461686f6a"},
   443  			want:    []string{"OP_RETURN (ahoj)"},
   444  			want2:   false,
   445  			wantErr: false,
   446  		},
   447  	}
   448  
   449  	parser := NewBitcoinParser(GetChainParams("test"), &Configuration{})
   450  
   451  	for _, tt := range tests {
   452  		t.Run(tt.name, func(t *testing.T) {
   453  			b, _ := hex.DecodeString(tt.args.script)
   454  			got, got2, err := parser.GetAddressesFromAddrDesc(b)
   455  			if (err != nil) != tt.wantErr {
   456  				t.Errorf("TestGetAddressesFromAddrDesc_Testnet() error = %v, wantErr %v", err, tt.wantErr)
   457  				return
   458  			}
   459  			if !reflect.DeepEqual(got, tt.want) {
   460  				t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got, tt.want)
   461  			}
   462  			if !reflect.DeepEqual(got2, tt.want2) {
   463  				t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got2, tt.want2)
   464  			}
   465  		})
   466  	}
   467  }
   468  
   469  var (
   470  	testTx1, testTx2, testTx3 bchain.Tx
   471  
   472  	testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
   473  	testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
   474  	testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
   475  )
   476  
   477  func init() {
   478  	testTx1 = bchain.Tx{
   479  		Hex:       "01000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700",
   480  		Blocktime: 1519053802,
   481  		Txid:      "056e3d82e5ffd0e915fb9b62797d76263508c34fe3e5dbed30dd3e943930f204",
   482  		LockTime:  512115,
   483  		VSize:     189,
   484  		Version:   1,
   485  		Vin: []bchain.Vin{
   486  			{
   487  				ScriptSig: bchain.ScriptSig{
   488  					Hex: "4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80",
   489  				},
   490  				Txid:     "425fed43ba74e9205875eb934d5bcf7bf338f146f70d4002d94bf5cbc9229a7f",
   491  				Vout:     4,
   492  				Sequence: 4294967294,
   493  			},
   494  		},
   495  		Vout: []bchain.Vout{
   496  			{
   497  				ValueSat: *big.NewInt(38812),
   498  				N:        0,
   499  				ScriptPubKey: bchain.ScriptPubKey{
   500  					Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
   501  					Addresses: []string{
   502  						"3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK",
   503  					},
   504  				},
   505  			},
   506  		},
   507  	}
   508  
   509  	testTx2 = bchain.Tx{
   510  		Hex:       "010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000",
   511  		Blocktime: 1235678901,
   512  		Txid:      "474e6795760ebe81cb4023dc227e5a0efe340e1771c89a0035276361ed733de7",
   513  		LockTime:  0,
   514  		VSize:     166,
   515  		Version:   1,
   516  		Vin: []bchain.Vin{
   517  			{
   518  				ScriptSig: bchain.ScriptSig{
   519  					Hex: "160014550da1f5d25a9dae2eafd6902b4194c4c6500af6",
   520  				},
   521  				Txid:     "c13e32a4428e31f85d7aee4ec7344504b12e72aaffcbde0160200d2ac7f0649d",
   522  				Vout:     0,
   523  				Sequence: 4294967295,
   524  			},
   525  		},
   526  		Vout: []bchain.Vout{
   527  			{
   528  				ValueSat: *big.NewInt(10000000),
   529  				N:        0,
   530  				ScriptPubKey: bchain.ScriptPubKey{
   531  					Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
   532  					Addresses: []string{
   533  						"2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu",
   534  					},
   535  				},
   536  			},
   537  			{
   538  				ValueSat: *big.NewInt(920081157),
   539  				N:        1,
   540  				ScriptPubKey: bchain.ScriptPubKey{
   541  					Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
   542  					Addresses: []string{
   543  						"2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D",
   544  					},
   545  				},
   546  			},
   547  		},
   548  	}
   549  
   550  	testTx3 = bchain.Tx{
   551  		Hex:       "02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000",
   552  		Blocktime: 1607805599,
   553  		Txid:      "24551a58a1d1fb89d7052e2bbac7cb69a7825ee1e39439befbec8c32148cf735",
   554  		LockTime:  15745,
   555  		VSize:     208,
   556  		Version:   2,
   557  		Vin: []bchain.Vin{
   558  			{
   559  				ScriptSig: bchain.ScriptSig{
   560  					Hex: "",
   561  				},
   562  				Txid:     "9d8b6a98d942ce077574fff2e5dd9e405ba75ed9fb126b3da1b07a859a99b1de",
   563  				Vout:     0,
   564  				Sequence: 4294967293,
   565  			},
   566  			{
   567  				ScriptSig: bchain.ScriptSig{
   568  					Hex: "",
   569  				},
   570  				Txid:     "98227ffe94726bc77c3c587e1e5375305beffb8e43a6eb75233b201e36d3d29f",
   571  				Vout:     0,
   572  				Sequence: 4294967293,
   573  			},
   574  		},
   575  		Vout: []bchain.Vout{
   576  			{
   577  				ValueSat: *big.NewInt(100000),
   578  				N:        0,
   579  				ScriptPubKey: bchain.ScriptPubKey{
   580  					Hex: "00148091746745464e7555c31e9a5afceac14a02978a",
   581  					Addresses: []string{
   582  						"tb1qszghge69ge8824wrr6d94l82c99q99u2ccgv5w",
   583  					},
   584  				},
   585  			},
   586  			{
   587  				ValueSat: *big.NewInt(1899751),
   588  				N:        1,
   589  				ScriptPubKey: bchain.ScriptPubKey{
   590  					Hex: "0014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e",
   591  					Addresses: []string{
   592  						"tb1q2e02nl6938f7qkapfxhxufth22lac2s792vsxp",
   593  					},
   594  				},
   595  			},
   596  		},
   597  	}
   598  }
   599  
   600  func TestPackTx(t *testing.T) {
   601  	type args struct {
   602  		tx        bchain.Tx
   603  		height    uint32
   604  		blockTime int64
   605  		parser    *BitcoinParser
   606  	}
   607  	tests := []struct {
   608  		name    string
   609  		args    args
   610  		want    string
   611  		wantErr bool
   612  	}{
   613  		{
   614  			name: "btc-1",
   615  			args: args{
   616  				tx:        testTx1,
   617  				height:    123456,
   618  				blockTime: 1519053802,
   619  				parser:    NewBitcoinParser(GetChainParams("main"), &Configuration{}),
   620  			},
   621  			want:    testTxPacked1,
   622  			wantErr: false,
   623  		},
   624  		{
   625  			name: "testnet-1",
   626  			args: args{
   627  				tx:        testTx2,
   628  				height:    510234,
   629  				blockTime: 1235678901,
   630  				parser:    NewBitcoinParser(GetChainParams("test"), &Configuration{}),
   631  			},
   632  			want:    testTxPacked2,
   633  			wantErr: false,
   634  		},
   635  		{
   636  			name: "signet-1",
   637  			args: args{
   638  				tx:        testTx3,
   639  				height:    15745,
   640  				blockTime: 1607805599,
   641  				parser:    NewBitcoinParser(GetChainParams("signet"), &Configuration{}),
   642  			},
   643  			want:    testTxPacked3,
   644  			wantErr: false,
   645  		},
   646  	}
   647  	for _, tt := range tests {
   648  		t.Run(tt.name, func(t *testing.T) {
   649  			got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
   650  			if (err != nil) != tt.wantErr {
   651  				t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
   652  				return
   653  			}
   654  			h := hex.EncodeToString(got)
   655  			if !reflect.DeepEqual(h, tt.want) {
   656  				t.Errorf("packTx() = %v, want %v", h, tt.want)
   657  			}
   658  		})
   659  	}
   660  }
   661  
   662  func TestUnpackTx(t *testing.T) {
   663  	type args struct {
   664  		packedTx string
   665  		parser   *BitcoinParser
   666  	}
   667  	tests := []struct {
   668  		name    string
   669  		args    args
   670  		want    *bchain.Tx
   671  		want1   uint32
   672  		wantErr bool
   673  	}{
   674  		{
   675  			name: "btc-1",
   676  			args: args{
   677  				packedTx: testTxPacked1,
   678  				parser:   NewBitcoinParser(GetChainParams("main"), &Configuration{}),
   679  			},
   680  			want:    &testTx1,
   681  			want1:   123456,
   682  			wantErr: false,
   683  		},
   684  		{
   685  			name: "testnet-1",
   686  			args: args{
   687  				packedTx: testTxPacked2,
   688  				parser:   NewBitcoinParser(GetChainParams("test"), &Configuration{}),
   689  			},
   690  			want:    &testTx2,
   691  			want1:   510234,
   692  			wantErr: false,
   693  		},
   694  		{
   695  			name: "signet-1",
   696  			args: args{
   697  				packedTx: testTxPacked3,
   698  				parser:   NewBitcoinParser(GetChainParams("signet"), &Configuration{}),
   699  			},
   700  			want:    &testTx3,
   701  			want1:   15745,
   702  			wantErr: false,
   703  		},
   704  	}
   705  	for _, tt := range tests {
   706  		t.Run(tt.name, func(t *testing.T) {
   707  			b, _ := hex.DecodeString(tt.args.packedTx)
   708  			got, got1, err := tt.args.parser.UnpackTx(b)
   709  			if (err != nil) != tt.wantErr {
   710  				t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
   711  				return
   712  			}
   713  			// ignore witness unpacking
   714  			for i := range got.Vin {
   715  				got.Vin[i].Witness = nil
   716  			}
   717  			if !reflect.DeepEqual(got, tt.want) {
   718  				t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
   719  			}
   720  			if got1 != tt.want1 {
   721  				t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
   722  			}
   723  		})
   724  	}
   725  }
   726  
   727  func TestParseXpubDescriptors(t *testing.T) {
   728  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   729  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
   730  	tests := []struct {
   731  		name    string
   732  		xpub    string
   733  		parser  *BitcoinParser
   734  		want    *bchain.XpubDescriptor
   735  		wantErr bool
   736  	}{
   737  		{
   738  			name:   "tpub",
   739  			xpub:   "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   740  			parser: btcTestnetParser,
   741  			want: &bchain.XpubDescriptor{
   742  				XpubDescriptor: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   743  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   744  				Type:           bchain.P2PKH,
   745  				Bip:            "44",
   746  				ChangeIndexes:  []uint32{0, 1},
   747  			},
   748  		},
   749  		{
   750  			name:   "tr(tpub)",
   751  			xpub:   "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)",
   752  			parser: btcTestnetParser,
   753  			want: &bchain.XpubDescriptor{
   754  				XpubDescriptor: "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)",
   755  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   756  				Type:           bchain.P2TR,
   757  				Bip:            "86",
   758  				ChangeIndexes:  []uint32{0, 1},
   759  			},
   760  		},
   761  		{
   762  			name:   "tr([5c9e228d/86'/1'/0']tpubD/{0,1,2}/*)#4rqwxvej",
   763  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej",
   764  			parser: btcTestnetParser,
   765  			want: &bchain.XpubDescriptor{
   766  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej",
   767  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   768  				Type:           bchain.P2TR,
   769  				Bip:            "86",
   770  				ChangeIndexes:  []uint32{0, 1, 2},
   771  			},
   772  		},
   773  		{
   774  			name:   "tr([5c9e228d/86'/1'/0']tpubD/<0;1;2>/*)#4rqwxvej",
   775  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej",
   776  			parser: btcTestnetParser,
   777  			want: &bchain.XpubDescriptor{
   778  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej",
   779  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   780  				Type:           bchain.P2TR,
   781  				Bip:            "86",
   782  				ChangeIndexes:  []uint32{0, 1, 2},
   783  			},
   784  		},
   785  		{
   786  			name:   "tr([5c9e228d/86'/1'/0']tpubD/3/*)#4rqwxvej",
   787  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej",
   788  			parser: btcTestnetParser,
   789  			want: &bchain.XpubDescriptor{
   790  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej",
   791  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   792  				Type:           bchain.P2TR,
   793  				Bip:            "86",
   794  				ChangeIndexes:  []uint32{3},
   795  			},
   796  		},
   797  		{
   798  			name:   "xpub",
   799  			xpub:   "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   800  			parser: btcMainParser,
   801  			want: &bchain.XpubDescriptor{
   802  				XpubDescriptor: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   803  				Xpub:           "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   804  				Type:           bchain.P2PKH,
   805  				Bip:            "44",
   806  				ChangeIndexes:  []uint32{0, 1},
   807  			},
   808  		},
   809  		{
   810  			name:   "ypub",
   811  			xpub:   "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   812  			parser: btcMainParser,
   813  			want: &bchain.XpubDescriptor{
   814  				XpubDescriptor: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   815  				Xpub:           "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   816  				Type:           bchain.P2SHWPKH,
   817  				Bip:            "49",
   818  				ChangeIndexes:  []uint32{0, 1},
   819  			},
   820  		},
   821  		{
   822  			name:   "zpub",
   823  			xpub:   "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   824  			parser: btcMainParser,
   825  			want: &bchain.XpubDescriptor{
   826  				XpubDescriptor: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   827  				Xpub:           "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   828  				Type:           bchain.P2WPKH,
   829  				Bip:            "84",
   830  				ChangeIndexes:  []uint32{0, 1},
   831  			},
   832  		},
   833  		{
   834  			name:   "sh(wpkh([5c9e228d/99'/0'/0']xpub/{122,123,4431}/*))",
   835  			xpub:   "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))",
   836  			parser: btcMainParser,
   837  			want: &bchain.XpubDescriptor{
   838  				XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))",
   839  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   840  				Type:           bchain.P2SHWPKH,
   841  				Bip:            "99",
   842  				ChangeIndexes:  []uint32{122, 123, 4431},
   843  			},
   844  		},
   845  		{
   846  			name:   "sh(wpkh([5c9e228d/99'/0'/0']xpub/<122;123;4431>/*))",
   847  			xpub:   "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))",
   848  			parser: btcMainParser,
   849  			want: &bchain.XpubDescriptor{
   850  				XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))",
   851  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   852  				Type:           bchain.P2SHWPKH,
   853  				Bip:            "99",
   854  				ChangeIndexes:  []uint32{122, 123, 4431},
   855  			},
   856  		},
   857  		{
   858  			name:   "pkh(xpub)",
   859  			xpub:   "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   860  			parser: btcMainParser,
   861  			want: &bchain.XpubDescriptor{
   862  				XpubDescriptor: "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   863  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   864  				Type:           bchain.P2PKH,
   865  				Bip:            "44",
   866  				ChangeIndexes:  []uint32{0, 1},
   867  			},
   868  		},
   869  		{
   870  			name:   "sh(wpkh(xpub))",
   871  			xpub:   "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))",
   872  			parser: btcMainParser,
   873  			want: &bchain.XpubDescriptor{
   874  				XpubDescriptor: "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))",
   875  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   876  				Type:           bchain.P2SHWPKH,
   877  				Bip:            "49",
   878  				ChangeIndexes:  []uint32{0, 1},
   879  			},
   880  		},
   881  		{
   882  			name:   "wpkh(xpub)",
   883  			xpub:   "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   884  			parser: btcMainParser,
   885  			want: &bchain.XpubDescriptor{
   886  				XpubDescriptor: "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   887  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   888  				Type:           bchain.P2WPKH,
   889  				Bip:            "84",
   890  				ChangeIndexes:  []uint32{0, 1},
   891  			},
   892  		},
   893  		{
   894  			name:    "xxx(xpub) error - unknown output script",
   895  			xpub:    "xxx(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   896  			parser:  btcMainParser,
   897  			wantErr: true,
   898  		},
   899  		{
   900  			name:    "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1)) error - * in index is mandatory",
   901  			xpub:    "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1))",
   902  			parser:  btcMainParser,
   903  			wantErr: true,
   904  		},
   905  		{
   906  			name:    "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1) error - path too long",
   907  			xpub:    "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1/*))",
   908  			parser:  btcMainParser,
   909  			wantErr: true,
   910  		},
   911  	}
   912  	for _, tt := range tests {
   913  		t.Run(tt.name, func(t *testing.T) {
   914  			got, err := tt.parser.ParseXpub(tt.xpub)
   915  			if (err != nil) != tt.wantErr {
   916  				t.Errorf("ParseXpub() error = %v, wantErr %v", err, tt.wantErr)
   917  				return
   918  			}
   919  			if err == nil {
   920  				if got.ExtKey == nil {
   921  					t.Errorf("ParseXpub() got nil ExtKey")
   922  					return
   923  				}
   924  				got.ExtKey = nil
   925  				if !reflect.DeepEqual(got, tt.want) {
   926  					t.Errorf("ParseXpub() = %+v, want %+v", got, tt.want)
   927  				}
   928  			}
   929  		})
   930  	}
   931  }
   932  
   933  func TestDeriveAddressDescriptors(t *testing.T) {
   934  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   935  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
   936  	type args struct {
   937  		xpub    string
   938  		change  uint32
   939  		indexes []uint32
   940  		parser  *BitcoinParser
   941  	}
   942  	tests := []struct {
   943  		name    string
   944  		args    args
   945  		want    []string
   946  		wantErr bool
   947  	}{
   948  		{
   949  			name: "m/86'/1'/0'",
   950  			args: args{
   951  				xpub:    "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej",
   952  				change:  0,
   953  				indexes: []uint32{0, 1, 10},
   954  				parser:  btcTestnetParser,
   955  			},
   956  			want: []string{"tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u", "tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald", "tb1pqr4803xedptkvsr6ksed2m7fx780y3u8shnd0fqdupnc0w75262sl49kwz"},
   957  		},
   958  		{
   959  			name: "m/86'/0'/0'",
   960  			args: args{
   961  				xpub:    "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
   962  				change:  0,
   963  				indexes: []uint32{0, 1},
   964  				parser:  btcMainParser,
   965  			},
   966  			want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr", "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh"},
   967  		},
   968  		{
   969  			name: "m/86'/0'/0'/1",
   970  			args: args{
   971  				xpub:    "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
   972  				change:  1,
   973  				indexes: []uint32{0},
   974  				parser:  btcMainParser,
   975  			},
   976  			want: []string{"bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7"},
   977  		},
   978  		{
   979  			name: "m/44'/0'/0'",
   980  			args: args{
   981  				xpub:    "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   982  				change:  0,
   983  				indexes: []uint32{0, 1234},
   984  				parser:  btcMainParser,
   985  			},
   986  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", "1P9w11dXAmG3QBjKLAvCsek8izs1iR2iFi"},
   987  		},
   988  		{
   989  			name: "m/49'/0'/0'",
   990  			args: args{
   991  				xpub:    "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   992  				change:  0,
   993  				indexes: []uint32{0, 1234},
   994  				parser:  btcMainParser,
   995  			},
   996  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", "367meFzJ9KqDLm9PX6U8Z8RdmkSNBuxX8T"},
   997  		},
   998  		{
   999  			name: "m/84'/0'/0'",
  1000  			args: args{
  1001  				xpub:    "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
  1002  				change:  0,
  1003  				indexes: []uint32{0, 1234},
  1004  				parser:  btcMainParser,
  1005  			},
  1006  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "bc1q4nm6g46ujzyjaeusralaz2nfv2rf04jjfyamkw"},
  1007  		},
  1008  	}
  1009  	for _, tt := range tests {
  1010  		t.Run(tt.name, func(t *testing.T) {
  1011  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1012  			if err != nil {
  1013  				t.Errorf("ParseXpub() error = %v", err)
  1014  				return
  1015  			}
  1016  			got, err := tt.args.parser.DeriveAddressDescriptors(descriptor, tt.args.change, tt.args.indexes)
  1017  			if (err != nil) != tt.wantErr {
  1018  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
  1019  				return
  1020  			}
  1021  			gotAddresses := make([]string, len(got))
  1022  			for i, ad := range got {
  1023  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
  1024  				if err != nil || len(aa) != 1 {
  1025  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
  1026  					return
  1027  				}
  1028  				gotAddresses[i] = aa[0]
  1029  			}
  1030  			if !reflect.DeepEqual(gotAddresses, tt.want) {
  1031  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
  1032  			}
  1033  		})
  1034  	}
  1035  }
  1036  
  1037  func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
  1038  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1039  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
  1040  	type args struct {
  1041  		xpub      string
  1042  		change    uint32
  1043  		fromIndex uint32
  1044  		toIndex   uint32
  1045  		parser    *BitcoinParser
  1046  	}
  1047  	tests := []struct {
  1048  		name    string
  1049  		args    args
  1050  		want    []string
  1051  		wantErr bool
  1052  	}{
  1053  		{
  1054  			name: "m/44'/0'/0'",
  1055  			args: args{
  1056  				xpub:      "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
  1057  				change:    0,
  1058  				fromIndex: 0,
  1059  				toIndex:   1,
  1060  				parser:    btcMainParser,
  1061  			},
  1062  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"},
  1063  		},
  1064  		{
  1065  			name: "m/49'/0'/0'",
  1066  			args: args{
  1067  				xpub:      "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
  1068  				change:    0,
  1069  				fromIndex: 0,
  1070  				toIndex:   1,
  1071  				parser:    btcMainParser,
  1072  			},
  1073  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"},
  1074  		},
  1075  		{
  1076  			name: "m/84'/0'/0'",
  1077  			args: args{
  1078  				xpub:      "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
  1079  				change:    0,
  1080  				fromIndex: 0,
  1081  				toIndex:   1,
  1082  				parser:    btcMainParser,
  1083  			},
  1084  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"},
  1085  		},
  1086  		{
  1087  			name: "m/86'/0'/0'",
  1088  			args: args{
  1089  				xpub:      "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
  1090  				change:    0,
  1091  				fromIndex: 0,
  1092  				toIndex:   1,
  1093  				parser:    btcMainParser,
  1094  			},
  1095  			want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"},
  1096  		},
  1097  		{
  1098  			name: "m/49'/1'/0'",
  1099  			args: args{
  1100  				xpub:      "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
  1101  				change:    0,
  1102  				fromIndex: 0,
  1103  				toIndex:   10,
  1104  				parser:    btcTestnetParser,
  1105  			},
  1106  			want: []string{"2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", "2Mt7P2BAfE922zmfXrdcYTLyR7GUvbwSEns", "2N6aUMgQk8y1zvoq6FeWFyotyj75WY9BGsu", "2NA7tbZWM9BcRwBuebKSQe2xbhhF1paJwBM", "2N8RZMzvrUUnpLmvACX9ysmJ2MX3GK5jcQM", "2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe", "2NBXaWu1HazjoUVgrXgcKNoBLhtkkD9Gmet", "2N791Ttf89tMVw2maj86E1Y3VgxD9Mc7PU7", "2NCJmwEq8GJm8t8GWWyBXAfpw7F2qZEVP5Y", "2NEgW71hWKer2XCSA8ZCC2VnWpB77L6bk68"},
  1107  		},
  1108  	}
  1109  	for _, tt := range tests {
  1110  		t.Run(tt.name, func(t *testing.T) {
  1111  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1112  			if err != nil {
  1113  				t.Errorf("ParseXpub() error = %v", err)
  1114  				return
  1115  			}
  1116  			got, err := tt.args.parser.DeriveAddressDescriptorsFromTo(descriptor, tt.args.change, tt.args.fromIndex, tt.args.toIndex)
  1117  			if (err != nil) != tt.wantErr {
  1118  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
  1119  				return
  1120  			}
  1121  			gotAddresses := make([]string, len(got))
  1122  			for i, ad := range got {
  1123  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
  1124  				if err != nil || len(aa) != 1 {
  1125  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
  1126  					return
  1127  				}
  1128  				gotAddresses[i] = aa[0]
  1129  			}
  1130  			if !reflect.DeepEqual(gotAddresses, tt.want) {
  1131  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
  1132  			}
  1133  		})
  1134  	}
  1135  }
  1136  
  1137  func BenchmarkDeriveAddressDescriptorsFromToXpub(b *testing.B) {
  1138  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1139  	for i := 0; i < b.N; i++ {
  1140  		descriptor, _ := btcMainParser.ParseXpub("xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj")
  1141  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1142  	}
  1143  }
  1144  
  1145  func BenchmarkDeriveAddressDescriptorsFromToYpub(b *testing.B) {
  1146  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1147  	for i := 0; i < b.N; i++ {
  1148  		descriptor, _ := btcMainParser.ParseXpub("ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP")
  1149  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1150  	}
  1151  }
  1152  
  1153  func BenchmarkDeriveAddressDescriptorsFromToZpub(b *testing.B) {
  1154  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1155  	for i := 0; i < b.N; i++ {
  1156  		descriptor, _ := btcMainParser.ParseXpub("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs")
  1157  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1158  	}
  1159  }
  1160  
  1161  func TestBitcoinParser_DerivationBasePath(t *testing.T) {
  1162  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518, Slip44: 0})
  1163  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198, Slip44: 1})
  1164  	zecMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, Slip44: 133})
  1165  	type args struct {
  1166  		xpub   string
  1167  		parser *BitcoinParser
  1168  	}
  1169  	tests := []struct {
  1170  		name    string
  1171  		args    args
  1172  		want    string
  1173  		wantErr bool
  1174  	}{
  1175  		{
  1176  			name: "m/86'/1'/0'",
  1177  			args: args{
  1178  				xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej",
  1179  				parser: btcTestnetParser,
  1180  			},
  1181  			want: "m/86'/1'/0'",
  1182  		},
  1183  		{
  1184  			name: "m/86'/0'/0'",
  1185  			args: args{
  1186  				xpub:   "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
  1187  				parser: btcMainParser,
  1188  			},
  1189  			want: "m/86'/0'/0'",
  1190  		},
  1191  		{
  1192  			name: "m/84'/0'/0'",
  1193  			args: args{
  1194  				xpub:   "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
  1195  				parser: btcMainParser,
  1196  			},
  1197  			want: "m/84'/0'/0'",
  1198  		},
  1199  		{
  1200  			name: "m/49'/0'/55 - not hardened account",
  1201  			args: args{
  1202  				xpub:   "ypub6XKbB5DJRAbW4TRJLp4uXQXG3ob5BtByXsNZFBjq9qcbzrczjVXfCz5cEo1SFDexmeWRnbCMDaRgaW4m9d2nBaa8FvUQCu3n9G1UBR8WhbT",
  1203  				parser: btcMainParser,
  1204  			},
  1205  			want: "m/49'/0'/55",
  1206  		},
  1207  		{
  1208  			name: "m/49'/0' - incomplete path, without account",
  1209  			args: args{
  1210  				xpub:   "ypub6UzM8PUqxcSoqC9gumfoiFhE8Qt84HbGpCD4eVJfJAojXTVtBxeddvTWJGJhGoaVBNJLmEgMdLXHgaLVJa4xEvk2tcokkdZhFdkxMLUE9sB",
  1211  				parser: btcMainParser,
  1212  			},
  1213  			want: "unknown/0'",
  1214  		},
  1215  		{
  1216  			name: "m/49'/1'/0'",
  1217  			args: args{
  1218  				xpub:   "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
  1219  				parser: btcTestnetParser,
  1220  			},
  1221  			want: "m/49'/1'/0'",
  1222  		},
  1223  		{
  1224  			name: "m/44'/133'/12'",
  1225  			args: args{
  1226  				xpub:   "xpub6CQdEahwhKRTLYpP6cyb7ZaGb3r4tVdyPX6dC1PfrNuByrCkWDgUkmpD28UdV9QccKgY1ZiAbGv1Fakcg2LxdFVSTNKHcjdRjqhjPK8Trkb",
  1227  				parser: zecMainParser,
  1228  			},
  1229  			want: "m/44'/133'/12'",
  1230  		},
  1231  	}
  1232  	for _, tt := range tests {
  1233  		t.Run(tt.name, func(t *testing.T) {
  1234  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1235  			if err != nil {
  1236  				t.Errorf("ParseXpub() error = %v", err)
  1237  				return
  1238  			}
  1239  			got, err := tt.args.parser.DerivationBasePath(descriptor)
  1240  			if (err != nil) != tt.wantErr {
  1241  				t.Errorf("BitcoinParser.DerivationBasePath() error = %v, wantErr %v", err, tt.wantErr)
  1242  				return
  1243  			}
  1244  			if got != tt.want {
  1245  				t.Errorf("BitcoinParser.DerivationBasePath() = %v, want %v", got, tt.want)
  1246  			}
  1247  		})
  1248  	}
  1249  }