├── __init__.py ├── .gitignore ├── data ├── mempool │ ├── package.json │ ├── .ipynb_checkpoints │ │ └── process-checkpoint.ipynb │ ├── sdk-setup.js │ ├── bn.js │ └── configuration.json └── sniping │ ├── e.py │ ├── query.txt │ └── tribe.csv ├── requirements.txt ├── util.py ├── aequitas_stress_test.py ├── sequence.py ├── README.md ├── transactions.py ├── orderingTests.py ├── ordering.py ├── Network ├── .ipynb_checkpoints │ └── geo-checkpoint.ipynb └── geo.ipynb ├── aequitas.txt ├── Uniswap └── models.py ├── execute.py └── aequitas.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env/ 2 | -------------------------------------------------------------------------------- /data/mempool/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | decorator==4.4.2 2 | networkx==2.5.1 3 | numpy==1.19.5 4 | pkg-resources==0.0.0 5 | -------------------------------------------------------------------------------- /data/mempool/.ipynb_checkpoints/process-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 5 6 | } 7 | -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | def prettyprint(obj): 2 | attributes = [(attr, obj.__dict__.get(attr, None)) for attr in dir(obj) if not attr.startswith('__')] 3 | print(attributes) 4 | -------------------------------------------------------------------------------- /aequitas_stress_test.py: -------------------------------------------------------------------------------- 1 | from aequitas import * 2 | import random 3 | 4 | 5 | ## generate large test that should pass 6 | import random 7 | expected_list = ["a","b","c","d","e"] 8 | shuffled_list = random.shuffle(expected_list) 9 | example_11 = {} 10 | for index in range(1, random.randint(1, 200)): 11 | example_11[index] = expected_list 12 | 13 | result_11 = aequitas(example_11, 1, 1) 14 | -------------------------------------------------------------------------------- /sequence.py: -------------------------------------------------------------------------------- 1 | from transactions import * 2 | 3 | class TransactionSequence: 4 | def __init__(self, transactions): 5 | # linaerly sorted transactions involved in a sequence 6 | self.transactions = transactions 7 | 8 | def get_output_with_tagged_metrics(self, metrics_tag): 9 | current_state = ETHState() 10 | for transaction in self.transactions: 11 | metric = transaction.execute(current_state) 12 | transaction.metrics[metrics_tag] = metric 13 | print("x: %d, y: %d" % (current_state.x, current_state.y)) 14 | return current_state 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Test Instructions 2 | 3 | ```sh 4 | python3 aequitas.py 5 | ``` 6 | `aequitas.py` implements an one-shot Aequitas simulator in the synchronous setting, the parameters of the algorithm are: 7 | 1. Number of nodes: `n` 8 | 2. Number of byzantine nodes: `f` 9 | 3. Order fairness parameter: `γ` 10 | 11 | *Receive-Order-Fairness*: If sufficiently many (at least γ-fraction) nodes receive a transaction tx before another transaction tx', then all honest nodes must output tx before tx'. 1/2 < γ ≤ 1 12 | 13 | 14 | ### Example 15 | In Example 3, Aequitas should output: `[{'a', 'e', 'c', 'b'}, {'d'}]`, 16 | 17 | which means the Aequitas algorithm treats transactions `{'a', 'e', 'c', 'b'}` as being of the same order, and this set as a whole(they are a strongly connected component in the graph) should be ordered in front of `'d'` 18 | -------------------------------------------------------------------------------- /data/mempool/sdk-setup.js: -------------------------------------------------------------------------------- 1 | // initialized sdk and exported configuration as parameters 2 | async function sdkSetup(sdk, configuration) { 3 | const parsedConfiguration = typeof configuration === 'string' ? JSON.parse(configuration) : configuration 4 | const globalConfiguration = parsedConfiguration.find(({ id }) => id === 'global') 5 | const addressConfigurations = parsedConfiguration.filter(({ id }) => id !== 'global') 6 | 7 | // save global configuration first and wait for it to be saved 8 | globalConfiguration && await sdk.configuration({scope: 'global', filters: globalConfiguration.filters}) 9 | 10 | addressConfigurations.forEach(({id, filters, abi}) => { 11 | const abiObj = abi ? { abi } : {} 12 | sdk.configuration({...abiObj, filters, scope: id, watchAddress: true}) 13 | }) 14 | 15 | } 16 | 17 | export default sdkSetup -------------------------------------------------------------------------------- /data/sniping/e.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | def tt (a): 4 | return int(a, 16) 5 | 6 | with open('onlytribe.csv') as csv_file: 7 | csv_reader = csv.reader(csv_file, delimiter=',') 8 | line_count = 0 9 | for row in csv_reader: 10 | # if {row[3]} == '\\xc7283b66eb1eb5fb86327f08e1b5816b0720212b' 11 | # print(type(row[2])) 12 | # print(type('0xef764bac8a438e7e498c2e5fccf0f174c3e3f8db')) 13 | # assert(row[2] != '0xef764bac8a438e7e498c2e5fccf0f174c3e3f8db') 14 | # print(int(row[2], 16)) 15 | print(f'// transaction {row[0]} block {row[1]}\n {tt(row[2])} swaps for {tt(row[3])} by providing {row[4]} {tt(row[5])} and {row[6]} {tt(row[7])} with a change 0 fee {row[8]} ;') 16 | line_count += 1 17 | # print(f'Processed {line_count} lines.') 18 | 19 | 20 | 21 | # // transaction 0x1c9b5b4731c8fb05a471752d6179aec4543d8f9f4c88148461d26c3a32738761 block 11920579 22 | # 697323163401596485410334513241460920685086001293 swaps for 1212984059034912911801913882730558476698418007999 by providing 200000000000000000000 1097077688018008265106216665536940668749033598146 and 0 1212984059034912911801913882730558476698418007999 with change 0 fee 1671587031433 ; -------------------------------------------------------------------------------- /data/sniping/query.txt: -------------------------------------------------------------------------------- 1 | WITH tradeinfo AS (SELECT * 2 | -- tx_hash, "token_b_address", 3 | -- "token_a_amount_raw", "token_a_address", "token_b_amount_raw", "token_b_address" 4 | From dex.trades 5 | Where block_time > '2021-04-03 06:59 UTC' 6 | And block_time < '2021-04-04 06:59 UTC' 7 | And ("token_a_address" = '\xc7283b66eb1eb5fb86327f08e1b5816b0720212b' 8 | Or "token_b_address" = '\xc7283b66eb1eb5fb86327f08e1b5816b0720212b' 9 | Or "token_a_address" = '\x956F47F50A910163D8BF957Cf5846D573E7f87CA' 10 | Or "token_b_address" = '\x956F47F50A910163D8BF957Cf5846D573E7f87CA') 11 | -- buying or selling TRIBE 12 | And "project" = 'Uniswap' 13 | Order By "block_time") 14 | 15 | Select hash, block_number, "from", tradeinfo."token_b_address", tradeinfo."token_a_amount_raw", 16 | tradeinfo."token_a_address", tradeinfo."token_b_amount_raw", tradeinfo."token_b_address", 17 | gas_used * gas_price As fee from ethereum.transactions 18 | Join 19 | tradeinfo On ethereum.transactions.hash = tradeinfo.tx_hash 20 | -- And success = True 21 | 22 | 23 | 24 | -- FEI 25 | -- \x956f47f50a910163d8bf957cf5846d573e7f87ca 26 | -- TRIBE 27 | -- \xc7283b66eb1eb5fb86327f08e1b5816b0720212b 28 | 29 | -- Select * from ethereum.transactions 30 | -- Where "hash" = '\x641b95d1f76a4a9e0101df94aab04aee23f95bca349fb6a68d79b180cf84e533' 31 | -- And block_time = "2021-04-03 19:08" 32 | -- one block = 15 sec, so 10 mins = 40 blocks -------------------------------------------------------------------------------- /data/mempool/bn.js: -------------------------------------------------------------------------------- 1 | // For Node >= v13 / es module environments 2 | import BlocknativeSdk from 'bnc-sdk' 3 | import Web3 from 'web3' 4 | 5 | 6 | import WebSocket from 'ws' // only neccessary in server environments 7 | 8 | // create options object 9 | const options = { 10 | dappId: 'Your dappId here', 11 | networkId: 1, 12 | system: 'bitcoin', // optional, defaults to ethereum 13 | transactionHandlers: [event => console.log(event.transaction)], 14 | ws: WebSocket, // only neccessary in server environments 15 | name: 'Instance name here', // optional, use when running multiple instances 16 | onerror: (error) => {console.log(error)} //optional, use to catch errors 17 | } 18 | 19 | // initialize and connect to the api 20 | const blocknative = new BlocknativeSdk(options) 21 | 22 | // initialize web3 23 | const web3 = new Web3(window.ethereum) 24 | 25 | // get current account 26 | const accounts = await web3.eth.getAccounts(); 27 | const address = accounts[0]; 28 | 29 | // create transaction options object 30 | const txOptions = { 31 | from: address, 32 | to: "0x792ec62e6840bFcCEa00c669521F678CE1236705", 33 | value: "1000000" 34 | } 35 | 36 | // initiate a transaction via web3.js 37 | web3.eth.sendTransaction(txOptions).on('transactionHash', hash => { 38 | // call with the transaction hash of the 39 | // transaction that you would like to receive status updates for 40 | const { emitter } = blocknative.transaction(hash) 41 | 42 | // listen to some events 43 | emitter.on('txPool', transaction => { 44 | console.log(`Sending ${transaction.value} wei to ${transaction.to}`) 45 | }) 46 | 47 | emitter.on('txConfirmed', transaction => { 48 | console.log('Transaction is confirmed!') 49 | }) 50 | 51 | // catch every other event that occurs and log it 52 | emitter.on('all', transaction => { 53 | console.log(`Transaction event: ${transaction.eventCode}`) 54 | }) 55 | }) -------------------------------------------------------------------------------- /transactions.py: -------------------------------------------------------------------------------- 1 | from functools import total_ordering 2 | 3 | class Transaction: 4 | """ A transaction on the Ethereum network """ 5 | def __init__(self, sender, fee,txid="",block=""): 6 | self.sender = sender 7 | self.fee = fee 8 | self.metrics = {} 9 | self.txid = txid 10 | self.block = block 11 | 12 | 13 | @total_ordering 14 | class UniswapTransaction(Transaction): 15 | def __init__(self, x_token, y_token, x_amount, y_amount, sender, fee,txid="",block=""): 16 | super().__init__(sender, fee,txid,block) 17 | # tokens involved in transaction 18 | self.x_token = x_token 19 | self.y_token = y_token 20 | # amounts involved in transaction 21 | self.x_amount = x_amount 22 | self.y_amount = y_amount 23 | 24 | 25 | def __eq__(self, other): 26 | return ((self.x_token, self.y_token, self.x_amount, self.y_amount) == (other.x_token, other.y_token, other.x_amount, other.y_amount)) 27 | 28 | def __ne__(self, other): 29 | return not (self == other) 30 | 31 | def __lt__(self, other): 32 | return ((self.x_token, self.y_token, self.x_amount, self.y_amount) < (other.x_token, other.y_token, other.x_amount, other.y_amount)) 33 | 34 | def __str__(self): 35 | return "".join([str(x) for x in [self.x_token, self.y_token, self.x_amount, self.y_amount]]) 36 | 37 | def __hash__(self): 38 | return hash(str(self)) 39 | 40 | def __str__(self): 41 | return "".join([str(self.x_token),str(self.y_token), str(self.x_amount), str(self.y_amount), str(self.sender), str(self.fee), str(self.txid),str(self.block)]) 42 | 43 | class ETHState: 44 | def __init__(self): 45 | self.x = 0 46 | self.y = 0 47 | 48 | 49 | class SwapTransaction(UniswapTransaction): 50 | 51 | def _swapquote(self,A, A_reserves, B_reserves): # Computes how much is swaped given the reserves 52 | k = A_reserves * B_reserves 53 | return B_reserves - k / (A_reserves + A) 54 | 55 | def execute(self, state): 56 | if (self.x_amount + self.y_amount == 0): 57 | pass 58 | elif self.x_amount == 0: 59 | # swap for x token 60 | amountX = self._swapquote(self.y_amount,state.y, state.x) 61 | state.x -= amountX # we use price as the relevant metric 62 | state.y += self.y_amount 63 | return amountX 64 | elif self.y_amount == 0: 65 | # swap for y token 66 | amountY = self._swapquote(self.x_amount,state.x, state.y) 67 | state.y -= amountY 68 | state.x += self.x_amount 69 | return amountY # we use price as the relevant metric 70 | 71 | class AddLiquidityTransaction(UniswapTransaction): 72 | 73 | def execute(self, state): 74 | state.x += self.x_amount 75 | state.y += self.y_amount 76 | 77 | class RemoveLiquidityTransaction(UniswapTransaction): 78 | 79 | def execute(self, state): 80 | #state.x -= self.x_amount 81 | #state.y -= self.y_amount 82 | pass 83 | -------------------------------------------------------------------------------- /orderingTests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from ordering import Tx, CausalOrdering 3 | 4 | 5 | class CausalOrderingTests(unittest.TestCase): 6 | def __init__(self): 7 | self.c = CausalOrdering() 8 | self.node_list = None 9 | self.sorted_tx_by_timestamp = None 10 | 11 | self.nodes_vs_tx_times = { 12 | 1: [Tx("b", 5), Tx("c", 6)], 13 | 2: [Tx("a", 2), Tx("c", 3), Tx("b", 1)], 14 | 3: [Tx("a", 1), Tx("c", 2), Tx("b", 3)] 15 | } 16 | 17 | self.nodes_vs_tx_times2 = { 18 | 1: [Tx("1", 5), Tx("2", 11), Tx("3", 16), Tx("4", 6), Tx("5", 7), Tx("6", 10), Tx("7", 25)], 19 | 2: [Tx("1", 3), Tx("2", 17), Tx("3", 19), Tx("4", 8), Tx("5", 11), Tx("6", 15), Tx("7", 21)], 20 | 3: [Tx("1", 6), Tx("2", 12), Tx("3", 13), Tx("4", 15), Tx("5", 9), Tx("6", 11), Tx("7", 20)], 21 | 4: [Tx("1", 2), Tx("2", 7), Tx("3", 9), Tx("4", 14), Tx("5", 18), Tx("6", 3), Tx("7", 24)], 22 | 5: [Tx("1", 1), Tx("2", 2), Tx("3", 5), Tx("4", 10), Tx("5", 12), Tx("6", 20), Tx("7", 21)], 23 | 6: [Tx("1", 1), Tx("2", 6), Tx("3", 9), Tx("4", 10), Tx("5", 15), Tx("6", 20), Tx("7", 26)], 24 | } 25 | 26 | self.nodes_vs_tx_times3 = { 27 | 1: [Tx("1", 5), Tx("2", 11), Tx("3", 16), Tx("4", 6), Tx("5", 7), Tx("6", 10), Tx("7", 25)], 28 | 2: [Tx("1", 3), Tx("2", 17), Tx("3", 19), Tx("4", 8), Tx("5", 11), Tx("6", 15), Tx("7", 21)], 29 | 3: [Tx("1", 6), Tx("2", 12), Tx("3", 13), Tx("4", 15), Tx("5", 9), Tx("6", 11), Tx("7", 20)], 30 | 4: [Tx("1", 2), Tx("2", 7), Tx("3", 9), Tx("4", 14), Tx("5", 18), Tx("6", 3), Tx("7", 24)], 31 | 5: [Tx("1", 1), Tx("2", 2), Tx("3", 5), Tx("4", 10), Tx("5", 12), Tx("6", 20), Tx("7", 21)], 32 | 6: [Tx("7", 1), Tx("4", 6), Tx("5", 9), Tx("1", 10), Tx("2", 15), Tx("6", 20), Tx("3", 26)], 33 | } 34 | 35 | def order_test(self): 36 | #print(self.c.order(self.nodes_vs_tx_times)) 37 | print(self.c.order(self.nodes_vs_tx_times2)) 38 | print(self.c.order(self.nodes_vs_tx_times3)) 39 | def sort_tx_by_timestamp_test(self): 40 | expected_nodes_vs_tx_times = { 41 | 1: [Tx("b", 5), Tx("c", 6)], 42 | 2: [Tx("b", 1), Tx("a", 2), Tx("c", 3)], 43 | 3: [Tx("a", 1), Tx("c", 2), Tx("b", 3)] 44 | } 45 | self.c.sort_tx_by_timestamp(self.nodes_vs_tx_times) 46 | self.sorted_tx_by_timestamp = expected_nodes_vs_tx_times 47 | #print(self.sorted_tx_by_timestamp) 48 | 49 | def extract_content_test(self): 50 | self.c.extract_content(self.sorted_tx_by_timestamp) 51 | print(self.sorted_tx_by_timestamp) 52 | #looks good 53 | def get_unique_tx_list_test(self): 54 | self.node_list = self.c.get_unique_tx_list(self.sorted_tx_by_timestamp) 55 | print(self.node_list) 56 | def first_tx_test(self): 57 | print(self.sorted_tx_by_timestamp) 58 | print(self.c.first_tx(self.sorted_tx_by_timestamp)) 59 | 60 | def tx_ordering_test(self): 61 | print("here it is:") 62 | print(self.sorted_tx_by_timestamp) 63 | print("end") 64 | self.c.tx_ordering(self.sorted_tx_by_timestamp, self.node_list) 65 | 66 | if __name__ == "__main__": 67 | #unittest.main() 68 | c = CausalOrderingTests() 69 | c.order_test() 70 | #c.sort_tx_by_timestamp_test() 71 | #c.extract_content_test() 72 | #c.get_unique_tx_list_test() 73 | #c.tx_ordering_test() 74 | #c.first_tx_test() -------------------------------------------------------------------------------- /ordering.py: -------------------------------------------------------------------------------- 1 | import statistics 2 | 3 | 4 | class Tx: 5 | def __init__(self, content, timestamp, bucket=None): 6 | self.content = content 7 | self.timestamp = timestamp # Unix timestamp 8 | self.bucket = bucket 9 | 10 | def __str__(self): 11 | return "Transaction: {0} , {1}".format(self.content, self.timestamp) 12 | 13 | def __repr__(self): 14 | return "Tx(content ='{0}', timestamp = {1}, bucket = {2})".format(self.content, self.timestamp, self.bucket) 15 | 16 | 17 | class CausalOrdering: 18 | def order(self, nodes_vs_tx_received): 19 | assert (len(nodes_vs_tx_received) != 0) 20 | self.sort_tx_by_timestamp(nodes_vs_tx_received) 21 | self.extract_content(nodes_vs_tx_received) 22 | tx_list = self.get_unique_tx_list(nodes_vs_tx_received) 23 | return self.tx_ordering(nodes_vs_tx_received, tx_list) 24 | 25 | def sort_tx_by_timestamp(self, nodes_vs_tx_received): 26 | for node in nodes_vs_tx_received: 27 | assert (len(nodes_vs_tx_received[node]) != 0) 28 | nodes_vs_tx_received[node].sort(key=lambda tx: tx.timestamp) 29 | 30 | def extract_content(self, nodes_vs_tx_received): 31 | for node in nodes_vs_tx_received: 32 | nodes_vs_tx_received[node] = [tx.content for tx in nodes_vs_tx_received[node]] # rename nodes_vs_tx_times 33 | 34 | def get_unique_tx_list(self, nodes_vs_tx_received): 35 | nodes_set = set() 36 | for node in nodes_vs_tx_received: 37 | for tx in nodes_vs_tx_received[node]: 38 | nodes_set.add(tx) 39 | return list(nodes_set) 40 | 41 | def tx_ordering(self, tx_id_ordered_by_timestamp, node_list): 42 | first_tx = self.first_tx(tx_id_ordered_by_timestamp) 43 | node_list.pop(node_list.index(first_tx)) 44 | tx_to_connect = first_tx 45 | tx_list = [first_tx] 46 | while node_list: 47 | added = False 48 | connections = self.get_upcoming_connection_to(tx_to_connect, tx_id_ordered_by_timestamp) 49 | for connection in connections: 50 | tx, _ = connection 51 | if tx not in tx_list: 52 | tx_list.append(tx) 53 | node_list.remove(tx) 54 | tx_to_connect = tx 55 | added = True 56 | break 57 | if not added: 58 | tx_list.append(node_list[0]) 59 | tx = node_list.pop(0) 60 | tx_to_connect = tx 61 | return tx_list 62 | 63 | def first_tx(self, tx_id_ordered_by_timestamp): 64 | first_tx_list = [tx_id_ordered_by_timestamp[tx][0] for tx in tx_id_ordered_by_timestamp] 65 | return statistics.mode(first_tx_list) 66 | 67 | def get_upcoming_connection_to(self, from_tx, ordered_tx_lists): 68 | # what if all connections are to one at end and the one at the end doesn't have any other connections? 69 | tx_to_count_dict = {} 70 | tx_count = None 71 | for node in ordered_tx_lists: 72 | tx_list = ordered_tx_lists[node] 73 | if not tx_count: 74 | tx_count = len(tx_list) 75 | tx_index = tx_list.index(from_tx) 76 | if tx_index < tx_count - 1: 77 | next_elem = tx_list[tx_index + 1] 78 | if next_elem not in tx_to_count_dict: 79 | tx_to_count_dict[next_elem] = 1 80 | else: 81 | tx_to_count_dict[next_elem] += 1 82 | return sorted(list(tx_to_count_dict.items()), key=lambda i: i[1], reverse=True) 83 | 84 | 85 | class AequitasOrdering: 86 | def order(self, transaction_sequence): 87 | pass 88 | -------------------------------------------------------------------------------- /Network/.ipynb_checkpoints/geo-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import random\n", 10 | "import networkx as nx\n", 11 | "import math\n", 12 | "import numpy as np\n", 13 | "import pyvista as pv\n", 14 | "from pyvista import examples" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "earth = examples.download_topo_global().triangulate().decimate(0.98)\n", 24 | "land = examples.download_topo_land().triangulate().decimate(0.98)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "def generate_points(n_nodes):\n", 34 | " \"\"\"A helper to make a 3D NumPy array of points (n_points by 3)\"\"\"\n", 35 | " dataset = land\n", 36 | " ids = np.random.randint(low=0, high=dataset.n_points-1,size=n_nodes)\n", 37 | " return dataset.points[ids]" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "position = generate_points(12)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "nodes_sphere = []\n", 56 | "for node in position:\n", 57 | " nodes_sphere.append(earth.find_closest_point(node))" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "peers = {}\n", 67 | "n_peers = 3\n", 68 | "for node in nodes_sphere:\n", 69 | " set_nodes = [element for element in nodes_sphere if element!=node]\n", 70 | " ordered = sorted(set_nodes, key=lambda peer:earth.geodesic_distance(node,peer))\n", 71 | " peers[node] = ordered[:n_peers]" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "peers" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "p = pv.Plotter(notebook=0)\n", 90 | "p.add_mesh(position, line_width=1000, color=\"blue\", label=\"Geodesic Path\")\n", 91 | "for node in peers.keys():\n", 92 | " for peer in peers:\n", 93 | " p.add_mesh(earth.geodesic(node,peer),line_width=10,color='red')\n", 94 | "p.add_mesh(land, color ='brown', show_edges=True)\n", 95 | "p.add_mesh(earth, show_edges=False)\n", 96 | "p.add_legend()\n", 97 | "p.camera_position = [(3.5839785524183934, 2.3915238111304924, 1.3993738227478327),\n", 98 | " (-0.06842917033182638, 0.15467201157962263, -0.07331693636555875),\n", 99 | " (-0.34851770951584765, -0.04724188391065845, 0.9361108965066047)]\n", 100 | "\n", 101 | "p.show()" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [] 124 | } 125 | ], 126 | "metadata": { 127 | "kernelspec": { 128 | "display_name": "Python 3", 129 | "language": "python", 130 | "name": "python3" 131 | }, 132 | "language_info": { 133 | "codemirror_mode": { 134 | "name": "ipython", 135 | "version": 3 136 | }, 137 | "file_extension": ".py", 138 | "mimetype": "text/x-python", 139 | "name": "python", 140 | "nbconvert_exporter": "python", 141 | "pygments_lexer": "ipython3", 142 | "version": "3.6.9" 143 | } 144 | }, 145 | "nbformat": 4, 146 | "nbformat_minor": 4 147 | } 148 | -------------------------------------------------------------------------------- /aequitas.txt: -------------------------------------------------------------------------------- 1 | n <- number of nodes 2 | f <- number of byzantine / malicious nodes 3 | gamma <- order fairness parameter 4 | g <- granularity 5 | 6 | Aequitas function 7 | Input - N lists of transaction input orderings 8 | Output - List of transaction orderings (fair ordering) 9 | 10 | // For both input/output, you can have different granularity of timestamps 11 | // Choose granularity g -> All transactions with timestamps [1,g] are in the same bucket, 12 | // [g+1, 2g] are in the same bucket. 13 | 14 | Algorithm: 15 | Create an empty graph 16 | For all pairs of transactions (a,b): 17 | if a < b in majority (should be >= gamma * n - f) of orderings: 18 | // note that x < y is also counted for an ordering even when only x is present 19 | add an edge (a,b) to the graph 20 | else if b < a in majority (should be >= gamma * n - f) of orderings: 21 | add an edge (b,a) to the graph 22 | 23 | // At this point, you have a graph G where transactions are vertices 24 | // and some vertices have edges between them. 25 | // Graph need not be complete. Graph need not be acyclic 26 | 27 | 28 | // Now, we need to add edges to vertices that dont have them currently. 29 | // Lets say vertices a and b dont have an edge between them 30 | // Now look at if a and b have some common descendant (some vertex thats a descendant of both) 31 | // If there is a common descendant, 32 | add (a,b) edge if a has more descendants 33 | (b,a) if b has more descendants 34 | deterministically (say alphabetically) if equal 35 | // If there is no common descendant, then there is currently not enough information to order both a,b 36 | // (one of them could still be ordered). 37 | // This is the streaming part. New transactions will come in later that will order a,b 38 | 39 | // Basically, the output list will not contain both 40 | 41 | 42 | // Now, to compute the output list 43 | 44 | Remove from graph G all transactions that are: 45 | (1) Not in all input lists or descendants of such transactions 46 | (2) Not fully connected 47 | // (now there is exactly one edge between every pair of vertices) 48 | // Let this graph be H 49 | Compute the condensation graph of H (collapse the strongly connected components into a single vertex) 50 | // Hopefully, any graph algorithm library you use should have this algorithm inbuilt 51 | 52 | Topologically sort this graph and then output the sorting (Here, every index is a set of vertices) 53 | 54 | While outputting the final list, you can just get back what transactions are in each set 55 | 56 | 57 | // Example 1 : simple 58 | Node 1: [a,b,c,d,e] 59 | Node 2: [a,b,c,e,d] 60 | Node 3: [a,b,c,d,e] 61 | 62 | (a->b), (a->c), (a->d), (a->e) 63 | (b->c), (b->d), (b->e) 64 | (c->d), (c->e) 65 | (d->e) 66 | // simple scenario, the graph is complete 67 | Final output ordering: a->b->c->d->e 68 | 69 | // Example 2: common descendant, and no common descendant 70 | Node 1: [a,b,c,e,d] 71 | Node 2: [a,c,b,d,e] 72 | Node 3: [b,a,c,e,d] 73 | Node 4: [a,b,d,c,e] 74 | Node 5: [a,c,b,d,e] 75 | 76 | gamma = 4/5 (to add an edge, you need xb), (a->c), (a->d), (a->e) 79 | (b->d), (b->e) 80 | (c->d), (c->e) 81 | 82 | // b and c dont have an edge but they have a common descendant: e 83 | // Lets say, we add (b,c) as the edge deterministically 84 | // d and e dont have an edge but they dont have a common descendant either, i.e. they wont be output yet 85 | Final output ordering: :a->b->c 86 | 87 | // Example 3: have cycles, look at condensation graph 88 | Node 1: [b,c,e,a,d] 89 | Node 2: [b,c,e,a,d] 90 | Node 3: [a,c,b,d,e] 91 | Node 4: [a,c,b,d,e] 92 | Node 5: [e,a,b,c,d] 93 | 94 | gamma = 3/5 (to add an edge, you need xb), (a->c), (a->d), 97 | (b->c), (b->d), (b->e) 98 | (c->d), (c->e) 99 | (e->a) 100 | 101 | // The graph contains two cycles: a,b,e and a,c,e 102 | // [a,b,c,e] is the strongly connected component(SCC), they are assumed to be output at the same time 103 | // we leave the specification up to the implementation (because we don’t consider unfairness within such an SCC) 104 | Final output ordering: [a,b,c,e] -> d -------------------------------------------------------------------------------- /Network/geo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 47, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import random\n", 10 | "import networkx as nx\n", 11 | "import math\n", 12 | "import numpy as np\n", 13 | "import pyvista as pv\n", 14 | "from pyvista import examples" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 48, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "earth = examples.download_topo_global().triangulate().decimate(0.98)\n", 24 | "land = examples.download_topo_land().triangulate().decimate(0.98)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 49, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "class Transaction:\n", 34 | " \"\"\" A transaction on the Ethereum network \"\"\"\n", 35 | " def __init__(self, sender,fee, timestamp = 0,dataset = None):\n", 36 | " self.sender = sender\n", 37 | " self.fee = fee\n", 38 | " self.metrics = {}\n", 39 | " self.send_timestamp = timestamp\n", 40 | " if dataset!= None:\n", 41 | " ids = np.random.randint(low=0, high=dataset.n_points-1,size=n_nodes)\n", 42 | " self.position = earth.find_closest_point(dataset.points[ids])" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 50, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "def generate_points(n_nodes):\n", 52 | " \"\"\"A helper to make a 3D NumPy array of points (n_points by 3)\"\"\"\n", 53 | " dataset = land\n", 54 | " ids = np.random.randint(low=0, high=dataset.n_points-1,size=n_nodes)\n", 55 | " return dataset.points[ids]\n", 56 | "\n", 57 | "def lenght_of_path(distance,node_path):\n", 58 | " dist = 0\n", 59 | " for i in range(0,len(node_path)-1):\n", 60 | " dist += distance[node_path[i]][node_path[i+1]]\n", 61 | " return dist" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 51, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "nodes_sphere = []\n", 71 | "position = generate_points(12)\n", 72 | "for node in position:\n", 73 | " nodes_sphere.append(earth.find_closest_point(node))" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 53, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "def network_nodes(n_peers,nodes_sphere):\n", 83 | " peers = {}\n", 84 | " distance = {}\n", 85 | " for node in nodes_sphere:\n", 86 | " distance[node] = {}\n", 87 | " for node in nodes_sphere:\n", 88 | " set_nodes = [element for element in nodes_sphere if element!=node]\n", 89 | " distance_node = {peer:earth.geodesic_distance(node,peer) for peer in set_nodes}\n", 90 | " ordered = sorted(set_nodes, key=lambda peer:distance_node[peer])\n", 91 | " peers[node] = ordered[:n_peers]\n", 92 | " for peer in peers[node]:\n", 93 | " distance[node][peer] = distance_node[peer]\n", 94 | " distance[peer][node] = distance_node[peer]\n", 95 | " G = nx.Graph()\n", 96 | " for node in nodes_sphere:\n", 97 | " for node2 in peers[node]:\n", 98 | " G.add_edge(node,node2,weight = distance[node][node2])\n", 99 | " for node in G.nodes():\n", 100 | " for node2 in G.nodes:\n", 101 | " distance[node][node2] = lenght_of_path(distance,nx.shortest_path(G,node,node2))\n", 102 | " return peers,distance, G" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 54, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "peers, distance, graph = network_nodes(n_peers, nodes_sphere)" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "p = pv.Plotter(notebook=0)\n", 121 | "p.add_point_labels(position, labels = range(0,12),font_size=20)\n", 122 | "p.add_mesh(position, line_width=1000, color=\"black\", label=\"Geodesic Path\")\n", 123 | "for node in peers.keys():\n", 124 | " for peer in peers:\n", 125 | " p.add_mesh(earth.geodesic(node,peer),line_width=4,color='blue')\n", 126 | "p.add_mesh(land,show_edges=False)\n", 127 | "#p.add_mesh(earth)\n", 128 | "p.add_legend()\n", 129 | "p.camera_position = [(3.5839785524183934, 2.3915238111304924, 1.3993738227478327),\n", 130 | " (-0.06842917033182638, 0.15467201157962263, -0.07331693636555875),\n", 131 | " (-0.34851770951584765, -0.04724188391065845, 0.9361108965066047)]\n", 132 | "\n", 133 | "p.show()" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [] 149 | } 150 | ], 151 | "metadata": { 152 | "kernelspec": { 153 | "display_name": "Python 3", 154 | "language": "python", 155 | "name": "python3" 156 | }, 157 | "language_info": { 158 | "codemirror_mode": { 159 | "name": "ipython", 160 | "version": 3 161 | }, 162 | "file_extension": ".py", 163 | "mimetype": "text/x-python", 164 | "name": "python", 165 | "nbconvert_exporter": "python", 166 | "pygments_lexer": "ipython3", 167 | "version": "3.6.9" 168 | } 169 | }, 170 | "nbformat": 4, 171 | "nbformat_minor": 4 172 | } 173 | -------------------------------------------------------------------------------- /Uniswap/models.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import networkx as nx 3 | import random 4 | from matplotlib import pyplot as plt 5 | 6 | 7 | 8 | 9 | class Pool: # Uniswap pool of tokenX and tokenY 10 | def __init__(self,X,Y, X_ID, Y_ID,creator_ID, fee = 0): 11 | self.X_ID = X_ID # X_ID simulates the token address 12 | self.Y_ID = Y_ID # Y_Id simulates the token address 13 | 14 | self.k = X*Y # k of the constant product formula 15 | 16 | self.X_reserves = X # X reserves in the pool 17 | self.Y_reserves = Y # Y reserves in the pool 18 | 19 | self.liquidity = {} # Dictionary of liquidity balances of the liquidity providers 20 | self.total_supply = 1 # Total supply of liquidit tokens 21 | self.liquidity[creator_ID] = 1 # The creator has all the liquidity tokens 22 | def _quote(self,amountA, reserveA, reserveB): # This formula is used to compute how to add liquidity 23 | assert amountA > 0, "Invalid quote" 24 | assert reserveA > 0 and reserveB > 0, "Invalid quote" 25 | amountB = amountA*reserveB/reserveA 26 | return amountB 27 | def AddLiquidity(self,x,y,x_min,y_min, trader_ID): # Simulates addLiquidity of Uniswap protocol 28 | if self.X_reserves == 0 and self.Y_reserves == 0: 29 | self.X_reserves = x 30 | self.Y_reserves = y 31 | return 0,0,0 32 | 33 | amountYOptimal = self._quote(x,self.X_reserves, self.Y_reserves) 34 | amountXOptimal = self._quote(y,self.Y_reserves, self.X_reserves) 35 | 36 | if amountYOptimal <= y: 37 | if (amountYOptimal>=y_min): 38 | self.positions[trader_ID] += self.total_supply * x/self.X_reserves 39 | self.total_supply += self.total_supply * x/self.X_reserves 40 | self.X_reserves += x 41 | self.Y_reserves += amountYOptimal 42 | 43 | return x, amountYOptimal, x/self.X_reserves 44 | else: 45 | return 0, 0, 0 46 | else: 47 | if(amountXOptimal >= x_min): 48 | self.positions[trader_ID] += self.total_supply * x/self.X_reserves 49 | self.total_supply += self.total_supply * x/self.X_reserves 50 | self.X_reserves += amountXOptimal 51 | self.Y_reserves += y 52 | return amountXOptimal, y, amountXOptimal / self.X_reserves 53 | else: 54 | return 0,0,0 55 | def RemoveLiquidity(self,position, trader_ID): # Removes liquidity of a trader. 56 | assert 0 < position and position <= self.liquidity[trader_ID], "Invalid_position" 57 | x = self.X_reserves * position 58 | y = self.Y_reserves * position 59 | 60 | self.X_reserves -= x 61 | self.Y_reserves -= y 62 | self.total_supply -= position 63 | self.liquidity[trader_ID] -= position 64 | 65 | return x,y 66 | 67 | def _swapquote(self,A, A_reserves, B_reserves): # Computes how much is swaped given the reserves 68 | k = A_reserves * B_reserves 69 | return B_reserves - k / (A_reserves + A) 70 | def SwapXForY(self,x,y_min): 71 | amountY = self._swapquote(x,self.X_reserves, self.Y_reserves) 72 | assert(y_min <= amountY) 73 | self.X_reserves += x 74 | self.Y_reserves -= amountY 75 | return amountY 76 | def SwapYForX(self,y,x_min): 77 | amountX = self._swapquote(y,self.Y_reserves, self.X_reserves) 78 | assert(x_min <= amountX) 79 | self.X_reserves -= amountX 80 | self.Y_reserves += y 81 | return amountX 82 | 83 | 84 | 85 | class AMM: 86 | def __init__(self): 87 | self.pools = {} # Pair_pools dictionary, contains pool created. 88 | self.tokens = [] # Tokens that have a pool 89 | self.pools_graph = nx.Graph() # Vertices = tokens, edges = Pools, this graph is useful for modelling 90 | # Dex arbitragers 91 | def create_pool(self,tokenA,tokenB, A_reserves, B_reserves,creator_ID): # Simulates the creation of a pool 92 | if ((tokenA, tokenB) in self.pools.keys() or (tokenB, tokenA) in self.pools.keys()): 93 | return "Already exists the pool" 94 | else: 95 | self.pools[(tokenA,tokenB)] = Pool(A_reserves,B_reserves, tokenA, tokenB, creator_ID) 96 | if tokenA not in self.tokens: 97 | self.tokens.append(tokenA) 98 | self.pools_graph.add_node(tokenA, pos =[random.uniform(0, 10),random.uniform(0, 10)]) 99 | if tokenB not in self.tokens: 100 | self.tokens.append(tokenB) 101 | self.pools_graph.add_node(tokenA, pos =[random.uniform(0, 10),random.uniform(0, 10)]) 102 | self.pools_graph.add_edge(tokenA,tokenB) 103 | return "pool created" 104 | 105 | #Geometric Brownian motion 106 | # Simulation of Centralized exchange with different stochastic process. 107 | # Will include random walks,... 108 | class reference_market: 109 | def __init__(self,tokens_list_ID, center_ID): 110 | self.tokens_list = tokens_list_ID 111 | self.center_token = center_ID 112 | self.token_prices = {} 113 | self.tokens_sigma = {} 114 | self.tokens_mu = {} 115 | self.tokens_tau = {} 116 | self.time = 0 117 | self._init_stochastic_proces() 118 | def _init_stochastic_proces(self): 119 | for token_ID in self.tokens_list: 120 | self.tokens_sigma[token_ID] = random.uniform(0, 1) 121 | self.tokens_mu[token_ID] = random.uniform(0, 1) 122 | self.tokens_tau[token_ID] = random.uniform(0, 1) 123 | self.token_prices[token_ID] = 1 124 | def update_prices(self): 125 | self.time +=1 126 | t = self.time 127 | for token_ID in self.tokens_list: 128 | mu = self.tokens_mu[token_ID] 129 | sigma = self.tokens_sigma[token_ID] 130 | x = np.random.normal(mu, sigma, 1) 131 | self.token_prices[token_ID] = np.exp((mu - sigma**2/2) * t + sigma * x) 132 | self.token_prices[self.center_token] = 1 133 | def update_prieces_Langevin(self): # Langevin stochastic process 134 | dt = 0.01 # Time step. 135 | T = 10 # Total time. 136 | n = int(T / dt) # Number of time steps. 137 | t = np.linspace(0., T, n) # Vector of times. 138 | 139 | sqrtdt = np.sqrt(dt) 140 | for token_ID in self.tokens_list: 141 | x = np.zeros(n) 142 | mu = self.tokens_mu[token_ID] 143 | sigma = self.tokens_sigma[token_ID] 144 | tau = self.tokens_tau[token_ID] 145 | sigma_bis = sigma * np.sqrt(2. / tau) 146 | for i in range(n - 1): 147 | x[i + 1] = abs(x[i] + dt * (-(x[i] - mu) / tau) + sigma_bis * sqrtdt * np.random.randn()) 148 | self.token_prices[token_ID] = x 149 | -------------------------------------------------------------------------------- /execute.py: -------------------------------------------------------------------------------- 1 | from transactions import * 2 | from sequence import * 3 | from util import * 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | from ordering import * 7 | from aequitas import * 8 | import copy 9 | 10 | tx_mapping = {} 11 | 12 | def get_percent_difference(current, previous): 13 | if current == previous: 14 | return 0.0 15 | try: 16 | diff = (abs(current - previous) / previous) * 100.0 17 | if diff > 100.0: 18 | return 100.0 19 | return diff 20 | except ZeroDivisionError: 21 | return 100 22 | 23 | def get_sequence_difference(txs, tag1, tag2): 24 | differences = [] 25 | for tx in txs: 26 | if len(tx.metrics) > 0 and tag1 in tx.metrics and tag2 in tx.metrics: 27 | print(tx.metrics) 28 | diff = get_percent_difference(tx.metrics[tag1], tx.metrics[tag2]) 29 | if diff != -1: 30 | differences.append(diff) 31 | return differences 32 | 33 | def LimitedRandDoubles(lim): 34 | return np.random.uniform(low=0,high=lim,size=(1, 1000000)) 35 | 36 | 37 | rand_timing_doubles = LimitedRandDoubles(30) 38 | rand_network_doubles = LimitedRandDoubles(10) 39 | last_timing_double = 0 40 | last_network_double = 0 41 | 42 | def get_timestep(): 43 | global last_timing_double, rand_timing_doubles 44 | last_timing_double += 1 45 | return rand_timing_doubles[0][last_timing_double] 46 | 47 | def get_network_delay(): 48 | global last_network_double 49 | last_network_double += 1 50 | return rand_network_doubles[0][last_network_double] 51 | 52 | def same_order(txs): 53 | return txs 54 | 55 | def process_example_uniswap_transactions(data_file, order_function): 56 | 57 | 58 | # Very messy parser of transactions in plaintext into objects 59 | transactions = [] 60 | num_tx = 200 61 | curr_num = 0 62 | nodes_seen = {} 63 | for transaction in open(data_file).read().splitlines()[0:]: 64 | transaction = transaction.split() 65 | tx = None 66 | if curr_num >= num_tx: 67 | break 68 | if '//' in transaction: 69 | # comment 70 | next_tx_id = transaction[2] 71 | next_tx_block = transaction[4] 72 | continue 73 | elif 'swaps' in transaction: 74 | tokens = sorted([[int(transaction[7]), int(transaction[6])], [int(transaction[10]), int(transaction[9])]]) 75 | fee = 0 76 | if len(transaction) == 17: 77 | fee = int(transaction[15]) 78 | tx = SwapTransaction(tokens[0][0], tokens[1][0], tokens[0][1], tokens[1][1], int(transaction[0]), fee, next_tx_id, next_tx_block) 79 | elif 'liquidity;' in transaction: 80 | print("first_token, second_token, first_amount, second_amount, sender, fee") 81 | print(transaction) 82 | for i in range(len(transaction)): 83 | print(i, transaction[i]) 84 | tokens = sorted([[int(transaction[3]), int(transaction[2])], [int(transaction[6]), int(transaction[5])]]) 85 | fee = 0 86 | #if len(transaction) == 17: 87 | # fee = int(transaction[15]) 88 | if 'adds' in transaction: 89 | tx = AddLiquidityTransaction(tokens[0][0], tokens[1][0], tokens[0][1], tokens[1][1], int(transaction[0]), fee, next_tx_id, next_tx_block) 90 | elif 'removes' in transaction: 91 | tx = RemoveLiquidityTransaction(tokens[0][0], tokens[1][0], tokens[0][1], tokens[1][1], int(transaction[0]), fee, next_tx_id, next_tx_block) 92 | if tx is not None: 93 | transactions.append(tx) 94 | curr_num += 1 95 | 96 | assert(len(transactions) >= num_tx) 97 | # transactions = transactions[:100] 98 | 99 | # simulate timing data 100 | curr_time = 0.0 101 | for tx in transactions: 102 | tx.time_sent = curr_time 103 | curr_time += get_timestep() 104 | # simulate network data 105 | for node in range(0, 5): 106 | if not node in nodes_seen: 107 | nodes_seen[node] = [] 108 | nodes_seen[node].append((tx, tx.time_sent + get_network_delay())) 109 | for node in range(0, 5): 110 | nodes_seen[node] = sorted(nodes_seen[node], key = lambda x : x[1]) 111 | print(nodes_seen[0]) 112 | 113 | transactions = order_function(transactions) 114 | print("Transactions", transactions) 115 | baseline_sequence = TransactionSequence(transactions) 116 | baseline_sequence = baseline_sequence.get_output_with_tagged_metrics("baseline") 117 | 118 | for node in nodes_seen: 119 | node_order_sequence = TransactionSequence([x[0] for x in nodes_seen[node]]) 120 | node_order = node_order_sequence.get_output_with_tagged_metrics(node) 121 | 122 | 123 | differences = {} 124 | 125 | for node in nodes_seen: 126 | differences[node] = get_sequence_difference(transactions, "baseline", node) 127 | plt.hist(differences.values(), alpha=0.5, bins=20) 128 | plt.yscale('log') 129 | plt.show() 130 | 131 | 132 | max_differences = {} 133 | curr_max_diff = 0 134 | for i in range(1): 135 | # Leader maliciously shuffling 136 | for node in nodes_seen: 137 | seq = [x[0] for x in nodes_seen[node]] 138 | random.shuffle(seq) 139 | node_order_sequence = TransactionSequence(seq) 140 | node_order = node_order_sequence.get_output_with_tagged_metrics(node) 141 | 142 | differences = {} 143 | 144 | for node in nodes_seen: 145 | differences[node] = get_sequence_difference(transactions, "baseline", node) 146 | max_diff = sum([sum(val > 95 for val in differences[node]) for node in nodes_seen]) 147 | 148 | if max_diff >= curr_max_diff: 149 | max_differences = differences 150 | curr_max_diff = max_diff 151 | 152 | 153 | plt.hist(max_differences.values(), alpha=0.5, bins=20) 154 | plt.yscale('log') 155 | plt.show() 156 | 157 | print(nodes_seen[0]) 158 | 159 | # set up input for causal order (same as aequitas) 160 | for node in nodes_seen: 161 | nodes_seen[node] = [Tx(x[0], x[1]) for x in nodes_seen[node]] 162 | 163 | # TODO: Need to fix this part given new tx format 164 | # causal_order = CausalOrdering() 165 | # causal_order = causal_order.order(copy.deepcopy(nodes_seen)) 166 | # #print(causal_order) 167 | # output = TransactionSequence(causal_order).get_output_with_tagged_metrics('causal') 168 | # difference_causal = get_sequence_difference(transactions, "baseline", "causal") 169 | 170 | # plt.hist(difference_causal, alpha=0.5, bins=20) 171 | # plt.yscale('log') 172 | # plt.show() 173 | 174 | for tx in transactions: 175 | tx_mapping[str(tx)] = tx 176 | 177 | print(nodes_seen[0]) 178 | aequitas_order = aequitas(copy.deepcopy(nodes_seen), 1, 1) 179 | final_order = [] 180 | for output_set in aequitas_order: 181 | y = [tx_mapping[x] for x in output_set] 182 | final_order += y 183 | print(final_order) 184 | 185 | output = TransactionSequence(final_order).get_output_with_tagged_metrics('aequitas') 186 | difference_aequitas = get_sequence_difference(transactions, "baseline", "aequitas") 187 | 188 | plt.hist(difference_aequitas, alpha=0.5, bins=20) 189 | plt.yscale('log') 190 | plt.title("Aequitas") 191 | plt.show() 192 | 193 | if __name__ == '__main__': 194 | process_example_uniswap_transactions('data/0x05f04f112a286c4c551897fb19ed2300272656c8.csv', same_order) 195 | -------------------------------------------------------------------------------- /aequitas.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import random 3 | import itertools 4 | import numpy as np 5 | import pprint as pp 6 | import sys 7 | from typing import Dict, List, Tuple 8 | 9 | # number of nodes n 10 | # number of byzantine / malicious nodes f 11 | # gamma : order fairness parameter 12 | # g : granularity 13 | 14 | 15 | 16 | class Tx: 17 | def __init__(self, content, timestamp, bucket=None): 18 | self.content = content 19 | self.timestamp = timestamp # Unix timestamp 20 | self.bucket = bucket 21 | 22 | def __str__(self): 23 | return f"Transaction: {self.content} , {self.timestamp}" 24 | 25 | def __repr__(self): 26 | return f"Tx(content ='{self.content}', timestamp = {self.timestamp}, bucket = {self.bucket})" 27 | 28 | 29 | 30 | def granularize(tx_ordering, starting_timestamp: int, granularity: int) -> List[Tx]: 31 | """Puts txs into buckets 32 | line 10-12 33 | All transactions with timestamps [0,g-1] are in the same bucket, [g, 2g-1] are in the same bucket etc. 34 | """ 35 | for tx in tx_ordering: 36 | if hasattr(tx, 'timestamp'): 37 | quotient = int((tx.timestamp - starting_timestamp) // granularity) 38 | tx.bucket = quotient 39 | return tx_ordering 40 | 41 | 42 | def get_all_tx_in_batch(tx_list: Dict[int, Tx]) -> Dict[int, Tx]: 43 | # TODO 44 | return 45 | 46 | def get_empty_edges(H: nx.DiGraph) -> List: 47 | # used undirected edges for easier computing 48 | empty_edges = [] 49 | edge_candidates = sorted(list(itertools.permutations(H.nodes, 2)), key=lambda x: (x[0], x[1])) 50 | unsorted_edges = H.edges 51 | sorted_edges = sorted(unsorted_edges, key=lambda x: (x[0], x[1])) 52 | value = list(set(edge_candidates) - set(sorted_edges)) 53 | for x, y in value: 54 | if (y,x) in empty_edges: 55 | continue 56 | if (y,x) in value: 57 | empty_edges.append((x,y)) 58 | print("empty_edges", empty_edges) 59 | return empty_edges 60 | 61 | def GetMaxLengthValue(d): 62 | maks=max(d, key=lambda k: len(d[k])) 63 | return len(d[maks]) 64 | 65 | def compute_initial_set_of_edges(tx_dict: Dict, gamma, f: int) -> Tuple[nx.DiGraph, Dict]: 66 | """ 67 | line 15-25 68 | 69 | Args: 70 | 71 | Returns: 72 | need not be complete. Graph need not be acyclic 73 | """ 74 | print("\n============== Aequitas: compute_initial_set_of_edges ==============") 75 | 76 | n = len(tx_dict) 77 | print("n = %s, gamma = %s, f = %s" % (n, gamma, f)) 78 | if gamma <=1/2 or gamma >1: 79 | print("gamma = %s" % gamma) 80 | sys.exit("Order-Fairness Parameter Out of Bounds, Exit") 81 | 82 | if not (n > 2 * f/(2 * gamma - 1)): 83 | print("2 * f/(2 * gamma - 1) = %s" %(2 * f/(2 * gamma - 1))) 84 | sys.exit("Corruption Bound Check Failed, Exit") 85 | 86 | nodes = set() 87 | for key in tx_dict: 88 | for tx in tx_dict[key]: 89 | if tx not in nodes: 90 | nodes.add(tx) 91 | nodes = sorted(nodes) 92 | print("nodes:", nodes) 93 | longest_ordering = GetMaxLengthValue(tx_dict) 94 | print("longest_ordering: ", longest_ordering) 95 | m = len(nodes) 96 | 97 | tx_list = list(tx_dict.values()) 98 | 99 | edge_candidates = list(itertools.combinations(nodes, 2)) 100 | edge_candidates = sorted(edge_candidates, key=lambda x: (x[0], x[1])) 101 | assert len(edge_candidates) == ((m ** 2 - m) / 2) # O(n^2) combinations 102 | print("edge_candidates: ", edge_candidates) 103 | 104 | # Get the indices of each tx in every nodes's vote 105 | indices = {} 106 | for i in nodes: 107 | idx = [] 108 | for row in tx_list: 109 | if i in row: 110 | idx.append(row.index(i)) 111 | else: 112 | idx.append(99999) # Hacky: if we can't find this tx, assume it has an extremely large index(i.e. arrive late eventually) 113 | indices[i] = np.array(idx) 114 | print("indices:") 115 | pp.pprint(indices) 116 | 117 | # Compute the differences between all pairs of txs, a negative value in this matrix means key[0] is in front of key[1] 118 | pairs_dict = {} 119 | for key in edge_candidates: 120 | lst = np.array(indices[key[0]] - indices[key[1]]) 121 | # print("debugging: list before", lst) 122 | lst[lst < -9999] = 0 # Hacky 123 | lst[lst > 9999] = 0 # Hacky 124 | # print("debugging: list after", lst) 125 | pairs_dict[key] = lst 126 | print("pairs_dict:") 127 | pp.pprint(pairs_dict) 128 | 129 | # Count number of negative elements 130 | counting_dict_neg = {} 131 | counting_dict_pos = {} 132 | for key in pairs_dict: 133 | counting_dict_neg[key] = np.sum(np.array((pairs_dict[key])) < 0, axis=0) 134 | counting_dict_pos[key] = np.sum(np.array((pairs_dict[key])) > 0, axis=0) 135 | print("counting_dict_neg:") 136 | pp.pprint(counting_dict_neg) 137 | 138 | print("counting_dict_pos:") 139 | pp.pprint(counting_dict_pos) 140 | 141 | # Filter using gamma - the fairness parameter as the thereshold 142 | edge_dict = {} 143 | 144 | for i in counting_dict_neg: 145 | if counting_dict_neg[i] >= n * gamma - f: 146 | print("neg adding " , i) 147 | edge_dict[i] = counting_dict_neg[i] 148 | 149 | for j in counting_dict_pos: 150 | print("j", j) 151 | i = j[::-1] 152 | if counting_dict_pos[j] >= n * gamma - f: 153 | print("pos adding " , i) 154 | edge_dict[i] = counting_dict_pos[j] 155 | 156 | print("edge_dict: ") 157 | pp.pprint(edge_dict) 158 | 159 | # Add edges to the graph 160 | G = nx.DiGraph() 161 | for i in edge_dict: 162 | G.add_edge(str(i[0]), str(i[1])) 163 | print("G.graph: ", G.edges) 164 | 165 | no_edge_dict = get_empty_edges(G) 166 | 167 | return G, no_edge_dict 168 | # returns a graph, and the empty edges 169 | 170 | def get_list_of_descendants(H: nx.DiGraph, key) -> List: 171 | lst = [] 172 | if key in H.nodes: 173 | lst = list(H.successors(key)) 174 | return lst 175 | 176 | def complete_list_of_edges(H: nx.DiGraph, no_edge_dict: Dict) -> nx.DiGraph: 177 | """ 178 | line 28-48: 179 | builds graph and for every pair of vertices that are not 180 | connected, look at common descendants 181 | If there is a common descendant, 182 | add (a,b) edge if a has more descendants 183 | (b,a) if b has more descendants 184 | deterministically (say alphabetically) if equal 185 | 186 | If there is no common descendant, then there is currently not enough information to order both a,b 187 | (one of them could still be ordered). 188 | Args: 189 | 190 | Returns: H, a fully connected graph 191 | """ 192 | print("\n============== Aequitas: complete_list_of_edges ==============") 193 | descendants_0 = iter([]) 194 | descendants_1 = iter([]) 195 | if len(no_edge_dict) == 0: 196 | n = len(H.nodes) 197 | assert(len(H.edges) == (n ** 2 - n) / 2) 198 | print("The graph is already fully connected") 199 | for key in no_edge_dict: 200 | assert H.has_edge(key[0], key[1]) is False 201 | print( 202 | "(%s, %s) does NOT have an edge, looking at common descendants: " 203 | % (key[0], key[1]) 204 | ) 205 | # TODO: If they are in the same SCC, pass 206 | descendants_0 = get_list_of_descendants(H, key[0]) 207 | descendants_1 = get_list_of_descendants(H, key[1]) 208 | print("%s's descendants: " % key[0], descendants_0) 209 | print("%s's descendants: " % key[1], descendants_1) 210 | if len(list(set(descendants_0) & set(descendants_1))) == 0: 211 | has_common_descendants = False 212 | print( 213 | "node %s and node %s have no common descendant, not enough info \n" 214 | % (key[0], key[1]) 215 | ) 216 | else: 217 | has_common_descendants = True 218 | if len(descendants_0) >= len(descendants_1): 219 | H.add_edge(key[0], key[1]) 220 | print( 221 | "node %s has more or equal descendants than %s, adding edge %s -> %s \n" 222 | % (key[0], key[1], key[0], key[1]) 223 | ) 224 | else: 225 | H.add_edge(key[1], key[0]) 226 | print( 227 | "node %s has more descendants than %s, adding edge %s -> %s \n" 228 | % (key[1], key[0], key[1], key[0]) 229 | ) 230 | n = len(H.nodes) 231 | # assert (len(H.edges)==(n**2-n)/2), "H is NOT a fully connected graph" 232 | return H 233 | 234 | 235 | 236 | # TODO: e.g. in Example 2: remove d(0) and (1) 237 | def prune(H: nx.DiGraph): 238 | """ 239 | remove an edge (x,y) from the condensed DAG if they are 240 | (1) in diferent SCC and 241 | (2) no edge between them and 242 | (3) no common descendants 243 | """ 244 | print("****** before pruning ****** : ", H.edges) 245 | empty_edges = get_empty_edges(H) 246 | if len(empty_edges) != 0: # no edge between them and 247 | for x, y in empty_edges: 248 | print("pruning x, y: %s, %s " %(x,y)) 249 | SCC = list(nx.strongly_connected_components(H)) 250 | print("SCC:", SCC) 251 | SCC_idx_1 = [i for i, lst in enumerate(SCC) if x in lst] 252 | SCC_idx_2 = [i for i, lst in enumerate(SCC) if y in lst] 253 | print("SCC_idx_1:", SCC_idx_1) 254 | print("SCC_idx_2:", SCC_idx_2) 255 | SCC_intersection = (list(set(SCC_idx_1) & set(SCC_idx_2))) # The index of the SCC in which both x and y are part of 256 | if len(SCC_intersection) == 0 : # is empty, x, y is in different SCC 257 | common_descendants = (list(set(get_list_of_descendants(H, x)) & set(get_list_of_descendants(H, y)))) 258 | print("common_descendants", common_descendants) 259 | if len(common_descendants) == 0 : # is empty, x, y has no common descendants 260 | if(x in H.nodes): 261 | H.remove_node(x) 262 | print("Pruned vertex %s successfully"% x) 263 | if(y in H.nodes): 264 | H.remove_node(y) 265 | print("Pruned vertex %s successfully"% y) 266 | 267 | 268 | print("****** after pruning ****** : ", H.edges) 269 | return H 270 | 271 | def finalize_output(H: nx.DiGraph, no_edge_dict: Dict) -> List: 272 | """ 273 | line 49-52: 274 | Compute the condensation graph of H(collapse the strongly connected components into a single vertex) 275 | Then topologically sort this graph and then output the sorting (Here, every index is a set of vertices) 276 | 277 | Returns: A list of final output ordering 278 | """ 279 | print("\n============== Aequitas: finalize_output ==============") 280 | print("H.graph: ", H.edges) 281 | condensed_DAG = nx.condensation(H) 282 | SCC =nx.strongly_connected_components(H) 283 | mapping = condensed_DAG.graph['mapping'] 284 | print("SCC: ", SCC) 285 | print("mapping: ", mapping) 286 | print("condensed_DAG: ", condensed_DAG.edges) 287 | 288 | assert(nx.is_directed_acyclic_graph(condensed_DAG) is True) 289 | 290 | # for v in condensed_DAG.nodes: 291 | # print(condensed_DAG.in_degree(v)) 292 | 293 | removed_DAG = prune(condensed_DAG) 294 | # remove an edge (x,y) from the condensed DAG if they are 295 | # (1) in diferent SCC and 296 | # (2) no edge between them and 297 | # (3) no common descendants 298 | 299 | print("removed_DAG: ", removed_DAG.edges) 300 | int_output = list(nx.topological_sort(removed_DAG)) 301 | print("int_output: ", int_output) 302 | node_output_ordered = [set() for _ in range(len(mapping.keys()))] 303 | node_output_topo = [set() for _ in range(len(int_output))] 304 | for k,v in mapping.items(): 305 | node_output_ordered[v].add(k) 306 | 307 | for i, index in enumerate(int_output): 308 | node_output_topo[i] = node_output_ordered[index] 309 | return node_output_topo 310 | # Final output ordering of Example 2: [a,b,c] 311 | 312 | def prettyprint(d, indent=0): 313 | for key, value in d.items(): 314 | print('\t' * indent + str(key)) 315 | if isinstance(value, dict): 316 | prettyprint(value, indent+1) 317 | else: 318 | print('\t' * (indent+1) + str(value)) 319 | 320 | # Calling aequitas once means processing this bucket/epoch/batch of Txs according to Aequitas ordering 321 | def aequitas(tx_dict: Dict, gamma, f: int): 322 | 323 | 324 | # Setup 325 | for node in tx_dict: 326 | # ToDo: any granularization 327 | tx_dict[node] = [str(tx.content) for tx in tx_dict[node]] 328 | 329 | 330 | 331 | (G, no_edge_dict) = compute_initial_set_of_edges(tx_dict, gamma, f) 332 | H = complete_list_of_edges(G, no_edge_dict) 333 | Out = finalize_output(H, no_edge_dict) 334 | print("\n============== Aequitas: done ==============") 335 | return Out 336 | 337 | 338 | def main(): 339 | 340 | starting_timestamp = 1326244364 341 | granularity = 5 342 | 343 | # This is a sample input to the aequitas main algorithm, we assume this is already sorted upon being passed, i.e. an ordering 344 | tx_dict = { 345 | 1: [Tx("a",1326244364), Tx("b",1326244365), Tx("c",1326244366), Tx("e",1326244367), Tx("d",1326244368), Tx("f",1326244369), Tx("g",1326244370)], 346 | 2: [Tx("a",1326244364), Tx("c",1326244365), Tx("b",1326244366), Tx("d",1326244367), Tx("e",1326244368), Tx("f",1326244369), Tx("g",1326244375)], 347 | 3: [Tx("b",1326244364), Tx("a",1326244365), Tx("c",1326244366), Tx("e",1326244367), Tx("d",1326244368), Tx("f",1326244376)], 348 | 4: [Tx("a",1326244364), Tx("b",1326244365), Tx("d",1326244366), Tx("c",1326244367), Tx("e",1326244368)], 349 | 5: [Tx("a",1326244364), Tx("c",1326244365), Tx("b",1326244366), Tx("d",1326244367), Tx("e",1326244368)] 350 | } 351 | 352 | # The function granularize figures txs into buckets/epochs/batches 353 | granularized_tx_dict = {} 354 | for i in tx_dict: 355 | granularized_tx_dict[i] = granularize( 356 | tx_dict.get(i), starting_timestamp, granularity 357 | ) 358 | # print("granularized_tx_dict: ") 359 | # pp.pprint(granularized_tx_dict) 360 | 361 | # TODO: Some data processing and cleaning to get the following granularized_tx_dict 362 | 363 | granularized_tx_dict_expected = { 364 | 1: [Tx(content ='a', timestamp = 1326244364, bucket = 0), Tx(content ='b', timestamp = 1326244365, bucket = 0), Tx(content ='c', timestamp = 1326244366, bucket = 0), Tx(content ='e', timestamp = 1326244367, bucket = 0), Tx(content ='d', timestamp = 1326244368, bucket = 0), Tx(content ='f', timestamp = 1326244369, bucket = 1), Tx(content ='g', timestamp = 1326244370, bucket = 1)], 365 | 2: [Tx(content ='a', timestamp = 1326244364, bucket = 0), Tx(content ='c', timestamp = 1326244365, bucket = 0), Tx(content ='b', timestamp = 1326244366, bucket = 0), Tx(content ='d', timestamp = 1326244367, bucket = 0), Tx(content ='e', timestamp = 1326244368, bucket = 0), Tx(content ='f', timestamp = 1326244369, bucket = 1), Tx(content ='g', timestamp = 1326244375, bucket = 2)], 366 | 3: [Tx(content ='b', timestamp = 1326244364, bucket = 0), Tx(content ='a', timestamp = 1326244365, bucket = 0), Tx(content ='c', timestamp = 1326244366, bucket = 0), Tx(content ='e', timestamp = 1326244367, bucket = 0), Tx(content ='d', timestamp = 1326244368, bucket = 0), Tx(content ='f', timestamp = 1326244376, bucket = 2)], 367 | 4: [Tx(content ='a', timestamp = 1326244364, bucket = 0), Tx(content ='b', timestamp = 1326244365, bucket = 0), Tx(content ='d', timestamp = 1326244366, bucket = 0), Tx(content ='c', timestamp = 1326244367, bucket = 0), Tx(content ='e', timestamp = 1326244368, bucket = 0)], 368 | 5: [Tx(content ='a', timestamp = 1326244364, bucket = 0), Tx(content ='c', timestamp = 1326244365, bucket = 0), Tx(content ='b', timestamp = 1326244366, bucket = 0), Tx(content ='d', timestamp = 1326244367, bucket = 0), Tx(content ='e', timestamp = 1326244368, bucket = 0)] 369 | } 370 | 371 | # TODO: Some data processing and cleaning to get the following simplified tx_dict for the 0th bucket/epoch/batch to be processed 372 | 373 | # example_1 = { 374 | # 1: ["a", "b", "c", "d", "e"], 375 | # 2: ["a", "b", "c", "e", "d"], 376 | # 3: ["a", "b", "c", "d", "e"], 377 | # } 378 | # result_1 = aequitas(example_1, 1, 1) 379 | # print("Example 1: ", result_1) 380 | 381 | # example_2 = { 382 | # 1: ["a", "b", "c", "e", "d"], 383 | # 2: ["a", "c", "b", "d", "e"], 384 | # 3: ["b", "a", "c", "e", "d"], 385 | # 4: ["a", "b", "d", "c", "e"], 386 | # 5: ["a", "c", "b", "d", "e"], 387 | # } 388 | # result_2 = aequitas(example_2, 1, 1) 389 | # print("Example 2: ", result_2) 390 | 391 | # example_2_prime = { 392 | # 1: ["a", "b", "c", "e", "d"], 393 | # 2: ["a", "c", "b", "d", "e"], 394 | # 3: ["b", "a", "c", "e", "d"], 395 | # 4: ["a", "b", "d", "c", "e"], 396 | # 5: ["a", "c", "b", "d", "e"], 397 | # } 398 | # result_2_prime = aequitas(example_2_prime, 0.8, 1) 399 | # print("Example 2_prime: ", result_2_prime) 400 | 401 | # The following test case contains cycles(Strongly-Connected-Components) 402 | # and the expected output is {'a', 'e', 'c', 'b'} -> {'d'} 403 | # which means the Aequitas treats {'a', 'e', 'c', 'b'} as being of the same order, and this set is ordered in front of 'd' 404 | # 1: ["b", "c", "e", "a", "d"], 405 | # 2: ["b", "c", "e", "a", "d"], 406 | # 3: ["a", "c", "b", "d", "e"], 407 | # 4: ["a", "c", "b", "d", "e"], 408 | # 5: ["e", "a", "b", "c", "d"], 409 | example_3 = { 410 | 1: [ 411 | Tx(content ='b', timestamp = 1326244364, bucket = 0), 412 | Tx(content ='c', timestamp = 1326244365, bucket = 0), 413 | Tx(content ='e', timestamp = 1326244366, bucket = 0), 414 | Tx(content ='a', timestamp = 1326244367, bucket = 0), 415 | Tx(content ='d', timestamp = 1326244368, bucket = 0) 416 | ], 417 | 2: [ 418 | Tx(content ='b', timestamp = 1326244364, bucket = 0), 419 | Tx(content ='c', timestamp = 1326244365, bucket = 0), 420 | Tx(content ='e', timestamp = 1326244366, bucket = 0), 421 | Tx(content ='a', timestamp = 1326244367, bucket = 0), 422 | Tx(content ='d', timestamp = 1326244368, bucket = 0) 423 | ], 424 | 3: [ 425 | Tx(content ='a', timestamp = 1326244364, bucket = 0), 426 | Tx(content ='c', timestamp = 1326244365, bucket = 0), 427 | Tx(content ='b', timestamp = 1326244366, bucket = 0), 428 | Tx(content ='d', timestamp = 1326244367, bucket = 0), 429 | Tx(content ='e', timestamp = 1326244368, bucket = 0) 430 | ], 431 | 4: [ 432 | Tx(content ='a', timestamp = 1326244364, bucket = 0), 433 | Tx(content ='c', timestamp = 1326244365, bucket = 0), 434 | Tx(content ='b', timestamp = 1326244366, bucket = 0), 435 | Tx(content ='d', timestamp = 1326244367, bucket = 0), 436 | Tx(content ='e', timestamp = 1326244368, bucket = 0) 437 | ], 438 | 5: [ 439 | Tx(content ='e', timestamp = 1326244364, bucket = 0), 440 | Tx(content ='a', timestamp = 1326244365, bucket = 0), 441 | Tx(content ='b', timestamp = 1326244366, bucket = 0), 442 | Tx(content ='c', timestamp = 1326244367, bucket = 0), 443 | Tx(content ='d', timestamp = 1326244368, bucket = 0) 444 | ], 445 | } 446 | result_3 = aequitas(example_3, 0.8, 1) 447 | print("Example 3: ", result_3) 448 | 449 | 450 | # # The following test case SHOULD FAIL, due to corruption bound checks 451 | # example_4 = { 452 | # 1: ["a", "b", "c", "d", "e"], 453 | # 2: ["a", "b", "c", "e", "d"], 454 | # 3: ["a", "b", "c", "d", "e"], 455 | # } 456 | # result_4 = aequitas(example_4, 0.8, 1) 457 | # print("Example 4: ", result_4) 458 | 459 | # # The following test case SHOULD FAIL, due to missing d 460 | # example_5 = { 461 | # 1: ["a", "b", "c", "e", "d"], 462 | # 2: ["a", "b", "c", "e", "e"], 463 | # 3: ["a", "b", "c", "e", "e"], 464 | # } 465 | # result_5 = aequitas(example_5, 1, 1) 466 | # print("Example 5: ", result_5) 467 | 468 | # # The following test case SHOULD FAIL, due to corruption bound checks (Float error) 469 | # example_6 = { 470 | # 1: ["a", "b", "c", "e", "d"], 471 | # 2: ["a", "b", "c", "d", "e"], 472 | # 3: ["a", "b", "c", "d", "e"], 473 | # 4: ["a", "b", "c", "d", "e"], 474 | # 5: ["a", "b", "c", "d", "e"], 475 | # } 476 | # result_6 = aequitas(example_6, 0.5, 1) 477 | # print("Example 6: ", result_6) 478 | 479 | # # The following test case SHOULD FAIL, due to corruption bound checks ("a" node not present) 480 | # example_7 = { 481 | # 1: ["a", "b", "c", "e", "d"], 482 | # 2: ["a", "b", "c", "d", "e"], 483 | # 3: ["a", "b", "c", "d", "e"], 484 | # 4: ["a", "b", "c", "d", "e"], 485 | # 5: ["a", "b", "c", "d", "e"], 486 | # } 487 | # result_7 = aequitas(example_7, 2.0, 1) 488 | # print("Example 7: ", result_7) 489 | 490 | # example_8 = { 491 | # 1: ["a", "b", "c", "e", "d"], 492 | # 2: ["a", "b", "c", "d", "e"], 493 | # 3: ["a", "b", "c", "d", "e"], 494 | # 4: ["a", "b", "c", "d", "e"], 495 | # 5: ["a", "b", "c", "d", "e"], 496 | # } 497 | # result_8 = aequitas(example_8, 0.0, 1) 498 | # print("Example 8: ", result_8) 499 | 500 | if __name__ == "__main__": 501 | main() -------------------------------------------------------------------------------- /data/mempool/configuration.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Uniswap v2", 4 | "id": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d", 5 | "filters": [], 6 | "abi": [ 7 | { 8 | "inputs": [ 9 | { 10 | "internalType": "address", 11 | "name": "_factory", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "_WETH", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "WETH", 26 | "outputs": [ 27 | { 28 | "internalType": "address", 29 | "name": "", 30 | "type": "address" 31 | } 32 | ], 33 | "stateMutability": "view", 34 | "type": "function" 35 | }, 36 | { 37 | "inputs": [ 38 | { 39 | "internalType": "address", 40 | "name": "tokenA", 41 | "type": "address" 42 | }, 43 | { 44 | "internalType": "address", 45 | "name": "tokenB", 46 | "type": "address" 47 | }, 48 | { 49 | "internalType": "uint256", 50 | "name": "amountADesired", 51 | "type": "uint256" 52 | }, 53 | { 54 | "internalType": "uint256", 55 | "name": "amountBDesired", 56 | "type": "uint256" 57 | }, 58 | { 59 | "internalType": "uint256", 60 | "name": "amountAMin", 61 | "type": "uint256" 62 | }, 63 | { 64 | "internalType": "uint256", 65 | "name": "amountBMin", 66 | "type": "uint256" 67 | }, 68 | { 69 | "internalType": "address", 70 | "name": "to", 71 | "type": "address" 72 | }, 73 | { 74 | "internalType": "uint256", 75 | "name": "deadline", 76 | "type": "uint256" 77 | } 78 | ], 79 | "name": "addLiquidity", 80 | "outputs": [ 81 | { 82 | "internalType": "uint256", 83 | "name": "amountA", 84 | "type": "uint256" 85 | }, 86 | { 87 | "internalType": "uint256", 88 | "name": "amountB", 89 | "type": "uint256" 90 | }, 91 | { 92 | "internalType": "uint256", 93 | "name": "liquidity", 94 | "type": "uint256" 95 | } 96 | ], 97 | "stateMutability": "nonpayable", 98 | "type": "function" 99 | }, 100 | { 101 | "inputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "token", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "amountTokenDesired", 110 | "type": "uint256" 111 | }, 112 | { 113 | "internalType": "uint256", 114 | "name": "amountTokenMin", 115 | "type": "uint256" 116 | }, 117 | { 118 | "internalType": "uint256", 119 | "name": "amountETHMin", 120 | "type": "uint256" 121 | }, 122 | { 123 | "internalType": "address", 124 | "name": "to", 125 | "type": "address" 126 | }, 127 | { 128 | "internalType": "uint256", 129 | "name": "deadline", 130 | "type": "uint256" 131 | } 132 | ], 133 | "name": "addLiquidityETH", 134 | "outputs": [ 135 | { 136 | "internalType": "uint256", 137 | "name": "amountToken", 138 | "type": "uint256" 139 | }, 140 | { 141 | "internalType": "uint256", 142 | "name": "amountETH", 143 | "type": "uint256" 144 | }, 145 | { 146 | "internalType": "uint256", 147 | "name": "liquidity", 148 | "type": "uint256" 149 | } 150 | ], 151 | "stateMutability": "payable", 152 | "type": "function" 153 | }, 154 | { 155 | "inputs": [], 156 | "name": "factory", 157 | "outputs": [ 158 | { 159 | "internalType": "address", 160 | "name": "", 161 | "type": "address" 162 | } 163 | ], 164 | "stateMutability": "view", 165 | "type": "function" 166 | }, 167 | { 168 | "inputs": [ 169 | { 170 | "internalType": "uint256", 171 | "name": "amountOut", 172 | "type": "uint256" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "reserveIn", 177 | "type": "uint256" 178 | }, 179 | { 180 | "internalType": "uint256", 181 | "name": "reserveOut", 182 | "type": "uint256" 183 | } 184 | ], 185 | "name": "getAmountIn", 186 | "outputs": [ 187 | { 188 | "internalType": "uint256", 189 | "name": "amountIn", 190 | "type": "uint256" 191 | } 192 | ], 193 | "stateMutability": "pure", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [ 198 | { 199 | "internalType": "uint256", 200 | "name": "amountIn", 201 | "type": "uint256" 202 | }, 203 | { 204 | "internalType": "uint256", 205 | "name": "reserveIn", 206 | "type": "uint256" 207 | }, 208 | { 209 | "internalType": "uint256", 210 | "name": "reserveOut", 211 | "type": "uint256" 212 | } 213 | ], 214 | "name": "getAmountOut", 215 | "outputs": [ 216 | { 217 | "internalType": "uint256", 218 | "name": "amountOut", 219 | "type": "uint256" 220 | } 221 | ], 222 | "stateMutability": "pure", 223 | "type": "function" 224 | }, 225 | { 226 | "inputs": [ 227 | { 228 | "internalType": "uint256", 229 | "name": "amountOut", 230 | "type": "uint256" 231 | }, 232 | { 233 | "internalType": "address[]", 234 | "name": "path", 235 | "type": "address[]" 236 | } 237 | ], 238 | "name": "getAmountsIn", 239 | "outputs": [ 240 | { 241 | "internalType": "uint256[]", 242 | "name": "amounts", 243 | "type": "uint256[]" 244 | } 245 | ], 246 | "stateMutability": "view", 247 | "type": "function" 248 | }, 249 | { 250 | "inputs": [ 251 | { 252 | "internalType": "uint256", 253 | "name": "amountIn", 254 | "type": "uint256" 255 | }, 256 | { 257 | "internalType": "address[]", 258 | "name": "path", 259 | "type": "address[]" 260 | } 261 | ], 262 | "name": "getAmountsOut", 263 | "outputs": [ 264 | { 265 | "internalType": "uint256[]", 266 | "name": "amounts", 267 | "type": "uint256[]" 268 | } 269 | ], 270 | "stateMutability": "view", 271 | "type": "function" 272 | }, 273 | { 274 | "inputs": [ 275 | { 276 | "internalType": "uint256", 277 | "name": "amountA", 278 | "type": "uint256" 279 | }, 280 | { 281 | "internalType": "uint256", 282 | "name": "reserveA", 283 | "type": "uint256" 284 | }, 285 | { 286 | "internalType": "uint256", 287 | "name": "reserveB", 288 | "type": "uint256" 289 | } 290 | ], 291 | "name": "quote", 292 | "outputs": [ 293 | { 294 | "internalType": "uint256", 295 | "name": "amountB", 296 | "type": "uint256" 297 | } 298 | ], 299 | "stateMutability": "pure", 300 | "type": "function" 301 | }, 302 | { 303 | "inputs": [ 304 | { 305 | "internalType": "address", 306 | "name": "tokenA", 307 | "type": "address" 308 | }, 309 | { 310 | "internalType": "address", 311 | "name": "tokenB", 312 | "type": "address" 313 | }, 314 | { 315 | "internalType": "uint256", 316 | "name": "liquidity", 317 | "type": "uint256" 318 | }, 319 | { 320 | "internalType": "uint256", 321 | "name": "amountAMin", 322 | "type": "uint256" 323 | }, 324 | { 325 | "internalType": "uint256", 326 | "name": "amountBMin", 327 | "type": "uint256" 328 | }, 329 | { 330 | "internalType": "address", 331 | "name": "to", 332 | "type": "address" 333 | }, 334 | { 335 | "internalType": "uint256", 336 | "name": "deadline", 337 | "type": "uint256" 338 | } 339 | ], 340 | "name": "removeLiquidity", 341 | "outputs": [ 342 | { 343 | "internalType": "uint256", 344 | "name": "amountA", 345 | "type": "uint256" 346 | }, 347 | { 348 | "internalType": "uint256", 349 | "name": "amountB", 350 | "type": "uint256" 351 | } 352 | ], 353 | "stateMutability": "nonpayable", 354 | "type": "function" 355 | }, 356 | { 357 | "inputs": [ 358 | { 359 | "internalType": "address", 360 | "name": "token", 361 | "type": "address" 362 | }, 363 | { 364 | "internalType": "uint256", 365 | "name": "liquidity", 366 | "type": "uint256" 367 | }, 368 | { 369 | "internalType": "uint256", 370 | "name": "amountTokenMin", 371 | "type": "uint256" 372 | }, 373 | { 374 | "internalType": "uint256", 375 | "name": "amountETHMin", 376 | "type": "uint256" 377 | }, 378 | { 379 | "internalType": "address", 380 | "name": "to", 381 | "type": "address" 382 | }, 383 | { 384 | "internalType": "uint256", 385 | "name": "deadline", 386 | "type": "uint256" 387 | } 388 | ], 389 | "name": "removeLiquidityETH", 390 | "outputs": [ 391 | { 392 | "internalType": "uint256", 393 | "name": "amountToken", 394 | "type": "uint256" 395 | }, 396 | { 397 | "internalType": "uint256", 398 | "name": "amountETH", 399 | "type": "uint256" 400 | } 401 | ], 402 | "stateMutability": "nonpayable", 403 | "type": "function" 404 | }, 405 | { 406 | "inputs": [ 407 | { 408 | "internalType": "address", 409 | "name": "token", 410 | "type": "address" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "liquidity", 415 | "type": "uint256" 416 | }, 417 | { 418 | "internalType": "uint256", 419 | "name": "amountTokenMin", 420 | "type": "uint256" 421 | }, 422 | { 423 | "internalType": "uint256", 424 | "name": "amountETHMin", 425 | "type": "uint256" 426 | }, 427 | { 428 | "internalType": "address", 429 | "name": "to", 430 | "type": "address" 431 | }, 432 | { 433 | "internalType": "uint256", 434 | "name": "deadline", 435 | "type": "uint256" 436 | } 437 | ], 438 | "name": "removeLiquidityETHSupportingFeeOnTransferTokens", 439 | "outputs": [ 440 | { 441 | "internalType": "uint256", 442 | "name": "amountETH", 443 | "type": "uint256" 444 | } 445 | ], 446 | "stateMutability": "nonpayable", 447 | "type": "function" 448 | }, 449 | { 450 | "inputs": [ 451 | { 452 | "internalType": "address", 453 | "name": "token", 454 | "type": "address" 455 | }, 456 | { 457 | "internalType": "uint256", 458 | "name": "liquidity", 459 | "type": "uint256" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "amountTokenMin", 464 | "type": "uint256" 465 | }, 466 | { 467 | "internalType": "uint256", 468 | "name": "amountETHMin", 469 | "type": "uint256" 470 | }, 471 | { 472 | "internalType": "address", 473 | "name": "to", 474 | "type": "address" 475 | }, 476 | { 477 | "internalType": "uint256", 478 | "name": "deadline", 479 | "type": "uint256" 480 | }, 481 | { 482 | "internalType": "bool", 483 | "name": "approveMax", 484 | "type": "bool" 485 | }, 486 | { 487 | "internalType": "uint8", 488 | "name": "v", 489 | "type": "uint8" 490 | }, 491 | { 492 | "internalType": "bytes32", 493 | "name": "r", 494 | "type": "bytes32" 495 | }, 496 | { 497 | "internalType": "bytes32", 498 | "name": "s", 499 | "type": "bytes32" 500 | } 501 | ], 502 | "name": "removeLiquidityETHWithPermit", 503 | "outputs": [ 504 | { 505 | "internalType": "uint256", 506 | "name": "amountToken", 507 | "type": "uint256" 508 | }, 509 | { 510 | "internalType": "uint256", 511 | "name": "amountETH", 512 | "type": "uint256" 513 | } 514 | ], 515 | "stateMutability": "nonpayable", 516 | "type": "function" 517 | }, 518 | { 519 | "inputs": [ 520 | { 521 | "internalType": "address", 522 | "name": "token", 523 | "type": "address" 524 | }, 525 | { 526 | "internalType": "uint256", 527 | "name": "liquidity", 528 | "type": "uint256" 529 | }, 530 | { 531 | "internalType": "uint256", 532 | "name": "amountTokenMin", 533 | "type": "uint256" 534 | }, 535 | { 536 | "internalType": "uint256", 537 | "name": "amountETHMin", 538 | "type": "uint256" 539 | }, 540 | { 541 | "internalType": "address", 542 | "name": "to", 543 | "type": "address" 544 | }, 545 | { 546 | "internalType": "uint256", 547 | "name": "deadline", 548 | "type": "uint256" 549 | }, 550 | { 551 | "internalType": "bool", 552 | "name": "approveMax", 553 | "type": "bool" 554 | }, 555 | { 556 | "internalType": "uint8", 557 | "name": "v", 558 | "type": "uint8" 559 | }, 560 | { 561 | "internalType": "bytes32", 562 | "name": "r", 563 | "type": "bytes32" 564 | }, 565 | { 566 | "internalType": "bytes32", 567 | "name": "s", 568 | "type": "bytes32" 569 | } 570 | ], 571 | "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", 572 | "outputs": [ 573 | { 574 | "internalType": "uint256", 575 | "name": "amountETH", 576 | "type": "uint256" 577 | } 578 | ], 579 | "stateMutability": "nonpayable", 580 | "type": "function" 581 | }, 582 | { 583 | "inputs": [ 584 | { 585 | "internalType": "address", 586 | "name": "tokenA", 587 | "type": "address" 588 | }, 589 | { 590 | "internalType": "address", 591 | "name": "tokenB", 592 | "type": "address" 593 | }, 594 | { 595 | "internalType": "uint256", 596 | "name": "liquidity", 597 | "type": "uint256" 598 | }, 599 | { 600 | "internalType": "uint256", 601 | "name": "amountAMin", 602 | "type": "uint256" 603 | }, 604 | { 605 | "internalType": "uint256", 606 | "name": "amountBMin", 607 | "type": "uint256" 608 | }, 609 | { 610 | "internalType": "address", 611 | "name": "to", 612 | "type": "address" 613 | }, 614 | { 615 | "internalType": "uint256", 616 | "name": "deadline", 617 | "type": "uint256" 618 | }, 619 | { 620 | "internalType": "bool", 621 | "name": "approveMax", 622 | "type": "bool" 623 | }, 624 | { 625 | "internalType": "uint8", 626 | "name": "v", 627 | "type": "uint8" 628 | }, 629 | { 630 | "internalType": "bytes32", 631 | "name": "r", 632 | "type": "bytes32" 633 | }, 634 | { 635 | "internalType": "bytes32", 636 | "name": "s", 637 | "type": "bytes32" 638 | } 639 | ], 640 | "name": "removeLiquidityWithPermit", 641 | "outputs": [ 642 | { 643 | "internalType": "uint256", 644 | "name": "amountA", 645 | "type": "uint256" 646 | }, 647 | { 648 | "internalType": "uint256", 649 | "name": "amountB", 650 | "type": "uint256" 651 | } 652 | ], 653 | "stateMutability": "nonpayable", 654 | "type": "function" 655 | }, 656 | { 657 | "inputs": [ 658 | { 659 | "internalType": "uint256", 660 | "name": "amountOut", 661 | "type": "uint256" 662 | }, 663 | { 664 | "internalType": "address[]", 665 | "name": "path", 666 | "type": "address[]" 667 | }, 668 | { 669 | "internalType": "address", 670 | "name": "to", 671 | "type": "address" 672 | }, 673 | { 674 | "internalType": "uint256", 675 | "name": "deadline", 676 | "type": "uint256" 677 | } 678 | ], 679 | "name": "swapETHForExactTokens", 680 | "outputs": [ 681 | { 682 | "internalType": "uint256[]", 683 | "name": "amounts", 684 | "type": "uint256[]" 685 | } 686 | ], 687 | "stateMutability": "payable", 688 | "type": "function" 689 | }, 690 | { 691 | "inputs": [ 692 | { 693 | "internalType": "uint256", 694 | "name": "amountOutMin", 695 | "type": "uint256" 696 | }, 697 | { 698 | "internalType": "address[]", 699 | "name": "path", 700 | "type": "address[]" 701 | }, 702 | { 703 | "internalType": "address", 704 | "name": "to", 705 | "type": "address" 706 | }, 707 | { 708 | "internalType": "uint256", 709 | "name": "deadline", 710 | "type": "uint256" 711 | } 712 | ], 713 | "name": "swapExactETHForTokens", 714 | "outputs": [ 715 | { 716 | "internalType": "uint256[]", 717 | "name": "amounts", 718 | "type": "uint256[]" 719 | } 720 | ], 721 | "stateMutability": "payable", 722 | "type": "function" 723 | }, 724 | { 725 | "inputs": [ 726 | { 727 | "internalType": "uint256", 728 | "name": "amountOutMin", 729 | "type": "uint256" 730 | }, 731 | { 732 | "internalType": "address[]", 733 | "name": "path", 734 | "type": "address[]" 735 | }, 736 | { 737 | "internalType": "address", 738 | "name": "to", 739 | "type": "address" 740 | }, 741 | { 742 | "internalType": "uint256", 743 | "name": "deadline", 744 | "type": "uint256" 745 | } 746 | ], 747 | "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", 748 | "outputs": [], 749 | "stateMutability": "payable", 750 | "type": "function" 751 | }, 752 | { 753 | "inputs": [ 754 | { 755 | "internalType": "uint256", 756 | "name": "amountIn", 757 | "type": "uint256" 758 | }, 759 | { 760 | "internalType": "uint256", 761 | "name": "amountOutMin", 762 | "type": "uint256" 763 | }, 764 | { 765 | "internalType": "address[]", 766 | "name": "path", 767 | "type": "address[]" 768 | }, 769 | { 770 | "internalType": "address", 771 | "name": "to", 772 | "type": "address" 773 | }, 774 | { 775 | "internalType": "uint256", 776 | "name": "deadline", 777 | "type": "uint256" 778 | } 779 | ], 780 | "name": "swapExactTokensForETH", 781 | "outputs": [ 782 | { 783 | "internalType": "uint256[]", 784 | "name": "amounts", 785 | "type": "uint256[]" 786 | } 787 | ], 788 | "stateMutability": "nonpayable", 789 | "type": "function" 790 | }, 791 | { 792 | "inputs": [ 793 | { 794 | "internalType": "uint256", 795 | "name": "amountIn", 796 | "type": "uint256" 797 | }, 798 | { 799 | "internalType": "uint256", 800 | "name": "amountOutMin", 801 | "type": "uint256" 802 | }, 803 | { 804 | "internalType": "address[]", 805 | "name": "path", 806 | "type": "address[]" 807 | }, 808 | { 809 | "internalType": "address", 810 | "name": "to", 811 | "type": "address" 812 | }, 813 | { 814 | "internalType": "uint256", 815 | "name": "deadline", 816 | "type": "uint256" 817 | } 818 | ], 819 | "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", 820 | "outputs": [], 821 | "stateMutability": "nonpayable", 822 | "type": "function" 823 | }, 824 | { 825 | "inputs": [ 826 | { 827 | "internalType": "uint256", 828 | "name": "amountIn", 829 | "type": "uint256" 830 | }, 831 | { 832 | "internalType": "uint256", 833 | "name": "amountOutMin", 834 | "type": "uint256" 835 | }, 836 | { 837 | "internalType": "address[]", 838 | "name": "path", 839 | "type": "address[]" 840 | }, 841 | { 842 | "internalType": "address", 843 | "name": "to", 844 | "type": "address" 845 | }, 846 | { 847 | "internalType": "uint256", 848 | "name": "deadline", 849 | "type": "uint256" 850 | } 851 | ], 852 | "name": "swapExactTokensForTokens", 853 | "outputs": [ 854 | { 855 | "internalType": "uint256[]", 856 | "name": "amounts", 857 | "type": "uint256[]" 858 | } 859 | ], 860 | "stateMutability": "nonpayable", 861 | "type": "function" 862 | }, 863 | { 864 | "inputs": [ 865 | { 866 | "internalType": "uint256", 867 | "name": "amountIn", 868 | "type": "uint256" 869 | }, 870 | { 871 | "internalType": "uint256", 872 | "name": "amountOutMin", 873 | "type": "uint256" 874 | }, 875 | { 876 | "internalType": "address[]", 877 | "name": "path", 878 | "type": "address[]" 879 | }, 880 | { 881 | "internalType": "address", 882 | "name": "to", 883 | "type": "address" 884 | }, 885 | { 886 | "internalType": "uint256", 887 | "name": "deadline", 888 | "type": "uint256" 889 | } 890 | ], 891 | "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", 892 | "outputs": [], 893 | "stateMutability": "nonpayable", 894 | "type": "function" 895 | }, 896 | { 897 | "inputs": [ 898 | { 899 | "internalType": "uint256", 900 | "name": "amountOut", 901 | "type": "uint256" 902 | }, 903 | { 904 | "internalType": "uint256", 905 | "name": "amountInMax", 906 | "type": "uint256" 907 | }, 908 | { 909 | "internalType": "address[]", 910 | "name": "path", 911 | "type": "address[]" 912 | }, 913 | { 914 | "internalType": "address", 915 | "name": "to", 916 | "type": "address" 917 | }, 918 | { 919 | "internalType": "uint256", 920 | "name": "deadline", 921 | "type": "uint256" 922 | } 923 | ], 924 | "name": "swapTokensForExactETH", 925 | "outputs": [ 926 | { 927 | "internalType": "uint256[]", 928 | "name": "amounts", 929 | "type": "uint256[]" 930 | } 931 | ], 932 | "stateMutability": "nonpayable", 933 | "type": "function" 934 | }, 935 | { 936 | "inputs": [ 937 | { 938 | "internalType": "uint256", 939 | "name": "amountOut", 940 | "type": "uint256" 941 | }, 942 | { 943 | "internalType": "uint256", 944 | "name": "amountInMax", 945 | "type": "uint256" 946 | }, 947 | { 948 | "internalType": "address[]", 949 | "name": "path", 950 | "type": "address[]" 951 | }, 952 | { 953 | "internalType": "address", 954 | "name": "to", 955 | "type": "address" 956 | }, 957 | { 958 | "internalType": "uint256", 959 | "name": "deadline", 960 | "type": "uint256" 961 | } 962 | ], 963 | "name": "swapTokensForExactTokens", 964 | "outputs": [ 965 | { 966 | "internalType": "uint256[]", 967 | "name": "amounts", 968 | "type": "uint256[]" 969 | } 970 | ], 971 | "stateMutability": "nonpayable", 972 | "type": "function" 973 | }, 974 | { 975 | "stateMutability": "payable", 976 | "type": "receive" 977 | } 978 | ], 979 | "type": "account" 980 | } 981 | ] -------------------------------------------------------------------------------- /data/sniping/tribe.csv: -------------------------------------------------------------------------------- 1 | // transaction 0xc9851f374701f76024c1f44f7166e0ef8a99456750463dc9d7b426e6359b9b20 block 12168367 2 | 1291493224839433460652286254471485403676430345488 adds 119248224557418002464468014 1136986367848084728997482848992353010604574777643 and 385878266886967004057471300 853121275925315230082299135533471935483885881290 of liquidity; 3 | // transaction 0x641b95d1f76a4a9e0101df94aab04aee23f95bca349fb6a68d79b180cf84e533 block 12168368 4 | 1367086874294120489657851107616899385891777411291 swaps for 853121275925315230082299135533471935483885881290 by providing 3650791146857396019846 1097077688018008265106216665536940668749033598146 and 7580513152923804785272828 853121275925315230082299135533471935483885881290 with a change 0 fee 5065046454000506454 ; 5 | // transaction 0x641b95d1f76a4a9e0101df94aab04aee23f95bca349fb6a68d79b180cf84e533 block 12168368 6 | 1367086874294120489657851107616899385891777411291 swaps for 1136986367848084728997482848992353010604574777643 by providing 1500858802284305819009811 853121275925315230082299135533471935483885881290 and 469310538337122748794652 1136986367848084728997482848992353010604574777643 with a change 0 fee 5065046454000506454 ; 7 | // transaction 0x768b550108b4a4bc74d897b19a5803e3e2a154934e9410c7f59ae9e829f08ed9 block 12168368 8 | 442369115386585060014488544864765222449798623673 swaps for 853121275925315230082299135533471935483885881290 by providing 83704080913890373912774 1136986367848084728997482848992353010604574777643 and 254720972749489069158784 853121275925315230082299135533471935483885881290 with a change 0 fee 45581000000000000 ; 9 | // transaction 0x5da2aaaf5b64ddc6fd8134636c08e3bc4d0e45d418091b324ef80e7b0aabf75d block 12168368 10 | 1361222972406622104922423989231800521529377588264 swaps for 853121275925315230082299135533471935483885881290 by providing 4771562326358659063994 1136986367848084728997482848992353010604574777643 and 11207722800977519042986 853121275925315230082299135533471935483885881290 with a change 0 fee 27345000000000000 ; 11 | // transaction 0x6bcdaeb8ba9e8bb9c35556685b54ec993d3e3b7f36f5f57f72acd03988a99968 block 12168368 12 | 481110740388440253237393012621935061741050743104 swaps for 853121275925315230082299135533471935483885881290 by providing 15063617344741911224266 1136986367848084728997482848992353010604574777643 and 32816000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 29304701800000000 ; 13 | // transaction 0xdaee07d6224f7ca33fca8a87fb71ed7738f9fabde745192f6187d8f7e9b4dd63 block 12168368 14 | 634765440242792942827168055992480995306379932332 swaps for 853121275925315230082299135533471935483885881290 by providing 4872599016837230517358 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26425374000000000 ; 15 | // transaction 0xe50cbe2c0a740c9ef9b80dbd8ab1e69548d9206bdaeea0aa5e3b1023d11cceb9 block 12168368 16 | 9684059395531886613116102915562525308755498520 swaps for 853121275925315230082299135533471935483885881290 by providing 4882993618542963371985 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 60563000000000000 ; 17 | // transaction 0xec05082dfb3dc7f5a1a0fef9dbf9352b1105eeb3eaab98d79d7d97bb363e1ce9 block 12168368 18 | 19800958059152695244609295437758439695101145134 swaps for 853121275925315230082299135533471935483885881290 by providing 11728849244625528030475 1136986367848084728997482848992353010604574777643 and 23617234473192628719586 853121275925315230082299135533471935483885881290 with a change 0 fee 31845000000000000 ; 19 | // transaction 0x276c13a9ec2c2c003e20348dbd44cd05e85ae8406b0b0cab27ac17f55d5c0c73 block 12168368 20 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 50511218881639466563152 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35343954000000000 ; 21 | // transaction 0x086f942fd365050251bef1638e6776ba132a2564eb4606522875a9537ba120de block 12168368 22 | 9684059395531886613116102915562525308755498520 swaps for 853121275925315230082299135533471935483885881290 by providing 5046697666450336932121 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 42450400000000000 ; 23 | // transaction 0xaee051b36c434989b7fc973b101c8475e30f429a4a80c5484fe76d1081571e43 block 12168368 24 | 475263292204539987865545617236070723235500475082 swaps for 853121275925315230082299135533471935483885881290 by providing 16086794619889641663090 1136986367848084728997482848992353010604574777643 and 31300000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 30163362000000000 ; 25 | // transaction 0xb8b22335473bfd9116f47440d8f0e6dd55e1117db9a2eeb01dc2163e7c9a18f5 block 12168368 26 | 1228326345553305550976148193278412307754404489625 swaps for 853121275925315230082299135533471935483885881290 by providing 26388350641450249607828 1136986367848084728997482848992353010604574777643 and 50000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 25290522000000000 ; 27 | // transaction 0xb73338f03a3d701d067448182577776e2ed11cf013a19c30f8219548178d57d4 block 12168418 28 | 526101665928632130822131281241297623504905290624 swaps for 853121275925315230082299135533471935483885881290 by providing 629387397522753732836194 1136986367848084728997482848992353010604574777643 and 1200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 59071000000000000 ; 29 | // transaction 0xe1f81d3b765eba299bd3727fd1954741983e2b6c987c44a007bfd139e0181c43 block 12168418 30 | 9684059395531886613116102915562525308755498520 swaps for 853121275925315230082299135533471935483885881290 by providing 5213277515691436054086 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 42450400000000000 ; 31 | // transaction 0x5187c225ace81e1bb1670444cb6dcd275d239812485ddc4aa9e21ac255527c67 block 12168418 32 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 52124766791300117108895 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35343954000000000 ; 33 | // transaction 0x829ac2ace644a9d48c3baee716783f71f12012c5ae897c7f95c2209ddd2a73d2 block 12168420 34 | 1128277754329020320735178462573158404755534708525 swaps for 917551056842671309452305380979543736893630245704 by providing 2661419076910802877843 1136986367848084728997482848992353010604574777643 and 2827757769 917551056842671309452305380979543736893630245704 with a change 0 fee 212983000000000000 ; 35 | // transaction 0xc84479388ac1086c1f2065e49628cf2694455d35de1f622d4c674108244c7fd9 block 12168420 36 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 53324990494529202136599 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35343954000000000 ; 37 | // transaction 0xedf2c562ff876656fa987f86dd60e861266fd2019e09a751b3be54c746cc80ee block 12168422 38 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 53445526264803733753084 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35343954000000000 ; 39 | // transaction 0x557e7f529780cf69f6f60950d980cc225f16a032260139ca998391cd61fe7715 block 12168423 40 | 916759615386715509769885869522114638029541227728 swaps for 853121275925315230082299135533471935483885881290 by providing 4999102828521476387031 1136986367848084728997482848992353010604574777643 and 9342310715659601593343 853121275925315230082299135533471935483885881290 with a change 0 fee 21344214870000000 ; 41 | // transaction 0xb6a9cb9e7582e1a3dfb8984460ef536172250f5b6488b338a9a7444fbad99ec1 block 12168423 42 | 475263292204539987865545617236070723235500475082 swaps for 853121275925315230082299135533471935483885881290 by providing 5351556280325237207550 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 25473120000000000 ; 43 | // transaction 0x17021abb6a3036cad8cca83a55029ae435b07489c3eec4bab2ceae2737697111 block 12168425 44 | 9684059395531886613116102915562525308755498520 swaps for 853121275925315230082299135533471935483885881290 by providing 5298880793212256208675 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 42455200000000000 ; 45 | // transaction 0x483ececd55525bd05953889350d8c13e2627b059fbe3fe41f6a10b3e325cd036 block 12168425 46 | 526101665928632130822131281241297623504905290624 swaps for 853121275925315230082299135533471935483885881290 by providing 701489510966108293198807 1136986367848084728997482848992353010604574777643 and 1318678000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 66166240000000000 ; 47 | // transaction 0x79d58551c75453a68883c4c6b6d9129f0fffbe533bf27261d9589435bbf2990c block 12168425 48 | 130165275011728338117659433401967294346375389490 swaps for 853121275925315230082299135533471935483885881290 by providing 4440950310772576335353 1136986367848084728997482848992353010604574777643 and 8151071127983650213081 853121275925315230082299135533471935483885881290 with a change 0 fee 22055396000000000 ; 49 | // transaction 0x957291ebfd2322f8356643c6bd23f3047c20a9f049ee8d3dac67ad1fcf01a108 block 12168425 50 | 1360360126667477365097079694329127427851914691108 swaps for 853121275925315230082299135533471935483885881290 by providing 50000000000000000000000 1136986367848084728997482848992353010604574777643 and 94408884593338704210946 853121275925315230082299135533471935483885881290 with a change 0 fee 36461334000000000 ; 51 | // transaction 0x3fb8a12d41cbd54e8590c127aff88861b0ccb085c4a52e71b66caaa4ad214a8b block 12168426 52 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 54519660522338438567002 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35343954000000000 ; 53 | // transaction 0x7814e15f449df05a38df48df5df1c03f6ff4059fd43e7ca2ca45c7a852d78309 block 12168428 54 | 1293335929339978850065539759241399034506782073066 swaps for 853121275925315230082299135533471935483885881290 by providing 61772594487552207222374 1136986367848084728997482848992353010604574777643 and 112463389458309812330554 853121275925315230082299135533471935483885881290 with a change 0 fee 23519796000000000 ; 55 | // transaction 0x31f156686df5037ce29e4f213780aad8a78d605d35f48d610139922f40215546 block 12168432 56 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 55416985001508291985126 1136986367848084728997482848992353010604574777643 and 100000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35339958000000000 ; 57 | // transaction 0x46d3b3a8101de58128348d607b57afeed31c261df0d80a63df06ddea9189e20a block 12168432 58 | 368591378834645328895427470194575073575727620870 swaps for 853121275925315230082299135533471935483885881290 by providing 5672650787909612816104 1136986367848084728997482848992353010604574777643 and 10188838909979562766351 853121275925315230082299135533471935483885881290 with a change 0 fee 21696556000000000 ; 59 | // transaction 0x63254128de512eccdcd16e3ef0aa26d15ea6d65d57308c33df155f768b57a6d3 block 12168433 60 | 911376113943689345597908586284241674928019370099 swaps for 853121275925315230082299135533471935483885881290 by providing 835477553354143606088 1136986367848084728997482848992353010604574777643 and 1500000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 27371764000000000 ; 61 | // transaction 0x04d26b12026c2b14220021229e5f2861c844ecd075887cb953a1793e8ac8832e block 12168435 62 | 65938512484888389691220952976671179803203565934 swaps for 853121275925315230082299135533471935483885881290 by providing 30000000000000000000000 1136986367848084728997482848992353010604574777643 and 53553870492116868938157 853121275925315230082299135533471935483885881290 with a change 0 fee 33420650000000000 ; 63 | // transaction 0xacb94c6262d3f7acde85f8b62a8e51fa99d0db18a846c635e3663b6a6dce3cb4 block 12168436 64 | 324302534840082494605361566234211851839546123442 swaps for 853121275925315230082299135533471935483885881290 by providing 1193715467055089600303 1136986367848084728997482848992353010604574777643 and 2125131335045369038225 853121275925315230082299135533471935483885881290 with a change 0 fee 23312804000000000 ; 65 | // transaction 0x200a1a0f9f97e2dbccc72de87b6e983866126f87218f6491a711be284d8e18d6 block 12168438 66 | 1318000584640465383136803678837070893438516182759 swaps for 853121275925315230082299135533471935483885881290 by providing 280822988337895813145898 1136986367848084728997482848992353010604574777643 and 500000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26109948165681418 ; 67 | // transaction 0xf92f786eb0fc3b140df24e0128b4d8cb47ae82b9f38b60366a1141dcd0049f33 block 12168442 68 | 569085091575443940505074054781296557955828778606 swaps for 853121275925315230082299135533471935483885881290 by providing 5000000000000000000000 1136986367848084728997482848992353010604574777643 and 8844480717156356049557 853121275925315230082299135533471935483885881290 with a change 0 fee 23670558000000000 ; 69 | // transaction 0xb57d5658ab28892a1c97637d504da7bff439d8c1e47e6597c9c01b0a54cb88d0 block 12168449 70 | 1083451854987363889601233713638418521944863013775 swaps for 853121275925315230082299135533471935483885881290 by providing 1212788084150330841118 1136986367848084728997482848992353010604574777643 and 2125123628822131411032 853121275925315230082299135533471935483885881290 with a change 0 fee 24950222600000000 ; 71 | // transaction 0xee78b1f03df745e8f8803ee5de214a1a47a04b8f3557d2bc4cb0466697007cd4 block 12168450 72 | 623093232331684105034239694899451461003593173319 swaps for 853121275925315230082299135533471935483885881290 by providing 14028293787631626169640 1136986367848084728997482848992353010604574777643 and 24453213383950950639243 853121275925315230082299135533471935483885881290 with a change 0 fee 20602612000000000 ; 73 | // transaction 0x8063fccc37c7921468acaade4fa3b295fd1a1d94fc13f6f57efb27126f73205a block 12168450 74 | 911376113943689345597908586284241674928019370099 swaps for 853121275925315230082299135533471935483885881290 by providing 458882797582615810817 1136986367848084728997482848992353010604574777643 and 800000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 23342440000000000 ; 75 | // transaction 0x7843d26f9d502a80e8d7ddde65c701eb2559d6ff165d0d41612fb3644637b8a4 block 12168451 76 | 1399033864321986312521628718171547076786308691280 swaps for 853121275925315230082299135533471935483885881290 by providing 5261720394600521788625 1136986367848084728997482848992353010604574777643 and 9169955018981606489716 853121275925315230082299135533471935483885881290 with a change 0 fee 20237964000000000 ; 77 | // transaction 0xe3639b52b6878d4de07ee6f720940898d6685837167dd6852227d60f1e37cb00 block 12168451 78 | 1224661412648498510685330405683573221766602517165 swaps for 853121275925315230082299135533471935483885881290 by providing 2800000000000000000000 1136986367848084728997482848992353010604574777643 and 4881564816969083659746 853121275925315230082299135533471935483885881290 with a change 0 fee 37282000000000000 ; 79 | // transaction 0x7553076e3ab17fbc72956c58bd2730dc3e04b2e559ca3ab792e14e8427b37be0 block 12168455 80 | 1130365142900232607253745005964962986584360062147 swaps for 853121275925315230082299135533471935483885881290 by providing 1259010352459613392130 1136986367848084728997482848992353010604574777643 and 2190933677324643037616 853121275925315230082299135533471935483885881290 with a change 0 fee 24305602000000000 ; 81 | // transaction 0xe83cd446ef6e606ce931d891cc258d34ecdc842881fd1d539473f591a235862d block 12168455 82 | 374998165038815605106464574927970515242504000236 swaps for 853121275925315230082299135533471935483885881290 by providing 10000000000000000000000 1136986367848084728997482848992353010604574777643 and 17421499798879586910214 853121275925315230082299135533471935483885881290 with a change 0 fee 24413580000000000 ; 83 | // transaction 0x1ca85f0e802e6944fed21f8a319678fded8acccb05807d8cdd27280f7f030652 block 12168455 84 | 1384149453956805550901335525472704262038059451032 swaps for 853121275925315230082299135533471935483885881290 by providing 51687713115871003498808 1136986367848084728997482848992353010604574777643 and 90000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 27861740000000000 ; 85 | // transaction 0x9a7f5ca61c8a17ffb407f2629d5eeab0adcd3f1c3f39d728cb69104e7f551b02 block 12168456 86 | 911376113943689345597908586284241674928019370099 swaps for 853121275925315230082299135533471935483885881290 by providing 508158768590707527500 1136986367848084728997482848992353010604574777643 and 882137122173437993135 853121275925315230082299135533471935483885881290 with a change 0 fee 19592090000000000 ; 87 | // transaction 0x1c4018062818b6a341dd10378a6116565f3594fdb2f79e8a6905caca5756b71e block 12168460 88 | 1386006841971238745562496966856851600877445708906 swaps for 853121275925315230082299135533471935483885881290 by providing 2926561974855205800585 1136986367848084728997482848992353010604574777643 and 5000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 24090602000000000 ; 89 | // transaction 0x57a732845a7e7b65a97f7aade8a592a59d406caff461690b1a3f5cce090b3537 block 12168460 90 | 85883903396560517067198355112357592947378836923 swaps for 853121275925315230082299135533471935483885881290 by providing 175002261102506566029652 1136986367848084728997482848992353010604574777643 and 300000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 28657260000000000 ; 91 | // transaction 0x95bd7a33edd6c0bf81c66944417508b7f16fdb457b0fae472d9b1e2197eab6f7 block 12168461 92 | 536117214108072430759478326245821846825575577466 swaps for 853121275925315230082299135533471935483885881290 by providing 2493327514075855865657 1136986367848084728997482848992353010604574777643 and 4257408164433122173250 853121275925315230082299135533471935483885881290 with a change 0 fee 22784500000000000 ; 93 | // transaction 0x5f025c37a7caa230fa3fadaf6b191175a7932d8f90d164f02e97026fe30ba898 block 12168462 94 | 862362742433020178219530259648050328478151863582 swaps for 853121275925315230082299135533471935483885881290 by providing 13167541636501586919282 1136986367848084728997482848992353010604574777643 and 22415445601955038085973 853121275925315230082299135533471935483885881290 with a change 0 fee 24176162400000000 ; 95 | // transaction 0x5afa80deaf25f80072f55f584c3aac30070f36f299c280785e0115253dc39596 block 12168463 96 | 1347598352652425337068309310510483809867225044732 swaps for 853121275925315230082299135533471935483885881290 by providing 2937493143601902592083 1136986367848084728997482848992353010604574777643 and 5000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 25576366000000000 ; 97 | // transaction 0xdf3f368199fdfce6f0ccfa3f5a6bcf6a788fbfedf99d5d18eb981b42d85a90b8 block 12168465 98 | 1418913005729813845750824651014068484684427737010 swaps for 853121275925315230082299135533471935483885881290 by providing 4400000000000000000000 1136986367848084728997482848992353010604574777643 and 7485761831323978866423 853121275925315230082299135533471935483885881290 with a change 0 fee 22816230000000000 ; 99 | // transaction 0x3cffbeed83bf8685b60a51eeec2fa141447cb4f234fa903ea9ff37d6e2859064 block 12168465 100 | 806179005551030784639303346409776994294011187000 swaps for 853121275925315230082299135533471935483885881290 by providing 29392771019339137162751 1136986367848084728997482848992353010604574777643 and 50000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26044670000000000 ; 101 | // transaction 0x5c67763e71d5c1bbc0e77c8de741f4bdf488b747a8ccfb351fafdadfe0773a1d block 12168469 102 | 162596131389139886802132062264335384989000940436 swaps for 853121275925315230082299135533471935483885881290 by providing 37060479303912748152761 1136986367848084728997482848992353010604574777643 and 62183329995927966035765 853121275925315230082299135533471935483885881290 with a change 0 fee 22425852000000000 ; 103 | // transaction 0x378c9c1a7b5c49752ebff98f7cf689b204014cd6e8e2bde23685377cd4d39bd5 block 12168471 104 | 475263292204539987865545617236070723235500475082 swaps for 853121275925315230082299135533471935483885881290 by providing 2977003927677699345471 1136986367848084728997482848992353010604574777643 and 5000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26000870000000000 ; 105 | // transaction 0xcc3295f9611bd169263cc096a36cb596a176fc61c7595a940125662920c3aa8c block 12168471 106 | 115022413383910582427825547294036647315144200938 swaps for 853121275925315230082299135533471935483885881290 by providing 1191507676334694280493 1136986367848084728997482848992353010604574777643 and 2000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 22496168000000000 ; 107 | // transaction 0xf9885349869fc7a89db789217b1f8ce9134ca92d27969156b0b762c4cfedcd5c block 12168471 108 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 119214559729595607025598 1136986367848084728997482848992353010604574777643 and 200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 29396902000000000 ; 109 | // transaction 0xec062422667b7ecbc2ede4273b0926051d83c1fadfbb97273597594075f13436 block 12168471 110 | 1137868699314345857876736026879479220536054603516 swaps for 853121275925315230082299135533471935483885881290 by providing 2443338343188350031394 1136986367848084728997482848992353010604574777643 and 4103489635647768945256 853121275925315230082299135533471935483885881290 with a change 0 fee 23057914000000000 ; 111 | // transaction 0xecdd1f643c1c812d41be7c948a50e07dabebbbb6b9eba94b749195dafd1eb090 block 12168471 112 | 614496722687926695061940682171063739199616732414 swaps for 917551056842671309452305380979543736893630245704 by providing 886558744994532291682 1136986367848084728997482848992353010604574777643 and 702555986 917551056842671309452305380979543736893630245704 with a change 0 fee 98603100000000000 ; 113 | // transaction 0xecdd1f643c1c812d41be7c948a50e07dabebbbb6b9eba94b749195dafd1eb090 block 12168471 114 | 614496722687926695061940682171063739199616732414 swaps for 917551056842671309452305380979543736893630245704 by providing 538580923089197122157 1136986367848084728997482848992353010604574777643 and 572242230 917551056842671309452305380979543736893630245704 with a change 0 fee 98603100000000000 ; 115 | // transaction 0xe16b000b5dac551cdccf6300326a015b171bcadce6628278b4615f536a301b7f block 12168472 116 | 269871274817532565992741693287699116336768911487 swaps for 853121275925315230082299135533471935483885881290 by providing 1809464121801187872570 1136986367848084728997482848992353010604574777643 and 3031000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 31834200000000000 ; 117 | // transaction 0xc2df31196d4265c77b583031cbef0e9c7b4af3845631a255303550908db7ceb3 block 12168475 118 | 1228326345553305550976148193278412307754404489625 swaps for 853121275925315230082299135533471935483885881290 by providing 30113693828714380403226 1136986367848084728997482848992353010604574777643 and 50000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 28705750000000000 ; 119 | // transaction 0x54313cd3473b6a43ef854e4e278efb463abc796cc57b746fe5fa153dd4a44239 block 12168475 120 | 65938512484888389691220952976671179803203565934 swaps for 853121275925315230082299135533471935483885881290 by providing 40000000000000000000000 1136986367848084728997482848992353010604574777643 and 66220803494323368502714 853121275925315230082299135533471935483885881290 with a change 0 fee 25999890000000000 ; 121 | // transaction 0xfbc6374c591d6a6403488d33a89bac32be1d5bfe2e7d4424b394d6fa03f3ad86 block 12168476 122 | 374998165038815605106464574927970515242504000236 swaps for 853121275925315230082299135533471935483885881290 by providing 10000000000000000000000 1136986367848084728997482848992353010604574777643 and 16535160170420839194240 853121275925315230082299135533471935483885881290 with a change 0 fee 27279522000000000 ; 123 | // transaction 0x2b6e240b5577462bb8759ff4d0409f73f94b72e425ad62c9bb86d46b006435f7 block 12168476 124 | 1414189478955926408175291044969885871699701283472 swaps for 853121275925315230082299135533471935483885881290 by providing 4680458815409368211551 1136986367848084728997482848992353010604574777643 and 7728959641626098924338 853121275925315230082299135533471935483885881290 with a change 0 fee 39949800000000000 ; 125 | // transaction 0x2a6470724c180f84d561984b95d67da820a7b75f644365925b26ea21d47f80dc block 12168476 126 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 120981330037769110021888 1136986367848084728997482848992353010604574777643 and 200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 29396902000000000 ; 127 | // transaction 0xdaa66d897ce7062a007835183b2cab6f6d655781189dcd838985926a76f9a520 block 12168477 128 | 454405079773158075607896254669294006011145671762 swaps for 853121275925315230082299135533471935483885881290 by providing 120893562146159633074473 1136986367848084728997482848992353010604574777643 and 200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 28229516000000000 ; 129 | // transaction 0xc9d02a67c884371205c230bf055492738d29d3ff94edb2fe0afb9ad3bf56ac17 block 12168477 130 | 1281320731356608907034210780722240384834932116408 swaps for 853121275925315230082299135533471935483885881290 by providing 10000000000000000000000 1136986367848084728997482848992353010604574777643 and 16561441531016495315282 853121275925315230082299135533471935483885881290 with a change 0 fee 26854938000000000 ; 131 | // transaction 0x6b21cdab6cec74fe6d6856cff9f67192bff6df11eae19780986db07993c05450 block 12168481 132 | 1412619211243908919679321931843534986166532101879 swaps for 853121275925315230082299135533471935483885881290 by providing 2906099372015392587932 1136986367848084728997482848992353010604574777643 and 4788754287690394500185 853121275925315230082299135533471935483885881290 with a change 0 fee 20053000000000000 ; 133 | // transaction 0x25ed892621c26c0e0f491261eb6198cdc7adc3279ffdfea520a992300af5b16e block 12168481 134 | 1146535556950889244783328250016797276088313413692 swaps for 853121275925315230082299135533471935483885881290 by providing 1000000000000000000000 1136986367848084728997482848992353010604574777643 and 1650766782671455206871 853121275925315230082299135533471935483885881290 with a change 0 fee 31836600000000000 ; 135 | // transaction 0x7b16fe2fe8441b44f84517dab68f55356fb82e151218441cd2260b2360980af4 block 12168483 136 | 426791940332712394739389808236786212304289385304 swaps for 853121275925315230082299135533471935483885881290 by providing 1687495715560119983473 1136986367848084728997482848992353010604574777643 and 2777000270041773328767 853121275925315230082299135533471935483885881290 with a change 0 fee 25037954200000000 ; 137 | // transaction 0x4e93cf78553ba30229431b362f4515106c1a45c8a2fd725b8ebfb9fe163fee73 block 12168484 138 | 409164343279350271865570757586322849177944041261 swaps for 853121275925315230082299135533471935483885881290 by providing 1142669983895182394261 1136986367848084728997482848992353010604574777643 and 1880000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 28263499031019290 ; 139 | // transaction 0x33836e2f2c4ef02229a772a850e30c5620504330a4b81d825cc6f178d7476f2c block 12168485 140 | 1096732850115699076508040790480850245475427575434 swaps for 853121275925315230082299135533471935483885881290 by providing 96275614981626761989464 1136986367848084728997482848992353010604574777643 and 158514665944799910801221 853121275925315230082299135533471935483885881290 with a change 0 fee 23092850000000000 ; 141 | // transaction 0x33836e2f2c4ef02229a772a850e30c5620504330a4b81d825cc6f178d7476f2c block 12168485 142 | 1096732850115699076508040790480850245475427575434 swaps for 853121275925315230082299135533471935483885881290 by providing 96275614981626761989464 1136986367848084728997482848992353010604574777643 and 158514665944799910801221 853121275925315230082299135533471935483885881290 with a change 0 fee 23092850000000000 ; 143 | // transaction 0xd0c7ce4270c77a4676c7814716fc163d13f4dcfff9adf35ae6cfcee6bebde191 block 12168486 144 | 575960215529994798650305948858572009465732389339 swaps for 853121275925315230082299135533471935483885881290 by providing 24829435173441403009714 1136986367848084728997482848992353010604574777643 and 40920595346088988906459 853121275925315230082299135533471935483885881290 with a change 0 fee 19323800000000000 ; 145 | // transaction 0x48870395a3acfb9e5325697ec4ccfb8044c6d036cc5b58a7f723d83c0d206f13 block 12168486 146 | 1396869218043499375274794049906232461077114976263 swaps for 853121275925315230082299135533471935483885881290 by providing 435627995244729976351 1136986367848084728997482848992353010604574777643 and 717084097934056941311 853121275925315230082299135533471935483885881290 with a change 0 fee 22288980000000000 ; 147 | // transaction 0x43892e789d5fdf8af6aae184e70de57492e947299ddd4571240af7de0748f9de block 12168487 148 | 1275329282750371442839269682382636549728298207507 swaps for 853121275925315230082299135533471935483885881290 by providing 120835001530556267466399 1136986367848084728997482848992353010604574777643 and 200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 35339958000000000 ; 149 | // transaction 0xa4c2577932da898ca7b6c4d90aa3c57751a53ee52ac38d8e41cc87a754b743fb block 12168487 150 | 132242830418859406665334485625386620194740193241 swaps for 853121275925315230082299135533471935483885881290 by providing 345225514759616716737078 1136986367848084728997482848992353010604574777643 and 570000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 88680564000000000 ; 151 | // transaction 0x56c370b3e6b0148172678aa7b6c34c23beddec99257bb63da4276bab4d40732f block 12168487 152 | 9684059395531886613116102915562525308755498520 swaps for 853121275925315230082299135533471935483885881290 by providing 6048491607690200305314 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 53069000000000000 ; 153 | // transaction 0x5637fb2722a7b296501a9fe98849675943abf753878d3f5ac60321e79c116534 block 12168488 154 | 1077551060927877730338406960899206225041163506286 swaps for 853121275925315230082299135533471935483885881290 by providing 20000000000000000000000 1136986367848084728997482848992353010604574777643 and 33066802831622595626225 853121275925315230082299135533471935483885881290 with a change 0 fee 22182006024729222 ; 155 | // transaction 0xa08b06486205a313133b1c23ea9d92ea990ad46692a4f26eafc12d25dfce3e24 block 12168488 156 | 627185636193690186778570194103547687436944325510 swaps for 853121275925315230082299135533471935483885881290 by providing 24201684894888368175846 1136986367848084728997482848992353010604574777643 and 40000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 22530549824727358 ; 157 | // transaction 0x39ac0926098186e89ac4a2df7131bab03024f0192681bc6ec950192eb87aa8e7 block 12168488 158 | 47187638473352512428481135386418767624286862285 swaps for 853121275925315230082299135533471935483885881290 by providing 7055599619060366309314 1136986367848084728997482848992353010604574777643 and 11590089701379843157431 853121275925315230082299135533471935483885881290 with a change 0 fee 34775445000000000 ; 159 | // transaction 0x7f08276cafb379676c875a86dbd7c0a75c2d29fc418f21a6fd08a733b94f133f block 12168488 160 | 806179005551030784639303346409776994294011187000 swaps for 853121275925315230082299135533471935483885881290 by providing 30237625669775727722817 1136986367848084728997482848992353010604574777643 and 50000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 22533097424730154 ; 161 | // transaction 0xfa922de45e195a2d1ed4aadc41b4a0a5d6a97faa3623929cffc6602fb26e4083 block 12168488 162 | 628587460936981243892932019428038008764474372787 swaps for 853121275925315230082299135533471935483885881290 by providing 6049747114791408506854 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 22182842024730154 ; 163 | // transaction 0x39ac0926098186e89ac4a2df7131bab03024f0192681bc6ec950192eb87aa8e7 block 12168488 164 | 47187638473352512428481135386418767624286862285 swaps for 853121275925315230082299135533471935483885881290 by providing 7055599619060366309314 1136986367848084728997482848992353010604574777643 and 11590089701379843157431 853121275925315230082299135533471935483885881290 with a change 0 fee 34775445000000000 ; 165 | // transaction 0x2e29a12791407d7e7694317d74420750ebeede17ea278d02d2be49a1c27d79b7 block 12168488 166 | 504567229221152618700786661809881738203832579647 swaps for 853121275925315230082299135533471935483885881290 by providing 23913481051466148752430 1136986367848084728997482848992353010604574777643 and 39519731305490193217903 853121275925315230082299135533471935483885881290 with a change 0 fee 23008694161060858 ; 167 | // transaction 0xbb8b6723b1e0466f52097cd34ed899a02bb350dcfeefcf447024bc7a87a61041 block 12168489 168 | 751785165147919810374404121359022263343591649525 swaps for 853121275925315230082299135533471935483885881290 by providing 6048825065412192467518 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 22602224000000000 ; 169 | // transaction 0x4e79e1fa15cbc917c5874dca373c36c3dcf22389add80b85d04e794834de126f block 12168489 170 | 916332897172970247063755967603346279758505074720 swaps for 853121275925315230082299135533471935483885881290 by providing 1814521911247644908166 1136986367848084728997482848992353010604574777643 and 3000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26210158000000000 ; 171 | // transaction 0xc961befe0f0e92547faa804b12d0f450d9e667355c0dc8d048295829b72e2b97 block 12168489 172 | 634765440242792942827168055992480995306379932332 swaps for 853121275925315230082299135533471935483885881290 by providing 6047988404218468828621 1136986367848084728997482848992353010604574777643 and 10000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 26216086000000000 ; 173 | // transaction 0xe1f396407b664a06ee374e026be951307ff98a84184d68c6c48a0eb3011dfd6e block 12168489 174 | 1299891068375644346709206500996814695680764470178 swaps for 853121275925315230082299135533471935483885881290 by providing 3824493963438735513083 1136986367848084728997482848992353010604574777643 and 6324516026215863341810 853121275925315230082299135533471935483885881290 with a change 0 fee 35449800000000000 ; 175 | // transaction 0xc9dd9468a9165c8f4d4cc39385326d39b9576923d00604063e9590f529d34979 block 12168489 176 | 1354375837468834729786242481266388281656159459022 swaps for 853121275925315230082299135533471935483885881290 by providing 9070840140101339741127 1136986367848084728997482848992353010604574777643 and 15000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 28830844000000000 ; 177 | // transaction 0x588f83ea4d7339ccc90c147e564660e3898517466a50af18f1a20f13d2b7f317 block 12168490 178 | 711218376118163577352205268749534927563644863334 swaps for 853121275925315230082299135533471935483885881290 by providing 8865560987708534323179 1136986367848084728997482848992353010604574777643 and 14983670752325702463874 853121275925315230082299135533471935483885881290 with a change 0 fee 24841908000000000 ; 179 | // transaction 0xa5a251a0d21b7ee78cbf6fe753fda9602f89d4050991714738f3fc2d271a34cb block 12168490 180 | 199693134660174125374602730100415995152402860850 swaps for 853121275925315230082299135533471935483885881290 by providing 1196636672938493049308311 1136986367848084728997482848992353010604574777643 and 2000000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 41410894000000000 ; 181 | // transaction 0x787ad61d17b3dcf61abf1d0e39b631baa19d68509f58ddd3a784e66d3e465061 block 12168490 182 | 969818967772646276632384458925270071707443621682 swaps for 853121275925315230082299135533471935483885881290 by providing 118277758349123661091659 1136986367848084728997482848992353010604574777643 and 200000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 36337800000000000 ; 183 | // transaction 0x7a46b8b47fa9f68925fadcf7518c47bf7e5f33627e974e3e1ead24dcc73345d1 block 12168493 184 | 80032731051468442569854268306908903181674702794 swaps for 853121275925315230082299135533471935483885881290 by providing 649676463729394807708 1136986367848084728997482848992353010604574777643 and 1095733108524672899585 853121275925315230082299135533471935483885881290 with a change 0 fee 29181074000000000 ; 185 | // transaction 0x058ac7348fc72c2cd47a3eced3e646aee91ecd1e3317bd9d71e0865f8abacb0b block 12168493 186 | 1356422588482975542881200915819705853476110926857 swaps for 853121275925315230082299135533471935483885881290 by providing 177731478276022788556767 1136986367848084728997482848992353010604574777643 and 300000000000000000000000 853121275925315230082299135533471935483885881290 with a change 0 fee 25717597428225154 ; 187 | --------------------------------------------------------------------------------