-
-
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') |
agree it, this method seem not secure
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
Sending the pkey to some site? Even if it's api.trongrid.io...
Why we can't sign our transaction? It comes super weird to me.
Is there are any way to do it without sending pkey?
Edit: Just use this...