Skip to content

Commit

Permalink
- add export to a contract
Browse files Browse the repository at this point in the history
- add query examples from a contract
- update config
- update readme
- update requirements
  • Loading branch information
Snedashkovsky committed Jul 19, 2023
1 parent a962eca commit c567ebf
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 48 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
On-chain based data allows to view all existing assets.<br><br>
- [**chain-registry like data**](data_json)
- [**csv data**](data_csv)
- **contracts** ([code](cw-on-chain-registry/contracts/on-chain-registry))
- **contracts** ([code](https://github.com/Snedashkovsky/cw-on-chain-registry/tree/main/contracts/on-chain-registry),
[schema](https://github.com/Snedashkovsky/cw-on-chain-registry/tree/main/contracts/on-chain-registry/schema))
- [bostrom](https://cyb.ai/contracts/bostrom1eeahgvdsun8a04rh5vy9je49nllq6nj8ljmaslsvjeyg0j0063mssjcjmt)

## Asset Data Structure
We use chain-registry like [asset data structure](assetlist.schema.json) for better compatibility.
Differences from [chain-registry asset data structure](chain-registry/assetlist.schema.json):
Differences from [chain-registry asset data structure](https://github.com/cosmos/chain-registry/blob/master/assetlist.schema.json):
- add `chain_id` required property;
- `denom_units`, `display`, `name` and `symbol` asset object properties are optional
- add `chain_id` required property in asset traces section
Expand Down
115 changes: 85 additions & 30 deletions asset_data.ipynb

Large diffs are not rendered by default.

13 changes: 4 additions & 9 deletions asset_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from src.lcd_extractor import extract_assets, get_cw20_token_info
from src.chain_registry_extractor import get_chain_names_and_lcd_dicts
from src.json_export import get_asset_json_dict
from src.contract_export import save_to_contract

filterwarnings('ignore')
tqdm.pandas()
Expand Down Expand Up @@ -44,9 +45,9 @@ def add_cw20(assets_df: pd.DataFrame,
for _chain_id, _assets in assets_df[(assets_df.type_asset_base == 'cw20') & (assets_df.one_channel == True)][
['chain_id_counterparty', 'denom_base']].drop_duplicates().groupby('chain_id_counterparty'):
if _chain_id not in chain_id_lcd_dict.keys():
print(f'{_chain_id} not in chain_id_lcd_dict')
logging.error(f'{_chain_id} not in chain_id_lcd_dict')
continue
print(_chain_id)
logging.info(f'Extract cw20 data for {_chain_id}')
for _denom in tqdm(_assets['denom_base'].to_list()):
_contract = _denom[5:]
_cw20_token_info = None
Expand All @@ -67,13 +68,6 @@ def add_cw20(assets_df: pd.DataFrame,
_cw20_token_info_list.append(_cw20_token_info)

_cw20_token_info_df = pd.DataFrame(_cw20_token_info_list)
print(_cw20_token_info_df.apply(
lambda x: [{
"denom": x.symbol.lower(),
"exponent": x.decimals,
"aliases": [x.symbol]
}],
axis=1))
_cw20_token_info_df['denom_units'] = _cw20_token_info_df.apply(
lambda x: [{
"denom": x.symbol.lower(),
Expand Down Expand Up @@ -176,6 +170,7 @@ def run_export() -> None:
'denom_base': ''})
save_to_csv(assets_df=_assets_df)
save_to_json(assets_df=_assets_df, chain_id_name_dict=_chain_id_name_dict)
save_to_contract()
logging.info(msg=f'extracted {len(_assets_df):>,} assets for {len(set(_assets_df.chain_id.to_list()))} chains')


Expand Down
21 changes: 16 additions & 5 deletions config.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import logging
import sys
from dotenv import dotenv_values

from cyber_sdk.client.lcd import LCDClient
from cyber_sdk.key.mnemonic import MnemonicKey


# logging config
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%d-%m-%Y %H:%M:%S',
handlers=[logging.FileHandler("arbitrage_osmosis.log"),
handlers=[logging.FileHandler("on-chain-registry.log"),
logging.StreamHandler(sys.stdout)])

# extra chains
PUSSY_CHAIN_ID = 'space-pussy'
PUSSY_CHAIN_NAME = 'space-pussy'
PUSSY_NODE_LCD_URL = 'https://lcd.space-pussy.cybernode.ai'

INIT_CHAIN_ID_NAME_DICT = {PUSSY_CHAIN_ID: PUSSY_CHAIN_NAME}
INIT_CHAIN_ID_LCD_DICT = {PUSSY_CHAIN_ID: [PUSSY_NODE_LCD_URL]}

CONTRACTS = {
'bostrom': 'bostrom1eeahgvdsun8a04rh5vy9je49nllq6nj8ljmaslsvjeyg0j0063mssjcjmt'
}
# for export to a contract
CHAIN_ID = 'bostrom'
NODE_RPC_URL = 'https://rpc.bostrom.cybernode.ai:443'
NODE_LCD_URL = 'https://lcd.bostrom.cybernode.ai'
CONTRACT_ADDRESS = 'bostrom1eeahgvdsun8a04rh5vy9je49nllq6nj8ljmaslsvjeyg0j0063mssjcjmt'
LCD_CLIENT = LCDClient(url=NODE_LCD_URL, chain_id=CHAIN_ID)
WALLET_SEED = dotenv_values('.env')['WALLET_SEED']
WALLET = LCD_CLIENT.wallet(MnemonicKey(mnemonic=WALLET_SEED))
WALLET_ADDRESS = WALLET.key.acc_address
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
pandas
tqdm
cyberutils
cyber_sdk
python-dotenv
103 changes: 103 additions & 0 deletions src/contract_export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import json
import pandas as pd
from tqdm import tqdm
import requests
import base64

from cyber_sdk.client.lcd import LCDClient, Wallet
from cyber_sdk.client.lcd.api.tx import BlockTxBroadcastResult
from cyberutils.contract import execute_contract

from config import logging, CONTRACT_ADDRESS, LCD_CLIENT, WALLET, WALLET_ADDRESS, NODE_LCD_URL


def batch(x: list, batch_size: int) -> list[list]:
return [x[_i: _i + batch_size] for _i in range(0, len(x), batch_size)]


def contract_query(
contract_address: str,
query: dict,
node_lcd_url: str = NODE_LCD_URL,
display_query: bool = False) -> dict:
"""
Query contract
:param contract_address: contract address
:param query: contract query
:param node_lcd_url: node lcd url
:param display_query: display a query url or not
:return: query result
"""
_query_msg = base64.b64encode(json.dumps(query).encode("utf-8")).decode("utf-8")
_query = f'{node_lcd_url}/cosmwasm/wasm/v1/contract/{contract_address}/smart/{_query_msg}'
if display_query:
logging.info(_query)
return requests.get(_query).json()


def save_to_contract(
all_asset_path: str = 'data_json/all_assets.json',
batch_size: int = 150,
contract_address: str = CONTRACT_ADDRESS,
lcd_client: LCDClient = LCD_CLIENT,
wallet: Wallet = WALLET,
wallet_address: str = WALLET_ADDRESS,
fee_denom: str = 'boot',
gas: int = 20_000_000,
memo: str = 'update assets in on-chain-registry') -> list[BlockTxBroadcastResult]:
"""
Save asset data to a contract
:param all_asset_path: path of file with all assets
:param batch_size: number of updated assets in one transaction
:param contract_address: contract address
:param lcd_client: LCD client
:param wallet: sender wallet
:param wallet_address: sender address
:param fee_denom: transaction fee denom
:param gas: gas amount
:param memo: transaction memo
:return: list of transaction results
"""
with open(all_asset_path, 'r') as _all_assets_file:
_all_assets_json = json.load(_all_assets_file)

_assets_list = []
for _assets_json in tqdm(_all_assets_json):
_assets = _assets_json['assets']
for i in range(len(_assets)):
_assets[i]['supply'] = str(_assets[i]['supply'])
_assets[i]['chain_name'] = _assets_json['chain_name']
_assets[i]['chain_id'] = _assets_json['chain_id']
if 'traces' in _assets[i].keys():
for _trace in _assets[i]['traces']:
if 'base_supply' in _trace.keys():
_trace['base_supply'] = str(_trace['base_supply'])
if 'counterparty' in _trace.keys() and 'base_supply' in _trace['counterparty'].keys():
_trace['counterparty']['base_supply'] = str(_trace['counterparty']['base_supply'])
if 'type' in _trace.keys():
_trace['trace_type'] = _trace.pop('type')
_assets_list.extend(_assets)

_res_list = []
for _assets_batch in tqdm(batch(_assets_list, batch_size)):
logging.info('Export to contract ' + ', '.join(
[f'{k} {v:>,}'
for k, v in pd.DataFrame(_assets_batch).groupby('chain_name')['chain_name'].agg(pd.value_counts).to_dict().items()]
)
)
_res = execute_contract(
execute_msgs=[{'UpdateAssets': {
'assets': _assets_batch}}],
contract_address=contract_address,
lcd_client=lcd_client,
fee_denom=fee_denom,
wallet=wallet,
sender=wallet_address,
memo=memo,
gas=gas
)
_res_list.append(_res)
if len(str(_res)) < 500:
logging.error(_res)

return _res_list
4 changes: 2 additions & 2 deletions src/lcd_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ def get_cw20_token_info(contract_address: str,
if 'data' in _res.keys():
return _res['data']
if 'code' in _res.keys():
print(f'{contract_address} {node_lcd_url} Not Implemented')
logging.error(f'{contract_address} {node_lcd_url} Not Implemented')
return _res
print(_res)
logging.error(f'{contract_address} {node_lcd_url} Error {_res}')
return {}


Expand Down

0 comments on commit c567ebf

Please sign in to comment.