629 lines
22 KiB
Go
629 lines
22 KiB
Go
package wallet_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/big"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/btcutil/base58"
|
|
"github.com/cosmos/go-bip39"
|
|
"github.com/phamminh0811/private-grpc/crypto"
|
|
"github.com/phamminh0811/private-grpc/nockchain"
|
|
"github.com/phamminh0811/private-grpc/wallet"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// The entropy, salt and result is taken from "nockchain-wallet keygen" command
|
|
func TestKeyGenV0(t *testing.T) {
|
|
entropyBigInt, isOk := new(big.Int).SetString("37133536588676344913489312523941366110857274548479981512263368615793750653450", 10)
|
|
assert.True(t, isOk)
|
|
|
|
entropy := entropyBigInt.Bytes()
|
|
assert.Len(t, entropy, 32)
|
|
|
|
saltBigInt, isOk := new(big.Int).SetString("251632902249061493058993135304695174381", 10)
|
|
assert.True(t, isOk)
|
|
|
|
salt := saltBigInt.Bytes()
|
|
assert.Len(t, salt, 16)
|
|
|
|
argonBytes := crypto.DeriveKey(0, entropy[:], salt[:], nil, nil, 6, 786432, 4, 32)
|
|
slices.Reverse(argonBytes)
|
|
mnemonic, err := bip39.NewMnemonic(argonBytes)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, mnemonic, "include lounge salad chicken trumpet embrace grace mercy pulp submit alter weapon plastic welcome funny female palm satoshi open file knock sun fade match")
|
|
|
|
masterKey, err := crypto.MasterKeyFromSeed(mnemonic)
|
|
assert.NoError(t, err)
|
|
|
|
pkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
|
|
assert.NoError(t, err)
|
|
|
|
fmt.Println(crypto.Tip5HashToBase58(wallet.HashPubkey(pkPoint)))
|
|
assert.Equal(t,
|
|
base58.Encode(masterKey.PublicKey),
|
|
"34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
)
|
|
assert.Equal(t,
|
|
base58.Encode(masterKey.PrivateKey),
|
|
"3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
)
|
|
assert.Equal(t,
|
|
base58.Encode(masterKey.ChainCode),
|
|
"2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8",
|
|
)
|
|
|
|
// assert import priv/pubkey
|
|
privBytes := append([]byte{0x00}, masterKey.PrivateKey...)
|
|
importPrivKey := crypto.SerializeExtend(masterKey.ChainCode, privBytes, 0, crypto.KeyType_PRIVATE)
|
|
assert.Len(t, importPrivKey, 83)
|
|
importPubKey := crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, 0, crypto.KeyType_PUBLIC)
|
|
assert.Len(t, importPubKey, 147)
|
|
|
|
assert.Equal(t,
|
|
base58.Encode(importPrivKey),
|
|
"zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx",
|
|
)
|
|
assert.Equal(t,
|
|
base58.Encode(importPubKey),
|
|
"zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo",
|
|
)
|
|
}
|
|
|
|
func TestKeyGenV1(t *testing.T) {
|
|
entropyBigInt, isOk := new(big.Int).SetString("90486886833626125109893864286343887304289963452245361030406651820586141463911", 10)
|
|
assert.True(t, isOk)
|
|
|
|
entropy := entropyBigInt.Bytes()
|
|
assert.Len(t, entropy, 32)
|
|
|
|
saltBigInt, isOk := new(big.Int).SetString("200764822674693794811396222039518854030", 10)
|
|
assert.True(t, isOk)
|
|
|
|
salt := saltBigInt.Bytes()
|
|
assert.Len(t, salt, 16)
|
|
|
|
argonBytes := crypto.DeriveKey(0, entropy[:], salt[:], nil, nil, 6, 786432, 4, 32)
|
|
slices.Reverse(argonBytes)
|
|
mnemonic, err := bip39.NewMnemonic(argonBytes)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, mnemonic, "holiday wage fan orange humble erode thought across boring cereal brass believe window drill until dry dish basket mean all banana tribe antenna engage")
|
|
|
|
masterKey, err := crypto.MasterKeyFromSeed(mnemonic)
|
|
assert.NoError(t, err)
|
|
|
|
pkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t,
|
|
crypto.Tip5HashToBase58(wallet.HashPubkey(pkPoint)),
|
|
"6DGFW4qAgCDx1AnP9fkhENwaPUeVWHEDB5WuJPiN1bZBjW2igMgU7N8",
|
|
)
|
|
|
|
// assert import priv/pubkey
|
|
privBytes := append([]byte{0x00}, masterKey.PrivateKey...)
|
|
importPrivKey := crypto.SerializeExtend(masterKey.ChainCode, privBytes, 1, crypto.KeyType_PRIVATE)
|
|
assert.Len(t, importPrivKey, 83)
|
|
importPubKey := crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, 1, crypto.KeyType_PUBLIC)
|
|
assert.Len(t, importPubKey, 147)
|
|
|
|
assert.Equal(t,
|
|
base58.Encode(importPrivKey),
|
|
"zprvLxxkCBq3s5HYzjhcW8wh3FhHSt5YowSGApRdHsptZQrtcCdqibUo7qwqfa7qkazttRgcaRwy4YYwv9DLhmUNcMG9uAtsgaPkfwyiGkf5Bpib",
|
|
)
|
|
assert.Equal(t,
|
|
base58.Encode(importPubKey),
|
|
"zpub2kRJ7D6VCvzVfDg5e6iXb4T2ea97QJKN6JzjTArrhgZzwHo6rmT8Z3mEp11T67fNvU8ZWLcTTFS17NLwvYs7ErmqCJQNrtjRgVcvZNeWBebpztihXzrhvHZumDiejPmLb6QQNhkPhhK3uyS6XBbaPybqGDdWAgHKvPHkKirVsSJWEmDJYEj8ePN4ufscv1DL2pTD",
|
|
)
|
|
}
|
|
func TestImportKey(t *testing.T) {
|
|
type Input struct {
|
|
req *nockchain.ImportKeysRequest
|
|
expectResp *nockchain.ImportKeysResponse
|
|
isErr bool
|
|
errStr string
|
|
}
|
|
|
|
correctImportPrivKeyV0 := base58.Decode("zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx")
|
|
correctImportPrivKeyV1 := base58.Decode("zprvLxxkCBq3s5HYziigQb3G4a7pyj7pG2f8MjogoqH4UoFDJy3GRBX5LF1tJAgsTYdgZAVfuM2DGrjqAqJX96SS8cTbVAaPV23834G1GqgfEEg7")
|
|
invalidImportPrivKeyPrefix := make([]byte, 83)
|
|
copy(invalidImportPrivKeyPrefix[:], correctImportPrivKeyV0)
|
|
invalidImportPrivKeyPrefix[46] = 0x01
|
|
|
|
invalidImportPrivKeyChecksum := make([]byte, 83)
|
|
copy(invalidImportPrivKeyChecksum[:], correctImportPrivKeyV0)
|
|
copy(invalidImportPrivKeyChecksum[79:], []byte{1, 2, 3, 4})
|
|
|
|
correctImportPubkeyV0 := base58.Decode("zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo")
|
|
correctImportPubkeyV1 := base58.Decode("zpub2kRJ7D6VCvzVfDb4F7drLsLVdViqUSiufhwkmZogDuTVLc5ird2DinQNHvu5WXgTcMGizEaqbnANjvg43bx3Lfz4fPVt27MPsiNBTuqqXgtvYbJZNwmXEa5vt87MGCRxKpAgo1zH6K7qy5Uokc94eUd47xEcmhij9YRm8twvU5y3ccCessJ8rdtEZahX6pv8RFBi")
|
|
invalidImportPubkeyChecksum := make([]byte, 147)
|
|
copy(invalidImportPubkeyChecksum[:], correctImportPubkeyV0)
|
|
copy(invalidImportPubkeyChecksum[143:], []byte{1, 2, 3, 4})
|
|
|
|
responseV0 := &nockchain.ImportKeysResponse{
|
|
Address: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
PrivateKey: "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8",
|
|
ImportPrivateKey: base58.Encode(correctImportPrivKeyV0),
|
|
ImportPublicKey: base58.Encode(correctImportPubkeyV0),
|
|
Version: 0,
|
|
}
|
|
responseV1 := &nockchain.ImportKeysResponse{
|
|
Address: "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q",
|
|
PrivateKey: "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8",
|
|
ImportPrivateKey: base58.Encode(correctImportPrivKeyV1),
|
|
ImportPublicKey: base58.Encode(correctImportPubkeyV1),
|
|
Version: 1,
|
|
}
|
|
|
|
responseV0ReadOnly := &nockchain.ImportKeysResponse{
|
|
Address: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
PrivateKey: "",
|
|
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8",
|
|
ImportPrivateKey: "",
|
|
ImportPublicKey: base58.Encode(correctImportPubkeyV0),
|
|
Version: 0,
|
|
}
|
|
responseV1ReadOnly := &nockchain.ImportKeysResponse{
|
|
Address: "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q",
|
|
PrivateKey: "",
|
|
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8",
|
|
ImportPrivateKey: "",
|
|
ImportPublicKey: base58.Encode(correctImportPubkeyV1),
|
|
Version: 1,
|
|
}
|
|
|
|
inputs := []Input{
|
|
// case invalid type
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "",
|
|
ImportType: nockchain.ImportType_UNDEFINED,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid import type",
|
|
},
|
|
// case invalid extended key
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "some wrong string",
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid extended key",
|
|
},
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "zprv wrong priv import key length",
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid extended private key length",
|
|
},
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(invalidImportPrivKeyPrefix),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid private key prefix at byte 46",
|
|
},
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(invalidImportPrivKeyChecksum),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid checksum",
|
|
},
|
|
// case success import priv key v0
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(correctImportPrivKeyV0),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: responseV0,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case success import priv key v1
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(correctImportPrivKeyV1),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 1,
|
|
},
|
|
expectResp: responseV1,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case invalid import pub key
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "zpub wrong public import key length",
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid extended public key length",
|
|
},
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(invalidImportPubkeyChecksum),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid checksum",
|
|
},
|
|
// case success import pub key v0
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(correctImportPubkeyV0),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: responseV0ReadOnly,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case success import pub key v1
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: base58.Encode(correctImportPubkeyV1),
|
|
ImportType: nockchain.ImportType_EXTENDED_KEY,
|
|
Version: 1,
|
|
},
|
|
expectResp: responseV1ReadOnly,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case missing chaincode when import master privkey
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ImportType: nockchain.ImportType_MASTER_PRIVKEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "master key must be in [chain_code],[key] format",
|
|
},
|
|
// case invalid length
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "abcdxyz,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ImportType: nockchain.ImportType_MASTER_PRIVKEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid chain code length",
|
|
},
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,abcdxyz",
|
|
ImportType: nockchain.ImportType_MASTER_PRIVKEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: nil,
|
|
isErr: true,
|
|
errStr: "invalid priv key length",
|
|
},
|
|
// case success import master privkey v0
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ImportType: nockchain.ImportType_MASTER_PRIVKEY,
|
|
Version: 0,
|
|
},
|
|
expectResp: responseV0,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case success import master privkey v1
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg",
|
|
ImportType: nockchain.ImportType_MASTER_PRIVKEY,
|
|
Version: 1,
|
|
},
|
|
expectResp: responseV1,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case success import seed v0
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "include lounge salad chicken trumpet embrace grace mercy pulp submit alter weapon plastic welcome funny female palm satoshi open file knock sun fade match",
|
|
ImportType: nockchain.ImportType_SEEDPHRASE,
|
|
Version: 0,
|
|
},
|
|
expectResp: responseV0,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case success import seed v1
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "include lounge salad chicken trumpet embrace grace mercy pulp submit alter weapon plastic welcome funny female palm satoshi open file knock sun fade match",
|
|
ImportType: nockchain.ImportType_SEEDPHRASE,
|
|
Version: 1,
|
|
},
|
|
expectResp: responseV1,
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case sucess import pubkey v0
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
ImportType: nockchain.ImportType_WATCH_ONLY,
|
|
Version: 0,
|
|
},
|
|
expectResp: &nockchain.ImportKeysResponse{
|
|
Address: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
Version: 0,
|
|
},
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
// case sucess import pubkey v1
|
|
{
|
|
req: &nockchain.ImportKeysRequest{
|
|
Key: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6",
|
|
ImportType: nockchain.ImportType_WATCH_ONLY,
|
|
Version: 1,
|
|
},
|
|
expectResp: &nockchain.ImportKeysResponse{
|
|
Address: "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q",
|
|
Version: 1,
|
|
},
|
|
isErr: false,
|
|
errStr: "",
|
|
},
|
|
}
|
|
|
|
for _, input := range inputs {
|
|
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
|
|
assert.NoError(t, err)
|
|
|
|
handler := wallet.NewGprcHandler(*nc)
|
|
|
|
resp, err := handler.ImportKeys(context.Background(), input.req)
|
|
if input.isErr {
|
|
assert.ErrorContains(t, err, input.errStr)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, resp, input.expectResp)
|
|
}
|
|
}
|
|
}
|
|
|
|
// This test should be run with timeout 120s
|
|
func TestScan(t *testing.T) {
|
|
// some random seed we take to get empty notes
|
|
seed1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter"
|
|
|
|
masterKey1, err := crypto.MasterKeyFromSeed(seed1)
|
|
assert.NoError(t, err)
|
|
fmt.Println("pk: ", base58.Encode(masterKey1.PublicKey))
|
|
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
|
|
assert.NoError(t, err)
|
|
|
|
masterKey1Scan, err := nc.WalletGetBalance(&nockchain.GetBalanceRequest{
|
|
Selector: &nockchain.GetBalanceRequest_Address{
|
|
Address: base58.Encode(masterKey1.PublicKey),
|
|
},
|
|
})
|
|
assert.NoError(t, err)
|
|
fmt.Println("masterKey1Scan:", masterKey1Scan)
|
|
assert.NotEmpty(t, masterKey1Scan.Notes)
|
|
}
|
|
|
|
func TestEncodeNoun(t *testing.T) {
|
|
lock1 := &nockchain.NockchainLock{
|
|
KeysRequired: 1,
|
|
Pubkeys: []string{"5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ"},
|
|
}
|
|
|
|
lock1Encode := wallet.EncodeNoteData(lock1)
|
|
assert.Equal(t, lock1Encode, []byte{89, 192, 131, 91, 67, 199, 5, 16, 32, 24, 199, 52, 39, 171, 121, 6, 15, 240, 167, 243, 69, 34, 254, 110, 4, 78, 3, 8, 44, 245, 128, 176, 69, 72, 150, 253, 6, 232, 167, 34, 133, 115, 154, 56, 106, 106, 192, 175, 176, 88, 89, 160, 208, 117, 55, 78, 5})
|
|
|
|
lock2 := lock1
|
|
lock2.Pubkeys = []string{"7UXNF2HXzEaPUvLDVDgGJyriKqpd2974Kj7U2RnLuBPeRGa7ZezhGmK"}
|
|
lock2Encode := wallet.EncodeNoteData(lock2)
|
|
assert.Equal(t, lock2Encode, []byte{89, 192, 131, 91, 67, 199, 5, 248, 151, 186, 241, 213, 183, 156, 103, 181, 1, 254, 206, 33, 184, 3, 142, 3, 99, 101, 0, 1, 246, 168, 22, 252, 21, 155, 53, 205, 0, 2, 172, 67, 150, 149, 228, 139, 80, 206, 0, 1, 203, 54, 188, 141, 54, 21, 39, 193, 84})
|
|
}
|
|
|
|
// // This test should be run with timeout 120s
|
|
// func TestFullFlow(t *testing.T) {
|
|
// mnemonic1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter"
|
|
// masterKey1, err := crypto.MasterKeyFromSeed(mnemonic1)
|
|
// assert.NoError(t, err)
|
|
// fmt.Println(base58.Encode(masterKey1.PublicKey))
|
|
// mnemonic2 := "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel"
|
|
// masterKey2, err := crypto.MasterKeyFromSeed(mnemonic2)
|
|
// assert.NoError(t, err)
|
|
|
|
// inputName := "[4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W 9cjUFbdtaFHeXNWCAKjsTphBchHmCoUU6a1aDbJAFz9qHqeG8osh4wF]"
|
|
|
|
// nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
|
|
// assert.NoError(t, err)
|
|
|
|
// masterKeyScan, err := nc.WalletGetBalance(base58.Encode(masterKey1.PublicKey))
|
|
// assert.NoError(t, err)
|
|
|
|
// var note *nockchain.NockchainNote
|
|
// for _, balanceEntry := range masterKeyScan.Notes {
|
|
// firstName := crypto.Tip5HashToBase58([5]uint64{
|
|
// balanceEntry.Name.First.Belt_1.Value,
|
|
// balanceEntry.Name.First.Belt_2.Value,
|
|
// balanceEntry.Name.First.Belt_3.Value,
|
|
// balanceEntry.Name.First.Belt_4.Value,
|
|
// balanceEntry.Name.First.Belt_5.Value,
|
|
// })
|
|
// lastName := crypto.Tip5HashToBase58([5]uint64{
|
|
// balanceEntry.Name.Last.Belt_1.Value,
|
|
// balanceEntry.Name.Last.Belt_2.Value,
|
|
// balanceEntry.Name.Last.Belt_3.Value,
|
|
// balanceEntry.Name.Last.Belt_4.Value,
|
|
// balanceEntry.Name.Last.Belt_5.Value,
|
|
// })
|
|
// nname := "[" + firstName + " " + lastName + "]"
|
|
// if nname == inputName {
|
|
// nnote := wallet.ParseBalanceEntry(balanceEntry)
|
|
// note = &nnote
|
|
// break
|
|
// }
|
|
// }
|
|
// assert.NotNil(t, note)
|
|
|
|
// parentHash, err := wallet.HashNote(note)
|
|
// assert.NoError(t, err)
|
|
|
|
// gift := uint64(100000)
|
|
// seed1 := &nockchain.NockchainSeed{
|
|
// OutputSource: nil,
|
|
// Recipient: &nockchain.NockchainLock{
|
|
// KeysRequired: 1,
|
|
// Pubkeys: []string{base58.Encode(masterKey2.PublicKey)},
|
|
// },
|
|
// TimelockIntent: nil,
|
|
// Gift: gift,
|
|
// ParentHash: crypto.Tip5HashToBase58(parentHash),
|
|
// }
|
|
|
|
// gift = note.Asset - gift - 100
|
|
// seed2 := &nockchain.NockchainSeed{
|
|
// OutputSource: nil,
|
|
// Recipient: &nockchain.NockchainLock{
|
|
// KeysRequired: 1,
|
|
// Pubkeys: []string{base58.Encode(masterKey1.PublicKey)},
|
|
// },
|
|
// TimelockIntent: nil,
|
|
// Gift: gift,
|
|
// ParentHash: crypto.Tip5HashToBase58(parentHash),
|
|
// }
|
|
|
|
// spend := nockchain.NockchainSpend{
|
|
// Signatures: nil,
|
|
// Seeds: []*nockchain.NockchainSeed{
|
|
// seed1, seed2,
|
|
// },
|
|
// Fee: 100,
|
|
// }
|
|
|
|
// msg, err := wallet.HashMsg(&spend)
|
|
// assert.NoError(t, err)
|
|
|
|
// chalT8, sigT8, err := wallet.ComputeSig(*masterKey1, msg)
|
|
// assert.NoError(t, err)
|
|
|
|
// spend.Signatures = []*nockchain.NockchainSignature{
|
|
// {
|
|
// Pubkey: base58.Encode(masterKey1.PublicKey),
|
|
// Chal: chalT8[:],
|
|
// Sig: sigT8[:],
|
|
// },
|
|
// }
|
|
|
|
// input := nockchain.NockchainInput{
|
|
// Name: &nockchain.NockchainName{
|
|
// First: "4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W",
|
|
// Last: "9cjUFbdtaFHeXNWCAKjsTphBchHmCoUU6a1aDbJAFz9qHqeG8osh4wF",
|
|
// },
|
|
// Note: note,
|
|
// Spend: &spend,
|
|
// }
|
|
|
|
// id, err := wallet.ComputeTxId([]*nockchain.NockchainInput{&input}, &nockchain.TimelockRange{
|
|
// Min: nil,
|
|
// Max: nil,
|
|
// }, 100)
|
|
// assert.NoError(t, err)
|
|
|
|
// rawTx := nockchain.RawTx{
|
|
// TxId: crypto.Tip5HashToBase58(id),
|
|
// Inputs: []*nockchain.NockchainInput{&input},
|
|
// TimelockRange: &nockchain.TimelockRange{
|
|
// Min: nil,
|
|
// Max: nil,
|
|
// },
|
|
// TotalFees: 100,
|
|
// }
|
|
// resp, err := nc.WalletSendTransaction(&rawTx)
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, resp.Result, &nockchain.WalletSendTransactionResponse_Ack{
|
|
// Ack: &nockchain.Acknowledged{},
|
|
// })
|
|
|
|
// txAcceptedResp, err := nc.TxAccepted(rawTx.TxId)
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, txAcceptedResp.Result, &nockchain.TransactionAcceptedResponse_Accepted{
|
|
// Accepted: true,
|
|
// })
|
|
// }
|
|
|
|
// This test should be run with timeout 300s
|
|
func TestCreateTx(t *testing.T) {
|
|
seed1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter"
|
|
masterKey1, err := crypto.MasterKeyFromSeed(seed1)
|
|
assert.NoError(t, err)
|
|
|
|
pkPoint1, err := crypto.CheetaPointFromBytes(masterKey1.PublicKey)
|
|
assert.NoError(t, err)
|
|
addr1 := wallet.HashPubkey(pkPoint1)
|
|
// nockchain-wallet create-tx --names '[4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W 8yd685r3WhvRYsYWFy3LNQqSMMNwWyE3QZe5fqp1jgG3PWtLPvXdYvR]" --fee 1867776 --recipient "5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ:2000000" --refund-pkh 7UXNF2HXzEaPUvLDVDgGJyriKqpd2974Kj7U2RnLuBPeRGa7ZezhGmK
|
|
|
|
seed2 := "anchor various pair jazz panel rubber virus address achieve opinion end silent runway bus wolf pony cigar nuclear moral mixed gold window timber member"
|
|
masterKey2, err := crypto.MasterKeyFromSeed(seed2)
|
|
assert.NoError(t, err)
|
|
fmt.Println("masterKey2", base58.Encode(masterKey2.PublicKey))
|
|
|
|
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
|
|
assert.NoError(t, err)
|
|
handler := wallet.NewGprcHandler(*nc)
|
|
|
|
inputs := "[4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W 8yd685r3WhvRYsYWFy3LNQqSMMNwWyE3QZe5fqp1jgG3PWtLPvXdYvR]"
|
|
|
|
pkPoint2, err := crypto.CheetaPointFromBytes(masterKey2.PublicKey)
|
|
assert.NoError(t, err)
|
|
addr2 := wallet.HashPubkey(pkPoint2)
|
|
|
|
recipients := fmt.Sprintf("%s:2000000", crypto.Tip5HashToBase58(addr2))
|
|
fee := 1867776 // min fee
|
|
|
|
req := &nockchain.CreateTxRequest{
|
|
Names: inputs,
|
|
Recipients: recipients,
|
|
Fee: uint64(fee),
|
|
IsMasterKey: true,
|
|
Seed: seed1,
|
|
Index: 0,
|
|
Hardened: false,
|
|
Version: 0,
|
|
RefundAddress: crypto.Tip5HashToBase58(addr1),
|
|
}
|
|
|
|
res, err := handler.CreateTx(context.Background(), req)
|
|
assert.NoError(t, err)
|
|
|
|
// the result is taken from create-tx scripts
|
|
assert.Equal(t, res.RawTx.TxId, "6oDgTWnk6sL98yK49hcQTRAfCdFfgKh58U6TDTKmGPirhoxkMii2D6E")
|
|
}
|