Skip to content

Commit

Permalink
add dns data parsing (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
dungeon-master-666 authored Aug 15, 2023
1 parent 8d88284 commit c187d0e
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
15 changes: 13 additions & 2 deletions pytonlib/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pytonlib.utils.address import prepare_address, detect_address
from pytonlib.utils.common import b64str_to_hex, hex_to_b64str, hash_to_hex
from pytonlib.utils.tokens import (parse_jetton_master_data, parse_jetton_wallet_data,
parse_nft_collection_data, parse_nft_item_data, parse_nft_content)
parse_nft_collection_data, parse_nft_item_data, parse_nft_content, parse_dns_content)

from tvm_valuetypes import serialize_tvm_stack, render_tvm_stack, deserialize_boc

Expand Down Expand Up @@ -773,7 +773,18 @@ async def get_token_data(self, address: str):
individual_content = result.pop('individual_content')
get_nft_content_request_stack = [['num', result['index']], ['tvm.Cell', individual_content]]
content_raw = await self.raw_run_method(prepare_address(result['collection_address']), 'get_nft_content', get_nft_content_request_stack)
content = parse_nft_content(content_raw['stack'])

# TON DNS collection
if prepare_address(result['collection_address']) == 'EQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz0Bz':
content = parse_dns_content(content_raw['stack'])
get_domain_res = await self.raw_run_method(address, 'get_domain', [])
if get_domain_res['exit_code'] == 0:
domain_bytes = get_domain_res['stack'][0][1]['bytes']
domain_boc = codecs.decode(codecs.encode(domain_bytes, 'utf-8'), 'base64')
domain_cell = deserialize_boc(domain_boc)
content['domain'] = domain_cell.data.data.tobytes().decode('ascii') + '.ton'
else:
content = parse_nft_content(content_raw['stack'])
else:
content = result.pop('individual_content')
result['content'] = content
Expand Down
64 changes: 63 additions & 1 deletion pytonlib/utils/tlb.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def __init__(self, cell_slice):
self.address = ba2hex(cell_slice.read_next(addr_len))

class TokenData:
attributes = ['uri', 'name', 'description', 'image', 'image_data', 'symbol', 'decimals']
attributes = ['uri', 'name', 'description', 'image', 'image_data', 'symbol', 'decimals', 'amount_style', 'render_type']
attributes_hashes = {}
for attr in attributes:
attributes_hashes[sha256(attr.encode('utf-8')).hexdigest()] = attr
Expand Down Expand Up @@ -518,6 +518,68 @@ def _parse_content_data(self, cell: Cell, encoding='utf-8'):
raise ValueError(f'Unexpected content data prefix: {prefix}')
return data.tobytes().decode(encoding)


class DNSRecord:
"""
dns_smc_address#9fd3 smc_addr:MsgAddressInt flags:(## 8) { flags <= 1 }
cap_list:flags . 0?SmcCapList = DNSRecord;
dns_next_resolver#ba93 resolver:MsgAddressInt = DNSRecord;
dns_adnl_address#ad01 adnl_addr:bits256 flags:(## 8) { flags <= 1 }
proto_list:flags . 0?ProtoList = DNSRecord;
dns_storage_address#7473 bag_id:bits256 = DNSRecord;
"""
def __init__(self, cell_slice):
prefix = ba2hex(cell_slice.read_next(16))
if prefix == '9fd3':
self.smc_addr = MsgAddressInt(cell_slice)
flags = ba2int(cell_slice.read_next(8))
if flags & 1:
#TODO: parse SmcCapList
cell_slice.read_next(cell_slice.bits_left())
elif prefix == 'ad01':
self.adnl_addr = ba2hex(cell_slice.read_next(256))
flags = ba2int(cell_slice.read_next(8))
if flags & 1:
#TODO: parse ProtoList
cell_slice.read_next(cell_slice.bits_left())
elif prefix == 'ba93':
self.resolver = MsgAddressInt(cell_slice)
elif prefix == '7473':
self.bag_id = ba2hex(cell_slice.read_next(256))
else:
raise ValueError(f'Unexpected content data prefix: {prefix}')

class DNSRecordSet:
attributes = ['wallet', 'site', 'storage', 'dns_next_resolver']
attributes_hashes = {}
for attr in attributes:
attributes_hashes[sha256(attr.encode('utf-8')).hexdigest()] = attr

def __init__(self, cell_slice):
prefix = cell_slice.read_next(8)
assert prefix == bitarray('00000000'), 'dns data expected to be onchain'
if cell_slice.read_next(1).any():
child_slice = cell_slice.read_next_ref()
hashmap_cell = Cell()
hashmap_cell.data.data = child_slice._data
hashmap_cell.refs = child_slice._refs
hashmap = {}
parse_hashmap(hashmap_cell, 256, hashmap, bitarray())
self.data = self._parse_attributes(hashmap)
else:
self.data = {}

def _parse_attributes(self, hashmap: dict):
res = {}
for attr_hash_bitstr, value_cell in hashmap.items():
attr_hash_hex = ba2hex(bitarray(attr_hash_bitstr))
attr_name = DNSRecordSet.attributes_hashes.get(attr_hash_hex)
if attr_name is None:
attr_name = attr_hash_hex
assert len(value_cell.refs) == 1, 'dict val should contain exact 1 ref'
res[attr_name] = DNSRecord(Slice(value_cell.refs[0]))
return res

class TextCommentMessage:
def __init__(self, cell_slice):
prefix = cell_slice.read_next(32)
Expand Down
5 changes: 4 additions & 1 deletion pytonlib/utils/tokens.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pytonlib.utils.tlb import parse_tlb_object, MsgAddress, MsgAddressInt, TokenData
from pytonlib.utils.tlb import parse_tlb_object, MsgAddress, MsgAddressInt, TokenData, DNSRecordSet
from pytonlib.utils.address import detect_address

def read_stack_num(entry: list):
Expand Down Expand Up @@ -105,3 +105,6 @@ def parse_nft_item_data(stack: list):

def parse_nft_content(stack: list):
return parse_tlb_object(read_stack_cell(stack[0]), TokenData)

def parse_dns_content(stack: list):
return parse_tlb_object(read_stack_cell(stack[0]), DNSRecordSet)

0 comments on commit c187d0e

Please sign in to comment.