@@ -2,9 +2,11 @@ package hdwallet
2
2
3
3
import (
4
4
"encoding/hex"
5
+ "fmt"
5
6
"testing"
6
7
7
8
"github.com/stretchr/testify/assert"
9
+ "github.com/stretchr/testify/require"
8
10
)
9
11
10
12
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
@@ -345,3 +347,159 @@ func TestPaddedPublicKey(t *testing.T) {
345
347
t .Errorf ("Unexpected address. Expected 0x2CDfa87C022744CceABC525FaA8e85Df6984A60d and Got %s" , key .Addresses [1 ].ETHAddress )
346
348
}
347
349
}
350
+
351
+ func TestDerivationPath (t * testing.T ) {
352
+ type testCase struct {
353
+ derivationPathInput string
354
+ nAddresses int
355
+ expectedSetPathError * error
356
+ expectedAddresses map [string ]string
357
+ }
358
+
359
+ const mnemonic = "test test test test test test test test test test test junk"
360
+ const password = ""
361
+ doesntMakeSenseErrFunc := func (path string ) * error {
362
+ err := fmt .Errorf ("the path %s doesn't seem to make sense" , path )
363
+ return & err
364
+ }
365
+
366
+ testCases := []testCase {
367
+ // no path derivation
368
+ {"" , 1 , nil , map [string ]string {
369
+ "m/44'/60'/0'" : "0x340d8879778d3D3Fec643D1736ebFd2bC5824662" ,
370
+ }},
371
+ {"" , 3 , nil , map [string ]string {
372
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
373
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
374
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
375
+ }},
376
+
377
+ // path derivation input with 1 part
378
+ {"m" , 1 , doesntMakeSenseErrFunc ("m" ), nil },
379
+ {"m" , 3 , doesntMakeSenseErrFunc ("m" ), nil },
380
+
381
+ // path derivation input with 2 parts
382
+ {"m/44'" , 1 , nil , map [string ]string {
383
+ "m/44'" : "0xBe0B49bD63bea56C4c18733ad9C8A41B7161318F" ,
384
+ }},
385
+ {"m/44'" , 3 , nil , map [string ]string {
386
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
387
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
388
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
389
+ }},
390
+
391
+ // path derivation input with 3 parts
392
+ {"m/44'/60'" , 1 , nil , map [string ]string {
393
+ "m/44'/60'" : "0x27439E87140CF69e87c89bB4C9776eAaD35BeFb3" ,
394
+ }},
395
+ {"m/44'/60'" , 3 , nil , map [string ]string {
396
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
397
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
398
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
399
+ }},
400
+
401
+ // path derivation input with 4 parts
402
+ {"m/44'/60'/0'" , 1 , nil , map [string ]string {
403
+ "m/44'/60'/0'" : "0x340d8879778d3D3Fec643D1736ebFd2bC5824662" ,
404
+ }},
405
+ {"m/44'/60'/0" , 3 , nil , map [string ]string {
406
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
407
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
408
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
409
+ }},
410
+
411
+ {"m/44'/60'/1" , 1 , nil , map [string ]string {
412
+ "m/44'/60'/1" : "0x5600C4Cda24214FAFB227703437a3C98751C3f4F" ,
413
+ }},
414
+ {"m/44'/60'/1" , 3 , nil , map [string ]string {
415
+ "m/44'/60'/1'/0/0" : "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650" ,
416
+ "m/44'/60'/1'/0/1" : "0x40FBBE484b8Ee6139Af08446950B088e10b2306A" ,
417
+ "m/44'/60'/1'/0/2" : "0x2b382887D362cCae885a421C978c7e998D3c95a6" ,
418
+ }},
419
+
420
+ // path derivation input with 5 parts
421
+ {"m/44'/60'/0'/0" , 1 , nil , map [string ]string {
422
+ "m/44'/60'/0'/0" : "0x1e59ce931B4CFea3fe4B875411e280e173cB7A9C" ,
423
+ }},
424
+ {"m/44'/60'/0'/0" , 3 , nil , map [string ]string {
425
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
426
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
427
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
428
+ }},
429
+
430
+ {"m/44'/60'/1'/2" , 1 , nil , map [string ]string {
431
+ "m/44'/60'/1'/2" : "0xDd74C01e87759Ca5787C0A166103Df20a9493836" ,
432
+ }},
433
+ {"m/44'/60'/1'/2" , 3 , nil , map [string ]string {
434
+ "m/44'/60'/1'/2/0" : "0x481Ea61d7635E00e32fd5BbA05E8eFe3855b0146" ,
435
+ "m/44'/60'/1'/2/1" : "0x14954c8606365f18013BCE3Af14ff4431766B3Aa" ,
436
+ "m/44'/60'/1'/2/2" : "0xC4094cD7436447541Fe5Dfe72023BBFE86799571" ,
437
+ }},
438
+
439
+ // path derivation input with 6 parts
440
+ {"m/44'/60'/0'/0/0" , 1 , nil , map [string ]string {
441
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
442
+ }},
443
+ {"m/44'/60'/0'/0/0" , 3 , nil , map [string ]string {
444
+ "m/44'/60'/0'/0/0" : "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ,
445
+ "m/44'/60'/0'/0/1" : "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ,
446
+ "m/44'/60'/0'/0/2" : "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ,
447
+ }},
448
+
449
+ {"m/44'/60'/1'/2/3" , 1 , nil , map [string ]string {
450
+ "m/44'/60'/1'/2/3" : "0xC0698b4Bf4Bf25219BFF2ef077e9979DE5263b60" ,
451
+ }},
452
+ {"m/44'/60'/1'/2/3" , 3 , nil , map [string ]string {
453
+ "m/44'/60'/1'/2/3" : "0xC0698b4Bf4Bf25219BFF2ef077e9979DE5263b60" ,
454
+ "m/44'/60'/1'/2/4" : "0x6B41E428F4C5a582666533B02af618291d4de347" ,
455
+ "m/44'/60'/1'/2/5" : "0x68331EB6CE792DF5c6cE927366Cb6dE41CFff51b" ,
456
+ }},
457
+
458
+ // custom derivation
459
+ {"m/44'/60'/1'/2/3/4/5/6/7/8/9/0" , 1 , nil , map [string ]string {
460
+ "m/44'/60'/1'/2/3/4/5/6/7/8/9/0" : "0x510F2Da3BAc8Bfbf5D1b07852f48FbA3d89aFf8a" ,
461
+ }},
462
+ {"m/44'/60'/1'/2/3/4/5/6/7/8/9/0" , 3 , nil , map [string ]string {
463
+ "m/44'/60'/1'/2/3/4/5/6/7/8/9/0" : "0x510F2Da3BAc8Bfbf5D1b07852f48FbA3d89aFf8a" ,
464
+ "m/44'/60'/1'/2/3/4/5/6/7/8/9/1" : "0xB3ce368159A8a60d0a71CA7161aBCa9b40fa68f4" ,
465
+ "m/44'/60'/1'/2/3/4/5/6/7/8/9/2" : "0x70DB395c0e92F3f32B6698174bBE355451Bde07A" ,
466
+ }},
467
+
468
+ // op
469
+ {"m/44'/60'/2'/470/10" , 1 , nil , map [string ]string {
470
+ "m/44'/60'/2'/470/10" : "0x86487B98fB4BeC557dEa441C06A3c4a7feCe152F" ,
471
+ }},
472
+ {"m/44'/60'/2'/470/10" , 3 , nil , map [string ]string {
473
+ "m/44'/60'/2'/470/10" : "0x86487B98fB4BeC557dEa441C06A3c4a7feCe152F" ,
474
+ "m/44'/60'/2'/470/11" : "0x2E29b5BD52b1D1D387c8dB9721Db93E8C210654E" ,
475
+ "m/44'/60'/2'/470/12" : "0x824FBFCb5F4B5dC2D01533f03C0c815a2F8Bcb03" ,
476
+ }},
477
+ }
478
+
479
+ for _ , tc := range testCases {
480
+ tcName := fmt .Sprintf ("Input: \" %s\" nAddresses: %d" , tc .derivationPathInput , tc .nAddresses )
481
+ t .Run (tcName , func (t * testing.T ) {
482
+ pw , err := NewPolyWallet (mnemonic , password )
483
+ require .NoError (t , err )
484
+
485
+ if len (tc .derivationPathInput ) > 0 {
486
+ err = pw .SetPath (tc .derivationPathInput )
487
+ if tc .expectedSetPathError != nil {
488
+ require .Error (t , err )
489
+ assert .Equal (t , * tc .expectedSetPathError , err )
490
+ return
491
+ }
492
+ require .NoError (t , err )
493
+ }
494
+
495
+ hdAddresses , err := pw .ExportHDAddresses (tc .nAddresses )
496
+ require .NoError (t , err )
497
+ assert .Len (t , hdAddresses .Addresses , tc .nAddresses )
498
+
499
+ for _ , addr := range hdAddresses .Addresses {
500
+ assert .Contains (t , tc .expectedAddresses , addr .Path )
501
+ assert .Equal (t , tc .expectedAddresses [addr .Path ], addr .ETHAddress )
502
+ }
503
+ })
504
+ }
505
+ }
0 commit comments