From cf9225c7493f4946bc5aebfa3464092d9681e76f Mon Sep 17 00:00:00 2001 From: Haidar Jbeily <112971443+HaidarJbeily7@users.noreply.github.com> Date: Fri, 19 Jul 2024 16:59:31 +0300 Subject: [PATCH] Support complex swap path for KXOR (#90) * add chameleon swap path support * flexible allocating and parsing for swaps. update custom types file * revert custom type * Update Jenkinsfile * Update Jenkinsfile --------- Co-authored-by: f33r0 <95526886+f33r0@users.noreply.github.com> --- data_models.py | 4 +- processing.py | 47 +++++++++---------- run_node_processing.py | 100 +++++++++++++++++++---------------------- 3 files changed, 73 insertions(+), 78 deletions(-) diff --git a/data_models.py b/data_models.py index 6757a42..9976905 100644 --- a/data_models.py +++ b/data_models.py @@ -113,7 +113,7 @@ """ from dataclasses import dataclass - +from typing import List, Tuple @dataclass class SoraOp: @@ -134,7 +134,7 @@ class LiquidityTx(SoraOp): class Swap(LiquidityTx): filter_mode: str swap_fee_amount: int - intermediate_amount: int + intermediate_amounts: List[Tuple[str, int]] dex_id: int diff --git a/processing.py b/processing.py index f69b3d0..d7604bf 100644 --- a/processing.py +++ b/processing.py @@ -17,6 +17,8 @@ VAL_ID = "0x0200040000000000000000000000000000000000000000000000000000000000" PSWAP_ID = "0x0200050000000000000000000000000000000000000000000000000000000000" XSTUSD_ID = "0x0200080000000000000000000000000000000000000000000000000000000000" +KXOR_ID = "0x02000e0000000000000000000000000000000000000000000000000000000000" +ETH_ID="0x0200070000000000000000000000000000000000000000000000000000000000" TECH_ACCOUNT = ( # "0x54734f90f971a02c609b2d684e61b5574e35ac9942579a2635aada58e5d836a7" # noqa "cnTQ1kbv7PBNNQrEb1tZpmK7ftiv4yCCpUQy1J2y7Y54Taiaw" # noqa @@ -67,7 +69,11 @@ def get_op_id(ex_dict) -> int: def is_extrinsic_success(event) -> bool: return event["event_id"] == "ExtrinsicSuccess" - +def is_eth_kxor_pair(input_asset_type, output_asset_type): + return (input_asset_type == KXOR_ID or output_asset_type == KXOR_ID) \ + and (input_asset_type == ETH_ID or output_asset_type == ETH_ID) + + def set_max_amount(value, current_value): if current_value is None or value > current_value: return value @@ -89,7 +95,7 @@ def process_swap_transaction(timestamp, extrinsicEvents, ex_dict, prices): xor_fee = 0 filter_mode = None - intermediate_amount = None + intermediate_amounts = [] for param in ex_dict["call"]["call_args"]: if param["name"] == "dex_id": @@ -116,26 +122,18 @@ def process_swap_transaction(timestamp, extrinsicEvents, ex_dict, prices): return None for event in extrinsicEvents: - if event["event_id"] == "SwapSuccess": + if event["event_id"] == "SwapSuccess" or event["event_id"] == "ExtrinsicSuccess": swap_success = True elif event["event_id"] == "ExtrinsicFailed": - swap_success = False - elif dex_id == 0 and event["module_id"] == "Balances" and event["event_id"] == "Endowed": - dest, amount = event["event"]["attributes"].values() - if get_value(dest) == TECH_ACCOUNT: - intermediate_amount = set_max_amount( - get_value(amount), intermediate_amount) - elif dex_id == 1 and event["module_id"] == "Tokens" and event["event_id"] == "Endowed": - _, dest, amount = event["event"]["attributes"].values() - if get_value(dest) == TECH_ACCOUNT: - intermediate_amount = set_max_amount( - get_value(amount), intermediate_amount) - elif dex_id == 0 and event["module_id"] == "Balances" and event["event_id"] == "Transfer" and get_value(event["attributes"]['from']) == TECH_ACCOUNT: - intermediate_amount = set_max_amount( - get_value(event['attributes']['amount']), intermediate_amount) - elif dex_id == 1 and event["module_id"] == "Tokens" and event["event_id"] == "Transfer" and get_value(event["attributes"]['from']) == TECH_ACCOUNT: - intermediate_amount = set_max_amount( - get_value(event['attributes']['amount']), intermediate_amount) + swap_success = False + elif event['module_id'] == "Assets" and event["event_id"] == "Transfer": + _, to_address, token_obj, amount = event["attributes"] + if to_address == TECH_ACCOUNT: + intermediate_amounts.append((token_obj['code'], amount)) + elif event['module_id'] == "Tokens" and event["event_id"] == "Deposited": + token_obj, who, amount = event["attributes"].values() + if who == TECH_ACCOUNT: + intermediate_amounts.append((token_obj['code'], amount)) elif event["event_id"] == "Exchange": input_amount = get_value(event["event"]["attributes"][4]) output_amount = get_value(event["event"]["attributes"][5]) @@ -144,9 +142,12 @@ def process_swap_transaction(timestamp, extrinsicEvents, ex_dict, prices): if not swap_success: # TODO: add swap fail handler return None + + if ((dex_id == 0 and input_asset_type != XOR_ID and output_asset_type != XOR_ID) \ + or (dex_id == 1 and input_asset_type != XSTUSD_ID and output_asset_type != XSTUSD_ID)) \ + and (not is_eth_kxor_pair(input_asset_type, output_asset_type)): + assert len(intermediate_amounts) > 0 , ex_dict - if (dex_id == 0 and input_asset_type != XOR_ID and output_asset_type != XOR_ID) or (dex_id == 1 and input_asset_type != XSTUSD_ID and output_asset_type != XSTUSD_ID): - assert intermediate_amount is not None, ex_dict return Swap( get_op_id(ex_dict), timestamp, @@ -157,7 +158,7 @@ def process_swap_transaction(timestamp, extrinsicEvents, ex_dict, prices): output_amount, filter_mode, swap_fee_amount, - intermediate_amount, + intermediate_amounts, dex_id, ) diff --git a/run_node_processing.py b/run_node_processing.py index adc4f86..0d51dbe 100644 --- a/run_node_processing.py +++ b/run_node_processing.py @@ -322,64 +322,56 @@ def get_end(substrate: SubstrateInterface): for tx in dataset: try: # skip transactions with invalid asset type 0x000....0 - from_asset = int(tx.pop("input_asset_id"), 16) - to_asset = int(tx.pop("output_asset_id"), 16) + input_asset_id = tx.pop("input_asset_id") + output_asset_id = tx.pop("output_asset_id") + from_asset = int(input_asset_id, 16) + to_asset = int(output_asset_id, 16) if not from_asset or not to_asset: continue - intermediate_amount = tx.pop("intermediate_amount") + intermediate_amounts = tx.pop("intermediate_amounts") dex_id = tx.pop("dex_id") - if dex_id == 0: - if from_asset == xor_id_int or to_asset == xor_id_int: - data = [ - ( - from_asset, - tx.pop("in_amount"), - to_asset, - tx.pop("out_amount"), - ) - ] - else: - data = [ - ( - from_asset, - tx.pop("in_amount"), - xor_id_int, - intermediate_amount, - ), - ( - xor_id_int, - intermediate_amount, - to_asset, - tx.pop("out_amount"), - ), - ] - if dex_id == 1: - if from_asset == xstusd_id_int or to_asset == xstusd_id_int: - data = [ - ( - from_asset, - tx.pop("in_amount"), - to_asset, - tx.pop("out_amount"), + if len(intermediate_amounts) == 0: + data = [ + ( + from_asset, + tx.pop("in_amount"), + to_asset, + tx.pop("out_amount"), + ) + ] + else: + for idx, (asset_id, amount) in enumerate(intermediate_amounts): + current_asset_id = int(asset_id, 16) + if idx == 0: + data = [ + ( + from_asset, + tx.pop("in_amount"), + current_asset_id, + amount, + ) + ] + else: + data.append( + ( + int(intermediate_amounts[idx - 1][0], 16), # Previous asset_id + intermediate_amounts[idx - 1][1], # Previous amount + current_asset_id, + amount, + ) ) - ] - else: - data = [ - ( - from_asset, - tx.pop("in_amount"), - xstusd_id_int, - intermediate_amount, - ), - ( - xstusd_id_int, - intermediate_amount, - to_asset, - tx.pop("out_amount"), - ), - ] + + if idx == len(intermediate_amounts) - 1: + data.append( + ( + current_asset_id, + amount, + to_asset, + tx.pop("out_amount"), + ) + ) tx["filter_mode"] = tx["filter_mode"][0] tx["txid"] = tx.pop("id") for from_asset, from_amount, to_asset, to_amount in data: @@ -537,8 +529,10 @@ def get_end(substrate: SubstrateInterface): other_asset = "{0:#0{1}x}".format(other_asset, 66) if swap[1] == base_id_int: input_asset_id, output_asset_id = base_id, other_asset - else: + elif swap[2] == base_id_int: input_asset_id, output_asset_id = other_asset, base_id + else: + input_asset_id, output_asset_id = "{0:#0{1}x}".format(swap[1], 66), "{0:#0{1}x}".format(swap[2], 66) params = [ dex_id, input_asset_id,