github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/examples/create_stateful_contract/main.go (about)

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