github.com/cryptohub-digital/blockbook-fork@v0.0.0-20230713133354-673c927af7f1/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/cryptohub-digital/blockbook-fork/bchain"
    13  	"github.com/martinboehm/btcutil/chaincfg"
    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  			if !reflect.DeepEqual(got, tt.want) {
   714  				t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
   715  			}
   716  			if got1 != tt.want1 {
   717  				t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
   718  			}
   719  		})
   720  	}
   721  }
   722  
   723  func TestParseXpubDescriptors(t *testing.T) {
   724  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   725  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
   726  	tests := []struct {
   727  		name    string
   728  		xpub    string
   729  		parser  *BitcoinParser
   730  		want    *bchain.XpubDescriptor
   731  		wantErr bool
   732  	}{
   733  		{
   734  			name:   "tpub",
   735  			xpub:   "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   736  			parser: btcTestnetParser,
   737  			want: &bchain.XpubDescriptor{
   738  				XpubDescriptor: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   739  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   740  				Type:           bchain.P2PKH,
   741  				Bip:            "44",
   742  				ChangeIndexes:  []uint32{0, 1},
   743  			},
   744  		},
   745  		{
   746  			name:   "tr(tpub)",
   747  			xpub:   "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)",
   748  			parser: btcTestnetParser,
   749  			want: &bchain.XpubDescriptor{
   750  				XpubDescriptor: "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)",
   751  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   752  				Type:           bchain.P2TR,
   753  				Bip:            "86",
   754  				ChangeIndexes:  []uint32{0, 1},
   755  			},
   756  		},
   757  		{
   758  			name:   "tr([5c9e228d/86'/1'/0']tpubD/{0,1,2}/*)#4rqwxvej",
   759  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej",
   760  			parser: btcTestnetParser,
   761  			want: &bchain.XpubDescriptor{
   762  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej",
   763  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   764  				Type:           bchain.P2TR,
   765  				Bip:            "86",
   766  				ChangeIndexes:  []uint32{0, 1, 2},
   767  			},
   768  		},
   769  		{
   770  			name:   "tr([5c9e228d/86'/1'/0']tpubD/<0;1;2>/*)#4rqwxvej",
   771  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej",
   772  			parser: btcTestnetParser,
   773  			want: &bchain.XpubDescriptor{
   774  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej",
   775  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   776  				Type:           bchain.P2TR,
   777  				Bip:            "86",
   778  				ChangeIndexes:  []uint32{0, 1, 2},
   779  			},
   780  		},
   781  		{
   782  			name:   "tr([5c9e228d/86'/1'/0']tpubD/3/*)#4rqwxvej",
   783  			xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej",
   784  			parser: btcTestnetParser,
   785  			want: &bchain.XpubDescriptor{
   786  				XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej",
   787  				Xpub:           "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN",
   788  				Type:           bchain.P2TR,
   789  				Bip:            "86",
   790  				ChangeIndexes:  []uint32{3},
   791  			},
   792  		},
   793  		{
   794  			name:   "xpub",
   795  			xpub:   "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   796  			parser: btcMainParser,
   797  			want: &bchain.XpubDescriptor{
   798  				XpubDescriptor: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   799  				Xpub:           "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   800  				Type:           bchain.P2PKH,
   801  				Bip:            "44",
   802  				ChangeIndexes:  []uint32{0, 1},
   803  			},
   804  		},
   805  		{
   806  			name:   "ypub",
   807  			xpub:   "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   808  			parser: btcMainParser,
   809  			want: &bchain.XpubDescriptor{
   810  				XpubDescriptor: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   811  				Xpub:           "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   812  				Type:           bchain.P2SHWPKH,
   813  				Bip:            "49",
   814  				ChangeIndexes:  []uint32{0, 1},
   815  			},
   816  		},
   817  		{
   818  			name:   "zpub",
   819  			xpub:   "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   820  			parser: btcMainParser,
   821  			want: &bchain.XpubDescriptor{
   822  				XpubDescriptor: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   823  				Xpub:           "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   824  				Type:           bchain.P2WPKH,
   825  				Bip:            "84",
   826  				ChangeIndexes:  []uint32{0, 1},
   827  			},
   828  		},
   829  		{
   830  			name:   "sh(wpkh([5c9e228d/99'/0'/0']xpub/{122,123,4431}/*))",
   831  			xpub:   "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))",
   832  			parser: btcMainParser,
   833  			want: &bchain.XpubDescriptor{
   834  				XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))",
   835  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   836  				Type:           bchain.P2SHWPKH,
   837  				Bip:            "99",
   838  				ChangeIndexes:  []uint32{122, 123, 4431},
   839  			},
   840  		},
   841  		{
   842  			name:   "sh(wpkh([5c9e228d/99'/0'/0']xpub/<122;123;4431>/*))",
   843  			xpub:   "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))",
   844  			parser: btcMainParser,
   845  			want: &bchain.XpubDescriptor{
   846  				XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))",
   847  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   848  				Type:           bchain.P2SHWPKH,
   849  				Bip:            "99",
   850  				ChangeIndexes:  []uint32{122, 123, 4431},
   851  			},
   852  		},
   853  		{
   854  			name:   "pkh(xpub)",
   855  			xpub:   "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   856  			parser: btcMainParser,
   857  			want: &bchain.XpubDescriptor{
   858  				XpubDescriptor: "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   859  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   860  				Type:           bchain.P2PKH,
   861  				Bip:            "44",
   862  				ChangeIndexes:  []uint32{0, 1},
   863  			},
   864  		},
   865  		{
   866  			name:   "sh(wpkh(xpub))",
   867  			xpub:   "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))",
   868  			parser: btcMainParser,
   869  			want: &bchain.XpubDescriptor{
   870  				XpubDescriptor: "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))",
   871  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   872  				Type:           bchain.P2SHWPKH,
   873  				Bip:            "49",
   874  				ChangeIndexes:  []uint32{0, 1},
   875  			},
   876  		},
   877  		{
   878  			name:   "wpkh(xpub)",
   879  			xpub:   "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   880  			parser: btcMainParser,
   881  			want: &bchain.XpubDescriptor{
   882  				XpubDescriptor: "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   883  				Xpub:           "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ",
   884  				Type:           bchain.P2WPKH,
   885  				Bip:            "84",
   886  				ChangeIndexes:  []uint32{0, 1},
   887  			},
   888  		},
   889  		{
   890  			name:    "xxx(xpub) error - unknown output script",
   891  			xpub:    "xxx(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)",
   892  			parser:  btcMainParser,
   893  			wantErr: true,
   894  		},
   895  		{
   896  			name:    "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1)) error - * in index is mandatory",
   897  			xpub:    "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1))",
   898  			parser:  btcMainParser,
   899  			wantErr: true,
   900  		},
   901  		{
   902  			name:    "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1) error - path too long",
   903  			xpub:    "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1/*))",
   904  			parser:  btcMainParser,
   905  			wantErr: true,
   906  		},
   907  	}
   908  	for _, tt := range tests {
   909  		t.Run(tt.name, func(t *testing.T) {
   910  			got, err := tt.parser.ParseXpub(tt.xpub)
   911  			if (err != nil) != tt.wantErr {
   912  				t.Errorf("ParseXpub() error = %v, wantErr %v", err, tt.wantErr)
   913  				return
   914  			}
   915  			if err == nil {
   916  				if got.ExtKey == nil {
   917  					t.Errorf("ParseXpub() got nil ExtKey")
   918  					return
   919  				}
   920  				got.ExtKey = nil
   921  				if !reflect.DeepEqual(got, tt.want) {
   922  					t.Errorf("ParseXpub() = %+v, want %+v", got, tt.want)
   923  				}
   924  			}
   925  		})
   926  	}
   927  }
   928  
   929  func TestDeriveAddressDescriptors(t *testing.T) {
   930  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   931  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
   932  	type args struct {
   933  		xpub    string
   934  		change  uint32
   935  		indexes []uint32
   936  		parser  *BitcoinParser
   937  	}
   938  	tests := []struct {
   939  		name    string
   940  		args    args
   941  		want    []string
   942  		wantErr bool
   943  	}{
   944  		{
   945  			name: "m/86'/1'/0'",
   946  			args: args{
   947  				xpub:    "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej",
   948  				change:  0,
   949  				indexes: []uint32{0, 1, 10},
   950  				parser:  btcTestnetParser,
   951  			},
   952  			want: []string{"tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u", "tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald", "tb1pqr4803xedptkvsr6ksed2m7fx780y3u8shnd0fqdupnc0w75262sl49kwz"},
   953  		},
   954  		{
   955  			name: "m/86'/0'/0'",
   956  			args: args{
   957  				xpub:    "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
   958  				change:  0,
   959  				indexes: []uint32{0, 1},
   960  				parser:  btcMainParser,
   961  			},
   962  			want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr", "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh"},
   963  		},
   964  		{
   965  			name: "m/86'/0'/0'/1",
   966  			args: args{
   967  				xpub:    "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
   968  				change:  1,
   969  				indexes: []uint32{0},
   970  				parser:  btcMainParser,
   971  			},
   972  			want: []string{"bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7"},
   973  		},
   974  		{
   975  			name: "m/44'/0'/0'",
   976  			args: args{
   977  				xpub:    "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   978  				change:  0,
   979  				indexes: []uint32{0, 1234},
   980  				parser:  btcMainParser,
   981  			},
   982  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", "1P9w11dXAmG3QBjKLAvCsek8izs1iR2iFi"},
   983  		},
   984  		{
   985  			name: "m/49'/0'/0'",
   986  			args: args{
   987  				xpub:    "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   988  				change:  0,
   989  				indexes: []uint32{0, 1234},
   990  				parser:  btcMainParser,
   991  			},
   992  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", "367meFzJ9KqDLm9PX6U8Z8RdmkSNBuxX8T"},
   993  		},
   994  		{
   995  			name: "m/84'/0'/0'",
   996  			args: args{
   997  				xpub:    "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   998  				change:  0,
   999  				indexes: []uint32{0, 1234},
  1000  				parser:  btcMainParser,
  1001  			},
  1002  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "bc1q4nm6g46ujzyjaeusralaz2nfv2rf04jjfyamkw"},
  1003  		},
  1004  	}
  1005  	for _, tt := range tests {
  1006  		t.Run(tt.name, func(t *testing.T) {
  1007  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1008  			if err != nil {
  1009  				t.Errorf("ParseXpub() error = %v", err)
  1010  				return
  1011  			}
  1012  			got, err := tt.args.parser.DeriveAddressDescriptors(descriptor, tt.args.change, tt.args.indexes)
  1013  			if (err != nil) != tt.wantErr {
  1014  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
  1015  				return
  1016  			}
  1017  			gotAddresses := make([]string, len(got))
  1018  			for i, ad := range got {
  1019  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
  1020  				if err != nil || len(aa) != 1 {
  1021  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
  1022  					return
  1023  				}
  1024  				gotAddresses[i] = aa[0]
  1025  			}
  1026  			if !reflect.DeepEqual(gotAddresses, tt.want) {
  1027  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
  1028  			}
  1029  		})
  1030  	}
  1031  }
  1032  
  1033  func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
  1034  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1035  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
  1036  	type args struct {
  1037  		xpub      string
  1038  		change    uint32
  1039  		fromIndex uint32
  1040  		toIndex   uint32
  1041  		parser    *BitcoinParser
  1042  	}
  1043  	tests := []struct {
  1044  		name    string
  1045  		args    args
  1046  		want    []string
  1047  		wantErr bool
  1048  	}{
  1049  		{
  1050  			name: "m/44'/0'/0'",
  1051  			args: args{
  1052  				xpub:      "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
  1053  				change:    0,
  1054  				fromIndex: 0,
  1055  				toIndex:   1,
  1056  				parser:    btcMainParser,
  1057  			},
  1058  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"},
  1059  		},
  1060  		{
  1061  			name: "m/49'/0'/0'",
  1062  			args: args{
  1063  				xpub:      "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
  1064  				change:    0,
  1065  				fromIndex: 0,
  1066  				toIndex:   1,
  1067  				parser:    btcMainParser,
  1068  			},
  1069  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"},
  1070  		},
  1071  		{
  1072  			name: "m/84'/0'/0'",
  1073  			args: args{
  1074  				xpub:      "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
  1075  				change:    0,
  1076  				fromIndex: 0,
  1077  				toIndex:   1,
  1078  				parser:    btcMainParser,
  1079  			},
  1080  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"},
  1081  		},
  1082  		{
  1083  			name: "m/86'/0'/0'",
  1084  			args: args{
  1085  				xpub:      "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
  1086  				change:    0,
  1087  				fromIndex: 0,
  1088  				toIndex:   1,
  1089  				parser:    btcMainParser,
  1090  			},
  1091  			want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"},
  1092  		},
  1093  		{
  1094  			name: "m/49'/1'/0'",
  1095  			args: args{
  1096  				xpub:      "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
  1097  				change:    0,
  1098  				fromIndex: 0,
  1099  				toIndex:   10,
  1100  				parser:    btcTestnetParser,
  1101  			},
  1102  			want: []string{"2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", "2Mt7P2BAfE922zmfXrdcYTLyR7GUvbwSEns", "2N6aUMgQk8y1zvoq6FeWFyotyj75WY9BGsu", "2NA7tbZWM9BcRwBuebKSQe2xbhhF1paJwBM", "2N8RZMzvrUUnpLmvACX9ysmJ2MX3GK5jcQM", "2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe", "2NBXaWu1HazjoUVgrXgcKNoBLhtkkD9Gmet", "2N791Ttf89tMVw2maj86E1Y3VgxD9Mc7PU7", "2NCJmwEq8GJm8t8GWWyBXAfpw7F2qZEVP5Y", "2NEgW71hWKer2XCSA8ZCC2VnWpB77L6bk68"},
  1103  		},
  1104  	}
  1105  	for _, tt := range tests {
  1106  		t.Run(tt.name, func(t *testing.T) {
  1107  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1108  			if err != nil {
  1109  				t.Errorf("ParseXpub() error = %v", err)
  1110  				return
  1111  			}
  1112  			got, err := tt.args.parser.DeriveAddressDescriptorsFromTo(descriptor, tt.args.change, tt.args.fromIndex, tt.args.toIndex)
  1113  			if (err != nil) != tt.wantErr {
  1114  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
  1115  				return
  1116  			}
  1117  			gotAddresses := make([]string, len(got))
  1118  			for i, ad := range got {
  1119  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
  1120  				if err != nil || len(aa) != 1 {
  1121  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
  1122  					return
  1123  				}
  1124  				gotAddresses[i] = aa[0]
  1125  			}
  1126  			if !reflect.DeepEqual(gotAddresses, tt.want) {
  1127  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
  1128  			}
  1129  		})
  1130  	}
  1131  }
  1132  
  1133  func BenchmarkDeriveAddressDescriptorsFromToXpub(b *testing.B) {
  1134  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1135  	for i := 0; i < b.N; i++ {
  1136  		descriptor, _ := btcMainParser.ParseXpub("xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj")
  1137  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1138  	}
  1139  }
  1140  
  1141  func BenchmarkDeriveAddressDescriptorsFromToYpub(b *testing.B) {
  1142  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1143  	for i := 0; i < b.N; i++ {
  1144  		descriptor, _ := btcMainParser.ParseXpub("ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP")
  1145  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1146  	}
  1147  }
  1148  
  1149  func BenchmarkDeriveAddressDescriptorsFromToZpub(b *testing.B) {
  1150  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
  1151  	for i := 0; i < b.N; i++ {
  1152  		descriptor, _ := btcMainParser.ParseXpub("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs")
  1153  		btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100)
  1154  	}
  1155  }
  1156  
  1157  func TestBitcoinParser_DerivationBasePath(t *testing.T) {
  1158  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518, Slip44: 0})
  1159  	btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198, Slip44: 1})
  1160  	zecMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, Slip44: 133})
  1161  	type args struct {
  1162  		xpub   string
  1163  		parser *BitcoinParser
  1164  	}
  1165  	tests := []struct {
  1166  		name    string
  1167  		args    args
  1168  		want    string
  1169  		wantErr bool
  1170  	}{
  1171  		{
  1172  			name: "m/86'/1'/0'",
  1173  			args: args{
  1174  				xpub:   "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej",
  1175  				parser: btcTestnetParser,
  1176  			},
  1177  			want: "m/86'/1'/0'",
  1178  		},
  1179  		{
  1180  			name: "m/86'/0'/0'",
  1181  			args: args{
  1182  				xpub:   "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr",
  1183  				parser: btcMainParser,
  1184  			},
  1185  			want: "m/86'/0'/0'",
  1186  		},
  1187  		{
  1188  			name: "m/84'/0'/0'",
  1189  			args: args{
  1190  				xpub:   "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
  1191  				parser: btcMainParser,
  1192  			},
  1193  			want: "m/84'/0'/0'",
  1194  		},
  1195  		{
  1196  			name: "m/49'/0'/55 - not hardened account",
  1197  			args: args{
  1198  				xpub:   "ypub6XKbB5DJRAbW4TRJLp4uXQXG3ob5BtByXsNZFBjq9qcbzrczjVXfCz5cEo1SFDexmeWRnbCMDaRgaW4m9d2nBaa8FvUQCu3n9G1UBR8WhbT",
  1199  				parser: btcMainParser,
  1200  			},
  1201  			want: "m/49'/0'/55",
  1202  		},
  1203  		{
  1204  			name: "m/49'/0' - incomplete path, without account",
  1205  			args: args{
  1206  				xpub:   "ypub6UzM8PUqxcSoqC9gumfoiFhE8Qt84HbGpCD4eVJfJAojXTVtBxeddvTWJGJhGoaVBNJLmEgMdLXHgaLVJa4xEvk2tcokkdZhFdkxMLUE9sB",
  1207  				parser: btcMainParser,
  1208  			},
  1209  			want: "unknown/0'",
  1210  		},
  1211  		{
  1212  			name: "m/49'/1'/0'",
  1213  			args: args{
  1214  				xpub:   "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
  1215  				parser: btcTestnetParser,
  1216  			},
  1217  			want: "m/49'/1'/0'",
  1218  		},
  1219  		{
  1220  			name: "m/44'/133'/12'",
  1221  			args: args{
  1222  				xpub:   "xpub6CQdEahwhKRTLYpP6cyb7ZaGb3r4tVdyPX6dC1PfrNuByrCkWDgUkmpD28UdV9QccKgY1ZiAbGv1Fakcg2LxdFVSTNKHcjdRjqhjPK8Trkb",
  1223  				parser: zecMainParser,
  1224  			},
  1225  			want: "m/44'/133'/12'",
  1226  		},
  1227  	}
  1228  	for _, tt := range tests {
  1229  		t.Run(tt.name, func(t *testing.T) {
  1230  			descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub)
  1231  			if err != nil {
  1232  				t.Errorf("ParseXpub() error = %v", err)
  1233  				return
  1234  			}
  1235  			got, err := tt.args.parser.DerivationBasePath(descriptor)
  1236  			if (err != nil) != tt.wantErr {
  1237  				t.Errorf("BitcoinParser.DerivationBasePath() error = %v, wantErr %v", err, tt.wantErr)
  1238  				return
  1239  			}
  1240  			if got != tt.want {
  1241  				t.Errorf("BitcoinParser.DerivationBasePath() = %v, want %v", got, tt.want)
  1242  			}
  1243  		})
  1244  	}
  1245  }