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") } } 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{ 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") } }