2025-10-11 13:04:57 +07:00
package wallet_test
import (
"context"
2025-10-16 12:31:21 +07:00
"fmt"
2025-10-11 13:04:57 +07:00
"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
2025-10-24 10:32:44 +07:00
func TestKeyGenV0 ( t * testing . T ) {
2025-10-20 10:12:49 +07:00
entropyBigInt , isOk := new ( big . Int ) . SetString ( "37133536588676344913489312523941366110857274548479981512263368615793750653450" , 10 )
2025-10-11 13:04:57 +07:00
assert . True ( t , isOk )
entropy := entropyBigInt . Bytes ( )
assert . Len ( t , entropy , 32 )
2025-10-20 10:12:49 +07:00
saltBigInt , isOk := new ( big . Int ) . SetString ( "251632902249061493058993135304695174381" , 10 )
2025-10-11 13:04:57 +07:00
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 )
2025-10-20 10:12:49 +07:00
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" )
2025-10-11 13:04:57 +07:00
masterKey , err := crypto . MasterKeyFromSeed ( mnemonic )
assert . NoError ( t , err )
2025-10-24 10:32:44 +07:00
pkPoint , err := crypto . CheetaPointFromBytes ( masterKey . PublicKey )
assert . NoError ( t , err )
fmt . Println ( crypto . Tip5HashToBase58 ( wallet . HashPubkey ( pkPoint ) ) )
2025-10-11 13:04:57 +07:00
assert . Equal ( t ,
base58 . Encode ( masterKey . PublicKey ) ,
2025-10-20 10:12:49 +07:00
"34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6" ,
2025-10-11 13:04:57 +07:00
)
assert . Equal ( t ,
base58 . Encode ( masterKey . PrivateKey ) ,
2025-10-20 10:12:49 +07:00
"3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
2025-10-11 13:04:57 +07:00
)
assert . Equal ( t ,
base58 . Encode ( masterKey . ChainCode ) ,
2025-10-20 10:12:49 +07:00
"2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8" ,
2025-10-11 13:04:57 +07:00
)
// assert import priv/pubkey
privBytes := append ( [ ] byte { 0x00 } , masterKey . PrivateKey ... )
2025-10-24 10:32:44 +07:00
importPrivKey := crypto . SerializeExtend ( masterKey . ChainCode , privBytes , 0 , crypto . KeyType_PRIVATE )
2025-10-20 10:12:49 +07:00
assert . Len ( t , importPrivKey , 83 )
2025-10-24 10:32:44 +07:00
importPubKey := crypto . SerializeExtend ( masterKey . ChainCode , masterKey . PublicKey , 0 , crypto . KeyType_PUBLIC )
2025-10-20 10:12:49 +07:00
assert . Len ( t , importPubKey , 147 )
2025-10-11 13:04:57 +07:00
assert . Equal ( t ,
base58 . Encode ( importPrivKey ) ,
2025-10-20 10:12:49 +07:00
"zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx" ,
2025-10-11 13:04:57 +07:00
)
assert . Equal ( t ,
base58 . Encode ( importPubKey ) ,
2025-10-20 10:12:49 +07:00
"zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo" ,
2025-10-11 13:04:57 +07:00
)
}
2025-10-24 10:32:44 +07:00
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 ... )
2025-10-27 08:29:32 +07:00
importPrivKey := crypto . SerializeExtend ( masterKey . ChainCode , privBytes , 1 , crypto . KeyType_PRIVATE )
2025-10-24 10:32:44 +07:00
assert . Len ( t , importPrivKey , 83 )
2025-10-27 08:29:32 +07:00
importPubKey := crypto . SerializeExtend ( masterKey . ChainCode , masterKey . PublicKey , 1 , crypto . KeyType_PUBLIC )
2025-10-24 10:32:44 +07:00
assert . Len ( t , importPubKey , 147 )
assert . Equal ( t ,
base58 . Encode ( importPrivKey ) ,
2025-10-27 08:29:32 +07:00
"zprvLxxkCBq3s5HYzjhcW8wh3FhHSt5YowSGApRdHsptZQrtcCdqibUo7qwqfa7qkazttRgcaRwy4YYwv9DLhmUNcMG9uAtsgaPkfwyiGkf5Bpib" ,
2025-10-24 10:32:44 +07:00
)
assert . Equal ( t ,
base58 . Encode ( importPubKey ) ,
2025-10-27 08:29:32 +07:00
"zpub2kRJ7D6VCvzVfDg5e6iXb4T2ea97QJKN6JzjTArrhgZzwHo6rmT8Z3mEp11T67fNvU8ZWLcTTFS17NLwvYs7ErmqCJQNrtjRgVcvZNeWBebpztihXzrhvHZumDiejPmLb6QQNhkPhhK3uyS6XBbaPybqGDdWAgHKvPHkKirVsSJWEmDJYEj8ePN4ufscv1DL2pTD" ,
2025-10-24 10:32:44 +07:00
)
}
2025-10-11 13:04:57 +07:00
func TestImportKey ( t * testing . T ) {
type Input struct {
req * nockchain . ImportKeysRequest
expectResp * nockchain . ImportKeysResponse
isErr bool
errStr string
}
2025-10-27 08:29:32 +07:00
correctImportPrivKeyV0 := base58 . Decode ( "zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx" )
correctImportPrivKeyV1 := base58 . Decode ( "zprvLxxkCBq3s5HYziigQb3G4a7pyj7pG2f8MjogoqH4UoFDJy3GRBX5LF1tJAgsTYdgZAVfuM2DGrjqAqJX96SS8cTbVAaPV23834G1GqgfEEg7" )
2025-10-20 10:12:49 +07:00
invalidImportPrivKeyPrefix := make ( [ ] byte , 83 )
2025-10-27 08:29:32 +07:00
copy ( invalidImportPrivKeyPrefix [ : ] , correctImportPrivKeyV0 )
2025-10-20 10:12:49 +07:00
invalidImportPrivKeyPrefix [ 46 ] = 0x01
2025-10-11 13:04:57 +07:00
2025-10-20 10:12:49 +07:00
invalidImportPrivKeyChecksum := make ( [ ] byte , 83 )
2025-10-27 08:29:32 +07:00
copy ( invalidImportPrivKeyChecksum [ : ] , correctImportPrivKeyV0 )
2025-10-20 10:12:49 +07:00
copy ( invalidImportPrivKeyChecksum [ 79 : ] , [ ] byte { 1 , 2 , 3 , 4 } )
2025-10-11 13:04:57 +07:00
2025-10-27 08:29:32 +07:00
correctImportPubkeyV0 := base58 . Decode ( "zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo" )
correctImportPubkeyV1 := base58 . Decode ( "zpub2kRJ7D6VCvzVfDb4F7drLsLVdViqUSiufhwkmZogDuTVLc5ird2DinQNHvu5WXgTcMGizEaqbnANjvg43bx3Lfz4fPVt27MPsiNBTuqqXgtvYbJZNwmXEa5vt87MGCRxKpAgo1zH6K7qy5Uokc94eUd47xEcmhij9YRm8twvU5y3ccCessJ8rdtEZahX6pv8RFBi" )
2025-10-20 10:12:49 +07:00
invalidImportPubkeyChecksum := make ( [ ] byte , 147 )
2025-10-27 08:29:32 +07:00
copy ( invalidImportPubkeyChecksum [ : ] , correctImportPubkeyV0 )
2025-10-20 10:12:49 +07:00
copy ( invalidImportPubkeyChecksum [ 143 : ] , [ ] byte { 1 , 2 , 3 , 4 } )
2025-10-11 13:04:57 +07:00
2025-10-24 10:32:44 +07:00
responseV0 := & nockchain . ImportKeysResponse {
Address : "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6" ,
2025-10-20 10:12:49 +07:00
PrivateKey : "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
ChainCode : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8" ,
2025-10-27 08:29:32 +07:00
ImportPrivateKey : base58 . Encode ( correctImportPrivKeyV0 ) ,
ImportPublicKey : base58 . Encode ( correctImportPubkeyV0 ) ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
}
responseV1 := & nockchain . ImportKeysResponse {
Address : "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q" ,
PrivateKey : "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
ChainCode : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8" ,
2025-10-27 08:29:32 +07:00
ImportPrivateKey : base58 . Encode ( correctImportPrivKeyV1 ) ,
ImportPublicKey : base58 . Encode ( correctImportPubkeyV1 ) ,
2025-10-24 10:32:44 +07:00
Version : 1 ,
2025-10-11 13:04:57 +07:00
}
2025-10-24 10:32:44 +07:00
responseV0ReadOnly := & nockchain . ImportKeysResponse {
Address : "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6" ,
2025-10-11 13:04:57 +07:00
PrivateKey : "" ,
2025-10-20 10:12:49 +07:00
ChainCode : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8" ,
2025-10-11 13:04:57 +07:00
ImportPrivateKey : "" ,
2025-10-27 08:29:32 +07:00
ImportPublicKey : base58 . Encode ( correctImportPubkeyV0 ) ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
}
2025-10-24 10:32:44 +07:00
responseV1ReadOnly := & nockchain . ImportKeysResponse {
Address : "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q" ,
PrivateKey : "" ,
ChainCode : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8" ,
ImportPrivateKey : "" ,
2025-10-27 08:29:32 +07:00
ImportPublicKey : base58 . Encode ( correctImportPubkeyV1 ) ,
2025-10-24 10:32:44 +07:00
Version : 1 ,
}
2025-10-11 13:04:57 +07:00
inputs := [ ] Input {
// case invalid type
{
req : & nockchain . ImportKeysRequest {
Key : "" ,
ImportType : nockchain . ImportType_UNDEFINED ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid import type" ,
} ,
// case invalid extended key
{
req : & nockchain . ImportKeysRequest {
Key : "some wrong string" ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid extended key" ,
} ,
{
req : & nockchain . ImportKeysRequest {
Key : "zprv wrong priv import key length" ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid extended private key length" ,
} ,
{
req : & nockchain . ImportKeysRequest {
Key : base58 . Encode ( invalidImportPrivKeyPrefix ) ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
2025-10-20 10:12:49 +07:00
errStr : "invalid private key prefix at byte 46" ,
2025-10-11 13:04:57 +07:00
} ,
{
req : & nockchain . ImportKeysRequest {
Key : base58 . Encode ( invalidImportPrivKeyChecksum ) ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid checksum" ,
} ,
2025-10-24 10:32:44 +07:00
// case success import priv key v0
2025-10-11 13:04:57 +07:00
{
req : & nockchain . ImportKeysRequest {
2025-10-27 08:29:32 +07:00
Key : base58 . Encode ( correctImportPrivKeyV0 ) ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
2025-10-24 10:32:44 +07:00
expectResp : responseV0 ,
isErr : false ,
errStr : "" ,
} ,
// case success import priv key v1
{
req : & nockchain . ImportKeysRequest {
2025-10-27 08:29:32 +07:00
Key : base58 . Encode ( correctImportPrivKeyV1 ) ,
2025-10-24 10:32:44 +07:00
ImportType : nockchain . ImportType_EXTENDED_KEY ,
Version : 1 ,
} ,
expectResp : responseV1 ,
2025-10-11 13:04:57 +07:00
isErr : false ,
errStr : "" ,
} ,
// case invalid import pub key
{
req : & nockchain . ImportKeysRequest {
Key : "zpub wrong public import key length" ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid extended public key length" ,
} ,
{
req : & nockchain . ImportKeysRequest {
Key : base58 . Encode ( invalidImportPubkeyChecksum ) ,
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid checksum" ,
} ,
2025-10-24 10:32:44 +07:00
// case success import pub key v0
{
req : & nockchain . ImportKeysRequest {
2025-10-27 08:29:32 +07:00
Key : base58 . Encode ( correctImportPubkeyV0 ) ,
2025-10-24 10:32:44 +07:00
ImportType : nockchain . ImportType_EXTENDED_KEY ,
Version : 0 ,
} ,
expectResp : responseV0ReadOnly ,
isErr : false ,
errStr : "" ,
} ,
// case success import pub key v1
2025-10-11 13:04:57 +07:00
{
req : & nockchain . ImportKeysRequest {
2025-10-27 08:29:32 +07:00
Key : base58 . Encode ( correctImportPubkeyV1 ) ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_EXTENDED_KEY ,
2025-10-24 10:32:44 +07:00
Version : 1 ,
2025-10-11 13:04:57 +07:00
} ,
2025-10-24 10:32:44 +07:00
expectResp : responseV1ReadOnly ,
2025-10-11 13:04:57 +07:00
isErr : false ,
errStr : "" ,
} ,
// case missing chaincode when import master privkey
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
Key : "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_MASTER_PRIVKEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "master key must be in [chain_code],[key] format" ,
} ,
// case invalid length
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
Key : "abcdxyz,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_MASTER_PRIVKEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid chain code length" ,
} ,
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
Key : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,abcdxyz" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_MASTER_PRIVKEY ,
2025-10-24 10:32:44 +07:00
Version : 0 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : nil ,
isErr : true ,
errStr : "invalid priv key length" ,
} ,
2025-10-24 10:32:44 +07:00
// 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
2025-10-11 13:04:57 +07:00
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
Key : "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_MASTER_PRIVKEY ,
2025-10-24 10:32:44 +07:00
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 ,
2025-10-11 13:04:57 +07:00
} ,
2025-10-24 10:32:44 +07:00
expectResp : responseV0 ,
2025-10-11 13:04:57 +07:00
isErr : false ,
errStr : "" ,
} ,
2025-10-24 10:32:44 +07:00
// case success import seed v1
2025-10-11 13:04:57 +07:00
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
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" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_SEEDPHRASE ,
2025-10-24 10:32:44 +07:00
Version : 1 ,
2025-10-11 13:04:57 +07:00
} ,
2025-10-24 10:32:44 +07:00
expectResp : responseV1 ,
2025-10-11 13:04:57 +07:00
isErr : false ,
errStr : "" ,
} ,
2025-10-24 10:32:44 +07:00
// 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
2025-10-11 13:04:57 +07:00
{
req : & nockchain . ImportKeysRequest {
2025-10-20 10:12:49 +07:00
Key : "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6" ,
2025-10-11 13:04:57 +07:00
ImportType : nockchain . ImportType_WATCH_ONLY ,
2025-10-24 10:32:44 +07:00
Version : 1 ,
2025-10-11 13:04:57 +07:00
} ,
expectResp : & nockchain . ImportKeysResponse {
2025-10-24 10:32:44 +07:00
Address : "BAmYAxgpVrJeFqqPnKAZHVZZdmVfzrgu7bBqcRBNca8HpxQofzUZG8Q" ,
Version : 1 ,
2025-10-11 13:04:57 +07:00
} ,
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
2025-11-04 10:38:31 +07:00
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"
2025-10-11 13:04:57 +07:00
masterKey1 , err := crypto . MasterKeyFromSeed ( seed1 )
assert . NoError ( t , err )
2025-11-04 10:38:31 +07:00
fmt . Println ( "pk: " , base58 . Encode ( masterKey1 . PublicKey ) )
2025-10-11 13:04:57 +07:00
nc , err := wallet . NewNockchainClient ( "nockchain-api.zorp.io:443" )
assert . NoError ( t , err )
2025-11-04 10:38:31 +07:00
masterKey1Scan , err := nc . WalletGetBalance ( & nockchain . GetBalanceRequest {
Selector : & nockchain . GetBalanceRequest_Address {
Address : base58 . Encode ( masterKey1 . PublicKey ) ,
2025-10-11 13:04:57 +07:00
} ,
2025-11-04 10:38:31 +07:00
} )
2025-10-11 13:04:57 +07:00
assert . NoError ( t , err )
2025-11-04 10:38:31 +07:00
fmt . Println ( "masterKey1Scan:" , masterKey1Scan )
assert . NotEmpty ( t , masterKey1Scan . Notes )
}
2025-10-11 13:04:57 +07:00
2025-11-07 11:16:19 +07:00
func TestEncodeDecodeNoun ( t * testing . T ) {
2025-11-04 10:38:31 +07:00
lock1 := & nockchain . NockchainLock {
KeysRequired : 1 ,
Pubkeys : [ ] string { "5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ" } ,
2025-10-11 13:04:57 +07:00
}
2025-11-04 10:38:31 +07:00
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 } )
2025-10-11 13:04:57 +07:00
2025-11-07 11:16:19 +07:00
lock1Decode := wallet . DecodeNoteData ( lock1Encode )
assert . Equal ( t , lock1Decode . KeysRequired , lock1 . KeysRequired )
assert . Equal ( t , lock1Decode . Pubkeys , lock1 . Pubkeys )
2025-11-04 10:38:31 +07:00
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 } )
2025-10-16 12:31:21 +07:00
2025-11-07 11:16:19 +07:00
lock2Decode := wallet . DecodeNoteData ( lock2Encode )
assert . Equal ( t , lock2Decode . KeysRequired , lock2 . KeysRequired )
assert . Equal ( t , lock2Decode . Pubkeys , lock2 . Pubkeys )
}
2025-11-04 10:38:31 +07:00
2025-10-16 12:31:21 +07:00
// This test should be run with timeout 300s
2025-11-07 11:16:19 +07:00
func TestCreateTxV0 ( t * testing . T ) {
2025-11-04 10:38:31 +07:00
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"
2025-10-16 12:31:21 +07:00
masterKey1 , err := crypto . MasterKeyFromSeed ( seed1 )
assert . NoError ( t , err )
2025-11-04 10:38:31 +07:00
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
2025-10-20 09:35:25 +07:00
2025-11-04 10:38:31 +07:00
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"
2025-10-16 12:31:21 +07:00
masterKey2 , err := crypto . MasterKeyFromSeed ( seed2 )
assert . NoError ( t , err )
2025-10-16 16:15:48 +07:00
fmt . Println ( "masterKey2" , base58 . Encode ( masterKey2 . PublicKey ) )
2025-10-16 12:31:21 +07:00
nc , err := wallet . NewNockchainClient ( "nockchain-api.zorp.io:443" )
assert . NoError ( t , err )
handler := wallet . NewGprcHandler ( * nc )
2025-11-04 10:38:31 +07:00
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
2025-10-16 12:31:21 +07:00
req := & nockchain . CreateTxRequest {
2025-11-04 10:38:31 +07:00
Names : inputs ,
Recipients : recipients ,
Fee : uint64 ( fee ) ,
IsMasterKey : true ,
Seed : seed1 ,
Index : 0 ,
Hardened : false ,
Version : 0 ,
RefundAddress : crypto . Tip5HashToBase58 ( addr1 ) ,
2025-10-16 12:31:21 +07:00
}
res , err := handler . CreateTx ( context . Background ( ) , req )
assert . NoError ( t , err )
// the result is taken from create-tx scripts
2025-11-04 10:38:31 +07:00
assert . Equal ( t , res . RawTx . TxId , "6oDgTWnk6sL98yK49hcQTRAfCdFfgKh58U6TDTKmGPirhoxkMii2D6E" )
2025-10-16 12:31:21 +07:00
}
2025-11-07 11:16:19 +07:00
func TestCreateTxV1 ( t * testing . T ) {
seed := "pledge vessel toilet sunny hockey skirt spend wire disorder attitude crumble lecture problem bundle bone rather address over suit ancient primary gospel silent repair"
_ , err := crypto . MasterKeyFromSeed ( seed )
assert . NoError ( t , err )
nc , err := wallet . NewNockchainClient ( "nockchain-api.zorp.io:443" )
assert . NoError ( t , err )
handler := wallet . NewGprcHandler ( * nc )
inputs := "[9McQZWZzqFCLwsF37gUHLHt3cxWVbLA64SabN3AMMSgNuSM2b9SmMsj 88uZqY63kneffJnVAEYpb67W96sk3xsdFYTjzj8DSBiigL9AZd9pHsC],[9McQZWZzqFCLwsF37gUHLHt3cxWVbLA64SabN3AMMSgNuSM2b9SmMsj 2JLcp5oXBTtgTCKN4na9Dnk2YuHJCXuDAkk5qT8n9iP1d4iz1c3Amfo]"
recipients := fmt . Sprintf ( "%s:747336" , "D6NUb9HC4ursvZzYdMAtWAMSyyJWwtdqnsyRXxsADsyqQwh5dcDsTRm" )
fee := 4456448
req := & nockchain . CreateTxRequest {
Names : inputs ,
Recipients : recipients ,
Fee : uint64 ( fee ) ,
IsMasterKey : true ,
Seed : seed ,
Index : 0 ,
Hardened : false ,
Version : 1 ,
}
resp , err := handler . CreateTx ( context . Background ( ) , req )
assert . NoError ( t , err )
assert . Equal ( t , resp . RawTx . TxId , "9DfaTJgtsGU8Fs2mAPhGpiMMw5RcRXjEVfnmFcTTxoSFMLWpv2Ae4eG" )
}