Skip to content

Commit 5c76f84

Browse files
authored
Merge branch 'main' into tck-node-methods
Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com>
2 parents 43293a5 + e39484e commit 5c76f84

8 files changed

Lines changed: 445 additions & 13 deletions

File tree

tck/cmd/server.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@ func main() {
4343
contractService := new(methods.ContractService)
4444
contractService.SetSdkService(sdkService)
4545

46+
4647
nodeService := new(methods.NodeService)
4748
nodeService.SetSdkService(sdkService)
4849

50+
scheduleService := new(methods.ScheduleService)
51+
scheduleService.SetSdkService(sdkService)
52+
4953
// Create a new RPC server
5054
assigner := handler.Map{
5155
"setup": postHandler(HandleError, handler.New(sdkService.Setup)),
@@ -86,6 +90,8 @@ func main() {
8690
"createContract": postHandler(HandleError, handler.New(contractService.CreateContract)),
8791
"updateContract": postHandler(HandleError, handler.New(contractService.UpdateContract)),
8892
"deleteContract": postHandler(HandleError, handler.New(contractService.DeleteContract)),
93+
"createSchedule": postHandler(HandleError, handler.New(scheduleService.CreateSchedule)),
94+
"signSchedule": postHandler(HandleError, handler.New(scheduleService.SignSchedule)),
8995
"executeContract": postHandler(HandleError, handler.New(contractService.ExecuteContract)),
9096
"createNode": postHandler(HandleError, handler.New(nodeService.CreateNode)),
9197
"generateKey": postHandler(HandleError, handler.New(methods.GenerateKey)),
@@ -158,8 +164,24 @@ func HandleError(_ context.Context, request *jrpc2.Request, err error) error {
158164

159165
// this wraps the jrpc2.Handler as it invokes the ErrorHandler func if error is returned
160166
func postHandler(handler Handler, h jrpc2.Handler) jrpc2.Handler {
161-
return func(ctx context.Context, req *jrpc2.Request) (any, error) {
162-
res, err := h(ctx, req)
167+
return func(ctx context.Context, req *jrpc2.Request) (res any, err error) {
168+
// Recover from panics
169+
defer func() {
170+
if r := recover(); r != nil {
171+
log.Printf("Panic recovered in JSON-RPC handler for request: %s, Panic: %v", req, r)
172+
// Convert panic to error and handle it through the error handler
173+
var panicErr error
174+
if e, ok := r.(error); ok {
175+
panicErr = fmt.Errorf("panic: %w", e)
176+
} else {
177+
panicErr = fmt.Errorf("panic: %v", r)
178+
}
179+
res = nil
180+
err = handler(ctx, req, panicErr)
181+
}
182+
}()
183+
184+
res, err = h(ctx, req)
163185
if err != nil {
164186
log.Printf("Error occurred processing JSON-RPC request: %s, Response error: %s", req, err)
165187
return nil, handler(ctx, req, err)

tck/methods/account.go

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,65 @@ func (a *AccountService) CreateAccount(_ context.Context, params param.CreateAcc
9797
return &response.AccountResponse{AccountId: accId, Status: receipt.Status.String()}, nil
9898
}
9999

100+
// buildCreateAccount builds an account create transaction without executing it (for scheduling)
101+
func (a *AccountService) buildCreateAccount(params param.CreateAccountParams) (*hiero.AccountCreateTransaction, error) {
102+
transaction := hiero.NewAccountCreateTransaction().SetGrpcDeadline(&threeSecondsDuration)
103+
104+
// Set key
105+
if err := utils.SetKeyIfPresent(params.Key, transaction.SetKeyWithoutAlias); err != nil {
106+
return nil, err
107+
}
108+
if params.InitialBalance != nil {
109+
initialBalance, err := strconv.ParseInt(*params.InitialBalance, 10, 64)
110+
if err != nil {
111+
return nil, err
112+
}
113+
transaction.SetInitialBalance(hiero.HbarFromTinybar(initialBalance))
114+
}
115+
if params.ReceiverSignatureRequired != nil {
116+
transaction.SetReceiverSignatureRequired(*params.ReceiverSignatureRequired)
117+
}
118+
if params.MaxAutomaticTokenAssociations != nil {
119+
transaction.SetMaxAutomaticTokenAssociations(*params.MaxAutomaticTokenAssociations)
120+
}
121+
// Set staked account ID
122+
if err := utils.SetAccountIDIfPresent(params.StakedAccountId, transaction.SetStakedAccountID); err != nil {
123+
return nil, err
124+
}
125+
if params.StakedNodeId != nil {
126+
stakedNodeID, err := params.StakedNodeId.Int64()
127+
if err != nil {
128+
return nil, response.InvalidParams.WithData(err.Error())
129+
}
130+
transaction.SetStakedNodeID(stakedNodeID)
131+
}
132+
if params.DeclineStakingReward != nil {
133+
transaction.SetDeclineStakingReward(*params.DeclineStakingReward)
134+
}
135+
if params.Memo != nil {
136+
transaction.SetAccountMemo(*params.Memo)
137+
}
138+
if params.AutoRenewPeriod != nil {
139+
autoRenewPeriodSeconds, err := strconv.ParseInt(*params.AutoRenewPeriod, 10, 64)
140+
if err != nil {
141+
return nil, err
142+
}
143+
144+
transaction.SetAutoRenewPeriod(time.Duration(autoRenewPeriodSeconds) * time.Second)
145+
}
146+
if params.Alias != nil {
147+
transaction.SetAlias(*params.Alias)
148+
}
149+
if params.CommonTransactionParams != nil {
150+
err := params.CommonTransactionParams.FillOutTransaction(transaction, a.sdkService.Client)
151+
if err != nil {
152+
return nil, err
153+
}
154+
}
155+
156+
return transaction, nil
157+
}
158+
100159
// UpdateAccount jRPC method for updateAccount
101160
func (a *AccountService) UpdateAccount(_ context.Context, params param.UpdateAccountParams) (*response.AccountResponse, error) {
102161
transaction := hiero.NewAccountUpdateTransaction().SetGrpcDeadline(&threeSecondsDuration)
@@ -204,8 +263,8 @@ func (a *AccountService) DeleteAccount(_ context.Context, params param.DeleteAcc
204263
return &response.AccountResponse{Status: receipt.Status.String()}, nil
205264
}
206265

207-
// ApproveAllowance jRPC method for approveAllowance
208-
func (a *AccountService) ApproveAllowance(_ context.Context, params param.AccountAllowanceApproveParams) (*response.AccountResponse, error) {
266+
// buildApproveAllowance builds an AccountAllowanceApproveTransaction from parameters
267+
func (a *AccountService) buildApproveAllowance(params param.AccountAllowanceApproveParams) (*hiero.AccountAllowanceApproveTransaction, error) {
209268
transaction := hiero.NewAccountAllowanceApproveTransaction().SetGrpcDeadline(&threeSecondsDuration)
210269

211270
allowances := *params.Allowances
@@ -307,6 +366,15 @@ func (a *AccountService) ApproveAllowance(_ context.Context, params param.Accoun
307366
return nil, err
308367
}
309368
}
369+
return transaction, nil
370+
}
371+
372+
// ApproveAllowance jRPC method for approveAllowance
373+
func (a *AccountService) ApproveAllowance(_ context.Context, params param.AccountAllowanceApproveParams) (*response.AccountResponse, error) {
374+
transaction, err := a.buildApproveAllowance(params)
375+
if err != nil {
376+
return nil, err
377+
}
310378

311379
txResponse, err := transaction.Execute(a.sdkService.Client)
312380
if err != nil {
@@ -375,8 +443,8 @@ func (a *AccountService) DeleteAllowance(_ context.Context, params param.Account
375443
return &response.AccountResponse{Status: receipt.Status.String()}, nil
376444
}
377445

378-
// TransferCrypto jRPC method for transferCrypto
379-
func (a *AccountService) TransferCrypto(_ context.Context, params param.TransferCryptoParams) (*response.AccountResponse, error) {
446+
// buildTransferCrypto builds a TransferTransaction from parameters
447+
func (a *AccountService) buildTransferCrypto(params param.TransferCryptoParams) (*hiero.TransferTransaction, error) {
380448
transaction := hiero.NewTransferTransaction().SetGrpcDeadline(&threeSecondsDuration)
381449

382450
if params.Transfers == nil {
@@ -400,6 +468,15 @@ func (a *AccountService) TransferCrypto(_ context.Context, params param.Transfer
400468
return nil, err
401469
}
402470
}
471+
return transaction, nil
472+
}
473+
474+
// TransferCrypto jRPC method for transferCrypto
475+
func (a *AccountService) TransferCrypto(_ context.Context, params param.TransferCryptoParams) (*response.AccountResponse, error) {
476+
transaction, err := a.buildTransferCrypto(params)
477+
if err != nil {
478+
return nil, err
479+
}
403480

404481
txResponse, err := transaction.Execute(a.sdkService.Client)
405482
if err != nil {

tck/methods/schedule.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package methods
2+
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
import (
6+
"context"
7+
"encoding/json"
8+
"fmt"
9+
"strconv"
10+
"time"
11+
12+
"github.com/hiero-ledger/hiero-sdk-go/tck/param"
13+
"github.com/hiero-ledger/hiero-sdk-go/tck/response"
14+
"github.com/hiero-ledger/hiero-sdk-go/tck/utils"
15+
hiero "github.com/hiero-ledger/hiero-sdk-go/v2/sdk"
16+
)
17+
18+
type ScheduleService struct {
19+
sdkService *SDKService
20+
}
21+
22+
func (s *ScheduleService) SetSdkService(service *SDKService) {
23+
s.sdkService = service
24+
}
25+
26+
// CreateSchedule jRPC method for createSchedule
27+
func (s *ScheduleService) CreateSchedule(_ context.Context, params param.ScheduleCreateParams) (*response.ScheduleResponse, error) {
28+
transaction := hiero.NewScheduleCreateTransaction().SetGrpcDeadline(&threeSecondsDuration)
29+
30+
if params.ScheduledTransaction != nil {
31+
scheduledTx, err := s.buildScheduledTransaction(params.ScheduledTransaction)
32+
if err != nil {
33+
return nil, fmt.Errorf("failed to build scheduled transaction: %w", err)
34+
}
35+
_, err = transaction.SetScheduledTransaction(scheduledTx)
36+
if err != nil {
37+
return nil, fmt.Errorf("failed to set scheduled transaction: %w", err)
38+
}
39+
}
40+
41+
if params.Memo != nil {
42+
transaction.SetScheduleMemo(*params.Memo)
43+
}
44+
45+
if err := utils.SetKeyIfPresent(params.AdminKey, transaction.SetAdminKey); err != nil {
46+
return nil, err
47+
}
48+
49+
if params.PayerAccountId != nil {
50+
payerAccountID, err := hiero.AccountIDFromString(*params.PayerAccountId)
51+
if err != nil {
52+
return nil, fmt.Errorf("failed to parse payer account ID: %w", err)
53+
}
54+
transaction.SetPayerAccountID(payerAccountID)
55+
}
56+
57+
if params.ExpirationTime != nil {
58+
expirationTime, err := strconv.ParseInt(*params.ExpirationTime, 10, 64)
59+
if err != nil {
60+
return nil, fmt.Errorf("failed to parse expiration time: %w", err)
61+
}
62+
transaction.SetExpirationTime(time.Unix(expirationTime, 0))
63+
}
64+
65+
if params.WaitForExpiry != nil {
66+
transaction.SetWaitForExpiry(*params.WaitForExpiry)
67+
}
68+
69+
if params.CommonTransactionParams != nil {
70+
err := params.CommonTransactionParams.FillOutTransaction(transaction, s.sdkService.Client)
71+
if err != nil {
72+
return nil, err
73+
}
74+
}
75+
76+
txResponse, err := transaction.Execute(s.sdkService.Client)
77+
if err != nil {
78+
return nil, err
79+
}
80+
receipt, err := txResponse.SetValidateStatus(true).GetReceipt(s.sdkService.Client)
81+
if err != nil {
82+
return nil, err
83+
}
84+
85+
var scheduleId string
86+
if receipt.Status == hiero.StatusSuccess {
87+
scheduleId = receipt.ScheduleID.String()
88+
}
89+
90+
fmt.Println(receipt.ScheduledTransactionID)
91+
return &response.ScheduleResponse{
92+
ScheduleId: scheduleId,
93+
TransactionId: receipt.ScheduledTransactionID.String(),
94+
Status: receipt.Status.String(),
95+
}, nil
96+
}
97+
98+
// SignSchedule jRPC method for signSchedule
99+
func (s *ScheduleService) SignSchedule(_ context.Context, params param.ScheduleSignParams) (*response.ScheduleResponse, error) {
100+
transaction := hiero.NewScheduleSignTransaction().SetGrpcDeadline(&threeSecondsDuration)
101+
102+
if params.ScheduleId != nil {
103+
scheduleID, err := hiero.ScheduleIDFromString(*params.ScheduleId)
104+
if err != nil {
105+
return nil, fmt.Errorf("failed to parse schedule ID: %w", err)
106+
}
107+
transaction.SetScheduleID(scheduleID)
108+
}
109+
110+
if params.CommonTransactionParams != nil {
111+
err := params.CommonTransactionParams.FillOutTransaction(transaction, s.sdkService.Client)
112+
if err != nil {
113+
return nil, err
114+
}
115+
}
116+
117+
txResponse, err := transaction.Execute(s.sdkService.Client)
118+
if err != nil {
119+
return nil, err
120+
}
121+
receipt, err := txResponse.SetValidateStatus(true).GetReceipt(s.sdkService.Client)
122+
if err != nil {
123+
return nil, err
124+
}
125+
126+
return &response.ScheduleResponse{
127+
Status: receipt.Status.String(),
128+
}, nil
129+
}
130+
131+
// buildScheduledTransaction creates the appropriate transaction based on method name
132+
func (s *ScheduleService) buildScheduledTransaction(scheduledTx *param.ScheduledTransaction) (hiero.TransactionInterface, error) {
133+
switch scheduledTx.Method {
134+
case "transferCrypto":
135+
var params param.TransferCryptoParams
136+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
137+
return nil, fmt.Errorf("failed to unmarshal transferCrypto params: %w", err)
138+
}
139+
accountService := &AccountService{sdkService: s.sdkService}
140+
return accountService.buildTransferCrypto(params)
141+
142+
case "approveAllowance":
143+
var params param.AccountAllowanceApproveParams
144+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
145+
return nil, fmt.Errorf("failed to unmarshal approveAllowance params: %w", err)
146+
}
147+
accountService := &AccountService{sdkService: s.sdkService}
148+
return accountService.buildApproveAllowance(params)
149+
150+
case "mintToken":
151+
var params param.MintTokenParams
152+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
153+
return nil, fmt.Errorf("failed to unmarshal mintToken params: %w", err)
154+
}
155+
tokenService := &TokenService{sdkService: s.sdkService}
156+
return tokenService.buildMintToken(params)
157+
158+
case "burnToken":
159+
var params param.BurnTokenParams
160+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
161+
return nil, fmt.Errorf("failed to unmarshal burnToken params: %w", err)
162+
}
163+
tokenService := &TokenService{sdkService: s.sdkService}
164+
return tokenService.buildBurnToken(params)
165+
166+
case "submitMessage":
167+
var params param.SubmitTopicMessageParams
168+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
169+
return nil, fmt.Errorf("failed to unmarshal submitMessage params: %w", err)
170+
}
171+
topicService := &TopicService{sdkService: s.sdkService}
172+
return topicService.buildSubmitTopicMessage(params)
173+
174+
case "createTopic":
175+
var params param.CreateTopicParams
176+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
177+
return nil, fmt.Errorf("failed to unmarshal createTopic params: %w", err)
178+
}
179+
topicService := &TopicService{sdkService: s.sdkService}
180+
return topicService.buildCreateTopic(params)
181+
182+
case "createAccount":
183+
var params param.CreateAccountParams
184+
if err := json.Unmarshal(scheduledTx.Params, &params); err != nil {
185+
return nil, fmt.Errorf("failed to unmarshal createAccount params: %w", err)
186+
}
187+
accountService := &AccountService{sdkService: s.sdkService}
188+
return accountService.buildCreateAccount(params)
189+
190+
default:
191+
return nil, fmt.Errorf("unsupported scheduled transaction method: %s (only transferCrypto, approveAllowance, mintToken, burnToken, submitMessage, createTopic, and createAccount are supported)", scheduledTx.Method)
192+
}
193+
}

0 commit comments

Comments
 (0)