status-im/status-go

View on GitHub
account/generator/generator_test.go

Summary

Maintainability
A
0 mins
Test Coverage
package generator

import (
    "fmt"
    "strings"
    "testing"

    "github.com/stretchr/testify/assert"

    "github.com/ethereum/go-ethereum/crypto"
)

var testAccount = struct {
    mnemonic           string
    bip39Passphrase    string
    encriptionPassword string
    extendedMasterKey  string
    bip44Key0          string
    bip44PubKey0       string
    bip44Address0      string
    bip44Address1      string
}{
    mnemonic:           "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
    bip39Passphrase:    "TREZOR",
    encriptionPassword: "TEST_PASSWORD",
    extendedMasterKey:  "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF",
    bip44Key0:          "0x62f1d86b246c81bdd8f6c166d56896a4a5e1eddbcaebe06480e5c0bc74c28224",
    bip44PubKey0:       "0x04986dee3b8afe24cb8ccb2ac23dac3f8c43d22850d14b809b26d6b8aa5a1f47784152cd2c7d9edd0ab20392a837464b5a750b2a7f3f06e6a5756b5211b6a6ed05",
    bip44Address0:      "0x9c32F71D4DB8Fb9e1A58B0a80dF79935e7256FA6",
    bip44Address1:      "0x7AF7283bd1462C3b957e8FAc28Dc19cBbF2FAdfe",
}

const testAccountJSONFile = `{
    "address":"9c32f71d4db8fb9e1a58b0a80df79935e7256fa6",
    "crypto":
        {
            "cipher":"aes-128-ctr","ciphertext":"8055b65d5e41ef467c0cfe52ce6beda7f8dbe689221c6c43be9e9401bf173004",
            "cipherparams":{"iv":"738f002e5e5343e0bb0e1050e098f721"},
            "kdf":"scrypt",
            "kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"9a54fbe1439ac567bd05039f76907b2c2846364a38b2f6813bcdac5ab0ec9d18"},
            "mac":"79d817cd21afd4944e70d804d7871d10cbd15f25c6755416f780f81c1588677e"
        },
    "id":"6202ced9-f0cd-42e4-bf21-6029cca0ea91",
    "version":3
}`

const (
    path0 = "m/44'/60'/0'/0/0"
    path1 = "m/44'/60'/0'/0/1"
)

func TestGenerator_Generate(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    accountsInfo, err := g.Generate(12, 5, "")
    assert.NoError(t, err)
    assert.Equal(t, 5, len(g.accounts))

    for _, info := range accountsInfo {
        words := strings.Split(info.Mnemonic, " ")
        assert.Equal(t, 12, len(words))
    }
}

func TestGenerator_CreateAccountFromPrivateKey(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    info, err := g.CreateAccountFromPrivateKey(testAccount.bip44Key0)

    assert.NoError(t, err)
    assert.Equal(t, 0, len(g.accounts))
    assert.Equal(t, 66, len(info.KeyUID))
}

func TestGenerator_ImportPrivateKey(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    info, err := g.ImportPrivateKey(testAccount.bip44Key0)
    assert.NoError(t, err)
    assert.Equal(t, 1, len(g.accounts))

    assert.Equal(t, testAccount.bip44PubKey0, info.PublicKey)
    assert.Equal(t, testAccount.bip44Address0, info.Address)
}

func TestGenerator_CreateAccountFromMnemonicAndDeriveAccountsForPaths(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    info, err := g.CreateAccountFromMnemonicAndDeriveAccountsForPaths(testAccount.mnemonic, testAccount.bip39Passphrase, []string{path0, path1})

    assert.NoError(t, err)
    assert.Equal(t, 0, len(g.accounts))
    assert.Equal(t, 66, len(info.KeyUID))

    assert.Equal(t, testAccount.bip44Address0, info.Derived[path0].Address)
    assert.Equal(t, testAccount.bip44Address1, info.Derived[path1].Address)
}

func TestGenerator_ImportMnemonic(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    info, err := g.ImportMnemonic(testAccount.mnemonic, testAccount.bip39Passphrase)
    assert.NoError(t, err)
    assert.Equal(t, 1, len(g.accounts))

    key := g.accounts[info.ID]
    assert.Equal(t, testAccount.extendedMasterKey, key.extendedKey.String())
}

func TestGenerator_ImportJSONKey(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    // wrong password
    _, err := g.ImportJSONKey(testAccountJSONFile, "wrong-password")
    assert.Error(t, err)

    // right password
    info, err := g.ImportJSONKey(testAccountJSONFile, testAccount.encriptionPassword)
    assert.NoError(t, err)
    assert.Equal(t, 1, len(g.accounts))
    assert.Equal(t, testAccount.bip44Address0, info.Address)

    key := g.accounts[info.ID]
    keyHex := fmt.Sprintf("0x%x", crypto.FromECDSA(key.privateKey))
    assert.Equal(t, testAccount.bip44Key0, keyHex)
}

func TestGenerator_DeriveAddresses(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    info, err := g.ImportMnemonic(testAccount.mnemonic, testAccount.bip39Passphrase)
    assert.NoError(t, err)
    assert.Equal(t, 1, len(g.accounts))

    addresses, err := g.DeriveAddresses(info.ID, []string{path0, path1})
    assert.NoError(t, err)

    assert.Equal(t, testAccount.bip44Address0, addresses[path0].Address)
    assert.Equal(t, testAccount.bip44Address1, addresses[path1].Address)
}

func TestGenerator_DeriveAddresses_FromImportedPrivateKey(t *testing.T) {
    g := New(nil)
    assert.Equal(t, 0, len(g.accounts))

    key, err := crypto.GenerateKey()
    assert.NoError(t, err)
    hex := fmt.Sprintf("%#x", crypto.FromECDSA(key))
    info, err := g.ImportPrivateKey(hex)
    assert.NoError(t, err)
    assert.Equal(t, 1, len(g.accounts))

    // normal imported accounts cannot derive child accounts,
    // but only the address/pubblic key of the current key.
    paths := []string{"", "m"}
    for _, path := range paths {
        addresses, err := g.DeriveAddresses(info.ID, []string{path})
        assert.NoError(t, err)

        expectedAddress := crypto.PubkeyToAddress(key.PublicKey).Hex()
        assert.Equal(t, expectedAddress, addresses[path].Address)
    }

    // cannot derive other child keys from a normal key
    _, err = g.DeriveAddresses(info.ID, []string{"m/0/1/2"})
    assert.Equal(t, ErrAccountCannotDeriveChildKeys, err)
}