Working with Transport
The nekoton-python library offers interaction with the TVM (TON Virtual Machine) blockchain network through its transport mechanisms. Specifically, there are two primary transport classes available:
GqlTransport: Implements transport using GraphQL.JrpcTransport: Implements transport using JRPC.
Both of these classes are subclasses of the base Transport class, providing specialized methods for their respective transport protocols.
Initialization
GqlTransport
To initialize a GqlTransport object, you need to provide a list of endpoints. Optionally, you can also provide a Clock object and a boolean indicating whether the connection is with a local node.
transport = nt.GqlTransport(
endpoints=["https://devnet.evercloud.dev/89a3b8f46a484f2ea3bdd364ddaee3a3"]
)
print(transport)Result
<builtins.GqlTransport object at 0x104f4c2a0>JrpcTransport
To initialize a JrpcTransport object, you need to provide a JRPC endpoint. Optionally, you can also provide a Clock object.
transport = nt.JrpcTransport(endpoint="https://jrpc.everwallet.net")
print(transport)Result
<builtins.JrpcTransport object at 0x104e3b0d0>Checking Connection
You can check the connection by calling the check_connection method. This method does not take any parameters.
await transport.check_connection()Blockchain Config
The nekoton-python library provides an easy way to fetch the latest blockchain configuration and work with it. The blockchain configuration provides crucial information about the blockchain parameters.
Fetching Blockchain Config
You can fetch the latest blockchain configuration by calling the get_blockchain_config method. This method does not take any parameters.
config = await transport.get_blockchain_config()
print(config)Result
<BlockchainConfig global_id=42 capabilities=0x00000000880737ae, global_version=0x36>The get_blockchain_config method returns a BlockchainConfig object, which provides a partially parsed blockchain configuration. This object contains various properties that offer insights into different blockchain parameters.
Accessing Properties
Here's how you can access and print the properties of the BlockchainConfig:
config = await transport.get_blockchain_config()
# Accessing and printing properties
print("Capabilities:", config.capabilities)
print("Global Version:", config.global_version)
print("Config Address:", config.config_address)
print("Elector Address:", config.elector_address)
print("Minter Address:", config.minter_address)
print("Fee Collector Address:", config.fee_collector_address)Result
Capabilities: 2281903790
Global Version: 32
Config Address: -1:5555555555555555555555555555555555555555555555555555555555555555
Elector Address: -1:3333333333333333333333333333333333333333333333333333333333333333
Minter Address: -1:0000000000000000000000000000000000000000000000000000000000000000
Fee Collector Address: -1:3333333333333333333333333333333333333333333333333333333333333333Checking Parameters
This method returns True if the config contains the specified parameter.
param_exists = config.contains_param(0)
print(param_exists) # TrueGetting Parameters
Returns the corresponding config value as a cell.
raw_param = config.get_raw_param(0)
print(raw_param)Result
<Cell repr_hash='e6025a4b06943baa939e0497bf474bf8b946938d5a4d70bd2fae2b7d481b3cb9', bits=256, refs=0>Fetching Signature ID
You can fetch the signature ID for the selected network using the get_signature_id method. This method does not take any parameters.
signature_id = await transport.get_signature_id()
print(signature_id)Result
NoneAccount Interaction
Account State
You can fetch the state of an account by calling the get_account_state method and providing an Address object.
example_address = nt.Address("0:06c404998bb4a6f5cfe465939e3e3562ed573e27f7906355b1a9e1cf61f5ba2e")
account_state = await transport.get_account_state(example_address)
print(account_state)Result
<AccountState balance=0.922934241, Active>Accounts by Code Hash
You can fetch a list of addresses of accounts with the specified code hash using the get_accounts_by_code_hash method. This method requires a code_hash as a parameter, and optionally a continuation address from the previous batch and a limit for the max number of items in the response.
code_hash = bytes.fromhex("1583b2bc6a3b8acc01ac653e2255407a140df286141e8bb77dd97419e6258554")
addresses = await transport.get_accounts_by_code_hash(
code_hash=code_hash,
continuation=None,
limit=5
)
for address in addresses:
print(address)Result
0:06c404998bb4a6f5cfe465939e3e3562ed573e27f7906355b1a9e1cf61f5ba2e
0:31eea318369c9019f9c65aa6aa2c3663ac8b5b853283f5af4e4b09deaefea1d6
0:4997f134bfa9d659ea2095223d59253931ca26a71460108ef5e19b7327570cc4Account States Iterator
To iterate over the account states, you can use the account_states method. This method requires an address as a parameter. The iterator will always have at least one iteration with the current state. If the state is None, it means the account does not exist.
Here's how you can use it:
async with transport.account_states(example_address) as states:
async for state in states:
if state is not None:
print(state)
else:
print("Account does not exist.")
break # You can remove this line if you want to iterate over all statesResult
<AccountState balance=0.922934241, Active>Account Transactions Iterator
You can get an asynchronous iterator over the account transactions using the account_transactions method. This method requires an address as a parameter.
async with transport.account_transactions(config.elector_address) as batches:
async for batch, batch_info in batches:
print(batch)
# Additional processing can be done here if needed
break # You can remove this line if you want to iterate over all batcheResult
[<Transaction hash='217ebed261828c71298ef2fe46a8ea52dc71335653c4760ddcd4de9446e561e0', Tick>, <Transaction hash='dfb8247a1cad5b1fc68210b57ba5ae55b3640da5fad4998209a60e33462a8b9a', Ordinary>, <Transaction hash='faf56e6d848a5a9a6625a26a547d1bc7aeec1f9c20fd90e666043d872a439526', Tick>, <Transaction hash='44d9239ee3a636b5e3c1b28522135df75e6a61ef3b6ae1382664478df4604ea6', Ordinary>]Transactions
Sending External Message
You can send an external message to the network and wait for the transaction using the send_external_message method. This method requires a SignedExternalMessage as a parameter.
transaction = await transport.send_external_message(signed_external_message)
print(transaction)Result
<Transaction hash='74a5de834a2b7b043c4d993c78cfb15fdb46c3f2346e2aee53834ab0c1bd28d1', Ordinary>Fetching Transaction
You can fetch a transaction by calling the get_transaction method and providing a transaction hash.
tx = await transport.get_transaction(
bytes.fromhex(
"2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552"
)
)
print(tx)Result
<Transaction hash='2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552', Ordinary>Destination Transaction
You can search for a transaction by the hash of the incoming message using the get_dst_transaction method. This method requires a message_hash as a parameter, which can be a hash of the incoming message or the message itself.
transaction = await transport.get_dst_transaction(message_hash=tx.in_msg_hash)
print(transaction)Result
<Transaction hash='2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552', Ordinary>Transactions Batch
You can fetch a transactions batch for a specific account using the get_transactions method. This method requires an address as a parameter, and optionally a lt (logical time of the latest transaction) and a limit (max number of items in the response).
transactions = await transport.get_transactions(
address=example_address,
lt=None,
limit=5
)
for transaction in transactions:
print(transaction)Result
<Transaction hash='2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552', Ordinary>
<Transaction hash='1ee4e54aae183b683d65149a4d34a822942b49e391fe33b7b8c80f7b0898f7b8', Ordinary>
<Transaction hash='2316322ca16010560c4146180415366c6a3a64ce62338866bd4f198cfeb660eb', Ordinary>
<Transaction hash='b6d560ffab7466e2f3cb4fc9e89130d69843a453cb1eaa8693ea430ba3abc953', Ordinary>
<Transaction hash='571e84432d76e6f297a4a540147ebfd17992c7e1d7da867daa6f1e82c3a2fd9e', Ordinary>Transactions Tree Iterator
You can get an asynchronous iterator over the transactions tree using the trace_transaction method. This method requires a transaction_hash as a parameter, which can be a hash of the root transaction or the root transaction itself, and optionally a yield_root boolean to specify whether to emit the root transaction.
async for transaction in transport.trace_transaction(transaction_hash=tx.hash, yield_root=True):
print(transaction)Result
<Transaction hash='2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552', Ordinary>
<Transaction hash='c9d0ecc9ebcf2ebdd077eae5168249f477bacdb3105b86145f0521291131668a', Ordinary>GqlTransport Queries
Transactions
You can run a transactions GQL query using the query_transactions method. This method requires a filter as a parameter, and optionally an order_by and a limit.
transactions = await transport.query_transactions(
[
nt.gql.tx.AccountAddr() == example_address,
nt.gql.tx.TrType() == nt.TransactionType.Ordinary,
],
order_by=[
nt.gql.tx.Lt().desc(),
],
limit=5,
)
print(transactions)Result
[<Transaction hash='2a7c997e25c5849460057e0e066525647d0b0f657195c81d5f7ffa522ab1d552', Ordinary>, <Transaction hash='1ee4e54aae183b683d65149a4d34a822942b49e391fe33b7b8c80f7b0898f7b8', Ordinary>, <Transaction hash='2316322ca16010560c4146180415366c6a3a64ce62338866bd4f198cfeb660eb', Ordinary>, <Transaction hash='b6d560ffab7466e2f3cb4fc9e89130d69843a453cb1eaa8693ea430ba3abc953', Ordinary>, <Transaction hash='571e84432d76e6f297a4a540147ebfd17992c7e1d7da867daa6f1e82c3a2fd9e', Ordinary>]Messages
You can run a messages GQL query using the query_messages method. This method requires a filter as a parameter, and optionally an order_by and a limit.
messages = await transport.query_messages(
nt.gql.or_(
[
nt.gql.msg.Src() == example_address,
nt.gql.msg.Dst() == example_address,
]
),
order_by=[
nt.gql.msg.CreatedLt().desc(),
],
limit=5,
)
print(messages)Result
[<Message hash='11b73e293fcbf34b2349dcbd0997520261a20325c72b03eee72771c60099ecf8', Internal>, <Message hash='c22a995050237f4e0fc88a25e187d2ede99199d3e6a7dc9ef8ac23bf8b2ac41e', ExternalOut>, <Message hash='44c4fe9d74053964b795c9be6af384a670c03dd6b90bb0b0b3b6b0e48c0304c5', Internal>, <Message hash='3a6054696fcb3c0d10e18d2ddca4d545e9e35b6d6b647992535e8f5594698630', ExternalOut>, <Message hash='a2a99a9f53031729ccb1f9b9a1c96ff23d855b3974c3ac44d034582f72925e62', ExternalOut>]Accounts
You can run an accounts GQL query using the query_accounts method. This method requires a filter as a parameter, and optionally an order_by and a limit.
accounts = await transport.query_accounts(
nt.gql.or_(
[
nt.gql.acc.Id() == example_address,
nt.gql.acc.CodeHash() == code_hash,
]
),
order_by=[nt.gql.acc.LastTransLt().asc()],
)
for addr, state in accounts:
print(addr, state)Result
0:4997f134bfa9d659ea2095223d59253931ca26a71460108ef5e19b7327570cc4 <AccountState balance=0.987386499, Active>
0:31eea318369c9019f9c65aa6aa2c3663ac8b5b853283f5af4e4b09deaefea1d6 <AccountState balance=0.987386499, Active>
0:06c404998bb4a6f5cfe465939e3e3562ed573e27f7906355b1a9e1cf61f5ba2e <AccountState balance=0.922934241, Active>