diff --git a/.circleci/config.yml b/.circleci/config.yml
index cbf7399..6477279 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -71,17 +71,43 @@ jobs:
- run:
name: run fast tests
command: |
- make lint
- make test
+ make ci
- upload-results
+ deploy:
+ executor: bitcartcc/docker-python
+ docker:
+ - image: cimg/python:3.8
+ steps:
+ - checkout
+
+ - run:
+ name: setup credentials
+ command: |
+ echo -e "[pypi]" >> ~/.pypirc
+ echo -e "username = $PYPI_USER" >> ~/.pypirc
+ echo -e "password = $PYPI_PASS" >> ~/.pypirc
+ - run:
+ name: create env, build dist and upload
+ command: |
+ virtualenv ~/venv
+ . ~/venv/bin/activate
+ pip install -U wheel twine
+ python setup.py sdist
+ python setup.py bdist_wheel
+ twine upload dist/*
+
workflows:
version: 2
test_and_deploy:
jobs:
+ - bitcartcc/lint:
+ name: lint
- test:
name: test-<< matrix.v >>
+ requires:
+ - lint
matrix:
parameters:
v:
@@ -90,3 +116,10 @@ workflows:
- "3.9"
- "3.10"
- "3.11"
+ - deploy:
+ context: global
+ filters:
+ tags:
+ only: /[0-9]+(\.[0-9]+)*/
+ branches:
+ ignore: /.*/
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..5abc5b2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[Makefile]
+indent_style = tab
+
+[*.{yml,yaml}]
+indent_size = 2
+
+[*.md]
+indent_size = 2
+trim_trailing_whitespace = false
diff --git a/.flake8 b/.flake8
index 92e5b76..caa88c8 100644
--- a/.flake8
+++ b/.flake8
@@ -1,4 +1,4 @@
[flake8]
max-complexity=11
max-line-length=127
-ignore=E266, E203, W503
\ No newline at end of file
+ignore=E266, E203, W503
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..75207f7
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,48 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.4.0
+ hooks:
+ - id: check-merge-conflict
+ - repo: https://github.com/asottile/yesqa
+ rev: v1.4.0
+ hooks:
+ - id: yesqa
+ - repo: https://github.com/psf/black
+ rev: 23.1.0
+ hooks:
+ - id: black
+ - repo: https://github.com/pycqa/isort
+ rev: 5.12.0
+ hooks:
+ - id: isort
+ - repo: https://github.com/pycqa/flake8
+ rev: 6.0.0
+ hooks:
+ - id: flake8
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v3.3.1
+ hooks:
+ - id: pyupgrade
+ args: ["--py37-plus"]
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.4.0
+ hooks:
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+ - id: mixed-line-ending
+ - id: requirements-txt-fixer
+ - id: check-case-conflict
+ - id: check-shebang-scripts-are-executable
+ - id: check-json
+ - id: check-toml
+ - id: check-yaml
+ - id: check-symlinks
+ - id: debug-statements
+ - id: fix-byte-order-marker
+ - id: fix-encoding-pragma
+ args: ["--remove"]
+ - id: detect-private-key
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: v3.0.0-alpha.4
+ hooks:
+ - id: prettier
diff --git a/Makefile b/Makefile
index 072f04f..7482a51 100644
--- a/Makefile
+++ b/Makefile
@@ -15,4 +15,4 @@ format:
test:
pytest tests/ ${TEST_ARGS}
-ci: checkformat lint test
\ No newline at end of file
+ci: checkformat lint test
diff --git a/README.md b/README.md
index 6937f16..26df8bb 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,12 @@
# tronpy
[![PyPI version](https://badge.fury.io/py/tronpy.svg)](https://pypi.org/project/tronpy/)
+[![CircleCI](https://dl.circleci.com/status-badge/img/gh/andelf/tronpy/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/andelf/tronpy/tree/master)
TRON Python Client Library. [Documentation](https://tronpy.readthedocs.io/en/latest/index.html)
+> Note: in case you want to use cryptocurrency functions in an universal way or e.g. reliably calculate transaction fees for BTC, ETH, Tron and many others, check out the [BitcartCC project](https://bitcartcc.com)
+
## How to use
```python
diff --git a/docs/conf.py b/docs/conf.py
index 378d1b2..e657104 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -17,9 +17,9 @@
# -- Project information -----------------------------------------------------
-project = 'TronPy'
-copyright = '2020, Andelf'
-author = 'Andelf'
+project = "TronPy"
+copyright = "2020, Andelf"
+author = "Andelf"
# -- General configuration ---------------------------------------------------
@@ -27,15 +27,15 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['sphinx.ext.autodoc']
+extensions = ["sphinx.ext.autodoc"]
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# -- Options for HTML output -------------------------------------------------
@@ -43,11 +43,11 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_theme = 'classic' # 'alabaster'
+html_theme = "classic" # 'alabaster'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ["_static"]
-master_doc = 'index'
+master_doc = "index"
diff --git a/docs/keys.rst b/docs/keys.rst
index 7835315..2c53123 100644
--- a/docs/keys.rst
+++ b/docs/keys.rst
@@ -23,4 +23,4 @@ Key API reference
.. automethod:: hex()
.. autoclass:: tronpy.keys.Signature
- :members:
\ No newline at end of file
+ :members:
diff --git a/examples/check_balance.py b/examples/check_balance.py
index 1525aee..d251fc9 100644
--- a/examples/check_balance.py
+++ b/examples/check_balance.py
@@ -1,6 +1,7 @@
+from pprint import pprint
+
from tronpy import Tron
from tronpy.exceptions import AddressNotFound
-from pprint import pprint
client = Tron()
@@ -10,7 +11,7 @@ def check_balance(address):
balance = client.get_account_balance(address)
return balance
except AddressNotFound:
- return 'Adress not found..!'
+ return "Adress not found..!"
-pprint(check_balance('
'))
+pprint(check_balance(""))
diff --git a/examples/generate_address.py b/examples/generate_address.py
index 049bf4f..0e7fcd9 100644
--- a/examples/generate_address.py
+++ b/examples/generate_address.py
@@ -1,6 +1,6 @@
-from tronpy import Tron
from pprint import pprint
+from tronpy import Tron
client = Tron()
pprint(client.generate_address())
diff --git a/examples/justswap.py b/examples/justswap.py
index 17060bf..26465c6 100644
--- a/examples/justswap.py
+++ b/examples/justswap.py
@@ -1,16 +1,13 @@
-
-
import json
import os
import time
-from tronpy import Tron
-from tronpy import keys
+from tronpy import Tron, keys
__dir__ = os.path.dirname(__file__)
-dzi_trade = 'TSMssi9ojNkzj5fT5bAjzuGjrLmsKau8Xj'
-from_addr = 'TVrSWkL6a9xvtxRKq5RHg2HjUpGdPN3wBa'
+dzi_trade = "TSMssi9ojNkzj5fT5bAjzuGjrLmsKau8Xj"
+from_addr = "TVrSWkL6a9xvtxRKq5RHg2HjUpGdPN3wBa"
priv_key = keys.PrivateKey.fromhex("975a98.....(omitted)..........86b98d97b")
@@ -23,7 +20,7 @@ def timestamp():
swap_abi = json.load(fp)
-client = Tron(network='nile')
+client = Tron(network="nile")
cntr = client.get_contract(dzi_trade)
cntr.abi = swap_abi
diff --git a/pyproject.toml b/pyproject.toml
index e49a3e5..922ff48 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "tronpy"
-version = "0.2.6"
+version = "0.3.0"
description = "TRON Python client library"
authors = ["andelf "]
license = "MIT"
@@ -49,28 +49,33 @@ filterwarnings = [
]
[tool.black]
-line-length = 100
-target-version = ['py36']
-include = '\.pyi?$'
-exclude = '''
-(
- /(
- \.eggs # exclude a few common directories in the
- | \.git # root of the project
- | \.hg
- | \.mypy_cache
- | \.tox
- | \.venv
- | _build
- | buck-out
- | build
- | dist
- )/
- | foo.py # also separately exclude a file named foo.py in
- # the root of the project
-)
-'''
+line-length = 127
+
+[tool.isort]
+profile = "black"
+line_length = 127
+
+[tool.mypy]
+warn_redundant_casts = true
+warn_unused_ignores = true
+disallow_untyped_calls = true
+disallow_untyped_defs = true
+check_untyped_defs = true
+warn_return_any = true
+no_implicit_optional = true
+strict_optional = true
+ignore_missing_imports = true
+
+
+[tool.coverage.run]
+omit = [
+ "*__init__.py",
+ "tests/*",
+ "venv/*",
+ "env/*",
+ "setup.py",
+]
[build-system]
requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
\ No newline at end of file
+build-backend = "poetry.core.masonry.api"
diff --git a/setup.py b/setup.py
index 3987659..2b4dce9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,34 +1,33 @@
-# -*- coding: utf-8 -*-
from setuptools import setup
-packages = ['tronpy', 'tronpy.keys', 'tronpy.providers']
+packages = ["tronpy", "tronpy.keys", "tronpy.providers"]
-package_data = {'': ['*']}
+package_data = {"": ["*"]}
install_requires = [
- 'base58',
- 'coincurve',
- 'eth_abi>=4.0.0a,<5.0.0',
- 'httpx',
- 'pycryptodome<4',
- 'requests',
+ "base58",
+ "coincurve",
+ "eth_abi>=4.0.0a,<5.0.0",
+ "httpx",
+ "pycryptodome<4",
+ "requests",
]
setup_kwargs = {
- 'name': 'tronpy',
- 'version': '0.2.6',
- 'description': 'TRON Python client library',
- 'long_description': open("README.md").read(),
- 'long_description_content_type': "text/markdown",
- 'author': 'andelf',
- 'author_email': 'andelf@gmail.com',
- 'maintainer': None,
- 'maintainer_email': None,
- 'url': 'https://github.com/andelf/tronpy',
- 'packages': packages,
- 'package_data': package_data,
- 'install_requires': install_requires,
- 'python_requires': '>=3.6,<4.0',
+ "name": "tronpy",
+ "version": "0.3.0",
+ "description": "TRON Python client library",
+ "long_description": open("README.md").read(),
+ "long_description_content_type": "text/markdown",
+ "author": "andelf",
+ "author_email": "andelf@gmail.com",
+ "maintainer": None,
+ "maintainer_email": None,
+ "url": "https://github.com/andelf/tronpy",
+ "packages": packages,
+ "package_data": package_data,
+ "install_requires": install_requires,
+ "python_requires": ">=3.7",
}
diff --git a/tests/test_abi.py b/tests/test_abi.py
index 3200068..b23d6ec 100644
--- a/tests/test_abi.py
+++ b/tests/test_abi.py
@@ -4,20 +4,20 @@
def test_abi_encode():
assert (
trx_abi.encode_single("address", "TLfuw4tRywtxCusvTudbjf7PbcXjfe7qrw").hex()
- == '0000000000000000000000007564105e977516c53be337314c7e53838967bdac'
+ == "0000000000000000000000007564105e977516c53be337314c7e53838967bdac"
)
assert trx_abi.encode_single("(address,uint256)", ["TLfuw4tRywtxCusvTudbjf7PbcXjfe7qrw", 100_000_000]).hex() == (
- '0000000000000000000000007564105e977516c53be337314c7e53838967bdac'
- + '0000000000000000000000000000000000000000000000000000000005f5e100'
+ "0000000000000000000000007564105e977516c53be337314c7e53838967bdac"
+ + "0000000000000000000000000000000000000000000000000000000005f5e100"
)
def test_abi_decode():
assert trx_abi.decode_abi(
- ['address', 'uint256'],
+ ["address", "uint256"],
bytes.fromhex(
- '0000000000000000000000007564105e977516c53be337314c7e53838967bdac'
- + '0000000000000000000000000000000000000000000000000000000005f5e100'
+ "0000000000000000000000007564105e977516c53be337314c7e53838967bdac"
+ + "0000000000000000000000000000000000000000000000000000000005f5e100"
),
- ) == ('TLfuw4tRywtxCusvTudbjf7PbcXjfe7qrw', 100000000)
+ ) == ("TLfuw4tRywtxCusvTudbjf7PbcXjfe7qrw", 100000000)
diff --git a/tests/test_client.py b/tests/test_client.py
index f317168..67feb64 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -11,9 +11,7 @@
# test_net address
FROM_ADDR = "TBDCyrZ1hT1PDDFf2yRABwPrFica5qqPUX"
# test_net private key
-FROM_PRIV_KEY = PrivateKey(
- bytes.fromhex("fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4")
-)
+FROM_PRIV_KEY = PrivateKey(bytes.fromhex("fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4"))
# test_net address
TO_ADDR = "TFVfhkyJAULWQbHMgVfgbkmgeGBkHo5zru"
CNR_ADDR = "THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia"
@@ -89,20 +87,11 @@ def test_client_sign_offline():
@pytest.mark.asyncio
async def test_async_client_sign_offline():
async with AsyncTron(network="nile") as client:
- tx = (
- await client.trx.transfer(FROM_ADDR, TO_ADDR, 1)
- .memo("test memo")
- .fee_limit(100_000_000)
- .build()
- )
+ tx = await client.trx.transfer(FROM_ADDR, TO_ADDR, 1).memo("test memo").fee_limit(100_000_000).build()
tx_j = tx.to_json()
- check_transaction_structure(
- tx_j, TRANSFER_EXPECTED_RESP, 100_000_000, expect_signature=False
- )
+ check_transaction_structure(tx_j, TRANSFER_EXPECTED_RESP, 100_000_000, expect_signature=False)
# offline
- tx_offline = await AsyncTransaction.from_json(
- tx_j
- ) # tx_offline._client is None so it's offline
+ tx_offline = await AsyncTransaction.from_json(tx_j) # tx_offline._client is None so it's offline
tx_offline.sign(FROM_PRIV_KEY)
tx_j2 = tx_offline.to_json()
check_transaction_structure(tx_j2, TRANSFER_EXPECTED_RESP, 100_000_000)
@@ -113,9 +102,7 @@ async def test_async_client_sign_offline():
def test_client_update_tx():
client = Tron(network="nile")
- tx: Transaction = (
- client.trx.transfer(FROM_ADDR, TO_ADDR, 1).memo("test memo").fee_limit(100_000_000).build()
- )
+ tx: Transaction = client.trx.transfer(FROM_ADDR, TO_ADDR, 1).memo("test memo").fee_limit(100_000_000).build()
tx.sign(FROM_PRIV_KEY)
tx_id = tx.txid
# update and transfer again
@@ -128,12 +115,9 @@ def test_client_update_tx():
@pytest.mark.asyncio
async def test_async_client():
async with AsyncTron(network="nile") as client:
- tx = (
- await client.trx.transfer(FROM_ADDR, TO_ADDR, 1)
- .memo("test memo")
- .fee_limit(100_000_000)
- .build()
- ).sign(FROM_PRIV_KEY)
+ tx = (await client.trx.transfer(FROM_ADDR, TO_ADDR, 1).memo("test memo").fee_limit(100_000_000).build()).sign(
+ FROM_PRIV_KEY
+ )
check_transaction_structure(tx.to_json(), TRANSFER_EXPECTED_RESP, 100_000_000)
@@ -151,12 +135,9 @@ async def test_async_manual_client():
provider = AsyncHTTPProvider(CONF_NILE, client=_http_client)
client = AsyncTron(provider=provider)
- tx = (
- await client.trx.transfer(FROM_ADDR, TO_ADDR, 1)
- .memo("test memo")
- .fee_limit(100_000_000)
- .build()
- ).sign(FROM_PRIV_KEY)
+ tx = (await client.trx.transfer(FROM_ADDR, TO_ADDR, 1).memo("test memo").fee_limit(100_000_000).build()).sign(
+ FROM_PRIV_KEY
+ )
check_transaction_structure(tx.to_json(), TRANSFER_EXPECTED_RESP, 100_000_000)
# must call .close at end to release connections
diff --git a/tests/test_contract.py b/tests/test_contract.py
index c5fb697..2c005ef 100644
--- a/tests/test_contract.py
+++ b/tests/test_contract.py
@@ -7,9 +7,7 @@
# test_net address
FROM_ADDR = "TBDCyrZ1hT1PDDFf2yRABwPrFica5qqPUX"
# test_net private key
-FROM_PRIV_KEY = PrivateKey(
- bytes.fromhex("fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4")
-)
+FROM_PRIV_KEY = PrivateKey(bytes.fromhex("fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4"))
# test_net address
TO_ADDR = "TFVfhkyJAULWQbHMgVfgbkmgeGBkHo5zru"
CNR_ADDR = "THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia"
@@ -50,9 +48,7 @@
{
"inputs": [],
"name": "get",
- "outputs": [
- {"internalType": "uint256", "name": "retVal", "type": "uint256"}
- ],
+ "outputs": [{"internalType": "uint256", "name": "retVal", "type": "uint256"}],
"stateMutability": "view",
"type": "function",
}
@@ -95,13 +91,7 @@ async def test_async_const_functions():
def test_trc20_transfer():
client = Tron(network="nile")
contract = client.get_contract(CNR_ADDR)
- tx = (
- contract.functions.transfer(TO_ADDR, 1_000)
- .with_owner(FROM_ADDR)
- .fee_limit(5_000_000)
- .build()
- .sign(FROM_PRIV_KEY)
- )
+ tx = contract.functions.transfer(TO_ADDR, 1_000).with_owner(FROM_ADDR).fee_limit(5_000_000).build().sign(FROM_PRIV_KEY)
check_transaction_structure(tx.to_json(), TRC20_EXPECTED_RESP, 5_000_000, expect_memo=False)
@@ -110,10 +100,7 @@ async def test_async_trc20_transfer():
async with AsyncTron(network="nile") as client:
contract = await client.get_contract(CNR_ADDR)
tx = (
- await (await contract.functions.transfer(TO_ADDR, 1_000))
- .with_owner(FROM_ADDR)
- .fee_limit(5_000_000)
- .build()
+ await (await contract.functions.transfer(TO_ADDR, 1_000)).with_owner(FROM_ADDR).fee_limit(5_000_000).build()
).sign(FROM_PRIV_KEY)
check_transaction_structure(tx.to_json(), TRC20_EXPECTED_RESP, 5_000_000, expect_memo=False)
@@ -131,12 +118,8 @@ def test_contract_create():
}
]
cntr = Contract(name="SimpleStore", bytecode=BYTECODE, abi=abi)
- tx = (
- client.trx.deploy_contract(FROM_ADDR, cntr).fee_limit(5_000_000).build().sign(FROM_PRIV_KEY)
- )
- check_transaction_structure(
- tx.to_json(), CREATE_CONTRACT_EXPECTED_RESP, 5_000_000, expect_memo=False
- )
+ tx = client.trx.deploy_contract(FROM_ADDR, cntr).fee_limit(5_000_000).build().sign(FROM_PRIV_KEY)
+ check_transaction_structure(tx.to_json(), CREATE_CONTRACT_EXPECTED_RESP, 5_000_000, expect_memo=False)
@pytest.mark.asyncio
@@ -152,9 +135,5 @@ async def test_async_contract_create():
}
]
cntr = AsyncContract(name="SimpleStore", bytecode=BYTECODE, abi=abi)
- tx = (await client.trx.deploy_contract(FROM_ADDR, cntr).fee_limit(5_000_000).build()).sign(
- FROM_PRIV_KEY
- )
- check_transaction_structure(
- tx.to_json(), CREATE_CONTRACT_EXPECTED_RESP, 5_000_000, expect_memo=False
- )
+ tx = (await client.trx.deploy_contract(FROM_ADDR, cntr).fee_limit(5_000_000).build()).sign(FROM_PRIV_KEY)
+ check_transaction_structure(tx.to_json(), CREATE_CONTRACT_EXPECTED_RESP, 5_000_000, expect_memo=False)
diff --git a/tests/test_keys.py b/tests/test_keys.py
index 346f64a..787584c 100644
--- a/tests/test_keys.py
+++ b/tests/test_keys.py
@@ -44,9 +44,7 @@ def address():
def test_private_key():
with pytest.raises(BadKey):
- PrivateKey(
- bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000")
- )
+ PrivateKey(bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000"))
def test_public_key():
@@ -55,9 +53,7 @@ def test_public_key():
def test_key_convert():
- priv_key = PrivateKey.fromhex(
- "0000000000000000000000000000000000000000000000000000000000000001"
- )
+ priv_key = PrivateKey.fromhex("0000000000000000000000000000000000000000000000000000000000000001")
assert priv_key.hex() == "0000000000000000000000000000000000000000000000000000000000000001"
@@ -75,9 +71,7 @@ def test_signature_verify(signature, txid, raw_data, pub_key):
def test_signature_sign(signature: Signature, raw_data: bytes, txid: bytes):
- priv_key = PrivateKey.fromhex(
- "0000000000000000000000000000000000000000000000000000000000000001"
- )
+ priv_key = PrivateKey.fromhex("0000000000000000000000000000000000000000000000000000000000000001")
sig = priv_key.sign_msg(raw_data)
pub_key = sig.recover_public_key_from_msg(raw_data)
@@ -89,9 +83,7 @@ def test_signature_sign(signature: Signature, raw_data: bytes, txid: bytes):
def test_key_derivation():
- priv_key = PrivateKey.fromhex(
- "fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4"
- )
+ priv_key = PrivateKey.fromhex("fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4")
assert priv_key.hex() == "fd605fb953fcdabb952be161265a75b8a3ce1c0def2c7db72265f9db9a471be4"
public_key = priv_key.public_key
assert (
diff --git a/tests/test_query.py b/tests/test_query.py
index 47cb421..347ceb5 100644
--- a/tests/test_query.py
+++ b/tests/test_query.py
@@ -33,9 +33,7 @@ async def test_async_query_account():
def test_query_event_logs():
client = Tron(network="nile")
- txi = client.get_transaction_info(
- "927c27150f70f0d5762486e3edd626775fe1edab1069ff2182d133807c37f705"
- )
+ txi = client.get_transaction_info("927c27150f70f0d5762486e3edd626775fe1edab1069ff2182d133807c37f705")
cnr = client.get_contract("TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf")
events = list(cnr.events.Transfer.process_receipt(txi))
assert events
@@ -51,9 +49,7 @@ def test_query_event_logs():
@pytest.mark.asyncio
async def test_async_query_event_logs():
async with AsyncTron(network="nile") as client:
- txi = await client.get_transaction_info(
- "927c27150f70f0d5762486e3edd626775fe1edab1069ff2182d133807c37f705"
- )
+ txi = await client.get_transaction_info("927c27150f70f0d5762486e3edd626775fe1edab1069ff2182d133807c37f705")
cnr = await client.get_contract("TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf")
events = list(cnr.events.Transfer.process_receipt(txi))
assert events
diff --git a/tests/utils.py b/tests/utils.py
index 2fb70ad..f6d396a 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -8,14 +8,10 @@
}
-def check_transaction_structure(
- tx, expected, fee_limit, *, expect_signature=True, expect_memo=True
-):
+def check_transaction_structure(tx, expected, fee_limit, *, expect_signature=True, expect_memo=True):
assert set(tx.keys()) == {"txID", "raw_data", "signature", "permission"}
assert tx["permission"] is None
- assert set(tx["raw_data"].keys()) == (
- RAW_DATA_KEYS | {"data"} if expect_memo else RAW_DATA_KEYS
- )
+ assert set(tx["raw_data"].keys()) == (RAW_DATA_KEYS | {"data"} if expect_memo else RAW_DATA_KEYS)
if fee_limit is not None:
assert tx["raw_data"]["fee_limit"] == fee_limit
assert len(tx["raw_data"]["contract"]) == 1
diff --git a/tronpy/__init__.py b/tronpy/__init__.py
index eb4db9b..a579f00 100644
--- a/tronpy/__init__.py
+++ b/tronpy/__init__.py
@@ -1,7 +1,7 @@
-from tronpy.tron import Tron
+from tronpy.async_contract import AsyncContract
from tronpy.async_tron import AsyncTron
from tronpy.contract import Contract, ShieldedTRC20
-from tronpy.async_contract import AsyncContract
+from tronpy.tron import Tron
TRX = 1_000_000
SUN = 1
diff --git a/tronpy/abi.py b/tronpy/abi.py
index 6a3a670..6056376 100644
--- a/tronpy/abi.py
+++ b/tronpy/abi.py
@@ -1,14 +1,13 @@
+import eth_abi
+from eth_abi.base import parse_type_str
+from eth_abi.codec import ABICodec as ETHABICodec
from eth_abi.decoding import Fixed32ByteSizeDecoder
from eth_abi.encoding import Fixed32ByteSizeEncoder
from eth_abi.exceptions import NonEmptyPaddingBytes
from eth_abi.registry import BaseEquals
-from eth_abi.base import parse_type_str
-from eth_abi.codec import ABICodec as ETHABICodec
-import eth_abi
from eth_abi.registry import registry as default_registry
-
-from tronpy.keys import to_base58check_address, is_address, to_tvm_address
+from tronpy.keys import is_address, to_base58check_address, to_tvm_address
class TronAddressDecoder(Fixed32ByteSizeDecoder):
@@ -24,10 +23,8 @@ def validate_padding_bytes(self, value, padding_bytes):
value_byte_size = self._get_value_byte_size()
padding_size = self.data_byte_size - value_byte_size
- if padding_bytes != b'\x00' * padding_size and padding_bytes != b'\x00' * (padding_size - 2) + b'\x00A':
- raise NonEmptyPaddingBytes(
- "Padding bytes were not empty: {0}".format(repr(padding_bytes))
- )
+ if padding_bytes != b"\x00" * padding_size and padding_bytes != b"\x00" * (padding_size - 2) + b"\x00A":
+ raise NonEmptyPaddingBytes(f"Padding bytes were not empty: {repr(padding_bytes)}")
class TronAddressEncoder(Fixed32ByteSizeEncoder):
@@ -55,14 +52,17 @@ def do_patching(registry):
registry.unregister("address")
registry.register(
- BaseEquals("address"), TronAddressEncoder, TronAddressDecoder, label="address",
+ BaseEquals("address"),
+ TronAddressEncoder,
+ TronAddressDecoder,
+ label="address",
)
registry.register(
- BaseEquals('trcToken'),
+ BaseEquals("trcToken"),
eth_abi.encoding.UnsignedIntegerEncoder,
eth_abi.decoding.UnsignedIntegerDecoder,
- label='trcToken',
+ label="trcToken",
)
diff --git a/tronpy/async_contract.py b/tronpy/async_contract.py
index 723de80..bc16023 100644
--- a/tronpy/async_contract.py
+++ b/tronpy/async_contract.py
@@ -1,13 +1,14 @@
-from typing import Union, Tuple
+from typing import Tuple, Union
import tronpy
from tronpy import keys
+from tronpy.contract import Contract, ContractFunctions, ContractMethod, ShieldedTRC20
from tronpy.exceptions import DoubleSpending
-from tronpy.contract import Contract, ContractMethod, ContractFunctions, ShieldedTRC20
class AsyncContract(Contract):
"""A smart contract object."""
+
@property
def functions(self) -> "ContractFunctions":
"""The :class:`~ContractFunctions` object, wraps all contract methods."""
@@ -28,7 +29,7 @@ def __getitem__(self, method: str):
if method_abi.get("type", "").lower() == "function" and method_abi["name"] == method:
return AsyncContractMethod(method_abi, self._contract)
- raise KeyError("contract has no method named '{}'".format(method))
+ raise KeyError(f"contract has no method named '{method}'")
# noinspection PyProtectedMember
@@ -46,7 +47,10 @@ async def _async_trigger_contract(self, parameter):
if self._abi.get("stateMutability", None).lower() in ["view", "pure"]:
# const call, contract ret
ret = await self._client.trigger_const_smart_contract_function(
- self._owner_address, self._contract.contract_address, self.function_signature, parameter,
+ self._owner_address,
+ self._contract.contract_address,
+ self.function_signature,
+ parameter,
)
return self.parse_output(ret)
@@ -69,6 +73,7 @@ async def _async_trigger_contract(self, parameter):
# noinspection PyProtectedMember
class AsyncShieldedTRC20(ShieldedTRC20):
"""Async Shielded TRC20 Wrapper."""
+
@property
async def trc20(self) -> AsyncContract:
"""The corresponding TRC20 contract."""
@@ -87,9 +92,7 @@ async def scale_factor(self) -> int:
async def get_rcm(self) -> str:
return (await self._client.provider.make_request("wallet/getrcm"))["value"]
- async def mint(
- self, taddr: str, zaddr: str, amount: int, memo: str = ""
- ) -> "tronpy.async_tron.AsyncTransactionBuilder":
+ async def mint(self, taddr: str, zaddr: str, amount: int, memo: str = "") -> "tronpy.async_tron.AsyncTransactionBuilder":
"""Mint, transfer from T-address to z-address."""
rcm = await self.get_rcm()
payload = {
@@ -120,7 +123,10 @@ async def mint(
)
async def transfer(
- self, zkey: dict, notes: Union[list, dict], *to: Union[Tuple[str, int], Tuple[str, int, str]],
+ self,
+ zkey: dict,
+ notes: Union[list, dict],
+ *to: Union[Tuple[str, int], Tuple[str, int, str]],
) -> "tronpy.async_tron.AsyncTransactionBuilder":
"""Transfer from z-address to z-address."""
if isinstance(notes, (dict,)):
@@ -135,9 +141,7 @@ async def transfer(
raise DoubleSpending
alpha = await self.get_rcm()
root, path = self.get_path(note.get("position", 0))
- spends.append(
- {"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)}
- )
+ spends.append({"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)})
spend_amount += note["note"]["value"]
receives = []
@@ -153,9 +157,7 @@ async def transfer(
rcm = await self.get_rcm()
- receives.append(
- {"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}
- )
+ receives.append({"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}})
if spend_amount != receive_amount:
raise ValueError("spend amount is not equal to receive amount")
@@ -191,16 +193,14 @@ async def burn(
root, path = self.get_path(note.get("position", 0))
if note.get("is_spent", False):
raise DoubleSpending
- spends.append(
- {"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)}
- )
+ spends.append({"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)})
change_amount = 0
receives = []
to_addr = None
to_amount = 0
- to_memo = ''
+ to_memo = ""
if not to:
- raise ValueError('burn must have a output')
+ raise ValueError("burn must have a output")
for receive in to:
addr = receive[0]
amount = receive[1]
@@ -209,12 +209,10 @@ async def burn(
else:
memo = ""
- if addr.startswith('ztron1'):
+ if addr.startswith("ztron1"):
change_amount += amount
rcm = await self.get_rcm()
- receives = [
- {"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}
- ]
+ receives = [{"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}]
else:
# assume T-address
to_addr = addr
@@ -301,4 +299,4 @@ async def is_note_spent(self, zkey: dict, note: dict) -> bool:
ret = await self._client.provider.make_request("wallet/isshieldedtrc20contractnotespent", payload)
- return ret.get('is_spent', None)
+ return ret.get("is_spent", None)
diff --git a/tronpy/async_tron.py b/tronpy/async_tron.py
index 27a3165..c9f3851 100644
--- a/tronpy/async_tron.py
+++ b/tronpy/async_tron.py
@@ -1,38 +1,38 @@
-import time
-import json
import asyncio
-from pprint import pprint
+import json
+import time
from decimal import Decimal
-from typing import Union, Tuple, Optional
+from pprint import pprint
+from typing import Optional, Tuple, Union
from tronpy import keys
-from tronpy.async_contract import AsyncContract, ShieldedTRC20, AsyncContractMethod
-from tronpy.keys import PrivateKey
from tronpy.abi import tron_abi
+from tronpy.async_contract import AsyncContract, AsyncContractMethod, ShieldedTRC20
from tronpy.defaults import conf_for_name
-from tronpy.providers.async_http import AsyncHTTPProvider
from tronpy.exceptions import (
- BadSignature,
- BadKey,
+ AddressNotFound,
+ ApiError,
+ AssetNotFound,
BadHash,
+ BadKey,
+ BadSignature,
BlockNotFound,
- AssetNotFound,
+ BugInJavaTron,
TaposError,
- UnknownError,
TransactionError,
- ValidationError,
- ApiError,
- AddressNotFound,
TransactionNotFound,
TvmError,
- BugInJavaTron,
+ UnknownError,
+ ValidationError,
)
+from tronpy.keys import PrivateKey
+from tronpy.providers.async_http import AsyncHTTPProvider
TAddress = str
DEFAULT_CONF = {
- 'fee_limit': 10_000_000,
- 'timeout': 10.0, # in second
+ "fee_limit": 10_000_000,
+ "timeout": 10.0, # in second
}
@@ -83,36 +83,38 @@ async def result(self, timeout=30, interval=1.6, solid=False) -> dict:
receipt = await self.wait(timeout, interval, solid)
- if receipt.get('result', None) == 'FAILED':
- msg = receipt.get('resMessage', receipt['result'])
+ if receipt.get("result", None) == "FAILED":
+ msg = receipt.get("resMessage", receipt["result"])
- if receipt['receipt']['result'] == 'REVERT':
+ if receipt["receipt"]["result"] == "REVERT":
try:
- result = receipt.get('contractResult', [])
+ result = receipt.get("contractResult", [])
if result and len(result[0]) > (4 + 32) * 2:
- error_msg = tron_abi.decode_single('string', bytes.fromhex(result[0])[4 + 32 :])
- msg = "{}: {}".format(msg, error_msg)
+ error_msg = tron_abi.decode_single("string", bytes.fromhex(result[0])[4 + 32 :])
+ msg = f"{msg}: {error_msg}"
except Exception:
pass
raise TvmError(msg)
- return self._method.parse_output(receipt['contractResult'][0])
+ return self._method.parse_output(receipt["contractResult"][0])
EMPTY = object()
# noinspection PyBroadException,PyProtectedMember
-class AsyncTransaction(object):
+class AsyncTransaction:
"""The Transaction object, signed or unsigned."""
- def __init__(self,
- raw_data: dict,
- client: "AsyncTron" = None,
- method: AsyncContractMethod = None,
- txid: str = "",
- permission: dict = None,
- signature: list = None):
+ def __init__(
+ self,
+ raw_data: dict,
+ client: "AsyncTron" = None,
+ method: AsyncContractMethod = None,
+ txid: str = "",
+ permission: dict = None,
+ signature: list = None,
+ ):
self._raw_data: dict = raw_data.get("raw_data", raw_data)
self._signature: list = raw_data.get("signature", signature or [])
self._client = client
@@ -137,15 +139,17 @@ async def check_sign_weight(self):
sign_weight = await self._client.get_sign_weight(self)
if "transaction" not in sign_weight:
self._client._handle_api_error(sign_weight)
- raise TransactionError('transaction not in sign_weight')
+ raise TransactionError("transaction not in sign_weight")
self.txid = sign_weight["transaction"]["transaction"]["txID"]
# when account not exist on-chain
self._permission = sign_weight.get("permission", None)
def to_json(self) -> dict:
return {
- "txID": self.txid, "raw_data": self._raw_data,
- "signature": self._signature, "permission": self._permission if self._permission is not EMPTY else None
+ "txID": self.txid,
+ "raw_data": self._raw_data,
+ "signature": self._signature,
+ "permission": self._permission if self._permission is not EMPTY else None,
}
@classmethod
@@ -154,8 +158,10 @@ async def from_json(cls, data: Union[str, dict], client: "AsyncTron" = None) ->
data = json.loads(data)
return await cls.create(
client=client,
- txid=data['txID'], permission=data['permission'],
- raw_data=data['raw_data'], signature=data['signature']
+ txid=data["txID"],
+ permission=data["permission"],
+ raw_data=data["raw_data"],
+ signature=data["signature"],
)
def inspect(self) -> "AsyncTransaction":
@@ -166,7 +172,7 @@ def sign(self, priv_key: PrivateKey) -> "AsyncTransaction":
"""Sign the transaction with a private key."""
assert self.txid, "txID not calculated"
- assert self.is_expired is False, 'expired'
+ assert self.is_expired is False, "expired"
if self._permission is not None:
addr_of_key = priv_key.public_key.to_hex_address()
@@ -176,8 +182,8 @@ def sign(self, priv_key: PrivateKey) -> "AsyncTransaction":
else:
raise BadKey(
"provided private key is not in the permission list",
- "provided {}".format(priv_key.public_key.to_base58check_address()),
- "required {}".format(self._permission),
+ f"provided {priv_key.public_key.to_base58check_address()}",
+ f"required {self._permission}",
)
sig = priv_key.sign_msg_hash(bytes.fromhex(self.txid))
self._signature.append(sig.hex())
@@ -194,7 +200,7 @@ def set_signature(self, signature: list) -> "AsyncTransaction":
@property
def is_expired(self) -> bool:
- return current_timestamp() >= self._raw_data['expiration']
+ return current_timestamp() >= self._raw_data["expiration"]
async def update(self):
"""update Transaction, change ref_block and txID, remove all signature"""
@@ -225,7 +231,7 @@ def __str__(self):
# noinspection PyBroadException
-class AsyncTransactionBuilder(object):
+class AsyncTransactionBuilder:
"""TransactionBuilder, to build a :class:`~Transaction` object."""
def __init__(self, inner: dict, client: "AsyncTron", method: AsyncContractMethod = None):
@@ -238,8 +244,8 @@ def __init__(self, inner: dict, client: "AsyncTron", method: AsyncContractMethod
"ref_block_hash": None,
}
- if inner.get('type', None) in ['TriggerSmartContract', 'CreateSmartContract']:
- self._raw_data["fee_limit"] = self._client.conf['fee_limit']
+ if inner.get("type", None) in ["TriggerSmartContract", "CreateSmartContract"]:
+ self._raw_data["fee_limit"] = self._client.conf["fee_limit"]
self._method = method
@@ -263,7 +269,7 @@ def memo(self, memo: Union[str, bytes]) -> "AsyncTransactionBuilder":
return self
def expiration(self, expiration: int) -> "AsyncTransactionBuilder":
- self._raw_data['expiration'] = current_timestamp() + expiration
+ self._raw_data["expiration"] = current_timestamp() + expiration
return self
def fee_limit(self, value: int) -> "AsyncTransactionBuilder":
@@ -286,7 +292,7 @@ async def build(self, options=None, **kwargs) -> AsyncTransaction:
# noinspection PyBroadException
-class AsyncTrx(object):
+class AsyncTrx:
"""The Trx(transaction) API."""
def __init__(self, tron):
@@ -296,11 +302,9 @@ def __init__(self, tron):
def client(self) -> "AsyncTron":
return self._tron
- def _build_transaction(
- self, type_: str, obj: dict, *, method: AsyncContractMethod = None
- ) -> AsyncTransactionBuilder:
+ def _build_transaction(self, type_: str, obj: dict, *, method: AsyncContractMethod = None) -> AsyncTransactionBuilder:
inner = {
- "parameter": {"value": obj, "type_url": "type.googleapis.com/protocol.{}".format(type_)},
+ "parameter": {"value": obj, "type_url": f"type.googleapis.com/protocol.{type_}"},
"type": type_,
}
if method:
@@ -391,25 +395,27 @@ def account_permission_update(self, owner: TAddress, perm: dict) -> "AsyncTransa
:param perm: Permission dict from :meth:`~tronpy.Tron.get_account_permission`
"""
- if 'owner' in perm:
- for key in perm['owner']['keys']:
- key['address'] = keys.to_hex_address(key['address'])
- if 'actives' in perm:
- for act in perm['actives']:
- for key in act['keys']:
- key['address'] = keys.to_hex_address(key['address'])
- if perm.get('witness', None):
- for key in perm['witness']['keys']:
- key['address'] = keys.to_hex_address(key['address'])
+ if "owner" in perm:
+ for key in perm["owner"]["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
+ if "actives" in perm:
+ for act in perm["actives"]:
+ for key in act["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
+ if perm.get("witness", None):
+ for key in perm["witness"]["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
return self._build_transaction(
- "AccountPermissionUpdateContract", dict(owner_address=keys.to_hex_address(owner), **perm),
+ "AccountPermissionUpdateContract",
+ dict(owner_address=keys.to_hex_address(owner), **perm),
)
def account_update(self, owner: TAddress, name: str) -> "AsyncTransactionBuilder":
"""Update account name. An account can only set name once."""
return self._build_transaction(
- "UpdateAccountContract", {"owner_address": keys.to_hex_address(owner), "account_name": name.encode().hex()},
+ "UpdateAccountContract",
+ {"owner_address": keys.to_hex_address(owner), "account_name": name.encode().hex()},
)
def freeze_balance(
@@ -475,7 +481,7 @@ def deploy_contract(self, owner: TAddress, contract: AsyncContract) -> "AsyncTra
# noinspection PyBroadException
-class AsyncTron(object):
+class AsyncTron:
"""The Async TRON API Client.
:param provider: An :class:`~tronpy.providers.HTTPProvider` object, can be configured to use private node
@@ -508,7 +514,7 @@ def __init__(self, provider: AsyncHTTPProvider = None, *, network: str = "mainne
self.conf = dict(DEFAULT_CONF, **conf)
if provider is None:
- self.provider = AsyncHTTPProvider(conf_for_name(network), self.conf['timeout'])
+ self.provider = AsyncHTTPProvider(conf_for_name(network), self.conf["timeout"])
elif isinstance(provider, (AsyncHTTPProvider,)):
self.provider = provider
else:
@@ -595,7 +601,16 @@ async def get_zkey_from_sk(self, sk: str, d: str = None) -> dict:
payment_address = ret["payment_address"]
return dict(
- sk=sk, ask=ask, nsk=nsk, ovk=ovk, ak=ak, nk=nk, ivk=ivk, d=d, pkD=pkD, payment_address=payment_address,
+ sk=sk,
+ ask=ask,
+ nsk=nsk,
+ ovk=ovk,
+ ak=ak,
+ nk=nk,
+ ivk=ivk,
+ d=d,
+ pkD=pkD,
+ payment_address=payment_address,
)
# Account query
@@ -614,12 +629,10 @@ async def get_account(self, addr: TAddress) -> dict:
async def get_bandwidth(self, addr: TAddress) -> dict:
"""Query the bandwidth of the account"""
- ret = await self.provider.make_request(
- "wallet/getaccountnet", {"address": keys.to_base58check_address(addr)}
- )
+ ret = await self.provider.make_request("wallet/getaccountnet", {"address": keys.to_base58check_address(addr)})
if ret:
# (freeNetLimit - freeNetUsed) + (NetLimit - NetUsed)
- return ret['freeNetLimit'] - ret.get('freeNetUsed', 0) + ret.get('NetLimit', 0) - ret.get('NetUsed', 0)
+ return ret["freeNetLimit"] - ret.get("freeNetUsed", 0) + ret.get("NetLimit", 0) - ret.get("NetUsed", 0)
else:
raise AddressNotFound("account not found on-chain")
@@ -627,7 +640,8 @@ async def get_account_resource(self, addr: TAddress) -> dict:
"""Get resource info of an account."""
ret = await self.provider.make_request(
- "wallet/getaccountresource", {"address": keys.to_base58check_address(addr), "visible": True},
+ "wallet/getaccountresource",
+ {"address": keys.to_base58check_address(addr), "visible": True},
)
if ret:
return ret
@@ -643,7 +657,7 @@ async def get_account_balance(self, addr: TAddress) -> Decimal:
async def get_account_asset_balances(self, addr: TAddress) -> dict:
"""Get all TRC10 token balances of an account."""
info = await self.get_account(addr)
- return {p['key']: p['value'] for p in info.get("assetV2", {}) if p['value'] > 0}
+ return {p["key"]: p["value"] for p in info.get("assetV2", {}) if p["value"] > 0}
async def get_account_asset_balance(self, addr: TAddress, token_id: Union[int, str]) -> int:
"""Get TRC10 token balance of an account. Result is in raw amount."""
@@ -742,9 +756,9 @@ async def get_block(self, id_or_num: Union[None, str, int] = None, *, visible: b
elif id_or_num is None:
block = await self.provider.make_request("wallet/getnowblock", {"visible": visible})
else:
- raise TypeError("can not infer type of {}".format(id_or_num))
+ raise TypeError(f"can not infer type of {id_or_num}")
- if 'Error' in (block or {}):
+ if "Error" in (block or {}):
raise BugInJavaTron(block)
elif block:
return block
@@ -793,9 +807,7 @@ async def get_solid_transaction_info(self, txn_id: str) -> dict:
if len(txn_id) != 64:
raise BadHash("wrong transaction hash length")
- ret = await self.provider.make_request(
- "walletsolidity/gettransactioninfobyid", {"value": txn_id, "visible": True}
- )
+ ret = await self.provider.make_request("walletsolidity/gettransactioninfobyid", {"value": txn_id, "visible": True})
self._handle_api_error(ret)
if ret:
return ret
@@ -842,16 +854,17 @@ async def get_asset(self, id: int = None, issuer: TAddress = None) -> dict:
return await self.provider.make_request("wallet/getassetissuebyid", {"value": id, "visible": True})
else:
return await self.provider.make_request(
- "wallet/getassetissuebyaccount", {"address": keys.to_base58check_address(issuer), "visible": True},
+ "wallet/getassetissuebyaccount",
+ {"address": keys.to_base58check_address(issuer), "visible": True},
)
async def get_asset_from_name(self, name: str) -> dict:
"""Get asset info from its abbr name, might fail if there're duplicates."""
- assets = [asset for asset in await self.list_assets() if asset['abbr'] == name]
+ assets = [asset for asset in await self.list_assets() if asset["abbr"] == name]
if assets:
if len(assets) == 1:
return assets[0]
- raise ValueError("duplicated assets with the same name", [asset['id'] for asset in assets])
+ raise ValueError("duplicated assets with the same name", [asset["id"] for asset in assets])
raise AssetNotFound
async def list_assets(self) -> list:
@@ -885,7 +898,7 @@ async def get_contract(self, addr: TAddress) -> AsyncContract:
cntr = AsyncContract(
addr=addr,
- bytecode=info.get("bytecode", ''),
+ bytecode=info.get("bytecode", ""),
name=info.get("name", ""),
abi=info.get("abi", {}).get("entrys", []),
origin_energy_limit=info.get("origin_energy_limit", 0),
@@ -902,7 +915,11 @@ async def get_contract_as_shielded_trc20(self, addr: TAddress) -> ShieldedTRC20:
return ShieldedTRC20(contract)
async def trigger_const_smart_contract_function(
- self, owner_address: TAddress, contract_address: TAddress, function_selector: str, parameter: str,
+ self,
+ owner_address: TAddress,
+ contract_address: TAddress,
+ function_selector: str,
+ parameter: str,
) -> str:
ret = await self.provider.make_request(
"wallet/triggerconstantcontract",
@@ -915,13 +932,13 @@ async def trigger_const_smart_contract_function(
},
)
self._handle_api_error(ret)
- if 'message' in ret.get('result', {}):
- msg = ret['result']['message']
- result = ret.get('constant_result', [])
+ if "message" in ret.get("result", {}):
+ msg = ret["result"]["message"]
+ result = ret.get("constant_result", [])
try:
if result and len(result[0]) > (4 + 32) * 2:
- error_msg = tron_abi.decode_single('string', bytes.fromhex(result[0])[4 + 32 :])
- msg = "{}: {}".format(msg, error_msg)
+ error_msg = tron_abi.decode_single("string", bytes.fromhex(result[0])[4 + 32 :])
+ msg = f"{msg}: {error_msg}"
except Exception:
pass
raise TvmError(msg)
diff --git a/tronpy/contract.py b/tronpy/contract.py
index 5521c12..266f060 100644
--- a/tronpy/contract.py
+++ b/tronpy/contract.py
@@ -1,11 +1,12 @@
import itertools
-from typing import Union, Optional, Any, Tuple, List, Generator
+from typing import Any, Generator, List, Optional, Tuple, Union
+
from Crypto.Hash import keccak
from eth_utils import decode_hex
import tronpy
-from tronpy.exceptions import DoubleSpending
from tronpy.abi import trx_abi
+from tronpy.exceptions import DoubleSpending
from tronpy.keys import to_hex_address
@@ -23,14 +24,14 @@ def assure_bytes(value: Union[str, bytes]) -> bytes:
raise ValueError("bad bytes format")
-class Contract(object):
+class Contract:
"""A smart contract object."""
def __init__(
self,
addr=None,
*,
- bytecode: Union[str, bytes] = '',
+ bytecode: Union[str, bytes] = "",
name: str = None,
abi: Optional[Union[dict, List[dict]]] = None,
user_resource_percent: int = 100,
@@ -72,7 +73,7 @@ def __init__(
self._client = client
def __str__(self):
- return "".format(self.name, self.contract_address)
+ return f""
@property
def bytecode(self):
@@ -85,7 +86,7 @@ def bytecode(self, value):
def deploy(self) -> Any:
if self.contract_address:
- raise RuntimeError("this contract has already deployed to {}".format(self.contract_address))
+ raise RuntimeError(f"this contract has already deployed to {self.contract_address}")
if self.origin_address != self.owner_address:
raise RuntimeError("origin address and owner address mismatch")
@@ -161,7 +162,7 @@ def functions(self) -> "ContractFunctions":
def constructor(self) -> "ContractConstructor":
"""The constructor of the contract."""
for method_abi in self.abi:
- if method_abi.get('type', '').lower() == 'constructor':
+ if method_abi.get("type", "").lower() == "constructor":
return ContractConstructor(method_abi, self)
raise NameError("Contract has no constructor")
@@ -176,7 +177,7 @@ def events(self) -> "ContractEvents":
raise ValueError("can not call a contract without ABI")
return self._events
- def get_function_by_selector(self, selector) -> Union['ContractMethod', None]:
+ def get_function_by_selector(self, selector) -> Union["ContractMethod", None]:
selector = selector.hex()
for fn in self.functions:
@@ -186,7 +187,7 @@ def get_function_by_selector(self, selector) -> Union['ContractMethod', None]:
return None
-class ContractEvents(object):
+class ContractEvents:
def __init__(self, contract):
self._contract = contract
@@ -195,14 +196,14 @@ def __getitem__(self, event_name: str):
if _abi.get("type", "").lower() == "event" and _abi["name"] == event_name:
return ContractEvent(_abi, self._contract, event_name)
- raise KeyError("contract has no event named '{}'".format(event_name))
+ raise KeyError(f"contract has no event named '{event_name}'")
def __getattr__(self, event: str):
"""Get the actual contract event object."""
try:
return self[event]
except KeyError:
- raise AttributeError("contract has no method named '{}'".format(event))
+ raise AttributeError(f"contract has no method named '{event}'")
def __dir__(self):
return [event["name"] for event in self._contract.abi if event.get("type", "").lower() == "event"]
@@ -211,53 +212,53 @@ def __iter__(self):
yield from [self[event] for event in dir(self)]
-class ContractEvent(object):
+class ContractEvent:
def __init__(self, abi: dict, contract: "Contract", event_name: str):
self._abi = abi
self._contract = contract
self._event_name = event_name
def process_receipt(self, txn_receipt: dict) -> Generator:
- return self.parse_logs(txn_receipt['log'])
+ return self.parse_logs(txn_receipt["log"])
def parse_logs(self, logs: List[dict]):
for log in logs:
- if log['address'] != self._contract.contract_address:
+ if log["address"] != self._contract.contract_address:
continue
yield self.get_event_data(log)
def get_event_data(self, log: dict):
- data_types, data_names, topic_types, topic_names = [], [], [], [] # cannot use `[[]] * 4`
- for arg in self._abi['inputs']:
- if arg.get('indexed', False) is False:
- data_types.append(arg.get('type', ''))
- data_names.append(arg['name'])
+ data_types, data_names, topic_types, topic_names = [], [], [], [] # cannot use `[[]] * 4`
+ for arg in self._abi["inputs"]:
+ if arg.get("indexed", False) is False:
+ data_types.append(arg.get("type", ""))
+ data_names.append(arg["name"])
else:
- topic_types.append(arg.get('type', ''))
- topic_names.append(arg['name'])
+ topic_types.append(arg.get("type", ""))
+ topic_names.append(arg["name"])
- topics = log['topics'][1:]
+ topics = log["topics"][1:]
decoded_topic_data = [
- trx_abi.decode_single(topic_type, decode_hex(topic_data))
- for topic_type, topic_data
- in zip(topic_types, topics)
+ trx_abi.decode_single(topic_type, decode_hex(topic_data)) for topic_type, topic_data in zip(topic_types, topics)
]
- data = decode_hex(log['data'])
+ data = decode_hex(log["data"])
decoded_data = trx_abi.decode_abi(data_types, data)
- event_args = dict(itertools.chain(
- zip(topic_names, decoded_topic_data),
- zip(data_names, decoded_data),
- ))
+ event_args = dict(
+ itertools.chain(
+ zip(topic_names, decoded_topic_data),
+ zip(data_names, decoded_data),
+ )
+ )
return {
- 'args': event_args,
- 'event': self._event_name,
- 'address': log['address'],
+ "args": event_args,
+ "event": self._event_name,
+ "address": log["address"],
}
-class ContractFunctions(object):
+class ContractFunctions:
def __init__(self, contract):
self._contract = contract
@@ -266,14 +267,14 @@ def __getitem__(self, method: str):
if method_abi.get("type", "").lower() == "function" and method_abi["name"] == method:
return ContractMethod(method_abi, self._contract)
- raise KeyError("contract has no method named '{}'".format(method))
+ raise KeyError(f"contract has no method named '{method}'")
def __getattr__(self, method: str):
"""Get the actual contract method object."""
try:
return self[method]
except KeyError:
- raise AttributeError("contract has no method named '{}'".format(method))
+ raise AttributeError(f"contract has no method named '{method}'")
def __dir__(self):
return [method["name"] for method in self._contract.abi if method.get("type", "").lower() == "function"]
@@ -282,11 +283,10 @@ def __iter__(self):
yield from [self[method] for method in dir(self)]
-class ContractConstructor(object):
+class ContractConstructor:
"""The constructor method of a contract."""
def __init__(self, abi: dict, contract: Contract):
-
self._abi = abi
self._contract = contract
@@ -295,7 +295,7 @@ def __init__(self, abi: dict, contract: Contract):
def __str__(self):
types = ", ".join(arg.get("type", "") + " " + arg.get("name", "") for arg in self.inputs)
- ret = "construct({})".format(types)
+ ret = f"construct({types})"
return ret
@property
@@ -311,14 +311,14 @@ def encode_parameter(self, *args, **kwargs) -> str:
if len(self.inputs) == 0:
if args or kwargs:
- raise TypeError("{} constructor requires {} arguments".format(self._contract.name, len(self.inputs)))
+ raise TypeError(f"{self._contract.name} constructor requires {len(self.inputs)} arguments")
elif args:
if len(args) != len(self.inputs):
- raise TypeError("wrong number of arguments, require {} got {}".format(len(self.inputs), len(args)))
+ raise TypeError(f"wrong number of arguments, require {len(self.inputs)} got {len(args)}")
parameter = trx_abi.encode_single(self.input_type, args).hex()
elif kwargs:
if len(kwargs) != len(self.inputs):
- raise TypeError("wrong number of arguments, require {} got {}".format(len(self.inputs), len(args)))
+ raise TypeError(f"wrong number of arguments, require {len(self.inputs)} got {len(args)}")
args = []
for arg in self.inputs:
try:
@@ -330,9 +330,8 @@ def encode_parameter(self, *args, **kwargs) -> str:
return parameter
-class ContractMethod(object):
+class ContractMethod:
def __init__(self, abi: dict, contract: Contract):
-
self._abi = abi
self._contract = contract
self._owner_address = contract.owner_address
@@ -394,14 +393,14 @@ def _prepare_parameter(self, *args, **kwargs) -> "tronpy.tron.TransactionBuilder
if len(self.inputs) == 0:
if args or kwargs:
- raise TypeError("{} expected {} arguments".format(self.name, len(self.inputs)))
+ raise TypeError(f"{self.name} expected {len(self.inputs)} arguments")
elif args:
if len(args) != len(self.inputs):
- raise TypeError("wrong number of arguments, require {} got {}".format(len(self.inputs), len(args)))
+ raise TypeError(f"wrong number of arguments, require {len(self.inputs)} got {len(args)}")
parameter = trx_abi.encode_single(self.input_type, args).hex()
elif kwargs:
if len(kwargs) != len(self.inputs):
- raise TypeError("wrong number of arguments, require {} got {}".format(len(self.inputs), len(args)))
+ raise TypeError(f"wrong number of arguments, require {len(self.inputs)} got {len(args)}")
args = []
for arg in self.inputs:
try:
@@ -410,14 +409,17 @@ def _prepare_parameter(self, *args, **kwargs) -> "tronpy.tron.TransactionBuilder
raise TypeError("missing argument '{}'".format(arg["name"]))
parameter = trx_abi.encode_single(self.input_type, args).hex()
else:
- raise TypeError("wrong number of arguments, require {}".format(len(self.inputs)))
+ raise TypeError(f"wrong number of arguments, require {len(self.inputs)}")
return parameter
def _trigger_contract(self, parameter):
if self._abi.get("stateMutability", None).lower() in ["view", "pure"]:
# const call, contract ret
ret = self._client.trigger_const_smart_contract_function(
- self._owner_address, self._contract.contract_address, self.function_signature, parameter,
+ self._owner_address,
+ self._contract.contract_address,
+ self.function_signature,
+ parameter,
)
return self.parse_output(ret)
@@ -449,15 +451,13 @@ def output_type(self) -> str:
return "({})".format(",".join(self.__format_json_abi_type_entry(arg) for arg in self.outputs))
def __format_json_abi_type_entry(self, entry) -> str:
- if entry.get('type', '').startswith('tuple'):
- surfix = entry['type'][5:]
- if 'components' not in entry:
+ if entry.get("type", "").startswith("tuple"):
+ surfix = entry["type"][5:]
+ if "components" not in entry:
raise ValueError("ABIEncoderV2 used, ABI should be set by hand")
- return "({}){}".format(
- ",".join(self.__format_json_abi_type_entry(arg) for arg in entry['components']), surfix
- )
+ return "({}){}".format(",".join(self.__format_json_abi_type_entry(arg) for arg in entry["components"]), surfix)
else:
- return entry.get('type', '')
+ return entry.get("type", "")
@property
def function_signature(self) -> str:
@@ -470,7 +470,7 @@ def function_signature_hash(self) -> str:
@property
def function_type(self) -> str:
types = ", ".join(arg.get("type", "") + " " + arg.get("name", "") for arg in self.inputs)
- ret = "function {}({})".format(self.name, types)
+ ret = f"function {self.name}({types})"
if self._abi.get("stateMutability", None).lower() == "view":
ret += " view"
elif self._abi.get("stateMutability", None).lower() == "pure":
@@ -483,7 +483,7 @@ def as_shielded_trc20(self, trc20_addr: str) -> "ShieldedTRC20":
return ShieldedTRC20(self, trc20_addr)
-class ShieldedTRC20(object):
+class ShieldedTRC20:
"""Shielded TRC20 Wrapper."""
def __init__(self, contract: Contract):
@@ -545,7 +545,10 @@ def mint(self, taddr: str, zaddr: str, amount: int, memo: str = "") -> "tronpy.t
)
def transfer(
- self, zkey: dict, notes: Union[list, dict], *to: Union[Tuple[str, int], Tuple[str, int, str]],
+ self,
+ zkey: dict,
+ notes: Union[list, dict],
+ *to: Union[Tuple[str, int], Tuple[str, int, str]],
) -> "tronpy.tron.TransactionBuilder":
"""Transfer from z-address to z-address."""
if isinstance(notes, (dict,)):
@@ -560,9 +563,7 @@ def transfer(
raise DoubleSpending
alpha = self.get_rcm()
root, path = self.get_path(note.get("position", 0))
- spends.append(
- {"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)}
- )
+ spends.append({"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)})
spend_amount += note["note"]["value"]
receives = []
@@ -578,9 +579,7 @@ def transfer(
rcm = self.get_rcm()
- receives.append(
- {"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}
- )
+ receives.append({"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}})
if spend_amount != receive_amount:
raise ValueError("spend amount is not equal to receive amount")
@@ -616,16 +615,14 @@ def burn(
root, path = self.get_path(note.get("position", 0))
if note.get("is_spent", False):
raise DoubleSpending
- spends.append(
- {"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)}
- )
+ spends.append({"note": note["note"], "alpha": alpha, "root": root, "path": path, "pos": note.get("position", 0)})
change_amount = 0
receives = []
to_addr = None
to_amount = 0
- to_memo = ''
+ to_memo = ""
if not to:
- raise ValueError('burn must have a output')
+ raise ValueError("burn must have a output")
for receive in to:
addr = receive[0]
amount = receive[1]
@@ -634,12 +631,10 @@ def burn(
else:
memo = ""
- if addr.startswith('ztron1'):
+ if addr.startswith("ztron1"):
change_amount += amount
rcm = self.get_rcm()
- receives = [
- {"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}
- ]
+ receives = [{"note": {"value": amount, "payment_address": addr, "rcm": rcm, "memo": memo.encode().hex()}}]
else:
# assume T-address
to_addr = addr
@@ -743,4 +738,4 @@ def is_note_spent(self, zkey: dict, note: dict) -> bool:
ret = self._client.provider.make_request("wallet/isshieldedtrc20contractnotespent", payload)
- return ret.get('is_spent', None)
+ return ret.get("is_spent", None)
diff --git a/tronpy/keys/__init__.py b/tronpy/keys/__init__.py
index dcbe255..2f9ae3c 100644
--- a/tronpy/keys/__init__.py
+++ b/tronpy/keys/__init__.py
@@ -1,12 +1,14 @@
-from Crypto.Hash import keccak
import hashlib
-import base58
-from collections.abc import ByteString, Hashable
import random
-from typing import Any, Union, Iterator
-from coincurve import PrivateKey as CoincurvePrivateKey, PublicKey as CoincurvePublicKey
+from collections.abc import ByteString, Hashable
+from typing import Any, Iterator, Union
+
+import base58
+from coincurve import PrivateKey as CoincurvePrivateKey
+from coincurve import PublicKey as CoincurvePublicKey
+from Crypto.Hash import keccak
-from tronpy.exceptions import BadKey, BadSignature, BadAddress
+from tronpy.exceptions import BadAddress, BadKey, BadSignature
SECPK1_N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
@@ -356,7 +358,7 @@ def hex(self) -> str:
return self._raw_signature.hex()
@classmethod
- def fromhex(cls, hex_str: str) -> 'Signature':
+ def fromhex(cls, hex_str: str) -> "Signature":
"""Construct a Signature from hex str."""
return cls(bytes.fromhex(hex_str))
diff --git a/tronpy/providers/__init__.py b/tronpy/providers/__init__.py
index 7dd429f..d8a1f38 100644
--- a/tronpy/providers/__init__.py
+++ b/tronpy/providers/__init__.py
@@ -1,4 +1,4 @@
-from .http import HTTPProvider
from .async_http import AsyncHTTPProvider
+from .http import HTTPProvider
__all__ = [HTTPProvider, AsyncHTTPProvider]
diff --git a/tronpy/providers/async_http.py b/tronpy/providers/async_http.py
index 27f4219..bf2e3c2 100644
--- a/tronpy/providers/async_http.py
+++ b/tronpy/providers/async_http.py
@@ -1,15 +1,15 @@
import os
-from urllib.parse import urljoin
from typing import Any, Union
+from urllib.parse import urljoin
import httpx
from httpx import Timeout
DEFAULT_TIMEOUT = 10.0
-DEFAULT_API_KEY = 'f92221d5-7056-4366-b96f-65d3662ec2d9'
+DEFAULT_API_KEY = "f92221d5-7056-4366-b96f-65d3662ec2d9"
-class AsyncHTTPProvider(object):
+class AsyncHTTPProvider:
"""An Async HTTP Provider for API request.
:params endpoint_uri: HTTP API URL base. Default value is ``"https://api.trongrid.io/"``. Can also be configured via
@@ -32,7 +32,7 @@ def __init__(
elif isinstance(endpoint_uri, (str,)):
self.endpoint_uri = endpoint_uri
else:
- raise TypeError("unknown endpoint uri {}".format(endpoint_uri))
+ raise TypeError(f"unknown endpoint uri {endpoint_uri}")
headers = {"User-Agent": "Tronpy/0.2", "Tron-Pro-Api-Key": api_key}
if client is None:
diff --git a/tronpy/providers/http.py b/tronpy/providers/http.py
index 3257ee1..9859d67 100644
--- a/tronpy/providers/http.py
+++ b/tronpy/providers/http.py
@@ -1,23 +1,24 @@
import os
-import requests
-from urllib.parse import urljoin
-from typing import Any, Union, List
import random
-import time
import sys
+import time
+from typing import Any, List, Union
+from urllib.parse import urljoin
+
+import requests
DEFAULT_TIMEOUT = 10.0
DEFAULT_API_KEYS = [
- 'f92221d5-7056-4366-b96f-65d3662ec2d9',
- '1e0a625f-cfa5-43ee-ba41-a09db1aae55f',
- 'f399168e-2259-481c-90fc-6b3d984c5463',
- 'da63253b-aa9c-46e7-a4e8-22d259a8026d',
- '88c10958-af7b-4d5a-8eef-6e84bf5fb809',
- '169bb4b3-cbe8-449a-984e-80e9adacac55',
+ "f92221d5-7056-4366-b96f-65d3662ec2d9",
+ "1e0a625f-cfa5-43ee-ba41-a09db1aae55f",
+ "f399168e-2259-481c-90fc-6b3d984c5463",
+ "da63253b-aa9c-46e7-a4e8-22d259a8026d",
+ "88c10958-af7b-4d5a-8eef-6e84bf5fb809",
+ "169bb4b3-cbe8-449a-984e-80e9adacac55",
]
-class HTTPProvider(object):
+class HTTPProvider:
"""An HTTP Provider for API request.
:param endpoint_uri: HTTP API URL base. Default value is ``"https://api.trongrid.io/"``. Can also be configured via
@@ -41,9 +42,9 @@ def __init__(
elif isinstance(endpoint_uri, (str,)):
self.endpoint_uri = endpoint_uri
else:
- raise TypeError("unknown endpoint uri {}".format(endpoint_uri))
+ raise TypeError(f"unknown endpoint uri {endpoint_uri}")
- if 'trongrid' in self.endpoint_uri:
+ if "trongrid" in self.endpoint_uri:
self.use_api_key = True
if isinstance(api_key, (str,)):
self._api_keys = [api_key]
@@ -72,8 +73,8 @@ def make_request(self, method: str, params: Any = None) -> dict:
resp = self.sess.post(url, json=params, timeout=self.timeout)
if self.use_api_key:
- if resp.status_code == 403 and b'Exceed the user daily usage' in resp.content:
- print("W:", resp.json().get('Error', 'rate limit!'), file=sys.stderr)
+ if resp.status_code == 403 and b"Exceed the user daily usage" in resp.content:
+ print("W:", resp.json().get("Error", "rate limit!"), file=sys.stderr)
self._handle_rate_limit()
return self.make_request(method, params)
diff --git a/tronpy/tron.py b/tronpy/tron.py
index eabad2a..7af9598 100644
--- a/tronpy/tron.py
+++ b/tronpy/tron.py
@@ -1,37 +1,37 @@
-import time
import json
-from pprint import pprint
+import time
from decimal import Decimal
-from typing import Union, Tuple, Optional
+from pprint import pprint
+from typing import Optional, Tuple, Union
from tronpy import keys
-from tronpy.contract import Contract, ShieldedTRC20, ContractMethod
-from tronpy.keys import PrivateKey
-from tronpy.providers import HTTPProvider
from tronpy.abi import tron_abi
+from tronpy.contract import Contract, ContractMethod, ShieldedTRC20
from tronpy.defaults import conf_for_name
from tronpy.exceptions import (
- BadSignature,
- BadKey,
+ AddressNotFound,
+ ApiError,
+ AssetNotFound,
BadHash,
+ BadKey,
+ BadSignature,
BlockNotFound,
- AssetNotFound,
+ BugInJavaTron,
TaposError,
- UnknownError,
TransactionError,
- ValidationError,
- ApiError,
- AddressNotFound,
TransactionNotFound,
TvmError,
- BugInJavaTron,
+ UnknownError,
+ ValidationError,
)
+from tronpy.keys import PrivateKey
+from tronpy.providers import HTTPProvider
TAddress = str
DEFAULT_CONF = {
- 'fee_limit': 10_000_000,
- 'timeout': 10.0, # in second
+ "fee_limit": 10_000_000,
+ "timeout": 10.0, # in second
}
@@ -81,30 +81,37 @@ def result(self, timeout=30, interval=1.6, solid=False) -> dict:
receipt = self.wait(timeout, interval, solid)
- if receipt.get('result', None) == 'FAILED':
- msg = receipt.get('resMessage', receipt['result'])
+ if receipt.get("result", None) == "FAILED":
+ msg = receipt.get("resMessage", receipt["result"])
- if receipt['receipt']['result'] == 'REVERT':
+ if receipt["receipt"]["result"] == "REVERT":
try:
- result = receipt.get('contractResult', [])
+ result = receipt.get("contractResult", [])
if result and len(result[0]) > (4 + 32) * 2:
- error_msg = tron_abi.decode_single('string', bytes.fromhex(result[0])[4 + 32 :])
- msg = "{}: {}".format(msg, error_msg)
+ error_msg = tron_abi.decode_single("string", bytes.fromhex(result[0])[4 + 32 :])
+ msg = f"{msg}: {error_msg}"
except Exception:
pass
raise TvmError(msg)
- return self._method.parse_output(receipt['contractResult'][0])
+ return self._method.parse_output(receipt["contractResult"][0])
EMPTY = object()
-class Transaction(object):
+class Transaction:
"""The Transaction object, signed or unsigned."""
- def __init__(self, raw_data: dict, client: "Tron" = None, method: ContractMethod = None,
- txid: str = "", permission: dict = EMPTY, signature: list = None):
+ def __init__(
+ self,
+ raw_data: dict,
+ client: "Tron" = None,
+ method: ContractMethod = None,
+ txid: str = "",
+ permission: dict = EMPTY,
+ signature: list = None,
+ ):
self._raw_data: dict = raw_data
self._signature: list = signature or []
self._client = client
@@ -128,8 +135,10 @@ def __init__(self, raw_data: dict, client: "Tron" = None, method: ContractMethod
def to_json(self) -> dict:
return {
- "txID": self.txid, "raw_data": self._raw_data,
- "signature": self._signature, "permission": self._permission if self._permission is not EMPTY else None,
+ "txID": self.txid,
+ "raw_data": self._raw_data,
+ "signature": self._signature,
+ "permission": self._permission if self._permission is not EMPTY else None,
}
@classmethod
@@ -138,8 +147,10 @@ def from_json(cls, data: Union[str, dict], client: "Tron" = None):
data = json.loads(data)
return cls(
client=client,
- txid=data['txID'], permission=data['permission'],
- raw_data=data['raw_data'], signature=data['signature']
+ txid=data["txID"],
+ permission=data["permission"],
+ raw_data=data["raw_data"],
+ signature=data["signature"],
)
def inspect(self) -> "Transaction":
@@ -150,7 +161,7 @@ def sign(self, priv_key: PrivateKey) -> "Transaction":
"""Sign the transaction with a private key."""
assert self.txid, "txID not calculated"
- assert self.is_expired is False, 'expired'
+ assert self.is_expired is False, "expired"
if self._permission is not None:
addr_of_key = priv_key.public_key.to_hex_address()
@@ -160,8 +171,8 @@ def sign(self, priv_key: PrivateKey) -> "Transaction":
else:
raise BadKey(
"provided private key is not in the permission list",
- "provided {}".format(priv_key.public_key.to_base58check_address()),
- "required {}".format(self._permission),
+ f"provided {priv_key.public_key.to_base58check_address()}",
+ f"required {self._permission}",
)
sig = priv_key.sign_msg_hash(bytes.fromhex(self.txid))
self._signature.append(sig.hex())
@@ -178,7 +189,7 @@ def set_signature(self, signature: list) -> "Transaction":
@property
def is_expired(self) -> bool:
- return current_timestamp() >= self._raw_data['expiration']
+ return current_timestamp() >= self._raw_data["expiration"]
def update(self):
"""update Transaction, change ref_block and txID, remove all signature"""
@@ -208,7 +219,7 @@ def __str__(self):
return json.dumps(self.to_json(), indent=2)
-class TransactionBuilder(object):
+class TransactionBuilder:
"""TransactionBuilder, to build a :class:`~Transaction` object."""
def __init__(self, inner: dict, client: "Tron", method: ContractMethod = None):
@@ -221,8 +232,8 @@ def __init__(self, inner: dict, client: "Tron", method: ContractMethod = None):
"ref_block_hash": None,
}
- if inner.get('type', None) in ['TriggerSmartContract', 'CreateSmartContract']:
- self._raw_data["fee_limit"] = self._client.conf['fee_limit']
+ if inner.get("type", None) in ["TriggerSmartContract", "CreateSmartContract"]:
+ self._raw_data["fee_limit"] = self._client.conf["fee_limit"]
self._method = method
@@ -246,7 +257,7 @@ def memo(self, memo: Union[str, bytes]) -> "TransactionBuilder":
return self
def expiration(self, expiration: int) -> "TransactionBuilder":
- self._raw_data['expiration'] = current_timestamp() + expiration
+ self._raw_data["expiration"] = current_timestamp() + expiration
return self
def fee_limit(self, value: int) -> "TransactionBuilder":
@@ -268,7 +279,7 @@ def build(self, options=None, **kwargs) -> Transaction:
return Transaction(self._raw_data, client=self._client)
-class Trx(object):
+class Trx:
"""The Trx(transaction) API."""
def __init__(self, tron):
@@ -280,7 +291,7 @@ def client(self) -> "Tron":
def _build_transaction(self, type_: str, obj: dict, *, method: ContractMethod = None) -> TransactionBuilder:
inner = {
- "parameter": {"value": obj, "type_url": "type.googleapis.com/protocol.{}".format(type_)},
+ "parameter": {"value": obj, "type_url": f"type.googleapis.com/protocol.{type_}"},
"type": type_,
}
if method:
@@ -371,25 +382,27 @@ def account_permission_update(self, owner: TAddress, perm: dict) -> "Transaction
:param perm: Permission dict from :meth:`~tronpy.Tron.get_account_permission`
"""
- if 'owner' in perm:
- for key in perm['owner']['keys']:
- key['address'] = keys.to_hex_address(key['address'])
- if 'actives' in perm:
- for act in perm['actives']:
- for key in act['keys']:
- key['address'] = keys.to_hex_address(key['address'])
- if perm.get('witness', None):
- for key in perm['witness']['keys']:
- key['address'] = keys.to_hex_address(key['address'])
+ if "owner" in perm:
+ for key in perm["owner"]["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
+ if "actives" in perm:
+ for act in perm["actives"]:
+ for key in act["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
+ if perm.get("witness", None):
+ for key in perm["witness"]["keys"]:
+ key["address"] = keys.to_hex_address(key["address"])
return self._build_transaction(
- "AccountPermissionUpdateContract", dict(owner_address=keys.to_hex_address(owner), **perm),
+ "AccountPermissionUpdateContract",
+ dict(owner_address=keys.to_hex_address(owner), **perm),
)
def account_update(self, owner: TAddress, name: str) -> "TransactionBuilder":
"""Update account name. An account can only set name once."""
return self._build_transaction(
- "UpdateAccountContract", {"owner_address": keys.to_hex_address(owner), "account_name": name.encode().hex()},
+ "UpdateAccountContract",
+ {"owner_address": keys.to_hex_address(owner), "account_name": name.encode().hex()},
)
def freeze_balance(
@@ -412,9 +425,7 @@ def freeze_balance(
payload["receiver_address"] = keys.to_hex_address(receiver)
return self._build_transaction("FreezeBalanceContract", payload)
- def unfreeze_balance(
- self, owner: TAddress, resource: str = "ENERGY", receiver: TAddress = None
- ) -> "TransactionBuilder":
+ def unfreeze_balance(self, owner: TAddress, resource: str = "ENERGY", receiver: TAddress = None) -> "TransactionBuilder":
"""Unfreeze balance to get TRX back.
:param owner:
@@ -459,7 +470,7 @@ def deploy_contract(self, owner: TAddress, contract: Contract) -> "TransactionBu
return contract.deploy()
-class Tron(object):
+class Tron:
"""The TRON API Client.
:param provider: An :class:`~tronpy.providers.HTTPProvider` object, can be configured to use private node
@@ -490,11 +501,11 @@ def __init__(self, provider: HTTPProvider = None, *, network: str = "mainnet", c
if conf is not None:
self.conf = dict(DEFAULT_CONF, **conf)
- if provider is not None and self.conf['timeout'] != DEFAULT_CONF['timeout']:
+ if provider is not None and self.conf["timeout"] != DEFAULT_CONF["timeout"]:
raise ValueError("timeout value should be set in provider")
if provider is None:
- self.provider = HTTPProvider(conf_for_name(network), self.conf['timeout'])
+ self.provider = HTTPProvider(conf_for_name(network), self.conf["timeout"])
elif isinstance(provider, (HTTPProvider,)):
self.provider = provider
else:
@@ -582,7 +593,16 @@ def get_zkey_from_sk(self, sk: str, d: str = None) -> dict:
payment_address = ret["payment_address"]
return dict(
- sk=sk, ask=ask, nsk=nsk, ovk=ovk, ak=ak, nk=nk, ivk=ivk, d=d, pkD=pkD, payment_address=payment_address,
+ sk=sk,
+ ask=ask,
+ nsk=nsk,
+ ovk=ovk,
+ ak=ak,
+ nk=nk,
+ ivk=ivk,
+ d=d,
+ pkD=pkD,
+ payment_address=payment_address,
)
# Account query
@@ -590,9 +610,7 @@ def get_zkey_from_sk(self, sk: str, d: str = None) -> dict:
def get_account(self, addr: TAddress) -> dict:
"""Get account info from an address."""
- ret = self.provider.make_request(
- "wallet/getaccount", {"address": keys.to_base58check_address(addr), "visible": True}
- )
+ ret = self.provider.make_request("wallet/getaccount", {"address": keys.to_base58check_address(addr), "visible": True})
if ret:
return ret
else:
@@ -602,7 +620,8 @@ def get_account_resource(self, addr: TAddress) -> dict:
"""Get resource info of an account."""
ret = self.provider.make_request(
- "wallet/getaccountresource", {"address": keys.to_base58check_address(addr), "visible": True},
+ "wallet/getaccountresource",
+ {"address": keys.to_base58check_address(addr), "visible": True},
)
if ret:
return ret
@@ -617,19 +636,17 @@ def get_account_balance(self, addr: TAddress) -> Decimal:
def get_bandwidth(self, addr: TAddress) -> int:
"""Query the bandwidth of the account"""
- ret = self.provider.make_request(
- "wallet/getaccountnet", {"address": keys.to_base58check_address(addr)}
- )
+ ret = self.provider.make_request("wallet/getaccountnet", {"address": keys.to_base58check_address(addr)})
if ret:
# (freeNetLimit - freeNetUsed) + (NetLimit - NetUsed)
- return ret['freeNetLimit'] - ret.get('freeNetUsed', 0) + ret.get('NetLimit', 0) - ret.get('NetUsed', 0)
+ return ret["freeNetLimit"] - ret.get("freeNetUsed", 0) + ret.get("NetLimit", 0) - ret.get("NetUsed", 0)
else:
raise AddressNotFound("account not found on-chain")
def get_account_asset_balances(self, addr: TAddress) -> dict:
"""Get all TRC10 token balances of an account."""
info = self.get_account(addr)
- return {p['key']: p['value'] for p in info.get("assetV2", {}) if p['value'] > 0}
+ return {p["key"]: p["value"] for p in info.get("assetV2", {}) if p["value"] > 0}
def get_account_asset_balance(self, addr: TAddress, token_id: Union[int, str]) -> int:
"""Get TRC10 token balance of an account. Result is in raw amount."""
@@ -724,9 +741,9 @@ def get_block(self, id_or_num: Union[None, str, int] = None, *, visible: bool =
elif id_or_num is None:
block = self.provider.make_request("wallet/getnowblock", {"visible": visible})
else:
- raise TypeError("can not infer type of {}".format(id_or_num))
+ raise TypeError(f"can not infer type of {id_or_num}")
- if 'Error' in (block or {}):
+ if "Error" in (block or {}):
raise BugInJavaTron(block)
elif block:
return block
@@ -808,16 +825,17 @@ def get_asset(self, id: int = None, issuer: TAddress = None) -> dict:
return self.provider.make_request("wallet/getassetissuebyid", {"value": id, "visible": True})
else:
return self.provider.make_request(
- "wallet/getassetissuebyaccount", {"address": keys.to_base58check_address(issuer), "visible": True},
+ "wallet/getassetissuebyaccount",
+ {"address": keys.to_base58check_address(issuer), "visible": True},
)
def get_asset_from_name(self, name: str) -> dict:
"""Get asset info from its abbr name, might fail if there're duplicates."""
- assets = [asset for asset in self.list_assets() if asset['abbr'] == name]
+ assets = [asset for asset in self.list_assets() if asset["abbr"] == name]
if assets:
if len(assets) == 1:
return assets[0]
- raise ValueError("duplicated assets with the same name", [asset['id'] for asset in assets])
+ raise ValueError("duplicated assets with the same name", [asset["id"] for asset in assets])
raise AssetNotFound
def list_assets(self) -> list:
@@ -854,7 +872,7 @@ def get_contract(self, addr: TAddress) -> Contract:
cntr = Contract(
addr=addr,
- bytecode=info.get("bytecode", ''),
+ bytecode=info.get("bytecode", ""),
name=info.get("name", ""),
abi=info.get("abi", {}).get("entrys", []),
origin_energy_limit=info.get("origin_energy_limit", 0),
@@ -871,7 +889,11 @@ def get_contract_as_shielded_trc20(self, addr: TAddress) -> ShieldedTRC20:
return ShieldedTRC20(contract)
def trigger_const_smart_contract_function(
- self, owner_address: TAddress, contract_address: TAddress, function_selector: str, parameter: str,
+ self,
+ owner_address: TAddress,
+ contract_address: TAddress,
+ function_selector: str,
+ parameter: str,
) -> str:
ret = self.provider.make_request(
"wallet/triggerconstantcontract",
@@ -884,13 +906,13 @@ def trigger_const_smart_contract_function(
},
)
self._handle_api_error(ret)
- if 'message' in ret.get('result', {}):
- msg = ret['result']['message']
- result = ret.get('constant_result', [])
+ if "message" in ret.get("result", {}):
+ msg = ret["result"]["message"]
+ result = ret.get("constant_result", [])
try:
if result and len(result[0]) > (4 + 32) * 2:
- error_msg = tron_abi.decode_single('string', bytes.fromhex(result[0])[4 + 32 :])
- msg = "{}: {}".format(msg, error_msg)
+ error_msg = tron_abi.decode_single("string", bytes.fromhex(result[0])[4 + 32 :])
+ msg = f"{msg}: {error_msg}"
except Exception:
pass
raise TvmError(msg)
@@ -901,8 +923,8 @@ def trigger_const_smart_contract_function(
def broadcast(self, txn: Transaction) -> dict:
payload = self.provider.make_request("wallet/broadcasttransaction", txn.to_json())
self._handle_api_error(payload)
- if payload.get('txid') is None:
- payload['txid'] = txn.txid
+ if payload.get("txid") is None:
+ payload["txid"] = txn.txid
return payload
def get_sign_weight(self, txn: Transaction) -> dict: