Skip to content

Example Go code for send a transaction

alexjlan edited this page May 4, 2020 · 6 revisions

This page include some example code to send transaction in OneLedger network:

Using keystore concept

package main

import (
	"encoding/hex"
	"fmt"
	"math/big"
	"time"

	"github.com/Oneledger/protocol/action"
	"github.com/Oneledger/protocol/action/transfer"
	"github.com/Oneledger/protocol/client"
	"github.com/Oneledger/protocol/data/accounts"
	"github.com/Oneledger/protocol/data/balance"
	"github.com/Oneledger/protocol/data/chain"
	"github.com/Oneledger/protocol/data/keys"
	"github.com/Oneledger/protocol/utils"
	"github.com/google/uuid"
)

func main() {

	// connect to the node running at localhost (testnet port: 26606, mainnet port 38606)
	conn := "http://127.0.0.1:26606"

	//connect to the sdk port (26606 for testnet, 38606 for mainnet)
	cli, err := client.NewServiceClient(conn)
	if err != nil {
		panic(err)
	}

	// ==================================== create account =================================================

	// load keystore folder as wallet folder
	wallet, err := accounts.NewWalletKeyStore("./keystore")
	if err != nil {
		panic(err)
	}
	// if you already have accounts in the keystore
	fmt.Println(wallet.ListAddresses())

	//generating a new account
	acc, err := accounts.GenerateNewAccount(chain.ONELEDGER, "testing")
	if err != nil {
		panic(err)
	}
	if !wallet.Open(acc.Address(), "123") {
		panic("error opening wallet")
	}
	err = wallet.Add(acc)
	if err != nil {
		panic(err)
	}
	wallet.Close()

	// ==================================== send transaction ===============================================
	//sender address, suppose you already created it in your keystore by "olclient account add"
	from, _ := hex.DecodeString(utils.TrimAddress("0lt87b38386d6b6ea805f6c3a5f82b48fb16ab899f5"))
	if err := keys.Address(from).Err(); err != nil {
		panic(err)
	}
	//receiver address
	to, _ := hex.DecodeString(utils.TrimAddress("0lt63b05eefad9462d6b24a55b261773a3f8c977588"))
        
        // verify address
	toAddr := keys.Address(to)
	if toAddr.Err() != nil {
		panic(toAddr.Err())
	}

	// 1 OLT is with 18 zeros as decimals.
	value, ok := big.NewInt(0).SetString("1000000000000000000", 10)
	if !ok {
		panic("failed to parse value")
	}
	// sending 1 OLT.
	amount := action.Amount{
		Currency: "OLT",
		Value:    *(balance.NewAmountFromBigInt(value)),
	}

	fee := action.Fee{
		Price: action.Amount{
			Currency: "OLT",                                                 // only OLT is allowed as fee for now
			Value:    *balance.NewAmountFromBigInt(big.NewInt(10000000000)), // minimal gas price is 10^-9 OLT
		},
		Gas: 40000, // recommend gas by default},
	}

	offlineTxCreation := true

	var packet []byte
	//create transaction without interact with node
	if offlineTxCreation {
		newuuid, _ := uuid.NewUUID()
		send := transfer.Send{
			From:   from,
			To:     to,
			Amount: amount,
		}
		data, err := send.Marshal()
		if err != nil {
			panic(err)
		}
		raw := action.RawTx{
			Type: action.SEND,
			Data: data,
			Fee:  fee,
			Memo: newuuid.String(), // you can add any information here
		}

		packet = raw.RawBytes()

		//create transaction with help of node sdk
	} else {
		req := client.SendTxRequest{
			From:     from,
			To:       to,
			Amount:   amount,
			GasPrice: action.Amount{},
			Gas:      0,
		}
		reply, err := cli.CreateRawSend(req)
		if err != nil {
			panic(err)
		}
		packet = reply.RawTx

	}
	// sign the tx
	ok = wallet.Open(keys.Address(from), "123")
	if !ok {
		panic("failed to open the wallet for address: " + keys.Address(from).String())
	}
	signer, signed, err := wallet.SignWithAddress(packet, from)
	if err != nil {
		panic(err)
	}
	wallet.Close()

	// broadcast to network
	response, err := cli.TxSync(client.BroadcastRequest{
		RawTx:     packet,
		Signature: signed,
		PublicKey: signer,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println("broadcast", response)
	time.Sleep(5 * time.Second)

	// Query the network for transaction
	req := client.TxRequest{
		Hash:  response.TxHash.String(),
		Prove: true,
	}
	reply := client.TxResponse{}

	err = cli.Call("query.Tx", &req, &reply)
	fmt.Println("tx: ", reply.Result.Hash.String(), reply.Result.Height)

}

Using raw private key

package main

import (
	"encoding/hex"
	"fmt"
	"math/big"
	"time"

	"github.com/Oneledger/protocol/action"
	"github.com/Oneledger/protocol/action/transfer"
	"github.com/Oneledger/protocol/client"
	"github.com/Oneledger/protocol/data/balance"
	"github.com/Oneledger/protocol/data/keys"
	"github.com/Oneledger/protocol/serialize"
	"github.com/Oneledger/protocol/utils"
	"github.com/google/uuid"
	"github.com/powerman/rpc-codec/jsonrpc2"
)

func main() {


	// ==================================== generate keys =================================================

	pubkey, privkey, err := keys.NewKeyPairFromTendermint()
	if err != nil {
		panic(err)
	}

	// ========================== serialize to store the key and deserialize the key ======================
	pubkeyStr, _ := serialize.GetSerializer(serialize.JSON).Serialize(pubkey)
	privkeyStr, _ := serialize.GetSerializer(serialize.JSON).Serialize(privkey)
	fmt.Println("pubkey: ", string(pubkeyStr))
	fmt.Println("privkey: ", string(privkeyStr))

	fmt.Println("pubkey: ", pubkey)
	fmt.Println("privkey: ", privkey)

	pubhandler, err := pubkey.GetHandler()
	if err != nil {
		panic(err)
	}
	fmt.Println("address: ", pubhandler.Address().String())

	// load private key from stored private key bytes.
	newprivkey := &keys.PrivateKey{}
	_ = serialize.GetSerializer(serialize.JSON).Deserialize(privkeyStr, newprivkey)

	newPrivHandler, err := newprivkey.GetHandler()
	if err != nil {
		panic(err)
	}

	fmt.Println(newPrivHandler.PubKey().Equal(pubkey))


	// ========================= prepare send transaction ===============================================
	// suppose you get some OLT already
	h, _ := newPrivHandler.PubKey().GetHandler()
	from := h.Address()
	//receiver address
	to, _ := hex.DecodeString(utils.TrimAddress("0ltdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))
        
        // verify address
	toAddr := keys.Address(to)
	if toAddr.Err() != nil {
		panic(toAddr.Err())
	}

	// 1 OLT is with 18 zeros as decimals.
	value, ok := big.NewInt(0).SetString("1000000000000000000", 10)
	if !ok {
		panic("failed to parse value")
	}
	// sending 1 OLT.
	amount := action.Amount{
		Currency: "OLT",
		Value:    *(balance.NewAmountFromBigInt(value)),
	}

	fee := action.Fee{
		Price: action.Amount{
			Currency: "OLT",                                                 // only OLT is allowed as fee for now
			Value:    *balance.NewAmountFromBigInt(big.NewInt(10000000000)), // minimal gas price is 10^-9 OLT
		},
		Gas: 40000, // recommend gas by default},
	}

	newuuid, _ := uuid.NewUUID()
	send := transfer.Send{
		From:   from,
		To:     to,
		Amount: amount,
	}
	data, err := send.Marshal()
	if err != nil {
		panic(err)
	}
	raw := action.RawTx{
		Type: action.SEND,
		Data: data,
		Fee:  fee,
		Memo: newuuid.String(), // you can add any information here
	}

	packet := raw.RawBytes()

	// ============================== sign tx and broadcast =============================================

	signed, err := newPrivHandler.Sign(packet)
	if err != nil {
		panic(err)
	}


	cli := jsonrpc2.NewHTTPClient("http://127.0.0.1:26602/jsonrpc")

	response := &client.BroadcastReply{}

	err = cli.Call("broadcast.TxSync", client.BroadcastRequest{
		RawTx:     packet,
		Signature: signed,
		PublicKey: newPrivHandler.PubKey(),
	}, response)
	if err != nil {
		panic(err)
	}
	fmt.Println("broadcast", response)
	time.Sleep(5 * time.Second)

	// Query the network for transaction
	req := client.TxRequest{
		Hash:  response.TxHash.String(),
		Prove: true,
	}

	reply := client.TxResponse{}
	err = cli.Call("query.Tx", &req, &reply)
	fmt.Println("tx: ", reply.Result.Hash.String(), reply.Result.Height)

}