Examples
This document describes how to interact with ICON Network using Python SDK. This document contains SDK installation, API usage guide, and code examples.
Get different types of examples as follows. Complete source code is found on Github at https://github.com/icon-project/icon-sdk-python/tree/master/quickstart​
Example
Description
​Wallet​
An example of creating and loading a keywallet.
​ICX Transfer​
An example of transferring ICX and confirming the result.
An example of deploying an IRC token, transferring the token and confirming the result.
​Sync Block​
An example of checking block confirmation and printing the ICX and token transfer information.

Prerequisite

Enumerate any required knowledge, configuration, or resources to complete this tutorial. Provide links to other useful resources. Helping your readers to prepare increases the likelihood that they will continue reading.
ICON SDK for Python development and execution requires the following environments.
  • Python
    • Version: Python 3.6+
    • IDE: Pycharm is recommended.

Installation

At first, you need to get ICON SDK for Python into your project. It can be installed using pip as follows:
1
$ pip install iconsdk

Using the SDK

Import, initialize, deinitialize, and basic call that applies to every or most code to use the SDK. This section also serves as a test if the SDK has been correctly installed and ready to use.

Create IconService and Set Provider

After that, you need to create an IconService instance and set a provider.
  • The IconService class contains a set of API methods. It accepts an HTTPProvider which serves the purpose of connecting to HTTP and HTTPS based JSON-RPC servers.
  • A provider defines how the IconService connects to Loopchain.
  • The HTTPProvider takes a base domain URL where the server can be found. For local development, this would be something like http://localhost:9000.
Note: You’ll need to set HTTPProvider with not a full URI but a base domain URL on iconsdk 1.0.9 or later on your local development machine.
Here is an example of calling a simple API method to get a block by its height :
1
from iconsdk.icon_service import IconService
2
from iconsdk.providers.http_provider import HTTPProvider
3
​
4
# Creates an IconService instance using the HTTP provider and set a provider.
5
icon_service = IconService(HTTPProvider("http://localhost:9000", 3))
6
​
7
# Gets a block by a given block height.
8
block = icon_service.get_block(1209)

Queries

1
from iconsdk.builder.call_builder import CallBuilder
2
​
3
# Returns block information by block height
4
block = icon_service.get_block(1000)
5
​
6
# Returns block information by block hash
7
block = icon_service.get_block("0x000...000")
8
​
9
# Returns the last block information
10
block = icon_service.get_block("latest")
11
​
12
# Returns the balance of the account of given address
13
balance = icon_service.get_balance("hx000...1")
14
​
15
# Returns a list of the SCORE APIs
16
score_apis = icon_service.get_score_api("cx000...1")
17
​
18
# Returns the total supply of ICX
19
total_supply = icon_service.get_total_supply()
20
​
21
# Returns information about a transaction requested by transaction hash
22
tx = icon_service.get_transaction("0x000...000")
23
​
24
# Returns the result of a transaction by transaction hash
25
tx_result = icon_service.get_transaction_result("0x000...000")
26
​
27
# Generates a call instance using the CallBuilder
28
call = CallBuilder().from_(wallet.get_address())\
29
.to("cx000...1")\
30
.method("balance_of")\
31
.params({"address": "hx000...1"})\
32
.build()
33
​
34
# Executes a call method to call a read-only API method on the SCORE immediately without creating a transaction on Loopchain
35
result = icon_service.call(call)

Transactions

Calling SCORE APIs to change states is requested as sending a transaction. Before sending a transaction, the transaction should be signed. It can be done using a Wallet object.
Generate a Transaction
After then, you should create an instance of the transaction using different types of transaction builders as follows.
1
from iconsdk.builder.transaction_builder import (
2
TransactionBuilder,
3
DeployTransactionBuilder,
4
CallTransactionBuilder,
5
MessageTransactionBuilder
6
)
7
from iconsdk.signed_transaction import SignedTransaction
8
​
9
# Generates an instance of transaction for sending icx.
10
transaction = TransactionBuilder()\
11
.from_(wallet.get_address())\
12
.to("cx00...02")\
13
.value(150000000)\
14
.step_limit(1000000)\
15
.nid(3)\
16
.nonce(100)\
17
.build()
18
​
19
# Generates an instance of the transaction for deploying SCORE.
20
transaction = DeployTransactionBuilder()\
21
.from_(wallet.get_address())\
22
.to("cx00...02")\
23
.step_limit(1000000)\
24
.nid(3)\
25
.nonce(100)\
26
.content_type("application/zip")\
27
.content(b'D8\xe9...\xfc')\
28
.params(params)\
29
.build()
30
​
31
# Generates an instance of the transaction for the calling method in SCORE.
32
transaction = CallTransactionBuilder()\
33
.from_(wallet.get_address())\
34
.to("cx00...02")\
35
.step_limit(1000000)\
36
.nid(3)\
37
.nonce(100)\
38
.method("transfer")\
39
.params(params)\
40
.build()
41
​
42
# Generates an instance of transaction for sending a message.
43
transaction = MessageTransactionBuilder()\
44
.from_(wallet.get_address())\
45
.to("cx00...02")\
46
.step_limit(1000000)\
47
.nid(3)\
48
.nonce(100)\
49
.data("0x74657374")\
50
.build()
51
​
52
# Returns the signed transaction object having a signature
53
signed_transaction = SignedTransaction(transaction, wallet)
54
​
55
# Sends the transaction
56
tx_hash = icon_service.send_transaction(signed_transaction)
Sign a Transaction
Before sending a transaction, the transaction should be signed by using SignedTransaction class. The SignedTransaction class is used to sign the transaction by returning an instance of the signed transaction as demonstrated in the example below. The instance of the signed transaction has the property of a signature.
1
# Returns the signed transaction object having a signature
2
signed_transaction = SignedTransaction(transaction, wallet)
Send a Transaction
Finally, you can send a transaction with the signed transaction object as follows.
1
# Sends the transaction
2
tx_hash = icon_service.send_transaction(signed_transaction)

Step Estimation

@ Available since: iconsdk 1.0.9
It is important to set a proper step_limit value in your transaction to make the submitted transaction executed successfully.
estimate_step API provides a way to estimate the Step usage of a given transaction. Using the method, you can get an estimated Step usage before sending your transaction then make a SignedTransaction with the step_limit based on the estimation.
1
# Generates a raw transaction without the stepLimit
2
transaction = TransactionBuilder()\
3
.from_(wallet.get_address())\
4
.to("cx00...02")\
5
.value(150000000)\
6
.nid(3)\
7
.nonce(100)\
8
.build()
9
​
10
# Returns an estimated step value
11
estimate_step = icon_service.estimate_step(transaction)
12
# Adds some margin to the estimated step
13
step_limit = estimate_step + 10000
14
# Returns the signed transaction object having a signature with the same raw transaction and the estimated step
15
signed_transaction = SignedTransaction(transaction, wallet, step_limit)
16
# Sends the transaction
17
tx_hash = icon_service.send_transaction(signed_transaction)
Note that the estimation can be smaller or larger than the actual amount of step to be used by the transaction, so it is recommended to add some margin to the estimation when you set the step_limit of the SignedTransaction.

Code Examples

Wallet

This example shows how to create a new KeyWallet and load wallet with privateKey or Keystore file.
Create a wallet
Create new EOA by calling create method. After creation, the address and private key can be looked up.
1
# Generates a wallet
2
wallet = KeyWallet.create()
3
print("address: ", wallet.get_address()) # Returns an address
4
print("private key: ", wallet.get_private_key()) # Returns a private key
5
​
6
# Output
7
address: hx684c9791784c10c419eaf9322ef42792e4979712
8
private key: 39765c71ed1884ce08010900ed817119f4227a8b3ee7a36c906c0ae9b5b11cae
Load a wallet
You can load an existing EOA by calling a load method. After creation, the address and private key can be looked up.
1
# Loads a wallet from a private key in bytes
2
wallet = KeyWallet.load(TEST_PRIVATE_KEY)
3
print("address: ", wallet.get_address()) # Returns an address
4
print("private key: ", wallet.get_private_key()) # Returns a private key
5
​
6
# Loads a wallet from a keystore file
7
wallet = KeyWallet.load("./keystore", "password")
8
print("address: ", wallet.get_address()) # Returns an address
9
print("private key: ", wallet.get_private_key()) # Returns a private key
Store the wallet
After creating a Wallet object, you can generate a keystore file on the file path by calling a store method.
1
# Stores a key store file on the file path
2
file_path = "./test/test_keystore"
3
wallet.store(file_path, "abcd1234*")

ICX Transfer

This example shows how to transfer ICX and check the result.
For the KeyWallet and IconService creation, please refer to the information above.
ICX transfer transaction
In this example, you can create two wallets for sending and receiving ICX to transfer 1ICX from wallet1 to wallet2.
1
# Wallet for sending ICX
2
wallet1 = KeyWallet.load(TEST_PRIVATE_KEY)
3
# Wallet for receiving ICX
4
wallet2 = KeyWallet.create()
5
print("address: ", wallet2.get_address()) # Returns an address
6
print("private key: ", wallet2.get_private_key()) # Returns a private key
You can get a default step cost used to transfer ICX as follows.
1
# Returns a step cost
2
# GOVERNANCE_ADDRESS : cx0000000000000000000000000000000000000001
3
def get_default_step_cost():
4
_call = CallBuilder()\
5
.from_(wallet1.get_address())\
6
.to(GOVERNANCE_ADDRESS)\
7
.method("getStepCosts")\
8
.build()
9
_result = icon_service.call(_call)
10
default_step_cost = convert_hex_str_to_int(_result["default"])
11
return default_step_cost
Generate transaction instance with the values as below.
1
# Enters transaction information
2
transaction = TransactionBuilder()\
3
.from_(wallet1.get_address())\
4
.to(wallet2.get_address())\
5
.value(10000)\
6
.step_limit(get_default_step_cost()) \
7
.nid(3) \
8
.nonce(2) \
9
.version(3) \
10
.timestamp(int(time() * 10 ** 6))\
11
.build()
  • nid is networkId; 1: mainnet, 2-: etc.
  • step_limit is recommended by using 'default' step cost in the response of getStepCosts API.
  • timestamp is used to prevent identical transactions. Only current time is required (Standard unit : us). If the timestamp is considerably different from the current time, the transaction will be rejected.
Generate SignedTransaction to add the signature of the transaction.
1
# Returns the signed transaction object having a signature
2
signed_transaction = SignedTransaction(transaction, wallet1)
3
​
4
# Reads params to transfer to nodes
5
print(signed_transaction.signed_transaction_dict)
By calling the method of send_transaction of IconService, you can send the transaction and check the transaction’s hash value. Finally, ICX transfer is sent.
1
# Sends the transaction
2
tx_hash = icon_service.send_transaction(signed_transaction)
3
# Prints transaction hash
4
print("txHash: ", tx_hash)
5
​
6
# Output
7
txHash: 0x243438ff59561f403bac4e7b193c00d803c3aabf79249e0246451b0db7751a59
Check the transaction result
After the transaction is sent, the result can be looked up with the returned hash value.
In this example, you can check your transaction result in every 2 seconds because of the block confirmation time. Checking the result is as follows:
1
# Returns the result of a transaction by transaction hash
2
tx_result = icon_service.get_transaction_result(tx_hash)
3
print("transaction status(1:success, 0:failure): ", tx_result["status"])
4
​
5
# Output
6
transaction status(1:success, 0:failure): 1
You can check the following information using the TransactionResult.
  • status : 1 (success), 0 (failure)
  • to : transaction’s receiving address
  • failure : Only exists if status is 0(failure). code(str), message(str) property included
  • txHash : transaction hash
  • txIndex : transaction index in a block
  • blockHeight : Block height of the transaction
  • blockHash : Block hash of the transaction
  • cumulativeStepUsed : Accumulated amount of consumed step’s until the transaction is executed in block
  • stepUsed : Consumed step amount to send the transaction
  • stepPrice : Consumed step price to send the transaction
  • scoreAddress : SCORE address if the transaction generated SCORE (optional)
  • eventLogs : List of EventLogs written during the execution of the transaction.
  • logsBloom : Bloom Filter of the indexed data of the Eventlogs.
Check the ICX balance
In this example, you can check the ICX balance by looking up the transaction before and after the transaction.
ICX balance can be checked with calling the getBalance method of IconService.
1
# Gets balance
2
balance = icon_service.get_balance(wallet2.get_address())
3
print("balance: ", balance)
4
​
5
# Output
6
balance: 10000

Token Deploy and Transfer

This example shows how to deploy token, transfer token and check the balance.
For the KeyWallet and IconService generation, please refer to the information above.
Token deploy transaction
You need the SCORE Project to deploy token.
In this example, you will use standard_token.zip from the sample_data folder.
  • standard_token.zip : TokenStandard SCORE Project Zip file.
    Generate Keywallet using TEST_PRIVATE_KEY, then read the binary data from standard_token.zip by using the function gen_deploy_data_content.
  • score_path: File path where the zip file of SCORE is on.
1
# Reads the zip file 'standard_token.zip' and returns bytes of the file
2
install_content_bytes = gen_deploy_data_content(score_path)
3
​
4
# Loads a wallet from a key store file
5
wallet1 = KeyWallet.load(TEST_PRIVATE_KEY)
You can get max step limit to send token as follows.
1
# Returns a max step limit
2
# GOVERNANCE_ADDRESS : cx0000000000000000000000000000000000000001
3
def get_max_step_limit():
4
_param = {
5
"context_type": "invoke"
6
}
7
_call = CallBuilder()\
8
.from_(wallet1.get_address())\
9
.to(GOVERNANCE_ADDRESS)\
10
.method("getMaxStepLimit")\
11
.params(_param)\
12
.build()
13
_result = icon_service.call(_call)
14
return convert_hex_str_to_int(_result)
Generate transaction with the given values.
  • SCORE_INSTALL_ADDRESS uses cx0000000000000000000000000000000000000000 to deploy SCORE.
  • step_limit is put by max step limit for sending transaction.
  • params enters the basic information of the token you want to deploy. It must enter the given values, 'initialSupply' data. Otherwise, your transaction will be rejected.
1
params = {
2
"initialSupply": 2000
3
}
4
​
5
# Enter transaction information.
6
deploy_transaction = DeployTransactionBuilder()\
7
.from_(wallet1.get_address())\
8
.to(SCORE_INSTALL_ADDRESS) \
9
.step_limit(get_max_step_limit())\
10
.nid(3)\
11
.nonce(3)\
12
.content_type("application/zip")\
13
.content(install_content_bytes)\
14
.params(params)\
15
.version(3)\
16
.build()
Generate SignedTransaction to add a signature to the transaction. You can check the transaction hash value by calling sendTransaction from IconService Token transfer is now completed.
1
# Returns the signed transaction object having a signature
2
signed_transaction = SignedTransaction(transaction, wallet1)
3
​
4
# Sends the transaction
5
tx_hash = icon_service.send_transaction(signed_transaction)
6
​
7
# Prints transaction hash
8
print("txHash: ", tx_hash)
Check the deploy transaction result
After sending the transaction, you can check the result with the returned hash value.
In this example, you can check your transaction result in every 2 seconds because of the block confirmation time.
If the transaction succeeds, you can check scoreAddress from the result.
You can use SCORE after SCORE audit is successfully accepted.
1
# Returns the result of a transaction by transaction hash
2
tx_result = icon_service.get_transaction_result(tx_hash)
3
print("transaction status(1:success, 0:failure): ", tx_result["status"])
4
print("score address: ", tx_result["scoreAddress"])
5
print("waiting a second for accepting score...\n")
6
​
7
# Output
8
transaction status(1:success, 0:failure): 1
9
score address: cx8c5ea60f73aafe10f9debfe2e3140b56335f5cfc
10
waiting a second for accepting score...
For the 'TransactionResult', please refer to the icx_transaction_example.
Token transfer transaction
You can send the token that have already generated.
You can generate KeyWallet using TEST_PRIVATE_KEY just like in the case of icx_transaction_example, then send 1 Token to the other wallet. You need the token SCORE address to send your token.
You can get the default step cost to send token as follows.
1
# Returns a step cost
2
# GOVERNANCE_ADDRESS : cx0000000000000000000000000000000000000001
3
def get_default_step_cost():
4
_call = CallBuilder()\
5
.from_(wallet1.get_address())\
6
.to(GOVERNANCE_ADDRESS)\
7
.method("getStepCosts")\
8
.build()
9
_result = icon_service.call(_call)
10
default_step_cost = convert_hex_str_to_int(_result["default"])
11
return default_step_cost
Generate Transaction with the given parameters as below. You have to add receiving address and value by entering the given key name('_to', '_value') to send the token. Otherwise, the transaction will be rejected.
  • nid is networkId; 1: mainnet, 2-: etc.
  • step_limit is recommended by using 'default' step cost multiplied by 2 in the response of getStepCosts API.
  • timestamp is used to prevent identical transactions. Only current time is required (Standard unit : us). If the timestamp is considerably different from the current time, the transaction will be rejected.
  • method is 'transfer' in this case.
  • params You must enter the given key name('_to', '_value'). Otherwise, the transaction will be rejected.
1
# You must enter the given key name("_to", "_value"). Otherwise, the transaction will be rejected.
2
params = {"_to": wallet2.get_address(), "_value": 10}
3
​
4
# Enters transaction information.
5
call_transaction = CallTransactionBuilder()\
6
.from_(wallet1.get_address())\
7
.to(SCORE_ADDRESS) \
8
.step_limit(get_default_step_cost()*2)\
9
.nid(3) \
10
.nonce(4) \
11
.method("transfer")\
12
.params(params)\
13
.build()
Generate SignedTransaction to add a signature to your transaction.
1
# Returns the signed transaction object having a signature
2
signed_transaction = SignedTransaction(call_transaction, wallet1)
3
​
4
# Reads params to transfer to nodes
5
print(signed_transaction.signed_transaction_dict)
Call sendTransaction of IconService to check the transaction hash. Token transaction is sent.
1
# Sends the transaction
2
tx_hash = icon_service.send_transaction(signed_transaction)
3
​
4
# Prints transaction hash
5
print("txHash: ", tx_hash)
6
​
7
# Output
8
txHash: 0x6b17886de346655d96373f2e0de494cb8d7f36ce9086cb15a57d3dcf24523c8f
Check the transfer transaction result
You can check the result with the returned hash value of the transaction.
In this example, you can check your transaction result in every 2 seconds because of the block confirmation time. Checking the result is as follows:
1
# Returns the result of a transaction by transaction hash
2
tx_result = icon_service.get_transaction_result(tx_hash)
3
print("transaction status(1:success, 0:failure): ", tx_result["status"])
4
​
5
# Output
6
transaction status(1:success, 0:failure): 1
For the TransactionResult, please refer to the icx_transaction_example.
Check the token balance
In this example, you can check the token balance before and after the transaction.
You can check the token balance by calling balanceOf from the token SCORE.
  • method is 'balanceOf' in this case
  • params should be put with '_owner' data. Otherwise, your transaction will be rejected.
1
params = {
2
"_owner": wallet2.get_address()
3
}
4
​
5
call = CallBuilder()\
6
.from_(wallet1.get_address())\
7
.to(SCORE_ADDRESS)\
8
.method("balanceOf")\
9
.params(params)\
10
.build()
11
​
12
result = icon_service.call(call)
13
print("balance: ", convert_hex_str_to_int(result))
14
​
15
# Output
16
balance: 1000000000000000000000

Sync Block

This example shows how to read block information and print the transaction result for every block creation.
Please refer to above for KeyWallet and IconService creation.
Read the block information
In this example, 'getLastBlock' is called periodically in order to check the new blocks, by updating the transaction information for every block creation.
1
# Checks the last block height
2
pre_last_height = icon_service.get_block("latest")["height"]
3
print(f"Starts to scan forward block at block height({pre_last_height})")
4
​
5
# Returns the last block
6
last_block = icon_service.get_block("latest")
7
​
8
# Returns the transaction list.
9
tx_list = last_block["confirmed_transaction_list"]
10
​
11
# Output
12
Starts to scan forward block at block height(129)
If a new block has been created, get the transaction list. You can check the following information.
  • version : json rpc server version
  • to : Receiving address of the transaction
  • value: The amount of ICX coins to transfer to the address. If omitted, the value is assumed to be 0
  • timestamp: timestamp of the transmitting transaction (unit: microseconds)
  • nid : network ID (1: mainnet, 2-: etc)
  • signature: digital signature data of the transaction
  • txHash : transaction hash
  • dataType: A value indicating the type of the data item (call, deploy, message)
  • data: Various types of data are included according to dataType.
Transaction output
After reading the transaction result, you can check history having sent ICX or tokens. Transaction output is as follows:
1
# Returns confirmed transaction list
2
tx_list = block["confirmed_transaction_list"]
3
​
4
if len(tx_list) > 0:
5
for tx in tx_list:
6
print("\ntxHash:", tx["txHash"])
7
tx_result = icon_service.get_transaction_result(tx["txHash"])
8
​
9
# Finds ICX transaction
10
if "value" in tx and tx["value"] > 0:
11
print("[ICX]")
12
print("status: ", tx_result["status"])
13
print("from : ", tx["from"])
14
print("to : ", tx["to"])
15
print("amount: ", tx["value"])
16
​
17
# Finds token transfer
18
if "dataType" in tx and tx["dataType"] == "call" and \
19
"method" in tx["data"] and tx["data"]["method"] == "transfer":
20
score_address = tx["to"]
21
print(f"[{get_token_name(score_address)} Token({get_token_symbol(score_address)})]")
22
print("status: ", tx_result["status"])
23
print("from : ", tx["from"])
24
print("to : ", tx["data"]["params"]["_to"])
25
print("amount: ", convert_hex_str_to_int(tx["data"]["params"]["_value"]))
Check the token name & symbol
You can check the token SCORE by calling the name andsymbol functions.
1
# Returns token name
2
def get_token_name(token_address: str):
3
call = CallBuilder()\
4
.from_(wallet.get_address())\
5
.to(token_address)\
6
.method("name")\
7
.build()
8
return icon_service.call(call)
9
​
10
# Returns token symbol
11
def get_token_symbol(token_address: str):
12
call = CallBuilder()\
13
.from_(wallet.get_address())\
14
.to(token_address)\
15
.method("symbol")\
16
.build()
17
return icon_service.call(call)

Changelog

References

Licenses

This project follows the Apache 2.0 License. Please refer to LICENSE for details.