Creating a Go Transaction with the PureStake API
Creating a transaction and sending it in to the network programmatically are foundational tasks for working with a blockchain. Using the PureStake API allows a developer full access to the complete Algorand MainNet/Testnet ledgers without running any infrastructure, but does require a few minor changes to the code.
Requirements
- The Go SDK: Download Here
- A PureStake Account: See Tutorial
- A Funded TestNet Account: See Tutorial
Background
- The PureStake API Service https://developer.purestake.io/
- About the PureStake API: https://www.purestake.com/technology/algorand-api/
- Code Samples: https://developer.purestake.io/code-samples
- API Examples: https://github.com/PureStake/api-examples
Steps
1. Set Configuration Values for the PureStake API
First, you’ll need to set the default configuration values for PureStake’s API. This process varies from the Algorand-published in that you need to create a common.Client
that overrides the default token header with X-API-Key
and then convert it to algod.Client
.
To do that, let’s define our imports and the connection constants:
import (
"fmt"
"context"
"github.com/algorand/go-algorand-sdk/client/v2/algod"
"github.com/algorand/go-algorand-sdk/client/v2/common"
"github.com/algorand/go-algorand-sdk/crypto"
"github.com/algorand/go-algorand-sdk/mnemonic"
)
import transaction "github.com/algorand/go-algorand-sdk/future"
const algodAddress = "https://testnet-algorand.api.purestake.io/ps2"
const psToken = "YOUR API KEY HERE"
2. Recover Private Key
Now you’ll need to recover your private key using your mnemonic.
Important Note: Mnemonics control your account. Never share them or store insecurely. The code below is for demonstration purposes only.
const fromAddr = "YOUR ACCOUNT ADDRESS HERE"
const mn = "YOUR MNEMONIC HERE"
fromAddrPvtKey, err := mnemonic.ToPrivateKey(mn)
if err != nil {
fmt.Printf("error getting suggested tx params: %s\n", err)
return
}
3. Create the Client
To instantiate the client, enter:
commonClient, err := common.MakeClient(algodAddress, "X-API-Key", psToken)
if err != nil {
fmt.Printf("failed to make common client: %s\n", err)
return
}
algodClient := (*algod.Client)(commonClient)
4. Get and Set Transaction Parameters
Get the transaction parameters from the blockchain using the client object and set the amount and destination address.
txParams, err := algodClient.SuggestedParams().Do(context.Background())
if err != nil {
fmt.Printf("error getting suggested tx params: %s\n", err)
return
}
const toAddr = "ZHGZZQ2PIWYRK6MIK44GKO3VGQUC7NS2V3UQ63M3DIMFUFGI4BRWK7WDBU"
note := []byte(nil)
closeRemainderTo := ""
amount := uint64(10000)
5. Create and Sign Transaction
Create a new transaction using the parameters defined above and sign it.
txn, err := transaction.MakePaymentTxn(fromAddr, toAddr, amount, note, closeRemainderTo, txParams)
if err != nil {
fmt.Printf("Error creating transaction: %s\n", err)
return
}
_, bytes, err := crypto.SignTransaction(fromAddrPvtKey, txn)
if err != nil {
fmt.Printf("Failed to sign transaction: %s\n", err)
return
}
6. Include Verification Function
After the transaction is complete and sent in, this function is called to verify that the transaction has been included in the blockchain:
// Function from Algorand Inc. - utility for waiting on a transaction confirmation
func waitForConfirmation(txID string, client *algod.Client) {
status, err := client.Status().Do(context.Background())
if err != nil {
fmt.Printf("error getting algod status: %s\n", err)
return
}
lastRound := status.LastRound
for {
pt, _, err := client.PendingTransactionInformation(txID).Do(context.Background())
if err != nil {
fmt.Printf("error getting pending transaction: %s\n", err)
return
}
if pt.ConfirmedRound > 0 {
fmt.Printf("Transaction confirmed in round %d\n", pt.ConfirmedRound)
break
}
fmt.Printf("Waiting for confirmation...\n")
lastRound++
status, err = client.StatusAfterBlock(lastRound).Do(context.Background())
}
}
7. Submit and Verify Transaction
Lastly, send the signed transaction to the blockchain.
sendResponse, err := algodClient.SendRawTransaction(bytes).Do(context.Background())
if err != nil {
fmt.Printf("failed to send transaction: %s\n", err)
return
}
fmt.Printf("Transaction successfull with ID: %s\n", sendResponse)
fmt.Printf("Waiting for confirmation...\n")
waitForConfirmation(sendResponse, algodClient)
You should see a response similar to this one:
Transaction sent with ID 7ESD6JX2EX3A7TWXKYRR53METIINB4CKYJYWMX5O22GTV26H2SIA
Waiting for confirmation...
Transaction confirmed in round 10462202
8. Run All of the Code Together
If you’d rather just drop in the code in its entirety, copy below. You’ll need to enter your API key, your mnemonic, and some other specifics in order for it to function properly.
package main
import (
"fmt"
"context"
"github.com/algorand/go-algorand-sdk/client/v2/algod"
"github.com/algorand/go-algorand-sdk/client/v2/common"
"github.com/algorand/go-algorand-sdk/crypto"
"github.com/algorand/go-algorand-sdk/mnemonic"
)
import transaction "github.com/algorand/go-algorand-sdk/future"
const algodAddress = "https://testnet-algorand.api.purestake.io/ps2"
const psToken = "YOU API KEY HERE"
// Function from Algorand Inc. - utility for waiting on a transaction confirmation
func waitForConfirmation(txID string, client *algod.Client) {
status, err := client.Status().Do(context.Background())
if err != nil {
fmt.Printf("error getting algod status: %s\n", err)
return
}
lastRound := status.LastRound
for {
pt, _, err := client.PendingTransactionInformation(txID).Do(context.Background())
if err != nil {
fmt.Printf("error getting pending transaction: %s\n", err)
return
}
if pt.ConfirmedRound > 0 {
fmt.Printf("Transaction confirmed in round %d\n", pt.ConfirmedRound)
break
}
fmt.Printf("Waiting for confirmation...\n")
lastRound++
status, err = client.StatusAfterBlock(lastRound).Do(context.Background())
}
}
func main() {
const fromAddr = "YOUR ACCOUNT ADDRESS HERE"
const mn = "YOU MNEMONIC HERE"
fromAddrPvtKey, err := mnemonic.ToPrivateKey(mn)
if err != nil {
fmt.Printf("error getting suggested tx params: %s\n", err)
return
}
commonClient, err := common.MakeClient(algodAddress, "X-API-Key", psToken)
if err != nil {
fmt.Printf("failed to make common client: %s\n", err)
return
}
algodClient := (*algod.Client)(commonClient)
// Get the suggested transaction parameters
txParams, err := algodClient.SuggestedParams().Do(context.Background())
if err != nil {
fmt.Printf("error getting suggested tx params: %s\n", err)
return
}
const toAddr = "ZHGZZQ2PIWYRK6MIK44GKO3VGQUC7NS2V3UQ63M3DIMFUFGI4BRWK7WDBU"
note := []byte(nil)
closeRemainderTo := ""
amount := uint64(10000)
// Make transaction
txn, err := transaction.MakePaymentTxn(fromAddr, toAddr, amount, note, closeRemainderTo, txParams)
if err != nil {
fmt.Printf("Error creating transaction: %s\n", err)
return
}
// Sign the Transaction
_, bytes, err := crypto.SignTransaction(fromAddrPvtKey, txn)
if err != nil {
fmt.Printf("Failed to sign transaction: %s\n", err)
return
}
// Broadcast the transaction to the network
sendResponse, err := algodClient.SendRawTransaction(bytes).Do(context.Background())
if err != nil {
fmt.Printf("failed to send transaction: %s\n", err)
return
}
fmt.Printf("Transaction sent with ID %s\n", sendResponse)
waitForConfirmation(sendResponse, algodClient)
}