Subscribe to our free newsletter

To make sure you won't miss any valuable content we share with our community.

Interacting with Terra Network Using Terra Python SDK

In this article, we are going to get familiar with the Terra network and how it works. Then, we will see how we can interact with the Terra network using Terra Python SDK to interact with Terra Testnet called Bombay 12 and Mainnet called Columbus-5. In this article and the next ones, we are going to see how we can connect to the Terra network using Python, create an account and a wallet, create and sign a transaction, estimate gas fees, and swap tokens.

What Is Terra SDK?

Terra is a DeFi protocol on Blockchain that powers the universal payment systems which are based on fiat currencies using the fiat-based stable coins. This protocol uses a mixture of wide adoption of stable coins and at the same time censorship resistance of Bitcoin. Terra is built on Cosmos SDK and tendermint. The main language that the Terra smart contracts are written in, is Rust. However, there are SDKs for Python and JavaScript, and creating the smart contracts called WASM contracts is explained in more detail in JavaScript. But don’t worry most of the interactions and useful functions can be found in Python. Throughout this tutorial, we are going to see all the things we can do to develop the Terra network using Terra.py SDK.

Dealing with Terra Smart Contracts Using Terra Python SDK

If you have already worked with Ethereum smart contracts or have read our content on brownie, solidity, and Ethereum network smart contracts, you will so easily understand most of the concepts and tools that we are going to talk about. However, if you haven’t, you can still follow along with this tutorial and get familiar with the new world of smart contracts. As always, like all the blockchains that we have interacted with, we start with the test network to get used to the scripts and then learn how to switch to mainnet. To get started with Terra python SDK, let us install it using the following command:

pip3 install terra-sdk

There are also other requirements that we will cover later in our tutorial. Now let’s connect to Terra network:

terra = LCDClient("https://lcd.terra.dev", "columbus-5")
print(terra.tendermint.node_info())

Result:

{‘node_info’: {‘protocol_version’: {‘p2p’: ‘8’, ‘block’: ’11’, ‘app’: ‘0’}, ‘id’: ‘979a7f9c646623535ba2ddc69c10f3d505ccd97a’, ‘listen_addr’: ‘tcp://0.0.0.0:26656’, ‘network’: ‘columbus-5’, ‘version’: ‘0.34.14’, ‘channels’: ‘40202122233038606100’, ‘moniker’: ‘rpc5-read4’, ‘other’: {‘tx_index’: ‘on’, ‘rpc_address’: ‘tcp://0.0.0.0:26657’}}, ‘application_version’: {‘name’: ‘terra’, ‘server_name’: ‘terrad’, ‘version’: ‘0.5.17-36- gfc7ef220’, ‘commit’: ‘fc7ef220ddcd683d8e1a37a3ac484abb4e8b88ef’, ‘build_tags’: ‘netgo,ledger’, ‘go’: ‘go version go1.18 linux/amd64’, ‘build_deps’: [‘filippo.io/[email protected]’, ‘github.com/99designs/[email protected] => github.com/cosmos/[email protected]’, ‘github.com/ChainSafe/[email protected]’, ‘github.com/CosmWasm/[email protected]’, ‘github.com/Workiva/[email protected]’, ‘github.com/armon/[email protected]’, ‘github.com/beorn7/[email protected]’, ‘github.com/bgentry/[email protected]’, ‘github.com/btcsuite/[email protected]’, ‘github.com/cespare/xxhash/[email protected]’, ‘github.com/coinbase/[email protected]’, ‘github.com/confio/ics23/[email protected]’, ‘github.com/cosmos/[email protected]’, ‘github.com/cosmos/[email protected] => github.com/terra-money/[email protected]’, ‘github.com/cosmos/[email protected]’, ‘github.com/cosmos/[email protected]’, ‘github.com/cosmos/[email protected]’, ‘github.com/cosmos/[email protected] => github.com/terramoney/[email protected]’, ‘github.com/cosmos/[email protected]’, ‘github.com/davecgh/[email protected]’, ‘github.com/desertbit/[email protected] 20180107155436-c41aec40b27f’, ‘github.com/dvsekhvalnov/[email protected] 20200901110807-248326c1351b’, ‘github.com/felixge/[email protected]’, ‘github.com/fsnotify/[email protected]’, ‘github.com/go-kit/[email protected]’, ‘github.com/go-logfmt/[email protected]’, ‘github.com/godbus/[email protected] 20190726142602-4481cbc300e2’, ‘github.com/gogo/[email protected]’, ‘github.com/gogo/[email protected] => github.com/regen-network/[email protected] alpha.regen.1’, ‘github.com/golang/[email protected]’, ‘github.com/golang/[email protected]’, ‘github.com/google/[email protected]’, ‘github.com/google/[email protected]’, ‘github.com/gorilla/[email protected]’, ‘github.com/gorilla/[email protected]’, ‘github.com/gorilla/[email protected]’, ‘github.com/grpc-ecosystem/[email protected]’, ‘github.com/grpcecosystem/[email protected]’, ‘github.com/gsterjov/[email protected] 20161001094733-a6f4afe4910c’, ‘github.com/gtank/[email protected]’, ‘github.com/gtank/[email protected]’, ‘github.com/hashicorp/[email protected]’, ‘github.com/hashicorp/[email protected]’, ‘github.com/hashicorp/[email protected]’, ‘github.com/hdevalence/[email protected] 59a8610d2b87’, ‘github.com/improbable-eng/[email protected]’, ‘github.com/klauspost/[email protected]’, ‘github.com/lib/[email protected]’, ‘github.com/libp2p/[email protected]’, ‘github.com/magiconair/[email protected]’, ‘github.com/mattn/[email protected]’, ‘github.com/matttproud/[email protected]’, ‘github.com/mimoo/[email protected]’, ‘github.com/minio/[email protected]’, ‘github.com/mitchellh/[email protected]’, ‘github.com/mtibben/[email protected]’, ‘github.com/pelletier/[email protected]’, ‘github.com/pkg/[email protected]’, ‘github.com/pmezard/[email protected]’, ‘github.com/prometheus/[email protected]’, ‘github.com/prometheus/[email protected]’, ‘github.com/prometheus/[email protected]’, ‘github.com/prometheus/[email protected]’, ‘github.com/rakyll/[email protected]’, ‘github.com/rcrowley/[email protected] 20200313005456-10cdbea86bc0’, ‘github.com/regen-network/[email protected]’, ‘github.com/rs/[email protected]’, ‘github.com/rs/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/spf13/[email protected]’, ‘github.com/stretchr/[email protected]’, ‘github.com/subosito/[email protected]’, ‘github.com/syndtr/[email protected]’, ‘github.com/tendermint/[email protected]’, ‘github.com/tendermint/[email protected] 20191022145703-50d29ede1e15’, ‘github.com/tendermint/[email protected]’, ‘github.com/tendermint/[email protected] => github.com/terra-money/[email protected]’, ‘github.com/tendermint/[email protected] => github.com/terra-money/[email protected] performance.7’, ‘github.com/zondax/[email protected]’, ‘golang.org/x/[email protected] 20210817164053-32db794688a5’, ‘golang.org/x/[email protected] ad29c8ab022f’, ‘golang.org/x/[email protected]’, ‘golang.org/x/[email protected]’, ‘golang.org/x/[email protected]’, ‘google.golang.org/[email protected] 66f60bf46e71’, ‘google.golang.org/[email protected] => google.golang.org/[email protected]’, ‘google.golang.org/[email protected]’, ‘gopkg.in/[email protected]’, ‘gopkg.in/[email protected]’, ‘gopkg.in/[email protected] 20210107192922-496545a6307b’, ‘nhooyr.io/[email protected]’], ‘cosmos_sdk_version’: ‘v0.44.5’}}

For the first step, we can create an account by creating a mnemonic key:

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
mk = MnemonicKey()
print(mk.mnemonic)


Now, let’s test run the code:

python3 Test.py

Result:

tonight panda own all coconut home tackle gap food uncle vacant account clap napkin boring mango cable funny tooth vanish opinion genre differ impact

Notice that the above mnemonic key works the same as the private key and you will need to save it somewhere safe. Because if you forget it, you will never be able to recover the phrases. Besides, do not pass this mnemonic key to anyone. Because if you have money in it, they will be able to withdraw it anytime they want. We can get the account address by:

print(mk.acc_address)

Result:

terra1krrcxa8ccs7dwagtuevt2m4d78z0uwf4qe25yu

And the private key by:

print(mk.private_key)

Result:

b’\xf1\x92IyzN<\x14\xf2{N\x8a=\x86\x06\x9c \xab\n~/*\xb0\xb8b+z\xecS\x10\xcd,'

And the private key by:

print(mk.private_key)

Besides, make sure you save the mnemonic key somewhere safe. Let’s get some Luna from Terra Testnet Faucet https://faucet.terra.money/. We need to copy the account address we’ve got in the box:

Terra network using Terra Python SDK

Once we get the message, we will be redirected to the Terrascope which is similar to Etherscan and we can see the test Luna that we have been given:

Terra network using Terra Python SDK

Terra network using Terra Python SDK-transaction details

We can also see the details of our account if we click on the to address:

Terra network using Terra Python SDK-creating account

We can retrieve the balance of our account using the following code:

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
terra = LCDClient("https://lcd.terra.dev", " bombay-12")
mk = MnemonicKey(mnemonic="disorder solar ride ecology father pear conduct 
     anger distance soul slow outside market twenty badge alter busy inspire tag 
     enforce chicken shaft giggle measure")
print(terra.bank.balance(mk.acc_address))


Notice that in the above code, we have managed to call back the account using the mnemonic key we got when we used the mk = MnemonicKey() script. We have also connected to the Bombay-12 Testnet. Now let’s run the code: python3 Test.py Result: Coins('1000000000uluna’)

Interacting with Terra Network Using SDK: Wallet and Changing

In this part, we are going to see how we can connect to the Terra network, create an account and a wallet, create and sign transactions, estimate gas fees, and swap tokens. Of course, all of these operations are going to be executed on a Testnet rather than a Mainnet in case we lose real money. In this article, we are going to cover more interactions with Terra Testnet by creating and signing transactions, transferring money, creating a wallet and an account, and sending JSON messages to Terra smart contracts.

Setting up the Network and the Chain ID

Up to now, we have learned how to connect to Terra chain Mainnet and Testnet, how to get some test Luna and how we can create test accounts. One thing to notice is how we can switch between different networks (Mainnet to Testnet). As we have mentioned before, there are 2 parameters for defining every network:
  1. URL
  2. Chain ID
Terra chain has had many test networks such as tequila which is outdated, Bombay (the newer one), and other custom networks created by developers. You can also create your own node using the guides on the Terra Documentation website https://docs.terra.money/docs/full-node/run-a-full-terra-node/join-a-network.html#.

If you are on Mainnet, you can enter as the https://lcd.terra.dev URL and as Columbus-5 chain id and if you are on Testnet, you can use https://bombay-lcd.terra.dev/ as the URL and Bombay-12 as your chain id. Notice that at the current time of writing, the Terra The faucet is on Bombay test network. So if you want to interact with the test ulunas sent from Bombay Faucet, you should use the specific URL and chain id of this test network.

Creating An Account on Terra Testnet

Using the below script, we can create an account, and get a mnemonic key for it. Make sure you copy the mnemonic somewhere so that you can use it later when you want to get some test Luna from Terra Faucet or when you want to get the balance of the account or create and sign a transaction using it.

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey()
print(Account1.mnemonic)


Result: call oil decrease loud pull indicate diet post sign cereal adapt rug reform alcohol math illegal major anchor unhappy govern win round ritual various Now, we can use the Bombay Faucet to get some test uluna. And using the below script we can see the balance of account 1 containing uluna,

print(terra.bank.balance(Account1.acc_address)[0]['uluna'].amount)


Result: 5000000 And using the below code, we can see all the assets of the account1: print(terra.bank.balance(Account1.acc_address)[0]) Result: Coins('5000000uluna')

Transferring Luna from One Account to Another Using Python Script

Now, we want to create a transaction using Account1 with the mnemonic key that we have got and creating a new account called Account2.

Notice that we define each account with its specific mnemonic key and here when we want to use the created account (Account1), we use the mnemonic key to reuse it, otherwise, a new account will be created with no funds in it.

Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post 
     sign cereal adapt rug reform alcohol math illegal 
     major anchor unhappy govern win round 
     ritual various")


And here comes the complete code to create a transaction and send a quarter of the balance of account 1 to account 2. We will also create a wallet for account 1 to be able to execute the transaction.

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
from terra_sdk.core.fee import Fee
from terra_sdk.core.bank import MsgSend
from terra_sdk.client.lcd.api.tx import CreateTxOptions

terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post 
     sign cereal adapt rug reform alcohol math illegal 
     major anchor unhappy govern win round 
     ritual various")
Account2 = MnemonicKey()
wallet = terra.wallet(Account1)
print(terra.bank.balance(Account1.acc_address)[0]['uluna'].amount)
print(terra.bank.balance(Account2.acc_address)[0]['uluna'].amount)
Amount_To_Send = (terra.bank.balance(Account1.acc_address)[0])/4
print(Amount_To_Send)

tx = wallet.create_and_sign_tx(CreateTxOptions(
     msgs = [MsgSend(from_address=Account1.acc_address, 
          to_address = Account2.acc_address, 
          amount=Amount_To_Send )],
     memo = "Only Testing",
     gas_prices = "1uluna", 
     gas_adjustment = "1.5")) 

result = terra.tx.broadcast(tx)
print(result)


Result: 5000000 0 1250000uluna BlockTxBroadcastResult(height=8795417, txhash='10B07115283D05126EF4DCA72576BB3E4DD812B24B002614913020532 2999645', raw_log='[{"events":[{"type":"coin_received","attributes": [{"key":"receiver","value":"terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4"}, {"key":"amount","value":"1250000uluna"}]},{"type":"coin_spent","attributes": [{"key":"spender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"amount","value":"1250000uluna"}]},{"type":"message","attributes": [{"key":"action","value":"/cosmos.bank.v1beta1.MsgSend"}, {"key":"sender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"module","value":"bank"}]},{"type":"transfer","attributes": [{"key":"recipient","value":"terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4"}, {"key":"sender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"amount","value":"1250000uluna"}]}]}]', gas_wanted=95229, gas_used=76149, logs=[TxLog(msg_index=0, log='', events=[{'type': 'coin_received', 'attributes': [{'key': 'receiver', 'value': 'terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4'}, {'key': 'amount', 'value': '1250000uluna'}]}, {'type': 'coin_spent', 'attributes': [{'key': 'spender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'amount', 'value': '1250000uluna'}]}, {'type': 'message', 'attributes': [{'key': 'action', 'value': '/cosmos.bank.v1beta1.MsgSend'}, {'key': 'sender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'module', 'value': 'bank'}]}, {'type': 'transfer', 'attributes': [{'key': 'recipient', 'value': 'terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4'}, {'key': 'sender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'amount', 'value': '1250000uluna'}]}], events_by_type={'coin_received': {'receiver': ['terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4'], 'amount': ['1250000uluna']}, 'coin_spent': {'spender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'], 'amount': ['1250000uluna']}, 'message': {'action': ['/cosmos.bank.v1beta1.MsgSend'], 'sender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'], 'module': ['bank']}, 'transfer': {'recipient': ['terra1e20tg4gat39ex4ezer724r5qs9dhnshjg065d4'], 'sender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'], 'amount': ['1250000uluna']}})], code=0, codespace='', info=None, data=None, timestamp=None) As you can see after a few seconds, the result of the transaction is printed out and you can get some of the data you need from this very long output. If we want to check our transaction details we can head over to Terra Finder https://finder.terra.money/ and paste the txhash from the resulting output. Notice that you should choose the network (Mainnet, Testnet, or local) from the top-right menu. And you will be able to see the details of the transaction similar to what we saw in Etherscan for the Ethereum blockchain.

In this article we are going to get familiar with the Terra Network Using Terra Python SDK and how it works. Then, we will see how we can use Terra Python SDK to interact with Terra Testnet called Bombay-12 and Mainnet called Columbus-5. In this 3rd part of Terra Python SDK, we are going to fetch price data from Terra Network, estimate gas fees for our transactions, and swap tokens using the Python SDK for Terra.

Terra Network Using Terra Python SDK: the Last Part

In this 3rd part of Terra Python SDK, we are going to fetch price data from Terra Network, estimate the gas fee for our transactions, and swap tokens using the Python SDK for Terra.

Requesting Price Data

We can fetch the price of uluna from FCD terra node with the following script:

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
import requests
import json

terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post 
     sign cereal adapt rug reform alcohol 
     math illegal major anchor unhappy 
     govern win round ritual various")

Account2 = MnemonicKey()
wallet = terra.wallet(Account1)
print(requests.get('https://fcd.terra.dev/v1/market/price?denom=uusd&interval=1h').json())


Result: {'lastPrice': 90.48744281649324, 'oneDayVariation': '2.03086440151527', 'oneDayVariationRate': '0.02244360475114567212', 'prices': [{'denom': 'uusd', 'price': 88.96415361266797, 'datetime': 1650888000000}, {'denom': 'uusd', 'price': 89.0900844450184, 'datetime': 1650891600000}, {'denom': 'uusd', 'price': 90.66006870152763, 'datetime': 1650895200000}, {'denom': 'uusd', 'price': 92.52536809614227, 'datetime': 1650898800000}, {'denom': 'uusd', 'price': 94.04939366114037, 'datetime': 1650902400000}, {'denom': 'uusd', 'price': 94.3395565349883, 'datetime': 1650906000000}, {'denom': 'uusd', 'price': 94.4164196214135, 'datetime': 1650909600000}, {'denom': 'uusd', 'price': 95.56109206654655, 'datetime': 1650913200000}, {'denom': 'uusd', 'price': 95.81135596156976, 'datetime': 1650916800000}, {'denom': 'uusd', 'price': 95.28242522306937, 'datetime': 1650920400000}, {'denom': 'uusd', 'price': 95.58401419222808, 'datetime': 1650924000000}, {'denom': 'uusd', 'price': 96.91434728345023, 'datetime': 1650927600000}, {'denom': 'uusd', 'price': 96.80871579823581, 'datetime': 1650931200000}, {'denom': 'uusd', 'price': 96.17697287838071, 'datetime': 1650934800000}, {'denom': 'uusd', 'price': 96.03501028344412, 'datetime': 1650938400000}, {'denom': 'uusd', 'price': 96.22807016895509, 'datetime': 1650942000000}, {'denom': 'uusd', 'price': 96.06570662357241, 'datetime': 1650945600000}, {'denom': 'uusd', 'price': 95.70176476651612, 'datetime': 1650949200000}, {'denom': 'uusd', 'price': 95.60364542853246, 'datetime': 1650952800000}, {'denom': 'uusd', 'price': 96.30584856654487, 'datetime': 1650956400000}, {'denom': 'uusd', 'price': 96.28680905438578, 'datetime': 1650960000000}, {'denom': 'uusd', 'price': 96.0928405310103, 'datetime': 1650963600000}, {'denom': 'uusd', 'price': 96.37104756437165, 'datetime': 1650967200000}, {'denom': 'uusd', 'price': 96.34377771748161, 'datetime': 1650970800000}, {'denom': 'uusd', 'price': 95.68353760426069, 'datetime': 1650974400000}, {'denom': 'uusd', 'price': 95.93167829936388, 'datetime': 1650978000000}, {'denom': 'uusd', 'price': 93.96949533359299, 'datetime': 1650981600000}, {'denom': 'uusd', 'price': 91.55576611528446, 'datetime': 1650985200000}, {'denom': 'uusd', 'price': 89.93169609113293, 'datetime': 1650988800000}, {'denom': 'uusd', 'price': 89.23415738171494, 'datetime': 1650992400000}, {'denom': 'uusd', 'price': 89.06808181910975, 'datetime': 1650996000000}, {'denom': 'uusd', 'price': 88.48694667915775, 'datetime': 1650999600000}, {'denom': 'uusd', 'price': 88.11627958903455, 'datetime': 1651003200000}, {'denom': 'uusd', 'price': 89.09030726339398, 'datetime': 1651006800000}, {'denom': 'uusd', 'price': 89.06232865592419, 'datetime': 1651010400000}, {'denom': 'uusd', 'price': 88.54428184656634, 'datetime': 1651014000000}, {'denom': 'uusd', 'price': 88.778354665981, 'datetime': 1651017600000}, {'denom': 'uusd', 'price': 89.00243656718825, 'datetime': 1651021200000}, {'denom': 'uusd', 'price': 88.7637772736078, 'datetime': 1651024800000}, {'denom': 'uusd', 'price': 88.43322633009933, 'datetime': 1651028400000}, {'denom': 'uusd', 'price': 88.03606836235143, 'datetime': 1651032000000}, {'denom': 'uusd', 'price': 88.30151817608929, 'datetime': 1651035600000}, {'denom': 'uusd', 'price': 88.60340905121288, 'datetime': 1651039200000}, {'denom': 'uusd', 'price': 89.83111008867395, 'datetime': 1651042800000}, {'denom': 'uusd', 'price': 89.64450032950381, 'datetime': 1651046400000}, {'denom': 'uusd', 'price': 89.34933700739906, 'datetime': 1651050000000}, {'denom': 'uusd', 'price': 89.27527287128059, 'datetime': 1651053600000}, {'denom': 'uusd', 'price': 88.73870274154594, 'datetime': 1651057200000}, {'denom': 'uusd', 'price': 88.83721399177365, 'datetime': 1651060800000}, {'denom': 'uusd', 'price': 89.2133569858777, 'datetime': 1651064400000}]}

Gas Fee Estimation on Terra Blockchain

Gas fee estimation is an important step when you want to execute a transaction on a blockchain. Using the following code in which we use https://fcd.terra.dev/v1/txs/gas_prices, we can get the gas fee in different tokens. So, we can estimate the gas fee for our transaction in the future:

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
import requests
import json
terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post
     sign cereal adapt rug reform alcohol math illegal major anchor unhappy govern win
     round ritual various")
Account2 = MnemonicKey()
wallet = terra.wallet(Account1)
fees = requests.get("https://fcd.terra.dev/v1/txs/gas_prices").json()
print(fees)


Result: {'uluna': '0.01133', 'usdr': '0.104938', 'uusd': '0.15', 'ukrw': '170.0', 'umnt': '428.571', 'ueur': '0.125', 'ucny': '0.98', 'ujpy': '16.37', 'ugbp': '0.11', 'uinr': '10.88', 'ucad': '0.19', 'uchf': '0.14', 'uaud': '0.19', 'usgd': '0.2', 'uthb': '4.62', 'usek': '1.25', 'unok': '1.25', 'udkk': '0.9', 'uidr': '2180.0', 'uphp': '7.6', 'uhkd': '1.17', 'umyr': '0.6', 'utwd': '4.0'} And you can see the .json output of the fee in different tokens. Now, it is time to estimate the gas fee using fee = str(float(fees["uusd"])) + "uusd":

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
import requests
import json
from terra_sdk.core.bank import MsgSend
terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post
     sign cereal adapt rug reform alcohol math illegal major anchor unhappy govern win
     round ritual various")
Account2 = MnemonicKey()
wallet = terra.wallet(Account1)
fees = requests.get("https://fcd.terra.dev/v1/txs/gas_prices").json()
Amount_To_Send = (terra.bank.balance(Account1.acc_address)[0])/10
print(Amount_To_Send)
msg = MsgSend(from_address=Account1.acc_address, 
     to_address=Account2.acc_address, 
     amount=Amount_To_Send )

fee = str(float(fees["uusd"])) + "uusd"
print(fee)


Result: 67360uluna 0.15uusd

Swapping Tokens on Terra Blockchain

One of the most useful features of Terra blockchain is the ability to swap between different tokens of its chain. For example, here we want to swap our Bombay testnet uluna with test UST. The below script shows how we simply do that. To make sure that the swapping transaction has been successfully completed, we check the balance before and after the transaction.

from terra_sdk.client.lcd import LCDClient
from terra_sdk.key.mnemonic import MnemonicKey
from terra_sdk.core.market import MsgSwap
from terra_sdk.client.lcd.api.tx import CreateTxOptions
terra = LCDClient("https://bombay-lcd.terra.dev/", "bombay-12")
Account1 = MnemonicKey(mnemonic="call oil decrease loud pull indicate diet post
     sign cereal adapt rug reform alcohol math illegal major anchor unhappy govern win
     round ritual various")
msg = MsgSwap(Account1.acc_address, "100uluna", "uusd")
wallet = terra.wallet(Account1)
print(terra.bank.balance(Account1.acc_address)[0])
tx = wallet.create_and_sign_tx(CreateTxOptions(msgs = [msg],
     memo = "Swapping luna for UST",
     gas_prices = "1uluna",
     gas_adjustment = "1.3",
     fee_denoms = ["uluna", "uusd"]
     ))
result = terra.tx.broadcast(tx)
print(result)
print(terra.bank.balance(Account1.acc_address)[0])


Result: 421527uluna,17604uusd BlockTxBroadcastResult(height=8805631, txhash='D87F2D6ACD0EAA919EA6AAE66DC173DCF162A58668560C9284EA4 52D42279125', raw_log='[{"events":[{"type":"burn","attributes": [{"key":"burner","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"100uluna"}]},{"type":"coin_received","attributes": [{"key":"receiver","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"100uluna"}, {"key":"receiver","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"8864uusd"}, {"key":"receiver","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"amount","value":"8820uusd"}, {"key":"receiver","value":"terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f"}, {"key":"amount","value":"44uusd"}]},{"type":"coin_spent","attributes": [{"key":"spender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"amount","value":"100uluna"}, {"key":"spender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"100uluna"}, {"key":"spender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"8820uusd"}, {"key":"spender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"44uusd"}]},{"type":"coinbase","attributes": [{"key":"minter","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"8864uusd"}]},{"type":"message","attributes": [{"key":"action","value":"/terra.market.v1beta1.MsgSwap"}, {"key":"sender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"sender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"sender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"module","value":"market"}]},{"type":"swap","attributes": [{"key":"offer","value":"100uluna"}, {"key":"trader","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"recipient","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"swap_coin","value":"8820uusd"},{"key":"swap_fee","value":"44uusd"}]}, {"type":"transfer","attributes": [{"key":"recipient","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"sender","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"amount","value":"100uluna"}, {"key":"recipient","value":"terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr"}, {"key":"sender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"8820uusd"}, {"key":"recipient","value":"terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f"}, {"key":"sender","value":"terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s"}, {"key":"amount","value":"44uusd"}]}]}]', gas_wanted=126031, gas_used=108830, logs=[TxLog(msg_index=0, log='', events=[{'type': 'burn', 'attributes': [{'key': 'burner', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '100uluna'}]}, {'type': 'coin_received', 'attributes': [{'key': 'receiver', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '100uluna'}, {'key': 'receiver', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '8864uusd'}, {'key': 'receiver', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'amount', 'value': '8820uusd'}, {'key': 'receiver', 'value': 'terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f'}, {'key': 'amount', 'value': '44uusd'}]}, {'type': 'coin_spent', 'attributes': [{'key': 'spender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'amount', 'value': '100uluna'}, {'key': 'spender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '100uluna'}, {'key': 'spender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '8820uusd'}, {'key': 'spender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '44uusd'}]}, {'type': 'coinbase', 'attributes': [{'key': 'minter', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '8864uusd'}]}, {'type': 'message', 'attributes': [{'key': 'action', 'value': '/terra.market.v1beta1.MsgSwap'}, {'key': 'sender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'sender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'sender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'module', 'value': 'market'}]}, {'type': 'swap', 'attributes': [{'key': 'offer', 'value': '100uluna'}, {'key': 'trader', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'recipient', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'swap_coin', 'value': '8820uusd'}, {'key': 'swap_fee', 'value': '44uusd'}]}, {'type': 'transfer', 'attributes': [{'key': 'recipient', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'sender', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'amount', 'value': '100uluna'}, {'key': 'recipient', 'value': 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'}, {'key': 'sender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '8820uusd'}, {'key': 'recipient', 'value': 'terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f'}, {'key': 'sender', 'value': 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'}, {'key': 'amount', 'value': '44uusd'}]}], events_by_type={'burn': {'burner': ['terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'], 'amount': ['100uluna']}, 'coin_received': {'receiver': ['terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr', 'terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f'], 'amount': ['100uluna', '8864uusd', '8820uusd', '44uusd']}, 'coin_spent': {'spender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'], 'amount': ['100uluna', '100uluna', '8820uusd', '44uusd']}, 'coinbase': {'minter': ['terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'], 'amount': ['8864uusd']}, 'message': {'action': ['/terra.market.v1beta1.MsgSwap','sender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'], 'module': ['market']}, 'swap': {'offer': ['100uluna'], 'trader': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'], 'recipient': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr'], 'swap_coin': ['8820uusd'], 'swap_fee': ['44uusd']}, 'transfer': {'recipient': ['terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr', 'terra1jgp27m8fykex4e4jtt0l7ze8q528ux2lh4zh0f'], 'sender': ['terra16q9hkwe9t5jac20e08tz4qwflwkjxymw9qm3kr', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s', 'terra1untf85jwv3kt0puyyc39myxjvplagr3wstgs5s'], 'amount': ['100uluna', '8820uusd', '44uusd']}})], code=0, codespace='', info=None, data=None, timestamp=None) 295396uluna,26424uusd And as you can see we have got some uusd in exchange for ulunas.

Learned to Work with Terra Network Using Terra Python SDK

Firstly, we have learned how to connect to Terra Mainnet and Testnet, create an account, and get the mnemonic key, private key, and the balance of the account.

Secondly, we have learned how to connect to the Terra Tesnet blockchain called Bombay-12, create an account, create a wallet, transfer money from one account to another and create and sign a transaction using python Terra SDK.

And finally, we have learned how to work with Terra Testnet and we have connected to the Bombay-12 test network in addition to creating a wallet, and an account, creating and signing a transaction, transferring money, swapping tokens, and estimating gas fees for a transaction.

Download this Article in PDF format

metaverse

Curious about What We’re Up To?

In Arashtad we provide custom services in various design and development fields. 3D websites, 3D games, metaverses, and other types of WebGL and 3D applications are just some of our expertise.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Request a Quote
Blockchain Development

Interacting with Local Terra Smart Contracts Using Python

In this article, we first connect to local Terra using Docker. Then we try to interact with local Terra smart contracts using Python scripts and at the same time use the CosmWasm functions inside LocalTerra\src folder written in Rust programming language. Finally, we will manage to interact with it.

Connecting to Local Terra with Docker with Python

First off, To start our interaction with local Terra, we need to make sure docker is running: sudo usermod -aG docker $USER Make sure you sign in to your docker profile to be able to easily log in using the following command docker login. docker-compose up Result: terrad_1 | 8:48PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"3F119B6520D17CCC29A23F016B9E40151E3A5784A3F83D65BD0DD2D282FB1A4F"," parts": {"hash":"5928F59D217852E3722E46A9134D40F9329D540555EAD1DAE4B5EFA8A41E88D4"," total":1}},"height":1948,"pol_round":- 1,"round":0,"signature":"cYh80NzZezistnyNzEP2yFDnsoc7JOB+/8J1wnell- Gq76IE3qvH9jU2KvQx6u4y+A9xYrIQEJonzxa//vOZfBw==","timestamp":"2022- 05-08T20:48:12.151658182Z"} terrad_1 | 8:48PM INF received complete proposal block hash=3F119B6520D17CCC29A23F016B9E40151E3A5784A3F83D65BD0DD2D282FB1A4F height=1948 module=consensus terrad_1 | 8:48PM INF finalizing commit of block hash=3F119B6520D17CCC29A23F016B9E40151E3A5784A3F83D65BD0DD2D282FB1A4F height=1948 module=consensus num_txs=0 root=332F90B4F0706BCB055547- FA8443A1F623FC3DAE4043162730F59D15612D5FAE terrad_1 | 8:48PM INF minted coins from module account amount=226578914uluna from=mint module=x/bank terrad_1 | 8:48PM INF executed block height=1948 module=state num_invalid_txs=0 num_valid_txs=0 terrad_1 | 8:48PM INF commit synced commit=436F6D6D697449447B5B393820323020343020323436203134362031303 32036342032313320393520313132203131372031353920393320313536203231312 03632203332203836203137203132352032333920323131203533203337203139352 03637203739203635203830203235322032203138355D3A3739437D terrad_1 | 8:48PM INF committed state app_hash=621428F6926740D55F70759F5D9CD33E2056117DEFD33525C3434F41 50FC02B9 height=1948 module=state num_txs=0 terrad_1 | 8:48PM INF indexed block height=1948 module=txindex terrad_1 | 8:48PM INF Timed out dur=4990.525864 height=1949 module=consensus round=0 step=1 terrad_1 | 8:48PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"43FEBF954F5FFEA7350E4D8D38FCCA39E439F2D3026ADE9ED3E21D2706AC2596"," parts": {"hash":"112F8B0B6AA51D1D0FCCE2D049F739EC7FEB9B6C2092B1141A55E88AC453FF57"," total":1}},"height":1 949,"pol_round":-1,"round":0,"signature":"tuusiNhk5kRrKpLykCNWb/4b1nrfk22n- RCyaLh650ouCugzK7rGOHq+4eQvBu3HQ3/Y4mF/RFbA67tqO2+nrBQ==","timestamp":" 2022-05-08T20:48:17.164422986Z"} terrad_1 | 8:48PM INF received complete proposal block hash=43FEBF954F5FFEA7350E4D8D38FCCA39E439F2D3026ADE9ED3E21D2706AC2596 height=1949 module=consensus terrad_1 | 8:48PM INF finalizing commit of block hash=43FEBF954F5FFEA7350E4D8D38FCCA39E439F2D3026ADE9ED3E21D2706AC2596 height=1949 module=consensus num_txs=0 root=621428F6926740D55F70759F5D9CD33E2056117DEFD33525C3434F4150FC 02B9 terrad_1 | 8:48PM INF minted coins from module account amount=226578918uluna from=mint module=x/bank terrad_1 | 8:48PM INF executed block height=1949 module=state num_invalid_txs=0 num_valid_txs=0 terrad_1 | 8:48PM INF commit synced commit=436F6D6D697449447B5B352032323420323437203734203133382033312 03231322035322032343220313637203134342037382038332036392032303720313 93920313335203337203230342032382033362031353320333920313930203232382 0333020313434203538203138342032343620313835203230375D3A3739447D terrad_1 | 8:48PM INF committed state app_hash=05E0F74A8A1FD434F2A7904E5345CFC78725CC1C249927BEE41E903AB8F6B9CF height=1949 module=state num_txs=0 terrad_1 | 8:48PM INF indexed block height=1949 module=txindex terrad_1 | 8:48PM INF Timed out dur=4987.072234 height=1950 module=consensus round=0 step=1 terrad_1 | 8:48PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"5E1C9EA0F662335- DAD4936E50C904AF1FF3D8BBF1083A967A8C4D8EA762942F7","parts": {"hash":"0C3DA2F2B1CDCDF56C432F85E3EE1B0A21064EF69E4DB2D5CAFBE0609FDDE699"," total":1}},"height":1950,"pol_round":- 1,"round":0,"signature":"ZQeA6WQaamDpW07PD64ezc+U1vs/IW3XzMp/yShIIMbJChJFiOJwDB+ dtipWPORdKHNrWVVFlei4drGlx70iCg==","timestamp":"2022- 05-08T20:48:22.181798507Z"} terrad_1 | 8:48PM INF received complete proposal block hash=5E1C9EA0F662335DAD4936E50C904AF1FF3D8BBF1083A967A8C4D8EA762942F7 height=1950 module=consensus terrad_1 | 8:48PM INF finalizing commit of block hash=5E1C9EA0F662335- DAD4936E50C904AF1FF3D8BBF1083A967A8C4D8EA762942F7 height=1950 module=consensus num_txs=0 root=05E0F74A8A1FD434F2A7904E5345CFC78725CC1C249927BEE41E903AB8F6B9CF terrad_1 | 8:48PM INF minted coins from module account amount=226578923uluna from=mint module=x/bank terrad_1 | 8:48PM INF executed block height=1950 module=state num_invalid_txs=0 num_valid_txs=0 terrad_1 | 8:48PM INF commit synced commit=436F6D6D697449447B5B323133203133342032343920393320313830203 13234203136342033372033342032313620313733203236203734203133322032343 22032352031383520313731203230322037302032333520313635203339203235352 0323532203233302035312037203134203135203537203130335D3A3739457D terrad_1 | 8:48PM INF committed state app_hash=D586F95DB47- CA42522D8AD1A4A84F219B9ABCA46EBA527FFFCE633070E0F3967 height=1950 module=state num_txs=0 terrad_1 | 8:48PM INF indexed block height=1950 module=txindex terrad_1 | 8:48PM INF Timed out dur=4983.73452 height=1951 module=consensus round=0 step=1 terrad_1 | 8:48PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"2D43F5FF6625BD376D71F60269615A5E556BEFF85FC44461B05AF17E54958490"," parts": {"hash":"8377DFE5E66B80B3B9DA5894F5778DF1585741A1C718626AE14167158F7A5DAE"," total":1}},"height":1951,"pol_round ":-1,"round":0,"signature":"Xtc1Wggm2dD/n3YNFjvykNUmXFkN9gNuVL/ yKab4js2DMl2xGJ7ZAjDW/0RceJIBle9SWX13smUamxfsd2wbCQ==","timestamp":" 2022-05-08T20:48:27.197935715Z"} terrad_1 | 8:48PM INF received complete proposal block hash=2D43F5FF6625BD376D71F60269615A5E556BEFF85FC44461B05AF17E54958490 height=1951 module=consensus terrad_1 | 8:48PM INF finalizing commit of block hash=2D43F5FF6625BD376D71F60269615A5E556BEFF85FC44461B05AF17E54958490 height=1951 module=consensus num_txs=1 root=D586F95DB47- CA42522D8AD1A4A84F219B9ABCA46EBA527FFFCE633070E0F3967 terrad_1 | 8:48PM INF minted coins from module account amount=226578928uluna from=mint module=x/bank terrad_1 | 8:48PM INF executed block height=1951 module=state num_invalid_txs=0 num_valid_txs=1

Interacting with Local Terra Using Python: Storing the Contract

Then you can create a new folder inside the local Terra directory and name it testing. Then create another new folder inside the testing folder and name it artifacts. From the artifacts folder of some of the created projects in the local Terra directory (Like NewProjectName), copy the .wasm file and paste it into the new artifacts folder. After that create a new python file inside of the testing folder and name it contract.py. You can write the following code in the contract.py.
		
from terra_sdk.client.localterra import LocalTerra
from terra_sdk.util.contract import read_file_as_b64
from terra_sdk.core.fee import Fee
from terra_sdk.client.lcd.api.tx import CreateTxOptions
from terra_sdk.core.wasm import MsgStoreCode

lt = LocalTerra()
deployer = lt.wallets["test1"]

def store_contract(contract_name:str) -> str:
	contract_bytes = read_file_as_b64(f"artifacts/{contract_name}.wasm")
	store_code = MsgStoreCode(
	deployer.key.acc_address,
	contract_bytes
	)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [store_code],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	print(result)

store_contract("Testing")

		
	
In the above code, at first, we connect to local Terra, then we create a wallet for the deployer of the contract (which is us). After that, we create a function called store contract, inside which we read the .wasm file in the artifacts folder and store it in a variable called contract_bytes. Then we create a message called the MsgStoreCode using the contract_bytes variable and after that, we create and sign a transaction using the store_code message. Finally, we broadcast the transaction and use the store_contract function with the name of the contract called Testing (The name of our project folder).

And run it in another bash, so as not to interfere with the docker running the local Terra, use the following command to start our first interaction with Terra network. python3 contract.py Result: BlockTxBroadcastResult(height=1626, txhash='1143BD1F71A9E951F3B99D7EEE4BF0EE304F0C6C4A63DADA96F7CE243F25F39A', raw_log='[{"events":[{"type":"message","attributes": [{"key":"action","value":"/terra.wasm.v1beta1.MsgStoreCode"}, {"key":"module","value":"wasm"}]},{"type":"store_code","attributes": [{"key":"sender","value":"terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v"}, {"key":"code_id","value":"1"}]}]}]', gas_wanted=4000000, gas_used=1606062, logs=[TxLog(msg_index=0, log='', events=[{'type': 'message', 'attributes': [{'key': 'action', 'value': '/terra.wasm.v1beta1.MsgStoreCode'}, {'key': 'module', 'value': 'wasm'}]}, {'type': 'store_code', 'attributes': [{'key': 'sender', 'value': 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'}, {'key': 'code_id', 'value': '1'}]}], events_by_type={'message': {'action': ['/terra.wasm.v1beta1.MsgStoreCode'], 'module': ['wasm']}, 'store_code': {'sender': ['terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'], 'code_id': ['1']}})], code=0, codespace='', info=None, data=None, timestamp= None) In the above dictionary, you can see data like txhash (transaction hash), code_id, sender of the store_code, and so on.

Interacting with Local Terra Using Python: Getting the Code ID

Now, let’s get the code id of the transaction using the very same code and making some small changes:
		
from terra_sdk.client.localterra import LocalTerra
from terra_sdk.util.contract import read_file_as_b64,get_code_id
from terra_sdk.core.fee import Fee
from terra_sdk.client.lcd.api.tx import CreateTxOptions
from terra_sdk.core.wasm import MsgStoreCode

lt = LocalTerra()
deployer = lt.wallets["test1"]

def store_contract(contract_name:str) -> str:
	contract_bytes = read_file_as_b64(f"artifacts/{contract_name}.wasm")
	store_code = MsgStoreCode(
	deployer.key.acc_address,
	contract_bytes
	)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [store_code],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	code_id = get_code_id(result)
	return(code_id)

print(store_contract("Testing"))

		
	
We have written the very same code as the previous one with the difference that this time we have specifically returned the code_id in the dictionary and have printed it. Now, let’s run the code using the following command on the terminal, and remember not to lose your connection with local Terra (keep the docker up and running). python3 contract.py Result: 3 Let us try another time: python3 contract.py Result: 4 And one more time to make sure everything works as it should: python3 contract.py Result: 5

Sending JSON Messages to Local Terra Smart Contracts Using Python

The following article is the continuation of the previous one and here we try to interact with local Terra smart contracts using python scripts and at the same time using the CosmWasm functions inside LocalTerra\src folder written in Rust programming language. We will instantiate from the contract and execute it by sending JSON messages to Local Terra smart contracts.

Instantiating form the Contract of the Local Terra

In the following code, we use the MsgInstantiateContract from terra_sdk.core.wasm to instantiate from the contract, using the code_id and return the contract address:
		
from terra_sdk.client.localterra import LocalTerra
from terra_sdk.util.contract import read_file_as_b64,get_code_id, get_contract_address
from terra_sdk.core.fee import Fee
from terra_sdk.client.lcd.api.tx import CreateTxOptions
from terra_sdk.core.wasm import MsgStoreCode,MsgInstantiateContract

lt = LocalTerra()
deployer = lt.wallets["test1"]

def store_contract(contract_name:str) -> str:
	contract_bytes = read_file_as_b64(f"artifacts/{contract_name}.wasm")
	store_code = MsgStoreCode(
		deployer.key.acc_address,
		contract_bytes
		)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [store_code],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	code_id = get_code_id(result)
	return(code_id)

def instantiate_contract(code_id: str,init_msg)-> str:
	instantiate = MsgInstantiateContract(
		deployer.key.acc_address,
		deployer.key.acc_address,
		code_id = code_id,
		init_msg = init_msg,
		)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [instantiate],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	contract_address = get_contract_address(result)
	return contract_address

code_id = store_contract("Testing")
contract_address = instantiate_contract(code_id,{"count": 15})
print(code_id, contract_address)

		
	
The goal of the above code is to instantiate from the contract using the code_id of the store_contract transaction. To do so, we define a function called instantiate_contract. Inside this function, we create a message with MsgInstantiateContract function. Then we will create and sign the transaction using the created message. Finally, we will broadcast the transaction and return the contract address. Notice that the function that we have defined has 2 attributes: code_id and init_msg. When we call this function, we can enter the code_id we have got from the output of store_contract. For init_msg, we enter the {"count": number} in which number can be any unsigned integer number. In the end, we print the code_id with the contract address which is the output of the instantiate_contract function.

Now, let’s try our script and see if it prints out the code_id and the contract address: python3 contract.py Result: 11 terra1wkgucw0zply6e5c4h30a4z5qljhazepw4jpf2s Try another time: python3 contract.py Result: 12 terra1mhf9cr9f70rd052rptnevcje2puq6heekrxdwa As you can see the code_id has incremented.

And another time: python3 contract.py Result: 13 terra1uw258kwqftsywjfv972y4d3f4mn0hrlkpt7y3y

Executing the Contract

Now, using the MsgExecuteContract, contract address, and account address, we execute the contract inside the local Terra directory.
		
from terra_sdk.client.localterra import LocalTerra
from terra_sdk.util.contract import read_file_as_b64,get_code_id, get_contract_address
from terra_sdk.core.fee import Fee
from terra_sdk.client.lcd.api.tx import CreateTxOptions
from terra_sdk.core.wasm import MsgStoreCode,MsgInstantiateContract, MsgExecuteContract

lt = LocalTerra()
deployer = lt.wallets["test1"]

def store_contract(contract_name:str) -> str:
	contract_bytes = read_file_as_b64(f"artifacts/{contract_name}.wasm")
	store_code = MsgStoreCode(
	deployer.key.acc_address,
	contract_bytes
	)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [store_code],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	code_id = get_code_id(result)
	return(code_id)

def instantiate_contract(code_id: str,init_msg)-> str:
	instantiate = MsgInstantiateContract(
		deployer.key.acc_address,
		deployer.key.acc_address,
		code_id = code_id,
		init_msg = init_msg,
		)
	tx = deployer.create_and_sign_tx(CreateTxOptions(
		msgs = [instantiate],
		fee = Fee(4000000,"10000000uluna")
		))
	result = lt.tx.broadcast(tx)
	contract_address = get_contract_address(result)
	return contract_address

def execute_contract(sender,contract_addr: str, execute_msg):
	execute = MsgExecuteContract(
	sender = sender.key.acc_address, contract = contract_addr,execute_msg = execute_msg)
	tx = sender.create_and_sign_tx(CreateTxOptions(
		msgs = [execute],
		fee = Fee(4000000,"10000000uluna")
		))
	)
	result = lt.tx.broadcast(tx)
	return result

code_id = store_contract("Testing")
contract_address = instantiate_contract(code_id,{"count": 15})
execute = execute_contract(deployer,contract_address,{"increment":{}})
execute1 = execute_contract(deployer,contract_address,{"increment":{}})
execute2 = execute_contract(deployer,contract_address,{"increment":{}})
execute3 = execute_contract(deployer,contract_address,{"increment":{}})
execute4 = execute_contract(deployer,contract_address,{"increment":{}})

print(execute1)
print(lt.wasm.contract_query(contract_address,{"get_count":{}}))
print(code_id, contract_address)
		
	
In the above Python script, we will use the execute_contract next to store_contract and instantiate_contract functions. In the execute function, we have done the 3 main jobs we did for other functions, creating the message, creating and signing the transaction , and broadcasting it. The execute function has 3 attributes:
  1. 1. The sender (deployer of the contract).
  2. 2. The contract address that we have got from instantiate_contract function.
  3. 3. The execute message which can be increment, reset ,etc.
Outside the execute function, we call it 5 times with the increment message. And to see the results, we print the second execution and also the query result of the get_count message which is going to check if we have successfully executed the contract 5 times. If so, the result must show that the count = 20. (15 +1+1+1+1+1 = 20).

Now, let’s see if our code prints out the result of local Terra contract execution, as well as the code_id, query result, and the contract address: python3 contract.py Result: BlockTxBroadcastResult(height=8030, txhash='F51A179323A3489F4629FB0ECA4B83C64237961F9244409EFBDBF88EFC8CFA97', raw_log='[{"events": [{"type":"execute_contract","attributes":[{"key":"sender","value":"terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v"}, {"key":"contract_address","value":"terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz"}]},{" type":"from_contract","attributes":[{"key":"contract_ address","value":"terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz"}, {"key":"method","value":"try_increment"}]},{"type":"message","attributes": [{"key":"action","value":"/terra.wasm.v1beta1.MsgExecuteContract"},{"key":"module"," value":"wasm"},{"key":"sender","value":"terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v"}]},{" type":"wasm","attributes": [{"key":"contract_address","value":"terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz"},{" key":"method","value":"try_increment"}]}]}]', gas_wanted=4000000, gas_used=102492, logs=[TxLog(msg_index=0, log='', events=[{'type': 'execute_contract', 'attributes': [{'key': 'sender', 'value': 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'}, {'key': 'contract_address', 'value': 'terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz'}]}, {'type': 'from_contract', 'attributes': [{'key': 'contract_address', 'value': 'terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz'}, {'key': 'method', 'value': 'try_increment'}]}, {'type': 'message', 'attributes': [{'key': 'action', 'value': '/terra.wasm.v1beta1.MsgExecuteContract'}, {'key': 'module', 'value': 'wasm'}, {'key': 'sender', 'value': 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'}]}, {'type': 'wasm', 'attributes': [{'key': 'contract_address', 'value': 'terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz'}, {'key': 'method', 'value': 'try_increment'}]}], events_by_type={'execute_contract': {'sender': ['terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'], 'contract_address': ['terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz']}, 'from_contract': {'contract_address': ['terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz'], 'method': ['try_increment']}, 'message': {'action': ['/terra.wasm.v1beta1.MsgExecuteContract'], 'module': ['wasm'], 'sender': ['terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v']}, 'wasm': {'contract_address': ['terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz'], 'method': ['try_increment']}})], code=0, codespace='', info=None, data=None, timestamp=None) {'count': 20} 17 terra1hteg5pjt0r27589yd67jwhq8an4j3w4u02qfmz Notice that it takes a few seconds for the contract to be instantiated and the transaction to be executed. As we have determined the count = 15 in the instantiate_contract function and executed the contract with the increment message 5 times, The result of the query count will be 20.

Try one more time, and you will see the same result with the code_id incremented. python3 contract.py Result: BlockTxBroadcastResult(height=8269, txhash='73C112C7B0DA968209310068DFCA9C26378A47EA383C3A4DBE350DCFE54079E8', raw_log='[{"events": [{"type":"execute_contract","attributes":[{"key":"sender","value":"terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v"}, {"key":"contract_address","value":"terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra"}]},{" type":"from_contract","attributes": [{"key":"contract_address","value":"terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra"},{" key":"method","value":"try_increment"}]},{"type":"message","attributes": [{"key":"action","value":"/terra.wasm.v1beta1.MsgExecuteContract"},{"key":"module"," value":"wasm"},{"key":"sender","value":"terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v"}]},{" type":"wasm","attributes": [{"key":"contract_address","value":"terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra"},{" key":"method","value":"try_increment"}]}]}]', gas_wanted=4000000, gas_used=102492, logs=[TxLog(msg_index=0, log='', events=[{'type': 'execute_contract', 'attributes': [{'key': 'sender', 'value': 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'}, {'key': 'contract_address', 'value': 'terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra'}]}, {'type': 'from_contract', 'attributes': [{'key': 'contract_address', 'value': 'terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra'}, {'key': 'method', 'value': 'try_increment'}]}, {'type': 'message', 'attributes': [{'key': 'action', 'value': '/terra.wasm.v1beta1.MsgExecuteContract'}, {'key': 'module', 'value': 'wasm'}, {'key': 'sender', 'value': 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'}]}, {'type': 'wasm', 'attributes': [{'key': 'contract_address', 'value': 'terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra'}, {'key': 'method', 'value': 'try_increment'}]}], events_by_type={'execute_contract': {'sender': ['terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'], 'contract_address': ['terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra']}, 'from_contract': {'contract_address': ['terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra'], 'method': ['try_increment']}, 'message': {'action': ['/terra.wasm.v1beta1.MsgExecuteContract'], 'module': ['wasm'], 'sender': ['terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v']}, 'wasm': {'contract_address': ['terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra'], 'method': ['try_increment']}})], code=0, codespace='', info=None, data=None, timestamp=None) {'count': 20} 18 terra1wfvvdh7vtq82xz3x6h63ul9xn8hxh5xhkwl5ra

Wrapping Up

In this article, we have managed to connect to local Terra using Docker and interact with it by the means of Python scripts. In detail, we have managed to store the contract and get the code_id of the transaction. In the next parts, we will focus on the other functions such as instantiating and executing the contract to complete the process of interacting with Terra smart contracts.

Finally, we have managed to interact with local Terra using the Python scripts. At first, we connected to local Terra using Docker. Then, we created a wallet, that, stored our contract, instantiated from the stored contract using the code_id, and executed it.

Download this Article in PDF format

3d websites

Care to Know Us More?

In Arashtad, we have gathered a professional team of developers who are working in fields such as 3D websites, 3D games, metaverses, and other types of WebGL and 3D applications as well as blockchain developemnet.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Fill in the Form
Blockchain Development