forked from hashgraph/hedera-sdk-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
247 lines (210 loc) · 8 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/hashgraph/hedera-sdk-go/v2"
)
type contract struct {
Abi string `json:"abi"`
Bin string `json:"bin"`
}
type contracts struct {
Contracts map[string]contract `json:"contracts"`
Version string `json:"version"`
}
func main() {
var client *hedera.Client
var err error
// Retrieving network type from environment variable HEDERA_NETWORK
client, err = hedera.ClientForName(os.Getenv("HEDERA_NETWORK"))
if err != nil {
println(err.Error(), ": error creating client")
return
}
// Retrieving operator ID from environment variable OPERATOR_ID
operatorAccountID, err := hedera.AccountIDFromString(os.Getenv("OPERATOR_ID"))
if err != nil {
println(err.Error(), ": error converting string to AccountID")
return
}
// Retrieving operator key from environment variable OPERATOR_KEY
operatorKey, err := hedera.PrivateKeyFromString(os.Getenv("OPERATOR_KEY"))
if err != nil {
println(err.Error(), ": error converting string to PrivateKey")
return
}
// Setting the client operator ID and key
client.SetOperator(operatorAccountID, operatorKey)
// Make sure to close client after running
defer func() {
err = client.Close()
if err != nil {
println(err.Error(), ": error closing client")
return
}
}()
// Read in the compiled contract from stateful.json
rawSmartContract, err := os.ReadFile("./stateful.json")
if err != nil {
println(err.Error(), ": error reading stateful.json")
return
}
// Initialize contracts
var smartContract contracts = contracts{}
// Parse the rawSmartContract into smartContract
err = json.Unmarshal([]byte(rawSmartContract), &smartContract)
if err != nil {
println(err.Error(), ": error unmarshaling")
return
}
// Retrieve the bytecode from the parsed smart contract
smartContractByteCode := smartContract.Contracts["stateful.sol:StatefulContract"].Bin
fmt.Println("Stateful contract example")
fmt.Printf("Contract bytecode size: %v bytes\n", len(smartContractByteCode))
// Upload a file containing the byte code
byteCodeTransactionResponse, err := hedera.NewFileCreateTransaction().
// A file is not implicitly owned by anyone, even the operator
// But we do use operator's key for this one
SetKeys(client.GetOperatorPublicKey()).
// Set the stateful contract bytes for this
SetContents([]byte(smartContractByteCode)).
Execute(client)
if err != nil {
println(err.Error(), ": error creating file")
return
}
// Retrieve the receipt to make sure the transaction went through and to get bytecode file ID
byteCodeTransactionReceipt, err := byteCodeTransactionResponse.GetReceipt(client)
if err != nil {
println(err.Error(), ": error getting file create transaction receipt")
return
}
// Retrieve bytecode file ID from the receipt
byteCodeFileID := *byteCodeTransactionReceipt.FileID
fmt.Printf("contract bytecode file: %v\n", byteCodeFileID)
// Set the parameters that should be passed to the contract constructor
// In this case we are passing in a string with the value "hello from hedera!"
// as the only parameter that is passed to the contract
contractFunctionParams := hedera.NewContractFunctionParameters().
AddString("hello from hedera")
// Instantiate the contract instance
contractTransactionID, err := hedera.NewContractCreateTransaction().
// Set gas to create the contract
// Failing to set this to a sufficient amount will result in "INSUFFICIENT_GAS" status
SetGas(100000).
// Failing to set parameters when required will result in "CONTRACT_REVERT_EXECUTED" status
SetConstructorParameters(contractFunctionParams).
// The contract bytecode must be set to the file ID containing the contract bytecode
SetBytecodeFileID(byteCodeFileID).
// Set the admin key on the contract in case the contract should be deleted or
// updated in the future
SetAdminKey(client.GetOperatorPublicKey()).
Execute(client)
if err != nil {
println(err.Error(), ": error creating contract")
return
}
// Get the new contract record to make sure the transaction ran successfully
contractRecord, err := contractTransactionID.GetRecord(client)
if err != nil {
println(err.Error(), ": error retrieving contract creation record")
return
}
// Get the contract create result from the record
contractCreateResult, err := contractRecord.GetContractCreateResult()
if err != nil {
println(err.Error(), ": error retrieving contract creation result")
return
}
// Get the new contract ID from the receipt contained in the record
newContractID := *contractRecord.Receipt.ContractID
fmt.Printf("Contract create gas used: %v\n", contractCreateResult.GasUsed)
fmt.Printf("Contract create transaction fee: %v\n", contractRecord.TransactionFee)
fmt.Printf("contract: %v\n", newContractID)
// Ask for the current message (set on creation)
callResult, err := hedera.NewContractCallQuery().
// Set which contract
SetContractID(newContractID).
// The amount of gas to use for the call
// All of the gas offered will be used and charged a corresponding fee
SetGas(100000).
// This query requires payment, depends on gas used
SetQueryPayment(hedera.NewHbar(1)).
// nil -> no parameters
// Specified which function to call, and the parameters to pass to the function
SetFunction("getMessage", nil).
Execute(client)
if err != nil {
println(err.Error(), ": error executing contract call query")
return
}
fmt.Printf("Call gas used: %v\n", callResult.GasUsed)
// Get the message from the result
// The `0` is the index to fetch a particular type from
//
// e.g.
// If the return type of `getMessage` was `(uint32, string)`
// then you'd need to get each field separately using:
// uint32 := callResult.getUint32(0);
// string := callResult.getString(1);
fmt.Printf("Message: %v\n", callResult.GetString(0))
// In this case we are passing in a string with the value "Hello from Hedera again!"
// as the only parameter that is passed to the contract
contractFunctionParams = hedera.NewContractFunctionParameters().
AddString("Hello from Hedera again!")
// Update the message
contractExecuteID, err := hedera.NewContractExecuteTransaction().
// Set which contract
SetContractID(newContractID).
// Set the gas to execute the contract call
SetGas(100000).
// Set the function to call and the parameters to send
// in this case we're calling function "set_message" with a single
// string parameter of value "Hello from Hedera again!"
// If instead the "setMessage" method were to require "uint32, string"
// parameters then you must do:
// contractFunctionParams := hedera.NewContractFunctionParameters().
// .addUint32(1)
// .addString("string 3")
SetFunction("setMessage", contractFunctionParams).
Execute(client)
if err != nil {
println(err.Error(), ": error executing contract")
return
}
// Retrieve the record to make sure the execute transaction ran
contractExecuteRecord, err := contractExecuteID.GetRecord(client)
if err != nil {
println(err.Error(), ": error retrieving contract execution record")
return
}
// Get the contract execute result, that contains gas used
contractExecuteResult, err := contractExecuteRecord.GetContractExecuteResult()
if err != nil {
println(err.Error(), ": error retrieving contract exe")
return
}
// Print gas used
fmt.Printf("Execute gas used: %v\n", contractExecuteResult.GasUsed)
// Call a method on a contract that exists on Hedera
secondCallResult, err := hedera.NewContractCallQuery().
// Set which contract
SetContractID(newContractID).
// Set gas to use
SetGas(100000).
// Set the query payment explicitly since sometimes automatic payment calculated
// is too low
SetQueryPayment(hedera.NewHbar(1)).
// Set the function to call on the contract
SetFunction("getMessage", nil).
Execute(client)
if err != nil {
println(err.Error(), ": error executing contract call query")
return
}
// Get gas used
fmt.Printf("Call gas used: %v\n", secondCallResult.GasUsed)
// Get a string from the result at index 0
fmt.Printf("Message: %v\n", secondCallResult.GetString(0))
}