nockchain-grpc/wallet/nockchain_service.go

153 lines
3.9 KiB
Go
Raw Normal View History

2025-10-06 13:38:53 +07:00
package wallet
import (
context "context"
"fmt"
"github.com/phamminh0811/private-grpc/nockchain"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
type NockchainClient struct {
conn *grpc.ClientConn
client nockchain.NockchainServiceClient
}
// NewNockchainClient creates a new gRPC client connection
func NewNockchainClient(address string) (*NockchainClient, error) {
creds := credentials.NewClientTLSFromCert(nil, "")
conn, err := grpc.NewClient(
address,
grpc.WithTransportCredentials(creds),
)
if err != nil {
return nil, fmt.Errorf("failed to connect: %w", err)
}
client := nockchain.NewNockchainServiceClient(conn)
return &NockchainClient{
conn: conn,
client: client,
}, nil
}
func (nc *NockchainClient) Close() error {
return nc.conn.Close()
}
func (nc *NockchainClient) WalletGetBalance(address string) (*nockchain.WalletBalanceData, error) {
pageToken := ""
allNotes := []*nockchain.BalanceEntry{}
var height *nockchain.BlockHeight
var blockId *nockchain.Hash
for {
req := nockchain.WalletGetBalanceRequest{
Address: address,
Page: &nockchain.PageRequest{
ClientPageItemsLimit: 0,
PageToken: pageToken,
MaxBytes: 0,
},
}
resp, err := nc.client.WalletGetBalance(context.Background(), &req)
if err != nil {
return nil, err
}
balance := nockchain.WalletBalanceData{}
switch resp.Result.(type) {
case *nockchain.WalletGetBalanceResponse_Balance:
balance = *resp.GetBalance()
case *nockchain.WalletGetBalanceResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
if height == nil {
height = balance.Height
blockId = balance.BlockId
}
if balance.Height != height || balance.BlockId != blockId {
return nil, fmt.Errorf("snapshot changed during pagination; retry")
}
allNotes = append(allNotes, balance.Notes...)
if balance.Page.NextPageToken == "" {
break
} else {
pageToken = balance.Page.NextPageToken
}
}
return &nockchain.WalletBalanceData{
Notes: allNotes,
Height: height,
BlockId: blockId,
Page: &nockchain.PageResponse{
NextPageToken: "",
},
}, nil
}
func (nc *NockchainClient) TxAccepted(txId string) (*nockchain.TransactionAcceptedResponse, error) {
req := nockchain.TransactionAcceptedRequest{
TxId: &nockchain.Base58Hash{
Hash: txId,
},
}
resp, err := nc.client.TransactionAccepted(context.Background(), &req)
if err != nil {
return nil, err
}
switch resp.Result.(type) {
case *nockchain.TransactionAcceptedResponse_Accepted:
return resp, nil
case *nockchain.TransactionAcceptedResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
}
2025-10-07 11:10:08 +07:00
func (nc *NockchainClient) WalletSendTransaction(tx *nockchain.RawTx) (*nockchain.WalletSendTransactionResponse, error) {
inputs := []*nockchain.NamedInput{}
for _, i := range tx.Inputs {
input, err := ConvertInput(i)
if err != nil {
return nil, fmt.Errorf("error converting input: %v", err)
}
inputs = append(inputs, input)
}
req := nockchain.WalletSendTransactionRequest{
TxId: ParseHash(tx.TxId),
RawTx: &nockchain.RawTransaction{
2025-10-07 22:24:54 +07:00
Id: ParseHash(tx.TxId),
2025-10-07 11:10:08 +07:00
NamedInputs: inputs,
TotalFees: &nockchain.Nicks{Value: tx.TotalFees},
TimelockRange: &nockchain.TimeLockRangeAbsolute{
Min: (*nockchain.BlockHeight)(tx.TimelockRange.Min),
Max: (*nockchain.BlockHeight)(tx.TimelockRange.Max),
},
},
}
resp, err := nc.client.WalletSendTransaction(context.Background(), &req)
if err != nil {
return nil, err
}
switch resp.Result.(type) {
case *nockchain.WalletSendTransactionResponse_Ack:
return resp, nil
case *nockchain.WalletSendTransactionResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
}