-
-
Save andelf/7c2b6b176872ff0e83086828e6f16d2b to your computer and use it in GitHub Desktop.
import requests | |
import base58 | |
import base64 | |
from pprint import pprint | |
ADDRESS = "T....your address" | |
PRIV_KEY = 'hex private key' | |
CONTRACT = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" # USDT | |
CONTRACT = "T,,,,,,,,,,,,,,,,,,,,,,ia" | |
API_URL_BASE = 'https://api.trongrid.io/' | |
# API_URL_BASE = 'https://api.shasta.trongrid.io/' | |
# API_URL_BASE = 'https://api.nileex.io/' | |
# 70a08231: balanceOf(address) | |
METHOD_BALANCE_OF = 'balanceOf(address)' | |
# a9059cbb: transfer(address,uint256) | |
METHOD_TRANSFER = 'transfer(address,uint256)' | |
DEFAULT_FEE_LIMIT = 1_000_000 # 1 TRX | |
def address_to_parameter(addr): | |
return "0" * 24 + base58.b58decode_check(addr)[1:].hex() | |
def amount_to_parameter(amount): | |
return '%064x' % amount | |
def get_balance(address=ADDRESS): | |
url = API_URL_BASE + 'wallet/triggerconstantcontract' | |
payload = { | |
'owner_address': base58.b58decode_check(ADDRESS).hex(), | |
'contract_address': base58.b58decode_check(CONTRACT).hex(), | |
'function_selector': METHOD_BALANCE_OF, | |
'parameter': address_to_parameter(address), | |
} | |
resp = requests.post(url, json=payload) | |
data = resp.json() | |
if data['result'].get('result', None): | |
print(data['constant_result']) | |
val = data['constant_result'][0] | |
print('balance =', int(val, 16)) | |
else: | |
print('error:', bytes.fromhex(data['result']['message']).decode()) | |
def get_trc20_transaction(to, amount, memo=''): | |
url = API_URL_BASE + 'wallet/triggersmartcontract' | |
payload = { | |
'owner_address': base58.b58decode_check(ADDRESS).hex(), | |
'contract_address': base58.b58decode_check(CONTRACT).hex(), | |
'function_selector': METHOD_TRANSFER, | |
'parameter': address_to_parameter(to) + amount_to_parameter(amount), | |
"fee_limit": DEFAULT_FEE_LIMIT, | |
'extra_data': base64.b64encode(memo.encode()).decode(), # TODO: not supported yet | |
} | |
resp = requests.post(url, json=payload) | |
data = resp.json() | |
if data['result'].get('result', None): | |
transaction = data['transaction'] | |
return transaction | |
else: | |
print('error:', bytes.fromhex(data['result']['message']).decode()) | |
raise RuntimeError | |
def sign_transaction(transaction, private_key=PRIV_KEY): | |
url = API_URL_BASE + 'wallet/addtransactionsign' | |
payload = {'transaction': transaction, 'privateKey': private_key} | |
resp = requests.post(url, json=payload) | |
data = resp.json() | |
if 'Error' in data: | |
print('error:', data) | |
raise RuntimeError | |
return data | |
def broadcast_transaction(transaction): | |
url = API_URL_BASE + 'wallet/broadcasttransaction' | |
resp = requests.post(url, json=transaction) | |
data = resp.json() | |
print(data) | |
def transfer(to, amount, memo=''): | |
transaction = get_trc20_transaction(to, amount, memo) | |
pprint(transaction) | |
transaction = sign_transaction(transaction) | |
broadcast_transaction(transaction) | |
get_balance() | |
transfer('T..............q', 5_000, 'test from python') |
Thanks @ygboucherk; Correct tronpy has a .sign function. See Here
cc: @EUA @G33kNoob
Here's a custom extract leveraging the tronpy library
from tronpy.keys import PrivateKey
def sign_transaction_offine(self, transaction_object, your_tron_private_key):
# CONVERT PRIVATE KEY TO BYTES
private_key_bytes = bytes.fromhex(your_tron_private_key)
# CONVERT INITIATED TRANSACTION ID TO BYTES
transaction_id_bytes = bytes.fromhex(transaction_object["txID"]
# SIGN TRANSACTION
data = PrivateKey(private_key_bytes=private_key_bytes).sign_msg_hash(transaction_id_bytes))
return data
Call your function and proceed to broadcast
How to get the balance of a TRX wallet itself? Not a TRC20 token, but TRX
can anybody give more information (best practice) how to transfer trc20 and sign it offline?
Hiii @ikamran, to further buttress what my Boss @andelf posted. Let's presume you want to transfer USDT (a trc20 contract). There are 3 basic steps:
- Create transaction
- Sign transaction (Offline)
- Broadcast transaction to the network
Create
Use the get_trc20_transaction
function in @andelf's initial gist above to Create your transaction
Sign Transaction
from tronpy.keys import PrivateKey
def sign_transaction_offine(self, transaction_object, your_tron_private_key):
# CONVERT PRIVATE KEY TO BYTES
private_key_bytes = bytes.fromhex(your_tron_private_key)
# CONVERT INITIATED TRANSACTION ID TO BYTES
transaction_id_bytes = bytes.fromhex(transaction_object["txID"]
# SIGN TRANSACTION
data = PrivateKey(private_key_bytes=private_key_bytes).sign_msg_hash(transaction_id_bytes))
return data
Broadcast
Use the broadcast_transaction
function in @andelf's initial gist to Broadcast the transaction to the network
Thanks for your help, according to your last email I already did it successfully without any issue the issue comes when I want to send from a multi-signiture address
from tronpy import Tron
from tronpy.keys import PrivateKey
client = Tron(network='nile', conf={'fee_limit': 10_000_000})
priv_key = PrivateKey(bytes.fromhex("e5f4a4acb3ecef9e8589d69c1aa9fa5723b04ff724b1c04ebe6cd746b241ad04"))
contractAddress = 'TLBaRhANQoJFTqre9Nf1mjuwNWjCJeYqUL'
myAddress = 'TGihHToJJ9B1NFi2Vx5bTM8muRmsbdAaJ8'
contract = client.get_contract(contractAddress)
oneUSDJ = 1_000_000_000_000_000_000
class Tron:
def __init__(self):
self.contract = contract
self.myAdd = myAddress
def getTokenBalance(self):
return contract.functions.balanceOf(myAddress) / 10 ** 6
def getBalance(self, address):
return client.get_account_balance(address)
def getAccount(self, address):
return client.get_account(address)
def sendTRX(self, accountAddress):
txn = (
client.trx.transfer(myAddress, accountAddress, 100_000_000)
.with_owner(myAddress)
.permission_id(2)
.build()
.sign(priv_key)
)
print(txn.txid)
print(txn.broadcast().wait())
return txn
tron = Tron()
I included permission_id but I got this error:
>>> tron.sendTRX('TC2r7dPEfMaMt8ToJ3rQ7SuVhX391cFhv5')
{'address': '414a0a401872a17daf91e753226e8981e434e97452', 'weight': 1}
a6c802ca8cbfd1562e6203a43437b98f30aef7b09f2d968be213afe56746c864
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\itk\dev\test\tronpy\example1.py", line 38, in sendTRX
print(txn.broadcast().wait())
File "C:\Users\itk\dev\test\venv\lib\site-packages\tronpy\tron.py", line 154, in broadcast
return TransactionRet(self._client. Broadcast(self), client=self._client, method=self._method)
File "C:\Users\itk\dev\test\venv\lib\site-packages\tronpy\tron.py", line 827, in broadcast
self._handle_api_error(payload)
File "C:\Users\itk\dev\test\venv\lib\site-packages\tronpy\tron.py", line 467, in _handle_api_error
raise BadSignature(msg)
tronpy.exceptions.BadSignature: Validate signature error: sig error
agree it, this method seem not secure