Created
June 22, 2019 00:42
-
-
Save fbsobreira/259eed793cffe4551854250884049f03 to your computer and use it in GitHub Desktop.
Test case TronWatchMarket Ledger
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
import sys | |
sys.path.append("./examples/proto") | |
import logging | |
import time | |
from ledgerblue.comm import getDongle | |
from base import parse_bip32_path | |
from pprint import pprint | |
''' | |
Tron Protobuf | |
''' | |
from api import api_pb2 as api | |
from core import Contract_pb2 as contract | |
from api.api_pb2_grpc import WalletStub | |
from core import Tron_pb2 as tron | |
from google.protobuf.any_pb2 import Any | |
import grpc | |
import base58 | |
import binascii | |
import struct | |
# Start Channel and WalletStub | |
channel = grpc.insecure_channel("grpc.trongrid.io:50051") | |
stub = WalletStub(channel) | |
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") | |
logger = logging.getLogger() | |
print(''' | |
TronWatch.Market | |
''') | |
def chunks(l, n): | |
"""Yield successive n-sized chunks from l.""" | |
for i in range(0, len(l), n): | |
yield l[i:i + n] | |
def apduMessage(INS, P1, P2, PATH, MESSAGE): | |
hexString = "" | |
if PATH: | |
hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) | |
else: | |
hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) | |
print(hexString) | |
return bytearray.fromhex(hexString) | |
def ledgerSign(PATH, tx, tokenSignature=[]): | |
raw_tx = tx.raw_data.SerializeToString().hex() | |
# Sign in chunks | |
chunkList = list(chunks(raw_tx,400)) | |
if len(tokenSignature)>0: | |
chunkList.extend(tokenSignature) | |
# P1 = P1_FIRST = 0x00 | |
if len(chunkList)>1: | |
result = dongle.exchange(apduMessage(0x04,0x00,0x00, PATH, chunkList[0])) | |
else: | |
result = dongle.exchange(apduMessage(0x04,0x10,0x00, PATH, chunkList[0])) | |
for i in range(1,len(chunkList)-1-len(tokenSignature)): | |
# P1 = P1_MODE = 0x80 | |
result = dongle.exchange(apduMessage(0x04,0x80,0x00, None, chunkList[i])) | |
for i in range(0,len(tokenSignature)-1): | |
result = dongle.exchange(apduMessage(0x04,0xA0 | (0x00+i), 0x00, None, tokenSignature[i])) | |
# P1 = P1_LAST = 0x90 | |
if len(chunkList)>1: | |
if len(tokenSignature)>0: | |
result = dongle.exchange(apduMessage(0x04,0xA0 | 0x08 | (0x00+len(tokenSignature)-1),0x00, None, chunkList[len(chunkList)-1])) | |
else: | |
result = dongle.exchange(apduMessage(0x04,0x90,0x00, None, chunkList[len(chunkList)-1])) | |
return raw_tx, result | |
def address_hex(address): | |
return base58.b58decode_check(address).hex().upper() | |
# Start Ledger | |
dongle = getDongle(True) | |
exchangeAddress = {} | |
exchangeAddress['address'] = 'TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M' | |
exchangeAddress['addressHex'] = address_hex(exchangeAddress['address']) | |
testAccount = {} | |
donglePath = parse_bip32_path("44'/195'/0'/0/0") | |
result = dongle.exchange(apduMessage(0x02,0x00,0x00,donglePath, "")) | |
size=result[0] | |
if size == 65 : | |
size=result[size+1] | |
if size == 34 : | |
testAccount['address'] = result[67:67+size].decode() | |
testAccount['addressHex'] = address_hex(testAccount['address']) | |
else: | |
logger.error('Error... Address Size: {:d}'.format(size)) | |
else: | |
logger.error('Error... Public Key Size: {:d}'.format(size)) | |
def toFixed(value): | |
if isinstance(value, str): | |
return value.zfill(64) | |
elif value is None: | |
return "0".zfill(64) | |
return '{:064x}'.format(value) | |
def tokenToUint(tokenType, tokenAddress): | |
if tokenType == "TRX": | |
return "0".zfill(64) | |
elif tokenType == "TRC10": | |
if isinstance(tokenAddress, str) or tokenAddress<=1000000: | |
raise ValueError('Invalid TRC10 tokenId (param tokenAddress): ') | |
return '{:064x}'.format(tokenAddress) | |
elif tokenType == "TRC20": | |
address = address_hex(tokenAddress) | |
return address[2:].zfill(64) | |
else: | |
raise ValueError('Invalid tokenType: Expecting TRX, TRC10, or TRC20') | |
def validateMakerOffer(makerOffer, skipDateCheck=None): | |
if makerOffer is None: raise ValueError("Missing param makerOffer") | |
if makerOffer['quote'] is None: | |
raise ValueError("Missing param makerOffer.quote, use null or 0 for TRX") | |
if makerOffer['maker'] is None: | |
raise ValueError("Missing param makerOffer.maker") | |
if makerOffer['amount'] is None: | |
raise ValueError("Missing param makerOffer.amount") | |
if makerOffer['affiliate'] is None: | |
raise ValueError("Missing param makerOffer.affiliate, use null for no affiliate") | |
if makerOffer['rateNumerator'] is None: | |
raise ValueError("Missing param makerOffer.rateNumerator") | |
if makerOffer['rateDenominator'] is None: | |
raise ValueError("Missing param makerOffer.rateDenominator") | |
if makerOffer['creationDate'] is None: | |
raise ValueError("Missing param makerOffer.creationDate") | |
if skipDateCheck is None and (makerOffer['creationDate'] > (1000000 + int(time.time()) ) ): | |
raise ValueError("makerOffer.creationDate out of range, use `Math.round(Date.now() / 1000)`") | |
if makerOffer['expirationDate'] is None: | |
raise ValueError("Missing param makerOffer.expirationDate") | |
if makerOffer['isBuy'] is None: | |
raise ValueError("Missing param makerOffer.isBuy") | |
if makerOffer['autoWithdraw'] is None: | |
raise ValueError("Missing param makerOffer.autoWithdraw") | |
def parseMakerUints(makerOffer): | |
uints = [] | |
uints.append(tokenToUint(makerOffer['baseType'], makerOffer['base'])) | |
uints.append(tokenToUint(makerOffer['quoteType'], makerOffer['quote'])) | |
uints.append(toFixed(makerOffer['amount'])) | |
uints.append(toFixed(makerOffer['rateNumerator'])) | |
uints.append(toFixed(makerOffer['rateDenominator'])) | |
uints.append(toFixed(makerOffer['creationDate'])) | |
uints.append(toFixed(makerOffer['expirationDate'])) | |
return uints | |
def getMakerHash(makerOffer): | |
validateMakerOffer(makerOffer) | |
uints = parseMakerUints(makerOffer) | |
'''ABI | |
[{"constant":true,"inputs":[{"name":"_maker","type":"address"},{"name":"_isMakerBuy","type":"bool"},{"name":"_makerAffiliate","type":"address"},{"name":"_uints","type":"uint256[7]"},{"name":"_autoWithdraw","type":"bool"}],"name":"getMakerHash","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"}] | |
''' | |
data = '{:08x}{}{:064x}{}{}{}{}{}{}{}{}{:064x}'.format( | |
0xe51fabf7, | |
address_hex(makerOffer['maker'])[2:].zfill(64), | |
makerOffer['isBuy'], | |
address_hex(makerOffer['affiliate'])[2:].zfill(64), | |
uints[0], | |
uints[1], | |
uints[2], | |
uints[3], | |
uints[4], | |
uints[5], | |
uints[6], | |
makerOffer['autoWithdraw'], | |
) | |
tx = stub.TriggerContract(contract.TriggerSmartContract( | |
owner_address=bytes.fromhex(testAccount['addressHex']), | |
contract_address=bytes.fromhex(exchangeAddress['addressHex']), | |
data=bytes.fromhex(data) | |
)) | |
tx.transaction.raw_data.fee_limit = 1000000000 | |
pprint(tx) | |
return tx.constant_result[0].hex() | |
hash = getMakerHash( | |
{ | |
"orderID": 14302, | |
"amountRemaining": 1, | |
"amountFilled": 0, | |
"affiliate": "TSWkgawBp6YmZmEJZSb5br44hZjU7H1BxF", | |
"signature": "0x1b,0x9a14e370b9e0aab7ca822d416f2c29fc369bbeb66b97bf44b848070491582199,0x0c84cd090ff7b84bb2acbd606ce4b08fcdfcf2707d2d2db6823e4659ff9465f1", | |
"hash": "0xc1d8afe8f63ad4cf873518bab3b91512e764af6e91ebf46d85ef3ab37f6ed4a7", | |
"maker": testAccount['address'], | |
"baseType": "TRC10", | |
"base": 1000933, | |
"quoteType": "TRX", | |
"quote": "TRX", | |
"amount": 1, | |
"rateNumerator": 276100, | |
"rateDenominator": 1, | |
"creationDate": 1558881044, | |
"expirationDate": 9008758135785, | |
"price": 276100.000000000000000000, | |
"side": "BUY", | |
"isBuy": True, | |
"status": "OPEN", | |
"autoWithdraw": 1 | |
} | |
) | |
message = bytes.fromhex(hash) | |
# Magic define | |
SIGN_MAGIC = b'\x19TRON Signed Message:\n' | |
encodedTx = struct.pack(">I", len(message))TronWatchMarket Ledger | |
encodedTx += messageTronWatchMarket LedgerTronWatchMarket Ledger | |
signedMessage = SIGN_MAGIC + str(len(message)).encode() + message | |
result = dongle.exchange(apduMessage(0x08,0x00,0x00, donglePath, encodedTx.hex())) | |
logger.debug('- Hash: {}'.format(hash)) | |
logger.debug('- Signed Message: {}'.format(signedMessage)) | |
logger.debug('- Signature: {}'.format(result.hex())) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment