# Manual TX Flow

The sequence below describes the standard transaction process from scratch, alongside accompanying code. If you are following along, be sure to use a testnet and be sure to top up with some testnet LUNA.

NOTE

This serves mainly to illustrate how to work with the low-level transaction API; in practice, you can use the convenience functions offered by the Wallet object to generate and sign transactions.

# Step 1: Define Messages

A transaction is comprised of one or more messages that get processed individually by message handlers in each module. Here, let's create a simple transaction with a MsgSend and a MsgSwap.

from jigu.core import Coin, Coins
from jigu.core.msg import MsgSend, MsgSwap
from jigu.key.mnemonic import MnemonicKey

key = MnemonicKey.generate()

send = MsgSend(
    from_address=key.acc_address,
    to_address="terra1aw0znxtlq0wrayyz7wppz3qnw94hfrmnnv5mzw",
    amount=Coins(uluna=1337)
)

swap = MsgSwap(
    trader=key.acc_address,
    offer_coin=Coin("uluna", 8888),
    ask_denom="umnt"
)

# Step 2: Create a StdSignMsg

The StdSignMsg is a structure that prepares the requisite information for signing a transaction.

from jigu.core import StdSignMsg

unsigned_tx = StdSignMsg(
    chain_id="columbus-3",
    account_number=123456,
    sequence=0,
    msgs=[send, swap], # NOTE: msgs, plural
    fee=None, # change this later
    memo="Deuteronomy 31:6"
)

There are several pieces of info intended for verification that are necessary:

# Chain ID

StdSignMsg.chain_id

Defines the name of the chain we are working with. A transaction prepared for the soju-0013 testnet will be rejected if it is broadcasted on a node connected to columbus-3.

# Account Number

StdSignMsg.account_number

This is literally the number of the account on the chain specified. Any time funds are sent to an account address that has never received funds, the blockchain increments the number of total accounts and assigns that account this number.

# Sequence Number

StdSignMsg.sequence

A nonce, or value that gets incremented everytime a successful transaction signed by this account was included in a block. This prevents transactions that have already been accepted from being replayed.

TIP

It is sometimes difficult to know the account number and sequence fields. The Wallet object dynamically will fetch the correct values to use and generate a transaction.

The memo field provides a place where you can put a short note. It is worth noting that the memo will be saved on the blockchain data and visible forever by the public, and that a larger memo will result in a higher fee.

# Step 3: Set the Fee

A fee must be added for your transaction to be accepted into the blockchain, otherwise it will likely get ignored by validators. The fee structure is defined by StdFee, and specifies 2 components, the gas limit and fee amount.

The gas limit defines how much gas is allowed to be consumed by the node that processes it, and puts an upper bound on the limit of computation. The fee amount is the actual fee that gets paid. These two components provide the necessary information for validators to decide on whether to accept your transaction before processing it, as they determine the minimum gas price.

Messages like MsgSend and MsgMultiSend also incur a stability fee, which is a tax on the amount of the transaction. This must be factored in when you set the fee amount.

from jigu.core import StdFee

# Option 1
fee = StdFee(gas=150000, amount=Coins(uluna=1000000))

# Option 2
fee = StdFee.make(150000, uluna=1000000)

# Automatic fee estimation

If you are unsure of which gas values and fee amount to use, you can optionally use your node to estimate the fees that your transaction may require.

from jigu import Terra

terra = Terra("https://lcd.terra.dev/", "columbus-3")
fee = terra.estimate_fee(unsigned_tx)
fee._pp

See more on automatic fee estimation.

# Step 4: Sign and Create a StdTx

You can now sign your StdSignMsg, resulting in a signature. Then, build the StdTx (the actual transaction) and set the signatures attribute to the result of signing.

from jigu.core import StdTx

signature = key.create_signature(unsigned_tx)
tx = StdTx(
    msg=unsigned_tx.msgs, # NOTE: msg, singular
    fee=fee,
    signatures=[signature],
    memo=unsigned_tx.memo
)

Alternatively, Key also provides a more convenient option:

tx = key.sign_tx(unsigned_tx) # result: StdTx

# Applying more than one signature

Some transactions may require multiple signatures (such as those including MsgMultiSend). If that is the case, each of the signing agents should sign the original StdSignMsg individually, and you should create one StdTx with both signatures. Make note that the order of signatures matters: the account corresponding to the first signature pays for the transacton fee.

# ...
signature = key.create_signature(unsigned_tx)
signature2 = key2.create_signature(unsigned_tx)
tx = StdTx(
    msg=unsigned_tx.msgs, # NOTE: singular
    fee=fee,
    signatures=[signature, signature2],
    memo=unsigned_tx.memo
)

# Step 5: Broadcast Transaction

Now we're ready to broadcast our transaction live to the blockchain.

from jigu import Terra

terra = Terra("https://lcd.terra.dev", "columbus-3")
res = terra.broadcast(tx, mode="block")

# Transaction Modes

You can broadcast the transaction in three modes:

# After Block Inclusion (default)

Wait until the transaction has been included into a block. This is lengthy and usually takes around 6-10 seconds.

# Synchronous

Returns after the transaction has been locally checked for any errors that can be detected without consulting the blockchain state CheckTx.

# Asynchronous

Returns immediately without checking.

Updated on: 3/11/2020, 9:08:33 PM