diff --git a/CHANGELOG.md b/CHANGELOG.md index 8293159..3318a0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [9.2.3] +- add method for trigger contract +- add method for check acc resources + +## [9.2.2] +- update actions upload-artifact +- add method for getting transactions receipt. + ## [9.2.1] - fix max_retries and retry_delay params adding for tron monitoring diff --git a/aiotx/clients/_tron_base_client.py b/aiotx/clients/_tron_base_client.py index 8e58a2c..21692b9 100644 --- a/aiotx/clients/_tron_base_client.py +++ b/aiotx/clients/_tron_base_client.py @@ -321,6 +321,44 @@ async def get_balance( address = self.base58_to_hex_address(address) return await super().get_balance(address, block_parameter) + async def get_account_resource(self, address) -> dict: + client = Tron() + path = "/wallet/getaccountresource" + if client.is_base58check_address(address): + address = self.base58_to_hex_address(address) + data = {"address": address, "visible": False} + return await self._make_api_call(payload=data, method="POST", path=path) + + async def trigger_constant_contract( + self, from_address, contract_address, to_address, amount + ) -> dict: + from eth_abi import encode + + client = Tron() + path = "/wallet/triggerconstantcontract" + hex_to_address = self.base58_to_hex_address(to_address) + if hex_to_address.startswith("41"): + hex_to_address = hex_to_address[2:] # Remove '41' prefix + hex_to_address = "0x" + hex_to_address + + transfer_data = encode(["address", "uint256"], [hex_to_address, amount]) + parameter = transfer_data.hex() + + if client.is_base58check_address(from_address): + from_address = self.base58_to_hex_address(from_address) + + if client.is_base58check_address(contract_address): + contract_address = self.base58_to_hex_address(contract_address) + + data = { + "owner_address": from_address, + "contract_address": contract_address, + "function_selector": "transfer(address,uint256)", + "parameter": parameter, + "visible": False, + } + return await self._make_api_call(payload=data, method="POST", path=path) + async def get_contract_balance( self, address, contract_address, block_parameter: BlockParam = BlockParam.LATEST ) -> int: diff --git a/tests/fixtures/cassettes/tron/get_account_resource.yaml b/tests/fixtures/cassettes/tron/get_account_resource.yaml new file mode 100644 index 0000000..fd661b2 --- /dev/null +++ b/tests/fixtures/cassettes/tron/get_account_resource.yaml @@ -0,0 +1,290 @@ +interactions: +- request: + body: '{"address": "41fd76d0c83ce08e518fc7fb4b38d963436f701fac", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetUsed": 264,"freeNetLimit": 600,"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '167' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:16:26 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "4199477b140c6266d7bd7c7f21145a44d80b21facf", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetUsed": 330,"freeNetLimit": 600,"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '167' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:16:27 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "4175f12b06daae11e5be71c1025732a02bea437d97", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetLimit": 600,"assetNetUsed": [{"key": "1001058","value": 0}],"assetNetLimit": + [{"key": "1001058","value": 0}],"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '245' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:16:28 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "411aef008c25dfec6e2d85cbe286d690bdd1e31dfa", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetLimit": 600,"assetNetUsed": [{"key": "1000520","value": 0},{"key": + "1001304","value": 0}],"assetNetLimit": [{"key": "1000520","value": 0},{"key": + "1001304","value": 1000000}],"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"EnergyLimit": 176989,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": + 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '333' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:16:29 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "41fd76d0c83ce08e518fc7fb4b38d963436f701fac", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetUsed": 261,"freeNetLimit": 600,"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '167' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:30:34 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "4199477b140c6266d7bd7c7f21145a44d80b21facf", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetUsed": 327,"freeNetLimit": 600,"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '167' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:30:35 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "4175f12b06daae11e5be71c1025732a02bea437d97", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetLimit": 600,"assetNetUsed": [{"key": "1001058","value": 0}],"assetNetLimit": + [{"key": "1001058","value": 0}],"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '245' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:30:36 GMT + Server: + - openresty + status: + code: 200 + message: OK +- request: + body: '{"address": "411aef008c25dfec6e2d85cbe286d690bdd1e31dfa", "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/getaccountresource + response: + body: + string: '{"freeNetLimit": 600,"assetNetUsed": [{"key": "1000520","value": 0},{"key": + "1001304","value": 0}],"assetNetLimit": [{"key": "1000520","value": 0},{"key": + "1001304","value": 1000000}],"TotalNetLimit": 43200000000,"TotalNetWeight": + 356265954283,"EnergyLimit": 176989,"TotalEnergyLimit": 180000000000,"TotalEnergyWeight": + 12774681836} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - '333' + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:30:37 GMT + Server: + - openresty + status: + code: 200 + message: OK +version: 1 diff --git a/tests/fixtures/cassettes/tron/trigger_contract.yaml b/tests/fixtures/cassettes/tron/trigger_contract.yaml new file mode 100644 index 0000000..03fa04c --- /dev/null +++ b/tests/fixtures/cassettes/tron/trigger_contract.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: '{"owner_address": "419ed04a2e2382789345340504560cafe2cd012fc9", "contract_address": + "4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0", "function_selector": "transfer(address,uint256)", + "parameter": "000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee0", + "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/triggerconstantcontract + response: + body: + string: '{"result":{"result":true,"message":"524556455254206f70636f6465206578656375746564"},"energy_used":821,"constant_result":["08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e536166654d6174683a207375627472616374696f6e206f766572666c6f770000"],"transaction":{"ret":[{"ret":"FAILED"}],"visible":false,"txID":"161ff639c7841ed55a5f508d0f799b8db86bce2310530c1f8a563b99ad518888","raw_data":{"contract":[{"parameter":{"value":{"data":"a9059cbb000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee0","owner_address":"419ed04a2e2382789345340504560cafe2cd012fc9","contract_address":"4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0"},"type_url":"type.googleapis.com/protocol.TriggerSmartContract"},"type":"TriggerSmartContract"}],"ref_block_bytes":"8033","ref_block_hash":"5a4fdb26f7ede46a","expiration":1759233381000,"timestamp":1759233321609},"raw_data_hex":"0a02803322085a4fdb26f7ede46a4088a5ecd399335aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a15419ed04a2e2382789345340504560cafe2cd012fc912154142a1e39aefa49290f2b3f9ed688d7cecf86cd6e02244a9059cbb000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee07089d5e8d39933"}} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:55:21 GMT + Server: + - openresty + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + status: + code: 200 + message: OK +- request: + body: '{"owner_address": "41a7daea6878a518695d7ffdea39aec1a08fbb6c3d", "contract_address": + "4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0", "function_selector": "transfer(address,uint256)", + "parameter": "000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee0", + "visible": false}' + headers: + Content-Type: + - application/json + method: POST + uri: https://api.shasta.trongrid.io/wallet/triggerconstantcontract + response: + body: + string: '{"result":{"result":true},"energy_used":13045,"constant_result":["0000000000000000000000000000000000000000000000000000000000000001"],"logs":[{"address":"42a1e39aefa49290f2b3f9ed688d7cecf86cd6e0","data":"0000000000000000000000000000000000000000000000000000000000002ee0","topics":["ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","000000000000000000000000a7daea6878a518695d7ffdea39aec1a08fbb6c3d","000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a06"]}],"transaction":{"ret":[{}],"visible":false,"txID":"cb4e0906a41d48311d64eccafc50e750f0b34dbad2bcde45c8474a2f857675c1","raw_data":{"contract":[{"parameter":{"value":{"data":"a9059cbb000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee0","owner_address":"41a7daea6878a518695d7ffdea39aec1a08fbb6c3d","contract_address":"4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0"},"type_url":"type.googleapis.com/protocol.TriggerSmartContract"},"type":"TriggerSmartContract"}],"ref_block_bytes":"8033","ref_block_hash":"5a4fdb26f7ede46a","expiration":1759233381000,"timestamp":1759233322797},"raw_data_hex":"0a02803322085a4fdb26f7ede46a4088a5ecd399335aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a1541a7daea6878a518695d7ffdea39aec1a08fbb6c3d12154142a1e39aefa49290f2b3f9ed688d7cecf86cd6e02244a9059cbb000000000000000000000000e81ed73a89d295a5dcea0fcd365a4c6e27072a060000000000000000000000000000000000000000000000000000000000002ee070addee8d39933"}} + + ' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json;charset=utf-8 + Date: + - Tue, 30 Sep 2025 11:55:22 GMT + Server: + - openresty + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_tron/test_tron_client.py b/tests/test_tron/test_tron_client.py index 711e327..c14b870 100644 --- a/tests/test_tron/test_tron_client.py +++ b/tests/test_tron/test_tron_client.py @@ -341,3 +341,52 @@ async def test_send_trc20_token( private_key, send_to, contract, sun_amount, memo ) assert tx_id == expected_tx_id + + +@pytest.mark.parametrize( + "address, net_limit", + [ + ("TZ5QJ3NEaMzbMso8hRDYsVQMmEpJqhQ2cM", 600), + ("TPwg1yp99H1iRZNGqE5ASvvSzvaD19Uhbh", 600), + ("TLipy9vXFXkbbaz4RPQqnYdFqfnTidmvFN", 600), + ("TCRctCvEse9Y6E6i5DaTjkaSwyKRe6QQP8", 600), + ], +) +@vcr_c.use_cassette("tron/get_account_resource.yaml") +async def test_get_account_resource(tron_client: AioTxTRONClient, address, net_limit): + result = await tron_client.get_account_resource(address) + assert result["freeNetLimit"] == net_limit + + +@pytest.mark.parametrize( + "from_address, contract, to_address, amount, energy_used", + [ + ( + "TQSwHbTVYYbSFqHSYTL4C8FoMnRnS9fQDZ", + "TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs", + "TX8YiR4RmBsqAPGgAQATowVnbkikNWLtos", + 12000, + 821, + ), + ( + "TRGk6cyqCnUaXpp92B9KXUdoNCbNKvkb3J", + "TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs", + "TX8YiR4RmBsqAPGgAQATowVnbkikNWLtos", + 12000, + 13045, + ), + ], +) +@vcr_c.use_cassette("tron/trigger_contract.yaml") +async def test_trigger_contract( + tron_client: AioTxTRONClient, + from_address, + contract, + to_address, + amount, + energy_used, +): + result = await tron_client.trigger_constant_contract( + from_address, contract, to_address, amount + ) + assert result["energy_used"] == energy_used