├── raw └── readme ├── acx ├── __init__.py ├── data │ ├── __init__.py │ ├── chains.py │ ├── chains.json │ ├── tokens.py │ └── tokens.json ├── abis │ ├── __init__.py │ ├── ERC20.json │ ├── v2SpokePool.json │ ├── SynapseBridge.json │ └── v2HubPool.json ├── utils.py └── thegraph.py ├── intermediate └── readme ├── requirements.txt ├── prices.py ├── makefile ├── README.md ├── .gitignore ├── lp_events.py ├── bt_final.py ├── combine_rewards.py ├── bt_cbridge.py ├── lp_cumulative.py ├── bridgoor_events.py ├── lp_exchange_rates.py ├── bridgoor_rewards.py ├── blocks.py ├── bt_combine.py ├── bt_rewards.py ├── bt_stargate.py ├── bridgoor_normalize.py ├── bt_hop.py ├── bt_synapse.py ├── lp_rewards.py └── parameters.yaml /raw/readme: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acx/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acx/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intermediate/readme: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas >= 1.0 2 | pyarrow 3 | pyaml-env 4 | web3 5 | -------------------------------------------------------------------------------- /acx/data/chains.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pkgutil 3 | 4 | 5 | # Load the chain list 6 | CHAINLIST = json.loads( 7 | pkgutil.get_data("acx.data", "chains.json") 8 | ) 9 | 10 | 11 | # 12 | # Use the chainlist to generate helpful mappings 13 | # 14 | ID_TO_NAME = { 15 | x["chainId"]: x["chainName"] for x in CHAINLIST 16 | } 17 | 18 | ID_TO_SHORTNAME = { 19 | x["chainId"]: x["shortName"] for x in CHAINLIST 20 | } 21 | 22 | SHORTNAME_TO_ID = { 23 | x["shortName"]: x["chainId"] for x in CHAINLIST 24 | } 25 | -------------------------------------------------------------------------------- /acx/data/chains.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"chainId": 1, "chainName": "mainnet", "shortName": "mainnet"}, 3 | {"chainId": 10, "chainName": "optimism-mainnet", "shortName": "optimism"}, 4 | {"chainId": 56, "chainName": "binance-mainnet", "shortName": "binance"}, 5 | {"chainId": 100, "chainName": "gnosis-mainnet", "shortName": "gnosis"}, 6 | {"chainId": 137, "chainName": "polygon-mainnet", "shortName": "polygon"}, 7 | {"chainId": 250, "chainName": "fantom-mainnet", "shortName": "fantom"}, 8 | {"chainId": 288, "chainName": "boba-mainnet", "shortName": "boba"}, 9 | {"chainId": 42161, "chainName": "arbitrum-one", "shortName": "arbitrum"}, 10 | {"chainId": 43114, "chainName": "avalanche-c-mainnet", "shortName": "avalanche"} 11 | ] 12 | -------------------------------------------------------------------------------- /acx/abis/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pkgutil 3 | 4 | 5 | # Mapping of ABI names to filenames 6 | ABIs = { 7 | "BridgePool": "v1BridgePool.json", 8 | "HubPool": "v2HubPool.json", 9 | "SpokePool": "v2SpokePool.json", 10 | "cBridge": "cBridge.json", 11 | "StargatePool": "StargatePool.json", 12 | "SynapseBridge": "SynapseBridge.json", 13 | "ERC20": "ERC20.json" 14 | } 15 | 16 | 17 | def getABI(x: str): 18 | """ 19 | Retrieve an ABI from the acx.abis folder using its contract name 20 | 21 | Available ABIs are: 22 | 23 | * "ERC20" 24 | * "BridgePool" 25 | * "HubPool" 26 | """ 27 | if x in ABIs.keys(): 28 | filename = ABIs[x] 29 | else: 30 | raise ValueError("Only certain ABIs available. Rtfd") 31 | 32 | return json.loads(pkgutil.get_data("acx.abis", filename)) 33 | -------------------------------------------------------------------------------- /acx/data/tokens.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pkgutil 3 | 4 | from acx.utils import createNewSubsetDict 5 | 6 | # Load the token list 7 | TOKENLIST = json.loads( 8 | pkgutil.get_data("acx.data", "tokens.json") 9 | ) 10 | 11 | # Make sure the keys are integers... JSON forces it to be a string 12 | # when stored 13 | for el in TOKENLIST: 14 | el["address"] = { 15 | int(k): v for k, v in el["address"].items() 16 | } 17 | 18 | # 19 | # Use the token list to generate helpful mappings 20 | # 21 | SYMBOL_TO_CGID = createNewSubsetDict("symbol", "cgId", TOKENLIST) 22 | SYMBOL_TO_DECIMALS = createNewSubsetDict("symbol", "decimals", TOKENLIST) 23 | SYMBOL_TO_CHAIN_TO_ADDRESS = createNewSubsetDict("symbol", "address", TOKENLIST) 24 | CHAIN_TO_ADDRESS_TO_SYMBOL = {} 25 | for el in TOKENLIST: 26 | _symbol = el["symbol"] 27 | _chain_to_address = el["address"] 28 | 29 | for (_chain, _address) in _chain_to_address.items(): 30 | subdict = CHAIN_TO_ADDRESS_TO_SYMBOL.get(_chain, dict()) 31 | subdict.update({_address: _symbol}) 32 | 33 | CHAIN_TO_ADDRESS_TO_SYMBOL[_chain] = subdict 34 | 35 | -------------------------------------------------------------------------------- /prices.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | import pandas as pd 3 | 4 | from pyaml_env import parse_config 5 | 6 | from acx.data.tokens import SYMBOL_TO_CGID 7 | from acx.utils import getWithRetries 8 | 9 | 10 | CG_BASE_URL = "https://api.coingecko.com/api/v3" 11 | 12 | 13 | def getCoinPriceHistory(_id, startDate, endDate): 14 | """ 15 | Retrieve historical data 16 | """ 17 | 18 | # Build request url 19 | req_url = f"{CG_BASE_URL}/coins/{_id}/market_chart/range" 20 | 21 | # Parameters 22 | params = { 23 | "vs_currency": "usd", 24 | "from": startDate.timestamp(), 25 | "to": endDate.timestamp() 26 | } 27 | res = getWithRetries(req_url, params=params) 28 | 29 | return res.json()["prices"] 30 | 31 | 32 | if __name__ == "__main__": 33 | # Load parameters 34 | params = parse_config("parameters.yaml") 35 | 36 | # Tokens that we want data for 37 | tokens = params["misc"]["price"]["tokens"] 38 | 39 | startDate = dt.datetime.utcfromtimestamp(params["misc"]["price"]["start_ts"]) 40 | endDate = dt.datetime.utcfromtimestamp(params["misc"]["price"]["end_ts"]) 41 | 42 | dfs = [] 43 | for token in tokens: 44 | # Get the Coingecko id 45 | cgid = SYMBOL_TO_CGID[token] 46 | 47 | prices = pd.DataFrame( 48 | getCoinPriceHistory(cgid, startDate, endDate), 49 | columns=["dt", "price"] 50 | ) 51 | prices["date"] = ( 52 | prices["dt"] 53 | .map(lambda x: dt.datetime.utcfromtimestamp(x/1000)) 54 | .dt.date 55 | ) 56 | prices["symbol"] = token 57 | 58 | dfs.append(prices.loc[:, ["date", "symbol", "price"]]) 59 | 60 | priceDf = pd.concat(dfs, axis=0) 61 | priceDf.to_json("raw/prices.json", orient="records") 62 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ## 2 | # ACX Airdrop 3 | # 4 | # @file 5 | # @version 0.1 6 | 7 | BLOCKS_FROM_SCRATCH=true 8 | EXCHANGERATES_FROM_SCRATCH=true 9 | PRICES_FROM_SCRATCH=true 10 | 11 | BRIDGOOR_FROM_SCRATCH=true 12 | LP_FROM_SCRATCH=true 13 | TRAVELER_FROM_SCRATCH=true 14 | 15 | all: blocks exchangerates prices bridgoor lp traveler 16 | python combine_rewards.py 17 | 18 | clean: 19 | cp raw/sybil.json sybil.json 20 | rm -rf raw/ 21 | mkdir raw 22 | mv sybil.json raw/sybil.json 23 | rm -rf intermediate 24 | mkdir intermediate 25 | rm -rf final 26 | mkdir final 27 | 28 | blocks: 29 | 30 | ifeq ($(BLOCKS_FROM_SCRATCH),true) 31 | @echo "Recompiling block-date data" 32 | python blocks.py 33 | endif 34 | 35 | exchangerates: 36 | 37 | ifeq ($(EXCHANGERATES_FROM_SCRATCH),true) 38 | @echo "Recompiling block-date data" 39 | python lp_exchange_rates.py 40 | endif 41 | 42 | prices: 43 | 44 | ifeq ($(PRICES_FROM_SCRATCH),true) 45 | @echo "Recompiling price data" 46 | python prices.py 47 | endif 48 | 49 | # Bridgoor rewards 50 | bridgoor: blocks prices 51 | @echo "Compiling bridgoor data" 52 | 53 | ifeq ($(BRIDGOOR_FROM_SCRATCH),true) 54 | @echo "Recompiling all bridgoor events" 55 | python bridgoor_events.py 56 | endif 57 | 58 | python bridgoor_normalize.py 59 | python bridgoor_rewards.py 60 | 61 | # LP rewards 62 | lp: blocks prices exchangerates 63 | 64 | ifeq ($(LP_FROM_SCRATCH),true) 65 | @echo "Recompiling all lp events" 66 | python lp_events.py 67 | endif 68 | 69 | python lp_cumulative.py 70 | python lp_rewards.py 71 | 72 | # Bridge traveler rewards 73 | traveler: blocks prices bridgoor lp 74 | 75 | ifeq ($(TRAVELER_FROM_SCRATCH),true) 76 | @echo "Recompiling all bridgoor events" 77 | python bt_cbridge.py 78 | python bt_hop.py 79 | python bt_stargate.py 80 | python bt_synapse.py 81 | endif 82 | 83 | python bt_combine.py 84 | python bt_rewards.py 85 | python bt_final.py 86 | 87 | # end 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Across Airdrop Qualifications 2 | 3 | This repository contains code used to generate the lists used for the Across airdrop. 4 | 5 | In order to run this code in its entirety, you will need access to a rpc node for mainnet, 6 | optimism, polygon, boba, and arbitrum. The LP portion only requires access to a rpc node 7 | for mainnet. However, for convenience (and to allow others to double check our work!), we have 8 | saved a list of the relevant event occurrences in the `raw` folder. 9 | 10 | The script will require the following variables to be defined in the `parameters.yaml` file: 11 | 12 | * `rpc_node.mainnet`: 13 | * `rpc_node.optimism`: 14 | * `rpc_node.polygon`: 15 | * `rpc_node.boba`: 16 | * `rpc_node.arbitrum`: 17 | 18 | For example, if your Infura project identifier were `iL0veACXt0k3nsTHAnky0u` then you might use the following settings: 19 | 20 | ``` 21 | rpc_node: 22 | mainnet: "https://mainnet.infura.io/v3/iL0veACXtok3nsThAnkY0u" 23 | optimism: "https://optimism-mainnet.infura.io/v3/iL0veACXtok3nsThAnkY0u" 24 | polygon: "https://polygon-mainnet.infura.io/v3/iL0veACXtok3nsThAnkY0u" 25 | boba: "https://lightning-replica.boba.network" 26 | arbitrum: "https://arbitrum-mainnet.infura.io/v3/iL0veACXtok3nsThAnkY0u" 27 | ``` 28 | 29 | as the rpc settings in your `parameters.yaml` file 30 | 31 | 32 | ## Bridgoors 33 | 34 | 15,000,000 ACX tokens will be distributed to individuals who have bridged using Across from 35 | November 8, 2021 (v1 launch) to July 18, 2022. 36 | 37 | In order to filter out noise, we have chosen to exclude transfers that fall below 38 | 39 | 40 | ## Liquidity Providers 41 | 42 | 65,000,000 ACX tokens will be distributed to liquidity providers who provided DAI, ETH/WETH, USDC, 43 | or WBTC to our liquidity pools. These distributions are pro-rated by (by USD equivalent size) and a 44 | fixed number of tokens will be emitted at each block since the inception of the protocol. 45 | 46 | (TODO: Describe what qualifies a liquidity provider for the airdrop) 47 | 48 | Liquidity providers 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | .ipynb_checkpoints/ 29 | 30 | __pycache__/ 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /lp_events.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | import web3 5 | 6 | from pyaml_env import parse_config 7 | 8 | from acx.abis import getABI 9 | from acx.data.tokens import SYMBOL_TO_CHAIN_TO_ADDRESS 10 | from acx.utils import findEvents 11 | 12 | 13 | if __name__ == "__main__": 14 | # Load parameters 15 | params = parse_config("parameters.yaml") 16 | nBlocks = params["lp"]["n_blocks"] 17 | 18 | # Connect to RPC node 19 | provider = web3.Web3.HTTPProvider( 20 | params["rpc_node"]["mainnet"], 21 | request_kwargs={"timeout": 60} 22 | ) 23 | w3 = web3.Web3(provider) 24 | 25 | # ------------------------------------- 26 | # V1 Liquidity Add/Remove 27 | # ------------------------------------- 28 | v1EndBlock = params["lp"]["v1_end_block"] 29 | 30 | v1Transfers = {} 31 | for token in params["lp"]["tokens"]: 32 | # Get information about specific BridgePool 33 | # NOTE: We have to start with `bridgeInfo["first_block"]` because 34 | # we need to track liquidity deposits/removals that occurred 35 | # prior to the first block we track for... 36 | bridgeInfo = params["across"]["v1"]["mainnet"]["bridge"][token] 37 | poolAddress = bridgeInfo["address"] 38 | v1FirstBlock = bridgeInfo["first_block"] 39 | v1EndBlock = params["lp"]["v1_end_block"] 40 | 41 | # Create BridgePool object 42 | pool = w3.eth.contract(address=poolAddress, abi=getABI("BridgePool")) 43 | 44 | # Track transfer events 45 | v1Transfers[token] = findEvents( 46 | w3, pool.events.Transfer, v1FirstBlock, v1EndBlock, 47 | nBlocks, {}, True 48 | ) 49 | 50 | with open("raw/v1Transfers.json", "w") as f: 51 | json.dump(v1Transfers, f) 52 | 53 | # ------------------------------------- 54 | # V2 Liquidity Add/Remove 55 | # ------------------------------------- 56 | hubInfo = params["across"]["v2"]["mainnet"]["hub"] 57 | v2FirstBlock = hubInfo["first_block"] 58 | v2EndBlock = params["lp"]["v2_end_block"] 59 | 60 | hub = w3.eth.contract(address=hubInfo["address"], abi=getABI("HubPool")) 61 | 62 | v2Transfers = {} 63 | for token in params["lp"]["tokens"]: 64 | lpTokenAddress = hub.functions.pooledTokens(SYMBOL_TO_CHAIN_TO_ADDRESS[token][1]).call()[0] 65 | lpToken = w3.eth.contract(address=lpTokenAddress, abi=getABI("ERC20")) 66 | 67 | v2Transfers[token] = findEvents( 68 | w3, lpToken.events.Transfer, v2FirstBlock, v2EndBlock, 69 | nBlocks, {}, True 70 | ) 71 | 72 | with open(f"raw/v2Transfers.json", "w") as f: 73 | json.dump(v2Transfers, f) 74 | -------------------------------------------------------------------------------- /bt_final.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | import web3 5 | 6 | from pyaml_env import parse_config 7 | 8 | 9 | if __name__ == "__main__": 10 | # Load parameters 11 | params = parse_config("parameters.yaml") 12 | 13 | # Reward parameters 14 | rewardLb = params["traveler"]["parameters"]["rewards"]["tokens_lb"] 15 | rewardUb = params["traveler"]["parameters"]["rewards"]["tokens_ub"] 16 | bonusThreshold = params["traveler"]["parameters"]["rewards"]["bonus_threshold"] 17 | clipThreshold = params["traveler"]["parameters"]["rewards"]["clip_threshold"] 18 | 19 | # Qualification parameters 20 | ethQual = params["traveler"]["parameters"]["qualification"]["eth"] 21 | usdcQual = params["traveler"]["parameters"]["qualification"]["usdc"] 22 | 23 | # Traveler blocks 24 | bridgoorStartBlock = params["bridgoor"]["v2_start_block"] 25 | travelStartBlock = params["traveler"]["travel_start_block"] 26 | travelEndBlock = params["traveler"]["travel_end_block"] 27 | 28 | # Qualified travelers 29 | travelerRewards = pd.DataFrame( 30 | pd.read_json("final/traveler_score.json", typ="series"), 31 | columns=["bridge-traveler"] 32 | ) 33 | travelers = travelerRewards.index 34 | 35 | # Read across transactions 36 | across = pd.read_json( 37 | "intermediate/allAcrossTransactions.json", 38 | orient="records" 39 | ) 40 | 41 | # Filter only transfers that can qualify for BT 42 | def filterTravelerTransfers(x): 43 | chainId = x["originChain"] 44 | 45 | travelerBlocks = ( 46 | (x["block"] >= bridgoorStartBlock[chainId]) & 47 | (x["block"] <= travelEndBlock[chainId]) & 48 | (x["version"] == 2) 49 | ) 50 | travelerQuantity = ( 51 | (x["symbol"] == "WETH") & (x["amount"] > ethQual) | 52 | (x["symbol"] == "USDC") & (x["amount"] > usdcQual) 53 | ) 54 | isTraveler = x["sender"] in travelers 55 | 56 | return travelerBlocks & travelerQuantity & isTraveler 57 | 58 | # Apply filter 59 | travelerRelevant = across.apply(filterTravelerTransfers, axis=1) 60 | travelerTransfers = across.loc[travelerRelevant, :] 61 | completedTravelers = travelerTransfers["sender"].unique() 62 | bridgeTravelers = travelerRewards.loc[completedTravelers] 63 | 64 | # Determine how many rewards will be distributed 65 | conversionRate = bridgeTravelers.size / travelers.size 66 | totalBtReward = ( 67 | rewardLb + 68 | (conversionRate > bonusThreshold)*(rewardUb - rewardLb) 69 | ) 70 | 71 | # Rescale everyone's share based on participation 72 | bridgeTravelers = bridgeTravelers / bridgeTravelers.sum() 73 | bridgeTravelers["airdrop"] = ( 74 | (bridgeTravelers * totalBtReward).clip(0.0, clipThreshold) 75 | ) 76 | 77 | bridgeTravelers["airdrop"].to_json("final/traveler_rewards.json") 78 | -------------------------------------------------------------------------------- /combine_rewards.py: -------------------------------------------------------------------------------- 1 | import decimal 2 | import json 3 | 4 | from decimal import Decimal 5 | 6 | import pandas as pd 7 | import web3 8 | 9 | 10 | bridgoor = pd.DataFrame( 11 | pd.read_json("final/bridgoor_rewards.json", typ="series"), 12 | columns=["bridgoor"] 13 | ) 14 | if bridgoor["bridgoor"].isna().any(): 15 | raise ValueError("Missing values in bridgoor data") 16 | 17 | lp = pd.DataFrame( 18 | pd.read_json("final/lp_rewards.json", typ="series"), 19 | columns=["lp"] 20 | ) 21 | if lp["lp"].isna().any(): 22 | raise ValueError("Missing values in lp data") 23 | 24 | travelers = pd.DataFrame( 25 | pd.read_json("final/traveler_rewards.json", typ="series"), 26 | columns=["bridge-traveler"] 27 | ) 28 | if travelers["bridge-traveler"].isna().any(): 29 | raise ValueError("Missing values in traveler data") 30 | 31 | community = pd.DataFrame( 32 | pd.read_json("final/community_rewards.json", typ="series"), 33 | columns=["community"] 34 | ) 35 | 36 | out = ( 37 | pd.DataFrame(travelers).join( 38 | [bridgoor, community, lp], how="outer" 39 | ) 40 | .fillna(0.0) 41 | ) 42 | out.index.name = "address" 43 | out.index = out.index.map(lambda x: web3.Web3.toChecksumAddress(x)) 44 | 45 | # Make sure no duplicates 46 | assert out.index.duplicated().sum() == 0 47 | 48 | # Convert everything to decimal types for more accurate/consistent computations 49 | out = out.applymap(lambda x: Decimal(x).quantize(Decimal("0.0000"))) 50 | 51 | # Format for mr 52 | mrout = {} 53 | mrout["recipients"] = [] 54 | 55 | # Metadata 56 | mrout["chainId"] = 1 57 | mrout["rewardToken"] = "" 58 | mrout["windowIndex"] = 0 59 | 60 | 61 | # Constant 1e18 for convenience 62 | zeros = Decimal(1e18) 63 | runningSum = Decimal(0) 64 | 65 | # Iterate through rows and compute total and save to merkle tree object 66 | def removeDecimals(x): 67 | return x.quantize(Decimal("0")) 68 | 69 | for (address, row) in out.iterrows(): 70 | 71 | # Add by hand because `.sum` converted to float 72 | totalDecimal = row["bridge-traveler"] + row["bridgoor"] + row["community"] + row["lp"] 73 | runningSum += totalDecimal*zeros 74 | out.at[address, "total"] = totalDecimal 75 | 76 | entry = { 77 | "account": address, 78 | "amount": str(removeDecimals(totalDecimal*zeros)), 79 | "metadata": { 80 | "amountBreakdown": { 81 | "communityRewards": str(removeDecimals(row["community"] * zeros)), 82 | "welcomeTravelerRewards": str(removeDecimals(row["bridge-traveler"] * zeros)), 83 | "earlyUserRewards": str(removeDecimals(row["bridgoor"] * zeros)), 84 | "liquidityProviderRewards": str(removeDecimals(row["lp"] * zeros)) 85 | } 86 | } 87 | } 88 | mrout["recipients"].append(entry) 89 | 90 | mrout["rewardsToDeposit"] = str(removeDecimals(runningSum)) 91 | 92 | out.to_json("final/final_combined.json", orient="index") 93 | out.to_csv("final/final_combined.csv") 94 | 95 | with open("final/mr.json", "w") as f: 96 | json.dump(mrout, f) 97 | -------------------------------------------------------------------------------- /bt_cbridge.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import web3 3 | 4 | from pyaml_env import parse_config 5 | 6 | from acx.abis import getABI 7 | from acx.data.chains import SHORTNAME_TO_ID 8 | from acx.data.tokens import ( 9 | CHAIN_TO_ADDRESS_TO_SYMBOL, SYMBOL_TO_CHAIN_TO_ADDRESS, SYMBOL_TO_DECIMALS 10 | ) 11 | from acx.utils import findEvents, scaleDecimals 12 | 13 | 14 | if __name__ == "__main__": 15 | # Load parameters 16 | params = parse_config("parameters.yaml") 17 | 18 | # Tokens to support 19 | SUPPORTED_CHAINS = params["traveler"]["cbridge"]["chains"] 20 | SUPPORTED_TOKENS = params["traveler"]["cbridge"]["tokens"] 21 | 22 | cbridgeRelays = [] 23 | for chain in SUPPORTED_CHAINS: 24 | chainId = SHORTNAME_TO_ID[chain] 25 | chainInfo = params["traveler"]["cbridge"]["contract_info"][chainId] 26 | 27 | # Web 3 instance for particular chain 28 | provider = web3.Web3.HTTPProvider( 29 | params["rpc_node"][chain], 30 | request_kwargs={"timeout": 60} 31 | ) 32 | w3 = web3.Web3(provider) 33 | 34 | # Create the cBridge bridge 35 | bridgeAddress = chainInfo["address"] 36 | bridge = w3.eth.contract( 37 | address=bridgeAddress, abi=getABI("cBridge") 38 | ) 39 | 40 | # Get first, last block, and number of blocks to query at once 41 | fb = chainInfo["first_block"] 42 | lb = chainInfo["last_block"] 43 | nBlocks = params["traveler"]["n_blocks"][chainId] 44 | 45 | # Find token addresses that we might be interested in 46 | wantedTokenAddresses = [] 47 | for token in SUPPORTED_TOKENS: 48 | if chainId in SYMBOL_TO_CHAIN_TO_ADDRESS[token].keys(): 49 | wantedTokenAddresses.append( 50 | SYMBOL_TO_CHAIN_TO_ADDRESS[token][chainId] 51 | ) 52 | 53 | relays = findEvents( 54 | w3, bridge.events.Relay, fb, lb, 55 | nBlocks, {}, True 56 | ) 57 | 58 | out = [] 59 | for relay in relays: 60 | relayArgs = relay["args"] 61 | 62 | # Skip tokens that aren't in our "tokens universe" 63 | tokenAddress = relayArgs["token"] 64 | if tokenAddress not in wantedTokenAddresses: 65 | continue 66 | 67 | symbol = CHAIN_TO_ADDRESS_TO_SYMBOL[chainId][tokenAddress] 68 | decimals = SYMBOL_TO_DECIMALS[symbol] 69 | 70 | # Save row by row 71 | row = {} 72 | 73 | row["block"] = relay["blockNumber"] 74 | row["tx"] = relay["transactionHash"] 75 | row["originChainId"] = relayArgs["srcChainId"] 76 | row["destinationChainId"] = chainId 77 | row["transferId"] = relayArgs["transferId"] 78 | row["sender"] = relayArgs["sender"] 79 | row["receiver"] = relayArgs["receiver"] 80 | row["symbol"] = symbol 81 | row["amount"] = scaleDecimals(relayArgs["amount"], decimals) 82 | 83 | out.append(row) 84 | chainDf = pd.DataFrame(out) 85 | cbridgeRelays.append(chainDf) 86 | 87 | df = pd.concat(cbridgeRelays, axis=0, ignore_index=True) 88 | df.to_parquet("raw/cbridge_transfers.parquet") 89 | -------------------------------------------------------------------------------- /lp_cumulative.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | 5 | from pyaml_env import parse_config 6 | 7 | from acx.data.tokens import SYMBOL_TO_DECIMALS 8 | from acx.utils import scaleDecimals 9 | 10 | 11 | def processTransfers(lpTransfers, version=1): 12 | """ 13 | Helper to process transfers and store in an LP friendly format 14 | """ 15 | out = [] 16 | for token in lpTransfers.keys(): 17 | decimals = SYMBOL_TO_DECIMALS[token] 18 | 19 | for transfer in lpTransfers[token]: 20 | args = transfer["args"] 21 | 22 | for dest in ["to", "from"]: 23 | # Person that transfer is to is increasing their LP position while 24 | # the person it is from is decreasing their LP position 25 | sign = 1 if dest == "to" else -1 26 | row = { 27 | "block": transfer["blockNumber"], 28 | "tx": transfer["transactionHash"], 29 | "lp": args[dest], 30 | "symbol": token, 31 | "amount": sign * scaleDecimals(args["value"], decimals), 32 | } 33 | out.append(row) 34 | 35 | return out 36 | 37 | 38 | if __name__ == "__main__": 39 | # Load parameters 40 | params = parse_config("parameters.yaml") 41 | 42 | # Get start/end blocks for LP rewards 43 | v1StartBlock = params["lp"]["v1_start_block"] 44 | v1EndBlock = params["lp"]["v1_end_block"] 45 | 46 | v2StartBlock = params["lp"]["v2_start_block"] 47 | v2EndBlock = params["lp"]["v2_end_block"] 48 | 49 | # Load raw data 50 | with open("raw/v1Transfers.json", "r") as f: 51 | v1TransfersRaw = json.loads(f.read()) 52 | v1Transfers = pd.DataFrame(processTransfers(v1TransfersRaw, 1)) 53 | 54 | with open("raw/v2Transfers.json", "r") as f: 55 | v2TransfersRaw = json.loads(f.read()) 56 | v2Transfers = pd.DataFrame(processTransfers(v2TransfersRaw, 2)) 57 | 58 | # Get all blocks and LPs -- We will exclude the 0x0 address since it 59 | # isn't a real LP and is just used in minting/burning 60 | allLps = list( 61 | set(v1Transfers["lp"].unique()) 62 | .union(set(v2Transfers["lp"].unique())) 63 | .difference(set(["0x0000000000000000000000000000000000000000"])) 64 | ) 65 | allTokens = params["lp"]["tokens"] 66 | newIndex = pd.MultiIndex.from_product([allTokens, allLps]) 67 | 68 | # Cumulative totals 69 | for version in [1, 2]: 70 | if version == 1: 71 | _df = v1Transfers 72 | startBlock, endBlock = v1StartBlock, v1EndBlock 73 | elif version == 2: 74 | _df = v2Transfers 75 | startBlock, endBlock = v2StartBlock, v2EndBlock 76 | else: 77 | raise ValueError("Version must be 1 or 2") 78 | 79 | data = ( 80 | _df 81 | .pivot_table( 82 | index="block", columns=["symbol", "lp"], values="amount", 83 | aggfunc="sum" 84 | ) 85 | .fillna(0.0) 86 | .reindex(columns=newIndex, fill_value=0.0) 87 | .sort_index() 88 | .cumsum() 89 | ) 90 | data.to_parquet(f"intermediate/v{version}CumulativeLp.parquet") 91 | -------------------------------------------------------------------------------- /bridgoor_events.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | import web3 5 | 6 | from pyaml_env import parse_config 7 | 8 | from acx.abis import getABI 9 | from acx.data.tokens import SYMBOL_TO_CHAIN_TO_ADDRESS 10 | from acx.utils import findEvents 11 | 12 | 13 | if __name__ == "__main__": 14 | # Load parameters 15 | params = parse_config("parameters.yaml") 16 | nBlocks = params["bridgoor"]["n_blocks"] 17 | 18 | # 19 | # V1 bridges 20 | # 21 | provider = web3.Web3.HTTPProvider( 22 | params["rpc_node"]["mainnet"], 23 | request_kwargs={"timeout": 60} 24 | ) 25 | w3 = web3.Web3(provider) 26 | 27 | v1StartBlock = params["bridgoor"]["v1_start_block"] 28 | v1EndBlock = params["bridgoor"]["v1_end_block"] 29 | 30 | # Iterate through each of the relevant pools 31 | # All v1 transfers are L2->L1 so we can only look at relays on L1 32 | v1Disputes = {} 33 | v1Relays = {} 34 | for token in params["bridgoor"]["tokens"]: 35 | # Get information about specific BridgePool 36 | bridgeInfo = params["across"]["v1"]["mainnet"]["bridge"][token] 37 | poolAddress = bridgeInfo["address"] 38 | 39 | # Create BridgePool object 40 | pool = w3.eth.contract(address=poolAddress, abi=getABI("BridgePool")) 41 | 42 | # Collect dispute information so they can be excluded 43 | v1Disputes[token] = findEvents( 44 | w3, pool.events.RelayDisputed, v1StartBlock, v1EndBlock, 45 | nBlocks[w3.eth.chainId], {}, True 46 | ) 47 | 48 | v1Relays[token] = findEvents( 49 | w3, pool.events.DepositRelayed, v1StartBlock, v1EndBlock, 50 | nBlocks[w3.eth.chainId], {}, True 51 | ) 52 | 53 | with open("raw/v1DisputedRelays.json", "w") as f: 54 | json.dump(v1Disputes, f) 55 | with open("raw/v1Relays.json", "w") as f: 56 | json.dump(v1Relays, f) 57 | 58 | 59 | # 60 | # V2 bridges 61 | # 62 | v2Deposits = [] 63 | for chain in params["bridgoor"]["chains"]: 64 | # No longer only L2->L1 so we need to retrieve data from each 65 | # chain 66 | provider = web3.Web3.HTTPProvider( 67 | params["rpc_node"][chain], 68 | request_kwargs={"timeout": 60} 69 | ) 70 | w3 = web3.Web3(provider) 71 | chainId = w3.eth.chainId 72 | 73 | # Create that chain's spoke pool 74 | spokeInfo = params["across"]["v2"][chain]["spoke"] 75 | spokeAddress = spokeInfo["address"] 76 | spoke = w3.eth.contract(address=spokeAddress, abi=getABI("SpokePool")) 77 | 78 | # Get token addresses that qualify 79 | addresses = [ 80 | SYMBOL_TO_CHAIN_TO_ADDRESS[token][chainId] 81 | for token in params["bridgoor"]["tokens"] 82 | ] 83 | 84 | # Get start block for qualifying 85 | v2StartBlock = params["bridgoor"]["v2_start_block"][chainId] 86 | 87 | # Collect data throughout end of BT (we'll need this for traveler) 88 | v2EndBlock = params["traveler"]["travel_end_block"][chainId] 89 | 90 | # Retrieve deposits 91 | deposits = findEvents( 92 | w3, spoke.events.FundsDeposited, v2StartBlock, v2EndBlock, 93 | nBlocks[w3.eth.chainId], {"originToken": addresses}, True 94 | ) 95 | v2Deposits.extend(deposits) 96 | 97 | with open("raw/v2Deposits.json", "w") as f: 98 | json.dump(v2Deposits, f) 99 | -------------------------------------------------------------------------------- /lp_exchange_rates.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | import web3 5 | 6 | from pyaml_env import parse_config 7 | 8 | from acx.abis import getABI 9 | from acx.data.tokens import SYMBOL_TO_CHAIN_TO_ADDRESS 10 | from acx.utils import scaleDecimals 11 | 12 | 13 | if __name__ == "__main__": 14 | # Load parameters 15 | params = parse_config("parameters.yaml") 16 | 17 | # Connect to RPC node 18 | provider = web3.Web3.HTTPProvider( 19 | params["rpc_node"]["mainnet"], 20 | request_kwargs={"timeout": 60} 21 | ) 22 | w3 = web3.Web3(provider) 23 | 24 | # Load block data 25 | BLOCKSTODATE = ( 26 | pd.read_json("raw/blocks.json", orient="records") 27 | .query("chainId == 1") 28 | .sort_values("block") 29 | .loc[:, ["block", "date"]] 30 | ) 31 | 32 | # Create the hub once up front 33 | hubInfo = params["across"]["v2"]["mainnet"]["hub"] 34 | hub = w3.eth.contract(address=hubInfo["address"], abi=getABI("HubPool")) 35 | 36 | # Block bounds -- v1 start block will depend on the pool so it 37 | # will be retrieved in the loop 38 | v2EndBlock = params["lp"]["v2_end_block"] 39 | v1EndBlock = params["lp"]["v1_end_block"] 40 | 41 | # ------------------------------------- 42 | # Compute exchange rates 43 | # ------------------------------------- 44 | v1ExchangeRates = [] 45 | v2ExchangeRates = [] 46 | for token in params["lp"]["tokens"]: 47 | # Create the v1 pool 48 | bridgeInfo = params["across"]["v1"]["mainnet"]["bridge"][token] 49 | poolAddress = bridgeInfo["address"] 50 | pool = w3.eth.contract(address=poolAddress, abi=getABI("BridgePool")) 51 | 52 | # Get the v1 first block 53 | v1FirstBlock = bridgeInfo["first_block"] 54 | 55 | # Iterate through each date to get exchange rates 56 | tokenErs = [] 57 | for row in BLOCKSTODATE.itertuples(): 58 | _date, _block = row.date, row.block 59 | print(f"{token} exchange rate for {_date}") 60 | 61 | # V1 exchange rate 62 | if (_block < v1FirstBlock) | (_block > v1EndBlock): 63 | v1Er = 0.0 64 | else: 65 | v1Er = scaleDecimals( 66 | pool.functions.exchangeRateCurrent().call(block_identifier=_block), 18 67 | ) 68 | 69 | v1Row = { 70 | "date": _date.strftime("%Y-%m-%d"), 71 | "block": _block, 72 | "symbol": token, 73 | "exchangeRate": v1Er 74 | } 75 | v1ExchangeRates.append(v1Row) 76 | 77 | # V2 exchange rate 78 | v2FirstBlock = params["lp"]["v2_lp_token_creation_block"][token] 79 | if (_block < v2FirstBlock) or (_block > v2EndBlock): 80 | v2Er = 0.0 81 | else: 82 | v2Er = scaleDecimals( 83 | hub.functions.exchangeRateCurrent( 84 | SYMBOL_TO_CHAIN_TO_ADDRESS[token][1] 85 | ).call(block_identifier=_block), 18 86 | ) 87 | 88 | v2Row = { 89 | "date": _date.strftime("%Y-%m-%d"), 90 | "block": _block, 91 | "symbol": token, 92 | "exchangeRate": v2Er 93 | } 94 | v2ExchangeRates.append(v2Row) 95 | 96 | with open("raw/v1ExchangeRates.json", "w") as f: 97 | json.dump(v1ExchangeRates, f) 98 | 99 | with open(f"raw/v2ExchangeRates.json", "w") as f: 100 | json.dump(v2ExchangeRates, f) 101 | 102 | -------------------------------------------------------------------------------- /bridgoor_rewards.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import numpy as np 4 | import pandas as pd 5 | 6 | from pyaml_env import parse_config 7 | 8 | from acx.data.chains import SHORTNAME_TO_ID 9 | from acx.utils import cutAndPowerScore 10 | 11 | 12 | 13 | if __name__ == "__main__": 14 | # Load parameters 15 | params = parse_config("parameters.yaml") 16 | 17 | # Create block to date lookup function 18 | blocks = pd.read_json("raw/blocks.json", orient="records") 19 | 20 | blockLookup = {} 21 | for chain in params["bridgoor"]["chains"]: 22 | chainId = SHORTNAME_TO_ID[chain] 23 | 24 | blockToDate = blocks.query("chainId == @chainId").sort_values("block") 25 | _block = blockToDate["block"].to_numpy() 26 | _date = blockToDate["date"].to_numpy() 27 | 28 | blockLookup[chainId] = {"blocks": _block, "dates": _date} 29 | 30 | 31 | def determineDate(x): 32 | chainId = 1 if x["version"] == 1 else x["originChain"] 33 | 34 | bl = blockLookup[chainId] 35 | 36 | _idx = np.searchsorted(bl["blocks"], x["block"]) 37 | _date = bl["dates"][_idx] 38 | 39 | return _date 40 | 41 | # Inclusion parameters 42 | transferCount = params["bridgoor"]["parameters"]["inclusion"]["transfer_count"] 43 | transferCountVol = params["bridgoor"]["parameters"]["inclusion"]["transfer_count_volume"] 44 | volumeInclusion = params["bridgoor"]["parameters"]["inclusion"]["volume_inclusion"] 45 | 46 | # Score parameters 47 | power = params["bridgoor"]["parameters"]["score"]["power"] 48 | ub = params["bridgoor"]["parameters"]["score"]["ub"] 49 | 50 | totalACX = params["bridgoor"]["parameters"]["total_rewards"] 51 | 52 | # Load bridge data 53 | bridgeData = pd.read_json( 54 | "intermediate/bridgoorTransactions.json", orient="records" 55 | ) 56 | bridgeData["date"] = bridgeData.apply(determineDate, axis=1) 57 | 58 | # Load prices data 59 | prices = ( 60 | pd.read_json("raw/prices.json", orient="records") 61 | .set_index(["date", "symbol"]) 62 | ) 63 | 64 | # Combine bridge and price data 65 | bridgesWPrices = bridgeData.merge( 66 | prices, left_on=["date", "symbol"], right_on=["date", "symbol"], 67 | how="left" 68 | ) 69 | bridgesWPrices["amountUSD"] = bridgesWPrices.eval("price * amount") 70 | 71 | # Make sure we have prices for all observations 72 | if bridgesWPrices["price"].isna().any(): 73 | raise ValueError("Missing prices and cannot compute bridgoor rewards") 74 | 75 | # Get transaction count and volume 76 | bridgoors = ( 77 | bridgesWPrices 78 | .groupby("recipient") 79 | .agg( 80 | { 81 | "tx": "count", 82 | "amountUSD": "sum", 83 | } 84 | ) 85 | .rename( 86 | columns={ 87 | "tx": "nTransfers", 88 | "amountUSD": "totalVolume" 89 | } 90 | ) 91 | .reset_index() 92 | ) 93 | 94 | # Only users that meet criteria specified included in score 95 | bridgoors = bridgoors.query( 96 | "(totalVolume > @volumeInclusion) |" + 97 | "((nTransfers >= @transferCount) & (totalVolume > @transferCountVol))" 98 | ) 99 | bridgoors["score"] = cutAndPowerScore( 100 | bridgoors["totalVolume"], 0.0, ub, power 101 | ) 102 | bridgoors["acx"] = bridgoors.eval("score * @totalACX") 103 | 104 | out = bridgoors.set_index("recipient")["acx"].to_dict() 105 | with open("final/bridgoor_rewards.json", "w") as f: 106 | json.dump(out, f) 107 | -------------------------------------------------------------------------------- /blocks.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | import json 3 | import time 4 | 5 | from pyaml_env import parse_config 6 | 7 | from acx.data.chains import SHORTNAME_TO_ID 8 | from acx.utils import getWithRetries 9 | 10 | 11 | CHAIN_TO_URL = { 12 | # ETHERSCAN 13 | 1: "https://api.etherscan.io/api", 14 | # OPTIMISTIC ETHERSCAN 15 | 10: "https://api-optimistic.etherscan.io/api", 16 | # POLYGONSCAN 17 | 137: "https://api.polygonscan.com/api", 18 | # BOBASCAN 19 | 288: "https://api.bobascan.com/api", 20 | # ARBISCAN 21 | 42161: "https://api.arbiscan.io/api" 22 | } 23 | 24 | 25 | def findMostRecentBlockAfterTs(ts: int, chainId: int=1, key=""): 26 | """ 27 | Finds the most recent block that occurs after a particular UTC 28 | timestamp 29 | 30 | This requires that the `action=getblocknobytime` api command is 31 | defined 32 | 33 | Parameters 34 | ---------- 35 | ts : int 36 | The timestamp that we want to find the block after 37 | chainId : int 38 | The identifier for the chain of interest 39 | """ 40 | apiurl = CHAIN_TO_URL[chainId] 41 | 42 | params = { 43 | "module": "block", 44 | "action": "getblocknobytime", 45 | "closest": "after", 46 | "timestamp": ts, 47 | "apikey": key 48 | } 49 | res = getWithRetries(apiurl, params=params, backoffFactor=1.5, preSleep=0.5) 50 | 51 | if res.json()["status"] == "1": 52 | return int(res.json()["result"]) 53 | else: 54 | print(res.json()) 55 | raise ValueError("Failed to find block") 56 | 57 | 58 | if __name__ == "__main__": 59 | # Load parameters 60 | params = parse_config("parameters.yaml") 61 | 62 | # Find relevant blocks for all chains 63 | blockData = [] 64 | for chain in params["misc"]["block"]["chains"]: 65 | print(f"Starting on chain: {chain}") 66 | 67 | # Get chain id and scan api key 68 | chainId = SHORTNAME_TO_ID[chain] 69 | someScanKey = params["etherscan_keys"][chain] 70 | 71 | 72 | # Get timestamps to start searching for 73 | if chain == "mainnet": 74 | blockStartTs = params["misc"]["block"]["start_ts_mainnet"] 75 | else: 76 | blockStartTs = params["misc"]["block"]["start_ts_nonmainnet"] 77 | blockEndTs = params["misc"]["block"]["end_ts"] 78 | 79 | # Get the block number for each day between (blockStartTs, blockEndTs) 80 | dateStarts = range(blockStartTs, blockEndTs+1, 24*60*60) 81 | for _ts in dateStarts: 82 | # Optimism - June 1, 2022 83 | if (_ts == 1654041600) and (chain == "optimism"): 84 | block = 9621060 85 | # Optimism June 2, 2022 86 | elif (_ts == 1654128000) and (chain == "optimism"): 87 | block = 10108895 88 | # Optimism - August 6, 2022 89 | elif (_ts == 1659744000) and (chain == "optimism"): 90 | block = 17974360 91 | # Boba - March 6, 2022 92 | elif (_ts == 1646524800) and (chain == "boba"): 93 | block = 382645 94 | else: 95 | block = findMostRecentBlockAfterTs(_ts, chainId, key=someScanKey) 96 | 97 | row = { 98 | "chain": chain, 99 | "chainId": chainId, 100 | "date": dt.datetime.utcfromtimestamp(_ts).strftime("%Y-%m-%dT00:00"), 101 | "block": block 102 | } 103 | blockData.append(row) 104 | print(row) 105 | 106 | with open("raw/blocks.json", "w") as f: 107 | json.dump(blockData, f) 108 | -------------------------------------------------------------------------------- /bt_combine.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | 3 | import numpy as np 4 | import pandas as pd 5 | import web3 6 | 7 | from pyaml_env import parse_config 8 | 9 | from acx.data.chains import SHORTNAME_TO_ID 10 | 11 | 12 | if __name__ == "__main__": 13 | # Load parameters 14 | params = parse_config("parameters.yaml") 15 | 16 | # Create block to date lookup function 17 | blocks = pd.read_json("raw/blocks.json", orient="records") 18 | 19 | blockLookup = {} 20 | for chain in params["traveler"]["chains"]: 21 | chainId = SHORTNAME_TO_ID[chain] 22 | 23 | blockToDate = blocks.query("chainId == @chainId").sort_values("block") 24 | _block = blockToDate["block"].to_numpy() 25 | _date = blockToDate["date"].to_numpy() 26 | 27 | blockLookup[chainId] = {"blocks": _block, "dates": _date} 28 | 29 | 30 | def determineDate(x): 31 | chainId = x["chainId"] 32 | 33 | bl = blockLookup[chainId] 34 | 35 | _idx = np.searchsorted(bl["blocks"], x["blockNumber"], side="right") 36 | _date = bl["dates"][_idx] 37 | 38 | return _date 39 | 40 | # Load data from each and transform to a common format 41 | cbridge = ( 42 | pd.read_parquet("raw/cbridge_transfers.parquet") 43 | .rename( 44 | columns={ 45 | "block": "blockNumber", 46 | "receiver": "traveler", 47 | "destinationChainId": "chainId" 48 | } 49 | ) 50 | .loc[:, ["chainId", "blockNumber", "tx", "traveler", "symbol", "amount"]] 51 | ) 52 | cbridge["date"] = cbridge.apply(determineDate, axis=1) 53 | 54 | hop = ( 55 | pd.read_parquet("raw/hop_transfers.parquet") 56 | .rename( 57 | columns={ 58 | "originChainId": "chainId", 59 | "recipient": "traveler", 60 | } 61 | ) 62 | .loc[:, ["chainId", "blockNumber", "tx", "traveler", "symbol", "amount", "timestamp"]] 63 | ) 64 | hop["date"] = hop["timestamp"].map( 65 | lambda x: dt.datetime.utcfromtimestamp(x).replace( 66 | hour=0, 67 | minute=0, 68 | second=0, 69 | ) 70 | ) 71 | hop = hop.drop(["timestamp"], axis="columns") 72 | 73 | stg = ( 74 | pd.read_parquet("raw/stg_transfers.parquet") 75 | .rename( 76 | columns={ 77 | "block": "blockNumber", 78 | "destinationChainId": "chainId", 79 | "to": "traveler" 80 | } 81 | ) 82 | .loc[:, ["chainId", "blockNumber", "tx", "traveler", "symbol", "amount"]] 83 | ) 84 | stg["date"] = stg.apply(determineDate, axis=1) 85 | 86 | syn = ( 87 | pd.read_parquet("raw/synapse_transfers.parquet") 88 | .rename( 89 | columns={ 90 | "block": "blockNumber", 91 | "recipient": "traveler", 92 | } 93 | ) 94 | .loc[:, ["chainId", "blockNumber", "tx", "traveler", "symbol", "amount"]] 95 | ) 96 | syn["date"] = syn.apply(determineDate, axis=1) 97 | 98 | # Stack normalized data together 99 | df = pd.concat([cbridge, hop, stg, syn], axis=0, ignore_index=True) 100 | 101 | # Make sure all addresses are checksum 102 | df["traveler"] = df["traveler"].map(web3.Web3.toChecksumAddress) 103 | 104 | # Convert less common symbols to more common counterparts 105 | df["symbol"] = df["symbol"].replace( 106 | { 107 | "SGETH": "WETH", 108 | "nETH": "WETH", 109 | "nUSD": "UDSC" 110 | } 111 | ) 112 | 113 | df.sort_values("date").to_parquet("intermediate/travelerTransfers.parquet") 114 | -------------------------------------------------------------------------------- /bt_rewards.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | import web3 5 | 6 | from pyaml_env import parse_config 7 | 8 | from acx.utils import cutAndPowerScore 9 | 10 | 11 | if __name__ == "__main__": 12 | # Load parameters 13 | params = parse_config("parameters.yaml") 14 | 15 | # Inclusion parameters 16 | transferCount = params["traveler"]["parameters"]["inclusion"]["transfer_count"] 17 | transferCountVol = params["traveler"]["parameters"]["inclusion"]["transfer_count_volume"] 18 | volumeInclusion = params["traveler"]["parameters"]["inclusion"]["volume_inclusion"] 19 | 20 | # Score parameters 21 | power = params["traveler"]["parameters"]["score"]["power"] 22 | ub = params["traveler"]["parameters"]["score"]["ub"] 23 | 24 | travelStartBlock = params["traveler"]["travel_start_block"] 25 | travelEndBlock = params["traveler"]["travel_end_block"] 26 | 27 | # Read all transfers that occurred on other bridges 28 | df = pd.read_parquet("intermediate/travelerTransfers.parquet") 29 | 30 | # Load prices and merge into dataframe 31 | prices = ( 32 | pd.read_json("raw/prices.json", orient="records") 33 | .set_index(["date", "symbol"]) 34 | ) 35 | df = df.merge( 36 | prices, left_on=["date", "symbol"], right_index=True, how="left" 37 | ) 38 | df["amountUSD"] = df.eval("price * amount") 39 | 40 | # Load Across transfers 41 | acrossAddresses = ( 42 | pd.read_json("intermediate/bridgoorTransactions.json", orient="records") 43 | ["recipient"] 44 | .unique() 45 | ) 46 | acrossAddresses = list(map(web3.Web3.toChecksumAddress, acrossAddresses)) 47 | 48 | # Filter out any users that have used Across already 49 | df = df.query("traveler not in @acrossAddresses") 50 | 51 | # Load Across LPs -- Only look at pre-traveler LPs for exclusion 52 | originalLpCutoff = 15_649_594 53 | v1LpPositions = ( 54 | pd.read_parquet("intermediate/v1CumulativeLp.parquet") 55 | .loc[:originalLpCutoff, :] 56 | .max() 57 | > 1e-18 58 | ) 59 | v2LpPositions = ( 60 | pd.read_parquet("intermediate/v2CumulativeLp.parquet") 61 | .loc[:originalLpCutoff, :] 62 | .max() 63 | > 1e-18 64 | ) 65 | 66 | acrossLps = list( 67 | set(v1LpPositions.index[v1LpPositions].get_level_values(1).unique()) 68 | .union(v2LpPositions.index[v2LpPositions].get_level_values(1).unique()) 69 | ) 70 | 71 | # Filter out any users that have LP'd for Across (prior to BT) 72 | df = df.query("traveler not in @acrossLps") 73 | 74 | # Filter out users who have been identified as sybil 75 | with open("raw/sybil.json", "r") as f: 76 | sybils = json.loads(f.read()) 77 | df = df.query("traveler not in @sybils") 78 | 79 | # Now we can aggregate and calculate scores 80 | travelers = ( 81 | df.groupby("traveler") 82 | .agg( 83 | { 84 | "tx": "count", 85 | "amountUSD": "sum" 86 | } 87 | ) 88 | .rename(columns={ 89 | "tx": "nTransfers", 90 | "amountUSD": "totalVolume" 91 | }) 92 | ) 93 | 94 | # Filter to only include bridgoors who met qualifications 95 | query_statement = "(nTransfers >= @transferCount & totalVolume >= @transferCountVol) |" 96 | query_statement += "(totalVolume >= @volumeInclusion)" 97 | travelers = travelers.query(query_statement) 98 | 99 | travelers["score"] = cutAndPowerScore( 100 | travelers["totalVolume"], 0.0, ub, power 101 | ) 102 | 103 | # Save output 104 | travelers = travelers.sort_values("totalVolume", ascending=False) 105 | (100 * travelers["score"]).to_json("final/traveler_score.json") 106 | -------------------------------------------------------------------------------- /bt_stargate.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import web3 3 | 4 | from pyaml_env import parse_config 5 | 6 | from acx.abis import getABI 7 | from acx.data.chains import SHORTNAME_TO_ID 8 | from acx.data.tokens import CHAIN_TO_ADDRESS_TO_SYMBOL, SYMBOL_TO_DECIMALS 9 | from acx.utils import findEvents, scaleDecimals 10 | 11 | 12 | def retrieveSwapRemotes(w3, pool, startBlock, lastBlock, nBlocks): 13 | """ 14 | Collect data about the `SwapRemote` events from the Stargate Pool 15 | contracts 16 | 17 | Parameters 18 | ---------- 19 | w3 : web3.Web3 20 | A web3 object 21 | pool : web3.Contract 22 | A web3 23 | start_block : int 24 | The starting block to collect 25 | last_block : int 26 | The ending block (inclusive) 27 | 28 | Returns 29 | ------- 30 | df : pd.DataFrame 31 | A DataFrame with all of the pool data for relevant time period 32 | """ 33 | # Meta data about the pool 34 | chainId = w3.eth.chainId 35 | tokenAddress = pool.functions.token().call() 36 | 37 | # Check whether we have data on this chainId/token address combo 38 | assert chainId in CHAIN_TO_ADDRESS_TO_SYMBOL.keys() 39 | assert tokenAddress in CHAIN_TO_ADDRESS_TO_SYMBOL[chainId].keys() 40 | 41 | # If they are, then we can proceed -- Otherwise we will error out 42 | # with an assertion error 43 | symbol = CHAIN_TO_ADDRESS_TO_SYMBOL[chainId][tokenAddress] 44 | decimals = SYMBOL_TO_DECIMALS[symbol] 45 | 46 | # Collect swap data 47 | swaps = findEvents( 48 | w3, pool.events.SwapRemote, startBlock, lastBlock, 49 | nBlocks, {}, True 50 | ) 51 | 52 | out = [] 53 | for swap in swaps: 54 | swapArgs = swap["args"] 55 | 56 | # Save row by row 57 | row = {} 58 | 59 | row["block"] = swap["blockNumber"] 60 | row["tx"] = swap["transactionHash"] 61 | row["destinationChainId"] = chainId 62 | row["to"] = swapArgs["to"] 63 | row["symbol"] = symbol 64 | row["amount"] = scaleDecimals(swapArgs["amountSD"], decimals) 65 | 66 | out.append(row) 67 | 68 | return out 69 | 70 | 71 | if __name__ == "__main__": 72 | # Load parameters 73 | params = parse_config("parameters.yaml") 74 | 75 | SUPPORTED_CHAINS = params["traveler"]["stg"]["chains"] 76 | SUPPORTED_TOKENS = params["traveler"]["stg"]["tokens"] 77 | 78 | swapRemotes = [] 79 | for chain in SUPPORTED_CHAINS: 80 | # Find chain ID 81 | chainId = SHORTNAME_TO_ID[chain] 82 | 83 | # Create a web3 instance 84 | provider = web3.Web3.HTTPProvider( 85 | params["rpc_node"][chain], 86 | request_kwargs={"timeout": 60} 87 | ) 88 | w3 = web3.Web3(provider) 89 | nBlocks = params["traveler"]["n_blocks"][chainId] 90 | 91 | for token in SUPPORTED_TOKENS: 92 | contractInfo = params["traveler"]["stg"]["contract_info"] 93 | 94 | # Check whether the pool exists -- If not, move on to the next 95 | if token not in contractInfo[chainId].keys(): 96 | continue 97 | 98 | # Get pool address and first/last block from params 99 | poolContract = contractInfo[chainId][token] 100 | poolAddress = poolContract["address"] 101 | fb = poolContract["first_block"] 102 | lb = poolContract["last_block"] 103 | 104 | # Create pool 105 | pool = w3.eth.contract( 106 | address=poolAddress, abi=getABI("StargatePool") 107 | ) 108 | 109 | _swaps = retrieveSwapRemotes(w3, pool, fb, lb, nBlocks) 110 | swapRemotes.extend(_swaps) 111 | 112 | stg = pd.DataFrame(swapRemotes) 113 | stg.to_parquet("raw/stg_transfers.parquet") 114 | -------------------------------------------------------------------------------- /bridgoor_normalize.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pandas as pd 4 | 5 | from pyaml_env import parse_config 6 | 7 | from acx.abis import getABI 8 | from acx.data.tokens import ( 9 | CHAIN_TO_ADDRESS_TO_SYMBOL, SYMBOL_TO_CHAIN_TO_ADDRESS, SYMBOL_TO_DECIMALS 10 | ) 11 | from acx.utils import scaleDecimals 12 | 13 | 14 | def getV1DisputeHashes(v1DisputesRaw): 15 | disputeHashes = [] 16 | for token in v1DisputesRaw.keys(): 17 | disputes = v1DisputesRaw[token] 18 | 19 | disputeHashes.extend([x["args"]["depositHash"] for x in disputes]) 20 | 21 | return disputeHashes 22 | 23 | 24 | def unpackV1Relays(v1RelaysRaw, disputes): 25 | out = [] 26 | for token in v1RelaysRaw.keys(): 27 | # Get all relays of a certain token 28 | relays = v1RelaysRaw[token] 29 | 30 | # Get decimals 31 | decimals = SYMBOL_TO_DECIMALS[token] 32 | 33 | for relay in relays: 34 | # Unpack deposit/relay data 35 | depositData = relay["args"]["depositData"] 36 | relayData = relay["args"]["relay"] 37 | 38 | if relay["args"]["depositHash"] in disputes: 39 | continue 40 | 41 | row = { 42 | "originChain": depositData[0], 43 | "destinationChain": 1, 44 | "block": relay["blockNumber"], 45 | "tx": relay["transactionHash"], 46 | "sender": depositData[3], 47 | "recipient": depositData[2], 48 | "symbol": token, 49 | "amount": scaleDecimals(depositData[4], decimals), 50 | "version": 1 51 | } 52 | out.append(row) 53 | 54 | return pd.DataFrame(out) 55 | 56 | 57 | def unpackV2Deposits(v2DepositsRaw): 58 | out = [] 59 | for deposit in v2DepositsRaw: 60 | # Unpack pieces of useful data 61 | args = deposit["args"] 62 | 63 | originChainId = args["originChainId"] 64 | 65 | tokenAddress = args["originToken"] 66 | symbol = CHAIN_TO_ADDRESS_TO_SYMBOL[originChainId][tokenAddress] 67 | decimals = SYMBOL_TO_DECIMALS[symbol] 68 | 69 | row = { 70 | "originChain": originChainId, 71 | "destinationChain": args["destinationChainId"], 72 | "block": deposit["blockNumber"], 73 | "tx": deposit["transactionHash"], 74 | "sender": args["depositor"], 75 | "recipient": args["recipient"], 76 | "symbol": symbol, 77 | "amount": scaleDecimals(args["amount"], decimals), 78 | "version": 2 79 | } 80 | out.append(row) 81 | 82 | 83 | return pd.DataFrame(out) 84 | 85 | 86 | if __name__ == "__main__": 87 | # Load parameters 88 | params = parse_config("parameters.yaml") 89 | 90 | # Load data 91 | with open("raw/v1DisputedRelays.json", "r") as f: 92 | v1DisputesRaw = json.loads(f.read()) 93 | with open("raw/v1Relays.json", "r") as f: 94 | v1RelaysRaw = json.loads(f.read()) 95 | with open("raw/v2Deposits.json", "r") as f: 96 | v2DepositsRaw = json.loads(f.read()) 97 | 98 | # Put into DataFrames 99 | v1Disputes = getV1DisputeHashes(v1DisputesRaw) 100 | v1Relays = unpackV1Relays(v1RelaysRaw, v1Disputes) 101 | v2Deposits = unpackV2Deposits(v2DepositsRaw) 102 | 103 | # Save a history of all Across transactions for convenience 104 | allAcross = pd.concat([v1Relays, v2Deposits], axis=0, ignore_index=True) 105 | allAcross.to_json("intermediate/allAcrossTransactions.json", orient="records") 106 | 107 | # Restrict v1 to only relevant blocks 108 | v1StartBlock = params["bridgoor"]["v1_start_block"] 109 | v1EndBlock = params["bridgoor"]["v1_end_block"] 110 | v1Relays = v1Relays.query("(block >= @v1StartBlock) & (block <= @v1EndBlock)") 111 | 112 | # Restrict v2 to only relevant blocks 113 | v2StartBlock = params["bridgoor"]["v2_start_block"] 114 | v2EndBlock = params["bridgoor"]["v2_end_block"] 115 | def v2Filter(x): 116 | gtBlock = x["block"] >= v2StartBlock[x["originChain"]] 117 | ltBlock = x["block"] <= v2EndBlock[x["originChain"]] 118 | 119 | return gtBlock & ltBlock 120 | v2DepositsKeep = v2Deposits.apply(v2Filter, axis=1) 121 | v2Deposits = v2Deposits.loc[v2DepositsKeep, :] 122 | 123 | # Only save the bridgoor relevant transactions 124 | bridgoors = pd.concat([v1Relays, v2Deposits], axis=0, ignore_index=True) 125 | bridgoors.to_json("intermediate/bridgoorTransactions.json", orient="records") 126 | -------------------------------------------------------------------------------- /bt_hop.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | 3 | import pandas as pd 4 | 5 | from pyaml_env import parse_config 6 | 7 | from acx.data.chains import SHORTNAME_TO_ID 8 | from acx.data.tokens import SYMBOL_TO_DECIMALS 9 | from acx.thegraph import submit_query_iterate 10 | 11 | 12 | def retrieveTransfers( 13 | network, startBlock, endBlock, 14 | destinationChainIds, tokens, 15 | npages=10, verbose=False 16 | ): 17 | """ 18 | Grabs all of the transfers from `network` 19 | 20 | Parameters 21 | ---------- 22 | network : str 23 | A short name identifier for a network 24 | start_block : int 25 | The block to start collecting data from 26 | end_block : int 27 | The block to stop collecting data from 28 | destinatinChainIds : list(int) 29 | A list of destination chain IDs that we want data from 30 | tokens : list(str) 31 | A list of tokens that we want to retrieve 32 | npages : int 33 | The maximum number of pages to retrieve 34 | verbose : bool 35 | Whether to print information about which transfers are 36 | being retrieved 37 | """ 38 | # Build query inputs 39 | if network == "mainnet": 40 | table = "transferSentToL2S" 41 | else: 42 | table = "transferSents" 43 | 44 | variables = [ 45 | "id", "blockNumber", "transactionHash", "timestamp", 46 | "destinationChainId", "from", "recipient", 47 | "token", "amount", 48 | ] 49 | arguments = { 50 | "first": 1_000, 51 | "where": { 52 | "blockNumber_gt": startBlock, 53 | "blockNumber_lte": endBlock, 54 | "destinationChainId_in": destinationChainIds, 55 | "token_in": "[\"" + "\", \"".join(tokens) + "\"]" 56 | }, 57 | } 58 | 59 | # Determine which subgraph to query 60 | transfers = submit_query_iterate( 61 | table, variables, arguments, 62 | "hop-protocol", f"hop-{network}", 63 | npages=npages, verbose=verbose 64 | ) 65 | 66 | return transfers 67 | 68 | 69 | if __name__ == "__main__": 70 | # Load parameters 71 | params = parse_config("parameters.yaml") 72 | 73 | # First and last block data 74 | HOP_FIRST_BLOCK = params["traveler"]["hop"]["first_block"] 75 | HOP_LAST_BLOCK = params["traveler"]["hop"]["last_block"] 76 | 77 | # Chains we collect data from 78 | HOP_ORIGIN_CHAINS = params["traveler"]["hop"]["chains"] 79 | SUPPORTED_TOKENS = params["traveler"]["hop"]["tokens"] 80 | 81 | # Chains that we want transfers to 82 | SUPPORTED_CHAINS = params["traveler"]["chains"] 83 | SUPPORTED_CHAIN_IDS = [SHORTNAME_TO_ID[c] for c in SUPPORTED_CHAINS] 84 | 85 | # Retrieve mainnet transfers separately since they're special 86 | allDfs = [] 87 | for chain in HOP_ORIGIN_CHAINS: 88 | chainId = SHORTNAME_TO_ID[chain] 89 | fb = HOP_FIRST_BLOCK[chainId] 90 | tb = HOP_LAST_BLOCK[chainId] 91 | 92 | # The Graph allows for retrieving 1,000 events at a time so we 93 | # set the number of pages to 999 as a magic number because we 94 | # know that no chain has more than 999,000 transfers 95 | transfers = retrieveTransfers( 96 | "xdai" if chainId == 100 else chain, fb, tb, 97 | SUPPORTED_CHAIN_IDS, SUPPORTED_TOKENS, 98 | npages=999, verbose=True 99 | ) 100 | 101 | # Put data into a dataframe so we can transform certain pieces of it 102 | _df = pd.DataFrame(transfers) 103 | _df["originChainId"] = chainId 104 | 105 | # Convert things to integers 106 | int_cols = ["destinationChainId", "blockNumber", "timestamp"] 107 | for col in int_cols: 108 | _df.loc[:, col] = pd.to_numeric(_df.loc[:, col]) 109 | 110 | # Convert dates to date 111 | _df["dt"] = _df.loc[:, "timestamp"].map( 112 | lambda x: dt.datetime.utcfromtimestamp(x) 113 | ) 114 | 115 | _scaleDecimals = ( 116 | 10**_df["token"].map(lambda x: SYMBOL_TO_DECIMALS[x]) 117 | ) 118 | _df.loc[:, "amount"] = ( 119 | _df.loc[:, "amount"].astype(float) / _scaleDecimals 120 | ) 121 | allDfs.append(_df) 122 | 123 | hop = pd.concat(allDfs) 124 | 125 | # Rename columns 126 | hop = hop.rename( 127 | columns={ 128 | "transactionHash": "tx", 129 | "token": "symbol", 130 | "from": "sender" 131 | } 132 | ) 133 | 134 | hop.to_parquet("raw/hop_transfers.parquet") 135 | -------------------------------------------------------------------------------- /acx/utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import time 4 | 5 | from requests.adapters import HTTPAdapter 6 | from urllib3.util.retry import Retry 7 | 8 | import web3 9 | 10 | from typing import Any, Dict, Union 11 | 12 | from eth_typing import HexStr 13 | from hexbytes import HexBytes 14 | from web3.datastructures import AttributeDict 15 | from web3._utils.encoding import FriendlyJsonSerde 16 | 17 | 18 | class Web3JsonEncoder(json.JSONEncoder): 19 | "Based on https://github.com/ethereum/web3.py/blob/master/web3/_utils/encoding.py#L286-L292" 20 | def default(self, obj: Any) -> Union[Dict[Any, Any], HexStr]: 21 | if isinstance(obj, AttributeDict): 22 | return {k: v for k, v in obj.items()} 23 | if isinstance(obj, HexBytes): 24 | return HexStr(obj.hex()) 25 | # If any of the args are bytes, just convert them to hex... Pray 26 | # to the blockchain gods that this is what it's meant to be 27 | if isinstance(obj, bytes): 28 | return obj.hex() 29 | return json.JSONEncoder.default(self, obj) 30 | 31 | 32 | def to_json(obj: Dict[Any, Any]) -> str: 33 | """ 34 | Convert a complex object (like a transaction object) to a JSON string 35 | """ 36 | return FriendlyJsonSerde().json_encode(obj, cls=Web3JsonEncoder) 37 | 38 | 39 | def findEvents(w3, event, startBlock, endBlock, blockStep, argFilters, v=False): 40 | """ 41 | Find all instances of a particular event between `startBlock` and 42 | `endBlock` 43 | 44 | Parameters 45 | ---------- 46 | w3 : web3.Web3 47 | A web3 object 48 | event : web3.Contract.Event 49 | A particular event from a contract (i.e. contract.event.EVENT) 50 | startBlock : int 51 | The block to start searching on 52 | endBlock : int 53 | The block to stop searching on 54 | blockStep : int 55 | The number of blocks to download at a time -- This could be 56 | "infinite" if the RPC provider could deliver sufficient 57 | information per request, but, in practice, there are heavy 58 | constraints (for example, on Infura one can only retrieve 10,000 59 | events at a time on mainnet and 3,500 blocks at a time on 60 | Polygon 61 | argFilters : dict 62 | The filters to be applied on indexed arguments 63 | v : bool 64 | Verbose 65 | 66 | Returns 67 | ------- 68 | events : list(dict) 69 | A list of dictionaries that contain the event information 70 | """ 71 | # Make sure block arguments are meaningful... i.e. >0 and an integer 72 | assert(isinstance(startBlock, int) and startBlock >= 0) 73 | assert(isinstance(endBlock, int) and endBlock > 0) 74 | assert(isinstance(blockStep, int) and blockStep > 0) 75 | assert(startBlock < endBlock) 76 | 77 | events = [] 78 | blockStarts = range(startBlock, endBlock, blockStep) 79 | for bs in blockStarts: 80 | be = min(bs + blockStep - 1, endBlock) 81 | 82 | if v: 83 | print( 84 | f"Beginning block {bs}\n" 85 | f"Ending block {be}" 86 | ) 87 | 88 | eventOccurrences = event.getLogs( 89 | fromBlock=bs, toBlock=be, argument_filters=argFilters 90 | ) 91 | nOccurrences = len(eventOccurrences) 92 | 93 | if v: 94 | print(f"Blocks {bs} to {be} contained {nOccurrences} transactions") 95 | 96 | if nOccurrences > 0: 97 | # Convert everything to JSON readable 98 | eventOccurrences = [ 99 | json.loads(to_json(x)) for x in eventOccurrences 100 | ] 101 | 102 | events.extend(eventOccurrences) 103 | 104 | return events 105 | 106 | 107 | def scaleDecimals(x, decimals=18): 108 | return x / 10**decimals 109 | 110 | 111 | def createNewSubsetDict(newKey, newValue, d): 112 | return {x[newKey]: x[newValue] for x in d} 113 | 114 | 115 | def createSessionWithRetries(nRetries=5, backoffFactor=1.0): 116 | # Create requests session 117 | session = requests.Session() 118 | 119 | # Retry adapter 120 | retry_strategy = Retry( 121 | total=nRetries, 122 | backoff_factor=backoffFactor, 123 | status_forcelist=[429, 500, 502, 503, 504], 124 | allowed_methods=["GET", "POST"] 125 | ) 126 | adapter = HTTPAdapter(max_retries=retry_strategy) 127 | session.mount("http://", adapter) 128 | session.mount("https://", adapter) 129 | 130 | return session 131 | 132 | 133 | def getWithRetries(url, params, nRetries=5, backoffFactor=1.0, preSleep=0.0): 134 | session = createSessionWithRetries(nRetries, backoffFactor) 135 | 136 | time.sleep(preSleep) 137 | res = session.get(url, params=params) 138 | 139 | return res 140 | 141 | 142 | def cutAndPowerScore(s, lb, ub, power): 143 | """ 144 | A function that takes a pandas series as an input and returns a 145 | new series where the values have been clipped at some ub and then 146 | raised to a power. It then computes the percentage of the total 147 | score that each observation is -- i.e. normalizes so that the sum 148 | of the values is 1 149 | 150 | Parameters 151 | ---------- 152 | s : pd.Series 153 | A series of data 154 | """ 155 | out = s.clip(lb, ub)**power 156 | 157 | return out / out.sum() 158 | -------------------------------------------------------------------------------- /acx/abis/ERC20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] 223 | -------------------------------------------------------------------------------- /acx/data/tokens.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "symbol": "BADGER", "decimals": 18, "cgId": "badger-dao", 4 | "address": { 5 | "1": "0x3472A5A71965499acd81997a54BBA8D852C6E53d", 6 | "137": "0x1FcbE5937B0cc2adf69772D228fA4205aCF4D9b2", 7 | "42161": "0xBfa641051Ba0a0Ad1b0AcF549a89536A0D76472E" 8 | } 9 | }, 10 | { 11 | "symbol": "BAL", "decimals": 18, "cgId": "balancer", 12 | "address": { 13 | "1": "0xba100000625a3754423978a60c9317c58a424e3D", 14 | "10": "0xFE8B128bA8C78aabC59d4c64cEE7fF28e9379921", 15 | "137": "0x9a71012B13CA4d3D0Cdc72A177DF3ef03b0E76A3", 16 | "42161": "0x040d1EdC9569d4Bab2D15287Dc5A4F10F56a56B8" 17 | } 18 | }, 19 | { 20 | "symbol": "BOBA", "decimals": 18, "cgId": "boba-network", 21 | "address": { 22 | "1": "0x42bBFa2e77757C645eeaAd1655E0911a7553Efbc", 23 | "288": "0xa18bF3994C0Cc6E3b63ac420308E5383f53120D7" 24 | } 25 | }, 26 | { 27 | "symbol": "BUSD", "decimals": 18, "cgId": "boba-network", 28 | "address": { 29 | "1": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", 30 | "56": "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56" 31 | } 32 | }, 33 | { 34 | "symbol": "DAI", "decimals": 18, "cgId": "dai", 35 | "address": { 36 | "1": "0x6B175474E89094C44Da98b954EedeAC495271d0F", 37 | "10": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", 38 | "137": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063", 39 | "288": "0xf74195Bb8a5cf652411867c5C2C5b8C2a402be35", 40 | "42161": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1" 41 | } 42 | }, 43 | { 44 | "symbol": "ETH", "decimals": 18, "cgId": "ethereum", 45 | "address": { 46 | "1": "0x0000000000000000000000000000000000000000", 47 | "10": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", 48 | "288": "0x4200000000000000000000000000000000000006", 49 | "42161": "0x0000000000000000000000000000000000000000" 50 | } 51 | }, 52 | { 53 | "symbol": "MATIC", "decimals": 18, "cgId": "matic-network", 54 | "address": { 55 | "1": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", 56 | "137": "0x0000000000000000000000000000000000001010" 57 | } 58 | }, 59 | { 60 | "symbol": "MIM", "decimals": 18, "cgId": "magic-internet-money", 61 | "address": { 62 | "1": "0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3", 63 | "42161": "0xFEa7a6a0B346362BF88A9e4A88416B77a57D6c2A" 64 | } 65 | }, 66 | { 67 | "symbol": "nETH", "decimals": 18, "cgId": "ethereum", 68 | "address": { 69 | "10": "0x809DC529f07651bD43A172e8dB6f4a7a0d771036", 70 | "288": "0x96419929d7949D6A801A6909c145C8EEf6A40431", 71 | "42161": "0x3ea9B0ab55F34Fb188824Ee288CeaEfC63cf908e" 72 | } 73 | }, 74 | { 75 | "symbol": "nUSD", "decimals": 18, "cgId": "ethereum", 76 | "address": { 77 | "1": "0x1B84765dE8B7566e4cEAF4D0fD3c5aF52D3DdE4F", 78 | "10": "0x67C10C397dD0Ba417329543c1a40eb48AAa7cd00", 79 | "137": "0xB6c473756050dE474286bED418B77Aeac39B02aF", 80 | "288": "0x6B4712AE9797C199edd44F897cA09BC57628a1CF", 81 | "42161": "0x2913E812Cf0dcCA30FB28E6Cac3d2DCFF4497688" 82 | } 83 | }, 84 | { 85 | "symbol": "SGETH", "decimals": 18, "cgId": "ethereum", 86 | "address": { 87 | "1": "0x72E2F4830b9E45d52F80aC08CB2bEC0FeF72eD9c", 88 | "10": "0xb69c8CBCD90A39D8D3d3ccf0a3E968511C3856A0", 89 | "42161": "0x82CbeCF39bEe528B5476FE6d1550af59a9dB6Fc0" 90 | } 91 | }, 92 | { 93 | "symbol": "SYN", "decimals": 18, "cgId": "synapse", 94 | "address": { 95 | "1": "0x0f2D719407FdBeFF09D87557AbB7232601FD9F29", 96 | "10": "0x5A5fFf6F753d7C11A56A52FE47a177a87e431655", 97 | "137": "0xf8F9efC0db77d8881500bb06FF5D6ABc3070E695", 98 | "288": "0xb554A55358fF0382Fb21F0a478C3546d1106Be8c", 99 | "42161": "0x080F6AEd32Fc474DD5717105Dba5ea57268F46eb" 100 | } 101 | }, 102 | { 103 | "symbol": "UMA", "decimals": 18, "cgId": "uma", 104 | "address": { 105 | "1": "0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828", 106 | "10": "0xE7798f023fC62146e8Aa1b36Da45fb70855a77Ea", 107 | "137": "0x3066818837c5e6eD6601bd5a91B0762877A6B731", 108 | "288": "0x780f33Ad21314d9A1Ffb6867Fe53d48a76Ec0D16", 109 | "42161": "0xd693Ec944A85eeca4247eC1c3b130DCa9B0C3b22" 110 | } 111 | }, 112 | { 113 | "symbol": "USDC", "decimals": 6, "cgId": "usd-coin", 114 | "address": { 115 | "1": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 116 | "10": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", 117 | "137": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", 118 | "250": "0x04068DA6C83AFCFA0e13ba15A6696662335D5B75", 119 | "288": "0x66a2A913e447d6b4BF33EFbec43aAeF87890FBbc", 120 | "42161": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", 121 | "43114": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" 122 | } 123 | }, 124 | { 125 | "symbol": "USDT", "decimals": 6, "cgId": "tether", 126 | "address": { 127 | "1": "0xdAC17F958D2ee523a2206206994597C13D831ec7", 128 | "10": "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", 129 | "137": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", 130 | "288": "0x5DE1677344D3Cb0D7D465c10b72A8f60699C062d", 131 | "42161": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", 132 | "43114": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7" 133 | } 134 | }, 135 | { 136 | "symbol": "WBTC", "decimals": 8, "cgId": "wrapped-bitcoin", 137 | "address": { 138 | "1": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 139 | "10": "0x68f180fcCe6836688e9084f035309E29Bf0A2095", 140 | "137": "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6", 141 | "288": "0xdc0486f8bf31DF57a952bcd3c1d3e166e3d9eC8b", 142 | "42161": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f" 143 | } 144 | }, 145 | { 146 | "symbol": "WETH", "decimals": 18, "cgId": "weth", 147 | "address": { 148 | "1": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 149 | "10": "0x4200000000000000000000000000000000000006", 150 | "137": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", 151 | "288": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", 152 | "42161": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1" 153 | } 154 | } 155 | ] 156 | -------------------------------------------------------------------------------- /bt_synapse.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import web3 3 | 4 | from pyaml_env import parse_config 5 | 6 | from acx.abis import getABI 7 | from acx.data.chains import SHORTNAME_TO_ID 8 | from acx.data.tokens import ( 9 | CHAIN_TO_ADDRESS_TO_SYMBOL, SYMBOL_TO_CHAIN_TO_ADDRESS, SYMBOL_TO_DECIMALS 10 | ) 11 | from acx.utils import findEvents, scaleDecimals 12 | 13 | 14 | # Mapping comes from going to the pool contract and identifying 15 | # the tokens using `getToken` function 16 | # List of pools can be found at: https://github.com/BlazeWasHere/SYN-Tracker-API/blob/819309573e0288f8b2466bb3455a949e4ebf3495/syn/utils/data.py#L110-L268 17 | CHAIN_TO_SYNTOKEN_TO_SWAPSYMBOL = { 18 | 1: { 19 | # USD pool 20 | "0x1B84765dE8B7566e4cEAF4D0fD3c5aF52D3DdE4F": { 21 | 0: "DAI", 22 | 1: "USDC", 23 | 2: "USDT" 24 | } 25 | }, 26 | 10: { 27 | # USD pool 28 | "0x67C10C397dD0Ba417329543c1a40eb48AAa7cd00": { 29 | 0: "nUSD", 30 | 1: "USDC", 31 | }, 32 | # ETH pool 33 | "0x809DC529f07651bD43A172e8dB6f4a7a0d771036": { 34 | 0: "nETH", 35 | 1: "WETH" 36 | } 37 | }, 38 | 137: { 39 | # USD pool 40 | "0xB6c473756050dE474286bED418B77Aeac39B02aF": { 41 | 0: "nUSD", 42 | 1: "DAI", 43 | 2: "USDC", 44 | 3: "USDT" 45 | } 46 | }, 47 | 288: { 48 | # USD pool 49 | "0x6B4712AE9797C199edd44F897cA09BC57628a1CF": { 50 | 0: "nUSD", 51 | 1: "DAI", 52 | 2: "USDC", 53 | 3: "USDT" 54 | }, 55 | "0x96419929d7949D6A801A6909c145C8EEf6A40431": { 56 | 0: "nETH", 57 | 1: "WETH" 58 | } 59 | }, 60 | 42161: { 61 | # USD pool 62 | "0x2913E812Cf0dcCA30FB28E6Cac3d2DCFF4497688": { 63 | 0: "nUSD", 64 | 1: "MIM", 65 | 2: "USDC", 66 | 3: "USDT" 67 | }, 68 | # ETH pool 69 | "0x3ea9B0ab55F34Fb188824Ee288CeaEfC63cf908e": { 70 | 0: "nETH", 71 | 1: "WETH" 72 | } 73 | }, 74 | } 75 | 76 | 77 | if __name__ == "__main__": 78 | # Load parameters 79 | params = parse_config("parameters.yaml") 80 | 81 | # Chains/Tokens to support 82 | SUPPORTED_CHAINS = params["traveler"]["synapse"]["chains"] 83 | SUPPORTED_TOKENS = params["traveler"]["synapse"]["tokens"] 84 | contractInfo = params["traveler"]["synapse"]["contract_info"] 85 | 86 | synapseInflows = [] 87 | for chain in SUPPORTED_CHAINS: 88 | chainId = SHORTNAME_TO_ID[chain] 89 | chainInfo = contractInfo[chainId] 90 | 91 | # Select a single chain so we have address -> symbol 92 | ADDRESS_TO_SYMBOL = CHAIN_TO_ADDRESS_TO_SYMBOL[chainId] 93 | 94 | # Web 3 instance for particular chain 95 | provider = web3.Web3.HTTPProvider( 96 | params["rpc_node"][chain], 97 | request_kwargs={"timeout": 60} 98 | ) 99 | w3 = web3.Web3(provider) 100 | 101 | # First, last block, and number of blocks to search at once 102 | fb = chainInfo["first_block"] 103 | lb = chainInfo["last_block"] 104 | nBlocks = params["traveler"]["n_blocks"][chainId] 105 | 106 | # Create synapse bridge 107 | bridgeAddress = chainInfo["address"] 108 | bridge = w3.eth.contract( 109 | address=bridgeAddress, abi=getABI("SynapseBridge") 110 | ) 111 | 112 | # Inflow events as defined by Synapse here: 113 | # https://github.com/synapsecns/synapse-indexer/blob/6d3fcb4cd57d2413800a1c6858b8215a880b27f3/config/topics.js 114 | inflowEvents = [ 115 | bridge.events.TokenWithdraw, bridge.events.TokenWithdrawAndRemove, 116 | bridge.events.TokenMint, bridge.events.TokenMintAndSwap 117 | ] 118 | 119 | for event in inflowEvents: 120 | # Get event name so that we can do logic on it 121 | eventName = event.event_name 122 | 123 | # Collect event data 124 | inflows = findEvents(w3, event, fb, lb, nBlocks, {}, True) 125 | 126 | for inflow in inflows: 127 | # Separate args into more accessible object 128 | inflowArgs = inflow["args"] 129 | 130 | # Extract token address and make sure that it's a token 131 | # in our list of tokens 132 | tokenAddress = inflowArgs["token"] 133 | if tokenAddress not in ADDRESS_TO_SYMBOL.keys(): 134 | continue 135 | 136 | # Depending on the event type, we have to do different things 137 | if eventName in ["TokenWithdraw", "TokenMint"]: 138 | symbolFrom = ADDRESS_TO_SYMBOL[tokenAddress] 139 | symbolTo = symbolFrom 140 | 141 | elif eventName == "TokenWithdrawAndRemove": 142 | symbolFrom = ADDRESS_TO_SYMBOL[tokenAddress] 143 | 144 | if inflowArgs["swapSuccess"]: 145 | idxTo = inflowArgs["swapTokenIndex"] 146 | symbolTo = CHAIN_TO_SYNTOKEN_TO_SWAPSYMBOL[chainId][tokenAddress][idxTo] 147 | else: 148 | symbolTo = ADDRESS_TO_SYMBOL[tokenAddress] 149 | 150 | elif eventName == "TokenMintAndSwap": 151 | # Determine index of entry and exit 152 | idxFrom = inflowArgs["tokenIndexFrom"] 153 | if inflowArgs["swapSuccess"]: 154 | idxTo = inflowArgs["tokenIndexTo"] 155 | else: 156 | idxTo = inflowArgs["tokenIndexFrom"] 157 | 158 | symbolFrom = CHAIN_TO_SYNTOKEN_TO_SWAPSYMBOL[chainId][tokenAddress][idxFrom] 159 | symbolTo = CHAIN_TO_SYNTOKEN_TO_SWAPSYMBOL[chainId][tokenAddress][idxTo] 160 | 161 | # Make sure it is a token that we are tracking for bridge traveler 162 | if symbolTo not in SUPPORTED_TOKENS: 163 | continue 164 | 165 | decimalsFrom = SYMBOL_TO_DECIMALS[symbolFrom] 166 | decimalsTo = SYMBOL_TO_DECIMALS[symbolTo] 167 | 168 | # Save row by row 169 | row = {} 170 | 171 | row["eventName"] = eventName 172 | row["kappa"] = inflowArgs["kappa"] 173 | row["block"] = inflow["blockNumber"] 174 | row["tx"] = inflow["transactionHash"] 175 | row["chainId"] = chainId 176 | row["recipient"] = inflowArgs["to"] 177 | row["symbol"] = symbolTo 178 | row["amount"] = scaleDecimals(inflowArgs["amount"], decimalsTo) 179 | row["fee"] = scaleDecimals(inflowArgs["fee"], decimalsFrom) 180 | 181 | synapseInflows.append(row) 182 | 183 | df = pd.DataFrame(synapseInflows) 184 | df.to_parquet("raw/synapse_transfers.parquet") 185 | -------------------------------------------------------------------------------- /acx/thegraph.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | 4 | import requests 5 | 6 | from acx.utils import createSessionWithRetries 7 | 8 | 9 | THEGRAPHURL = "https://api.thegraph.com/" 10 | 11 | 12 | def add_line(text, level=0): 13 | return " "*level + text + "\n" 14 | 15 | 16 | def _unpack_variable(variable, indent_level=1): 17 | "Unpacks a single variable or a dict variable" 18 | # If a string, simply return the string 19 | if isinstance(variable, str): 20 | return add_line(variable, level=indent_level) 21 | 22 | # If the variable isn't a string then it must be a dict with a 23 | # single element 24 | assert isinstance(variable, dict) 25 | assert len(variable.keys()) == 1 26 | 27 | out = "" 28 | for variable, subvariables in variable.items(): 29 | # Make sure they gave you a list for the subvariables 30 | assert isinstance(subvariables, list) 31 | 32 | out += add_line(f"{variable} {{", level=indent_level) 33 | out += _unpack_variables(subvariables, indent_level+1) 34 | out += add_line("}", level=indent_level) 35 | 36 | return out 37 | 38 | 39 | def _unpack_variables(variables, indent_level=0): 40 | "Takes a list of variables and unpacks them into a string" 41 | # Start an empty string to fill 42 | var_str = add_line("{", level=indent_level) 43 | for v in variables: 44 | var_str += _unpack_variable(v, indent_level=indent_level+1) 45 | var_str += add_line("}", level=indent_level) 46 | 47 | return var_str 48 | 49 | 50 | def _unpack_arguments(first=None, orderBy=None, orderDirection=None, where=None): 51 | "Unpacks query arguments" 52 | # Check whether each arg is None 53 | fin = first is None 54 | obin = orderBy is None 55 | odin = orderDirection is None 56 | win = where is None 57 | 58 | # If each argument is None, return nothing 59 | if fin and obin and odin and win: 60 | return "" 61 | 62 | out = add_line("(", level=0) 63 | if not fin: 64 | out += add_line(f"first: {first}", level=1) 65 | if not (obin or odin): 66 | out += add_line(f"orderBy: {orderBy}", level=1) 67 | out += add_line(f"orderDirection: {orderDirection}", level=1) 68 | if not win: 69 | if isinstance(where, str): 70 | out += add_line(f"where: {where}", level=1) 71 | elif isinstance(where, list): 72 | out += add_line("where: {", level=1) 73 | for w in where: 74 | out += add_line(f"{w}", level=2) 75 | out += add_line("}", level=1) 76 | elif isinstance(where, dict): 77 | out += add_line("where: {", level=1) 78 | for k, v in where.items(): 79 | out += add_line(f"{k}: {v}", level=2) 80 | out += add_line("}", level=1) 81 | 82 | out += add_line(")", level=0) 83 | 84 | return out 85 | 86 | 87 | def build_query(table, variables, arguments={"first": 5}): 88 | """ 89 | Helper to construct a graph query from strings and lists of strings 90 | 91 | Parameters 92 | ---------- 93 | table : string 94 | Which table to collect data from 95 | variables : list(dict or string) 96 | The variables to collect from the table. If these are nested 97 | variables then you should input a dict with the variable and 98 | subvariable 99 | arguments : dict, optional 100 | The arguments to the query for things like filtering and 101 | ordering. 102 | """ 103 | query = "{" 104 | 105 | # First, add table name and open curly brackets 106 | query += add_line(table, level=0) 107 | 108 | # Next, add arguments 109 | query += _unpack_arguments(**arguments) 110 | 111 | # Finally, add variables and end line 112 | query += _unpack_variables(variables, indent_level=0) 113 | query += "}" 114 | 115 | return query 116 | 117 | 118 | def submit_single_query(table, variables, arguments, organization, subgraph): 119 | """ 120 | Submits a single query to `organization/subgraph` for `variables` 121 | from `table` with `arguments`. 122 | 123 | Parameters 124 | ---------- 125 | table : string 126 | Which table to collect data from 127 | variables : list(dict or string) 128 | The variables to collect from the table. If these are nested 129 | variables then you should input a dict with the variable and 130 | subvariable 131 | arguments : dict, optional 132 | The arguments to the query for things like filtering and 133 | ordering. 134 | organization : str 135 | The organization the subgraph belongs to 136 | subgraph : str 137 | The subgraph the table belongs to 138 | """ 139 | # Requests session with retries 140 | session = createSessionWithRetries(nRetries=5, backoffFactor=1.0) 141 | 142 | # Build query 143 | query = build_query(table, variables, arguments) 144 | 145 | # Set the query url using org/subgraph info 146 | queryable_url = ( 147 | THEGRAPHURL + 148 | "subgraphs/name/{organization}/{subgraph}" 149 | ).format(organization=organization, subgraph=subgraph) 150 | 151 | # Build the query 152 | query_json = { 153 | "query": query, 154 | } 155 | 156 | # Make the request 157 | res = session.post(queryable_url, json=query_json) 158 | 159 | if "errors" in res.json().keys(): 160 | print(f"""Error\n{queryable_url}\n{query_json["query"]}\n{res}""") 161 | raise ValueError("Failed to get data") 162 | 163 | return res 164 | 165 | 166 | def submit_query_iterate( 167 | table, variables, arguments, organization, subgraph, 168 | npages=1, verbose=False 169 | ): 170 | """ 171 | Submits a multiple queries to `organization/subgraph` for `variables` 172 | from `table` with `arguments` by iterating over a column called `id`. 173 | 174 | Parameters 175 | ---------- 176 | table : string 177 | Which table to collect data from 178 | variables : list(dict or string) 179 | The variables to collect from the table. If these are nested 180 | variables then you should input a dict with the variable and 181 | subvariable 182 | arguments : dict, optional 183 | The arguments to the query for things like filtering and 184 | ordering. 185 | organization : str 186 | The organization the subgraph belongs to 187 | subgraph : str 188 | The subgraph the table belongs to 189 | """ 190 | # Grab first argument or set it to 1,000 191 | limit = arguments.get("first", 1_000) 192 | 193 | # Order ascending by id 194 | if "id" not in variables: 195 | variables.append("id") 196 | arguments.update({"orderBy": "id", "orderDirection": "asc"}) 197 | 198 | # Iterate until done iterating through pages 199 | last_id = '' 200 | page = 0 201 | out = [] 202 | while True: 203 | # Update where argument 204 | where_arg = arguments.get("where", {}) 205 | where_arg.update({"id_gt": f'"{last_id}"'}) 206 | arguments.update({"where": where_arg}) 207 | 208 | if verbose: 209 | print(arguments) 210 | print(limit) 211 | print(page, npages) 212 | print(last_id) 213 | print(f"Retrieving {limit*page + 1} to {limit*(page+1)}") 214 | 215 | res = submit_single_query( 216 | table, variables, arguments, organization, subgraph 217 | ) 218 | _out = res.json()["data"][table] 219 | if len(_out) > 0: 220 | last_id = _out[-1]["id"] 221 | 222 | # Add new value to list of all output 223 | out.extend(_out) 224 | 225 | page += 1 226 | nout = len(_out) 227 | 228 | if (nout < limit) or (page >= npages): 229 | break 230 | 231 | return out 232 | -------------------------------------------------------------------------------- /lp_rewards.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import numpy as np 4 | import pandas as pd 5 | 6 | from pyaml_env import parse_config 7 | 8 | 9 | # Load block data 10 | BLOCKSTODATE = ( 11 | pd.read_json("raw/blocks.json", orient="records") 12 | .query("chainId == 1") 13 | .sort_values("block") 14 | .loc[:, ["block", "date"]] 15 | ) 16 | 17 | 18 | def computeLpRewards( 19 | df, exchangeRates, prices, 20 | startBlock, endBlock, rewardPerBlock 21 | ): 22 | """ 23 | This function computes the rewards earned between `startBlock` and 24 | `endBlock` by breaking the data up into day-at-a-time calculations 25 | 26 | Parameters 27 | ---------- 28 | df : DataFrame 29 | Contains all of the LP token transfers for either v1 or v2 30 | exchangeRates : DataFrame 31 | Contains all of the LP token exchange rates at a daily frequency 32 | prices : DataFrame 33 | Contains token prices at a daily frequency 34 | startBlock : int 35 | The block to start tracking rewards at 36 | endBlock : int 37 | The block to stop tracking rewards at 38 | 39 | Returns 40 | ------- 41 | addressRewards : Series 42 | The rewards an LP will receive -- Original + rewards from 43 | `startBlock` to `endBlock` 44 | """ 45 | # df has multi-level columns with (symbol, lp address) as 46 | # the two levels -- This extracts the unique lp addresses from 47 | # that multi-level 48 | lps = df.columns.get_level_values("lp").unique() 49 | out = pd.Series(np.zeros_like(lps, dtype=float), index=lps) 50 | 51 | # Find the index of the date to start/end 52 | startIdx = BLOCKSTODATE["block"].searchsorted(startBlock, side="right") - 1 53 | endIdx = BLOCKSTODATE["block"].searchsorted(endBlock, side="right") - 1 54 | 55 | # Can directly use `.loc` because the index is already the 56 | # ordered positive integers 57 | _datetoblock = BLOCKSTODATE.loc[startIdx:endIdx, :] 58 | 59 | # Date-by-date iteration so that the data we are working with is always 60 | # "small enough" 61 | for (idx, block_date) in _datetoblock.iterrows(): 62 | # Extract date from _datetoblock 63 | date = block_date["date"] 64 | dailyBlockStart = max(startBlock, block_date["block"]) 65 | print(f"Working on {date}") 66 | 67 | # Get daily price/exchange rate information 68 | dailyPrices = ( 69 | prices.query("date == @date") 70 | .droplevel("date") 71 | ) 72 | dailyERs = ( 73 | exchangeRates.query("date == @date") 74 | .loc[:, ["symbol", "exchangeRate"]] 75 | .set_index("symbol") 76 | ) 77 | 78 | # Convert price/exchange rate into a multiplier for each lp 79 | # token position 80 | dailyMultiplier = ( 81 | dailyPrices.merge( 82 | dailyERs, left_index=True, right_index=True, 83 | how="right" 84 | ) 85 | .assign( 86 | multiplier=lambda x: x["price"] * x["exchangeRate"], 87 | ) 88 | .loc[:, "multiplier"] 89 | ) 90 | 91 | # Determine which block number to stop tracking at 92 | if (idx + 1) in _datetoblock.index: 93 | # Subtract one from the block because we want to be exclusive on 94 | # the upper interval 95 | dailyBlockEnd = min(_datetoblock.at[idx+1, "block"], endBlock) - 1 96 | else: 97 | dailyBlockEnd = endBlock 98 | 99 | # Make sure not to set the block to be the first block of a day -- 100 | # Rather, you should use the last block of the previous day. If it is 101 | # the first block of a day then it creates a size 0 dataframe 102 | if dailyBlockStart == dailyBlockEnd: 103 | continue 104 | 105 | # Find the last position prior to today's positions and, if there's 106 | # data in the first block of the day, add that as the first block 107 | # values 108 | # 109 | positionIdx = df.index.searchsorted(dailyBlockStart, side="right") - 1 110 | lastBlockWPosition = df.index[positionIdx] 111 | 112 | # Select only the relevant blocks for today 113 | dailyDf = df.loc[lastBlockWPosition:dailyBlockEnd, :].copy(deep=True) 114 | 115 | # Create a new index that includes the daily start/end block if they 116 | # are not already included and use that to reindex 117 | newIndex = ( 118 | dailyDf.index 119 | .union([dailyBlockStart, dailyBlockEnd]) 120 | .sort_values() 121 | ) 122 | dailyDf = dailyDf.reindex(newIndex) 123 | 124 | # Fill missing data (dailyBlockStart and dailyBlockEnd with 125 | # previous values) and then index into only today's blocks 126 | dailyDf = dailyDf.ffill() 127 | dailyDf = dailyDf.loc[dailyBlockStart:dailyBlockEnd, :] 128 | 129 | # Compute the difference between each block to "how long that 130 | # relative position was held" -- The final block was manually 131 | # added so it will only be valid for a single block 132 | blockDiff = np.hstack( 133 | [ 134 | np.diff(dailyDf.index.values), 135 | np.ones(1) 136 | ] 137 | ) 138 | 139 | # Create a `nColumns` length array with all of the corresponding 140 | # multipliers for each column (i.e repeated multipliers based on 141 | # which symbol the column corresponds to) 142 | _multiplier = ( 143 | dailyMultiplier.loc[dailyDf.columns.get_level_values("symbol")] 144 | .to_numpy() 145 | ) 146 | 147 | # Multiply positions by the multiplier 148 | # (i.e. exchange rate * price * bonus) 149 | dailyDf = dailyDf.multiply(_multiplier, axis="columns") 150 | 151 | # Get usd totals for each block and convert the positions into 152 | # a pro rata amount 153 | usdTotals = dailyDf.sum(axis=1) 154 | proRata = dailyDf.divide(usdTotals, axis=0) 155 | 156 | # Compute daily rewards 157 | dailyRewards = ( 158 | # Number of rewards for each row is the number of rewards per 159 | # block by the number of blocks that position was good for 160 | proRata.multiply(blockDiff * rewardPerBlock, axis="rows") 161 | # Convert fraction of pool -> rewards 162 | # blocks x (symbol, address) 163 | # Sum all rewards for each column 164 | # (symbol, address) x 1 165 | .sum(axis=0) 166 | # Move symbol to columns 167 | # address x symbol 168 | .unstack(level="symbol") 169 | # Sum all of the rewards for each LP 170 | # address x 1 171 | .sum(axis=1) 172 | ) 173 | print(f"\tTotal Rewards: {dailyRewards.sum()}") 174 | out += dailyRewards 175 | 176 | return out 177 | 178 | 179 | 180 | if __name__ == "__main__": 181 | # 182 | # Load parameters 183 | # 184 | params = parse_config("parameters.yaml") 185 | 186 | # Block start and end information 187 | v1StartBlock = params["lp"]["v1_start_block"] 188 | v1EndBlock = params["lp"]["v1_end_block"] 189 | v2StartBlock = params["lp"]["v2_start_block"] 190 | v2EndBlock = params["lp"]["v2_end_block"] 191 | 192 | # Compute rewards per block -- Add 1 because inclusive on both ends 193 | nBlocks = (v2EndBlock - v2StartBlock + 1) + (v1EndBlock - v1StartBlock + 1) 194 | totalRewards = params["lp"]["parameters"]["total_rewards"] 195 | rewardPerBlock = totalRewards / nBlocks 196 | 197 | # 198 | # Load data 199 | # 200 | 201 | # Load prices data 202 | prices = ( 203 | pd.read_json("raw/prices.json", orient="records") 204 | .set_index(["date", "symbol"]) 205 | ) 206 | 207 | # Load all positions an LP had at each relevant block 208 | v1LpPositions = pd.read_parquet("intermediate/v1CumulativeLp.parquet") 209 | v2LpPositions = pd.read_parquet("intermediate/v2CumulativeLp.parquet") 210 | for lpDf in [v1LpPositions, v2LpPositions]: 211 | lpDf.columns = lpDf.columns.set_names(["symbol", "lp"]) 212 | 213 | # Create a list of all LPs - The LPs should all be in both datasets 214 | # but, if not, this makes sure that they are included 215 | lps = list( 216 | set(v1LpPositions.columns.get_level_values("lp").unique()) 217 | .union(v2LpPositions.columns.get_level_values("lp").unique()) 218 | ) 219 | 220 | # Allocate space to save/update results 221 | addressRewards = pd.Series(np.zeros_like(lps, dtype=float), index=lps) 222 | 223 | # Separate v1 and v2 rewards 224 | for version in ["v1", "v2"]: 225 | print(f"Working on {version}") 226 | # Depending on version get different subset of data 227 | if version == "v1": 228 | startBlock = v1StartBlock 229 | endBlock = v1EndBlock 230 | df = v1LpPositions.sort_index() 231 | exchangeRates = pd.read_json("raw/v1ExchangeRates.json", orient="records") 232 | else: 233 | startBlock = v2StartBlock 234 | endBlock = v2EndBlock 235 | df = v2LpPositions.sort_index() 236 | exchangeRates = pd.read_json("raw/v2ExchangeRates.json", orient="records") 237 | 238 | # Compute total rewards for each version using the function defined 239 | # above 240 | out = computeLpRewards( 241 | df, exchangeRates, prices, 242 | startBlock, endBlock, rewardPerBlock 243 | ) 244 | addressRewards = addressRewards + out 245 | 246 | # Round small rewards to 1 ACX 247 | addressRewardsClipped = addressRewards.clip(lower=1) 248 | 249 | with open("final/lp_rewards.json", "w") as f: 250 | json.dump(addressRewardsClipped.to_dict(), f) 251 | -------------------------------------------------------------------------------- /parameters.yaml: -------------------------------------------------------------------------------- 1 | # Nodes that can be used to request data 2 | rpc_node: 3 | mainnet: !ENV ${MAINNET_NODE} 4 | optimism: !ENV ${OPTIMISM_NODE} 5 | polygon: !ENV ${POLYGON_NODE} 6 | boba: !ENV ${BOBA_NODE} 7 | arbitrum: !ENV ${ARBITRUM_NODE} 8 | 9 | etherscan_keys: 10 | mainnet: !ENV ${ETHERSCAN_API_KEY} 11 | optimism: !ENV ${OPTIMISTIC_ETHERSCAN_API_KEY} 12 | polygon: !ENV ${POLYGONSCAN_API_KEY} 13 | boba: !ENV ${BOBASCAN_API_KEY} 14 | arbitrum: !ENV ${ARBISCAN_API_KEY} 15 | 16 | # `across` parameters contain certain pieces of information that are useful 17 | # to reference in multiple places 18 | across: 19 | v1: 20 | mainnet: 21 | bridge: 22 | DAI: 23 | address: "0x43f133FE6fDFA17c417695c476447dc2a449Ba5B" 24 | first_block: 14_302_709 25 | USDC: 26 | address: "0x256C8919CE1AB0e33974CF6AA9c71561Ef3017b6" 27 | first_block: 13_545_487 28 | WBTC: 29 | address: "0x02fbb64517E1c6ED69a6FAa3ABf37Db0482f1152" 30 | first_block: 13_996_048 31 | WETH: 32 | address: "0x7355Efc63Ae731f584380a9838292c7046c1e433" 33 | first_block: 13_545_377 34 | optimism: 35 | deposit_box: 36 | address: "0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96" 37 | first_block: 204_576 38 | boba: 39 | deposit_box: 40 | address: "0xCD43CEa89DF8fE39031C03c24BC24480e942470B" 41 | first_block: 223_808 42 | arbitrum: 43 | deposit_box: 44 | address: "0xD8c6dD978a3768F7DDfE3A9aAD2c3Fd75Fa9B6Fd" 45 | first_block: 2_811_998 46 | v2: 47 | mainnet: 48 | hub: 49 | address: "0xc186fA914353c44b2E33eBE05f21846F1048bEda" 50 | first_block: 14_819_537 51 | spoke: 52 | address: "0x4D9079Bb4165aeb4084c526a32695dCfd2F77381" 53 | first_block: 14_819_486 54 | optimism: 55 | spoke: 56 | address: "0xa420b2d1c0841415A695b81E5B867BCD07Dff8C9" 57 | first_block: 8_747_136 58 | polygon: 59 | spoke: 60 | address: "0x69B5c72837769eF1e7C164Abc6515DcFf217F920" 61 | first_block: 28_604_263 62 | boba: 63 | spoke: 64 | address: "0xBbc6009fEfFc27ce705322832Cb2068F8C1e0A58" 65 | first_block: 619_993 66 | arbitrum: 67 | spoke: 68 | address: "0xB88690461dDbaB6f04Dfad7df66B7725942FEb9C" 69 | first_block: 12_741_972 70 | 71 | # `bridgoor` parameters correspond to specifications on how bridge users 72 | # are included in the airdrop 73 | bridgoor: 74 | # The number of blocks to request at a time for both v1/v2 bridge events 75 | n_blocks: 76 | 1: 25_000 77 | 10: 100_000 78 | 137: 3_500 79 | 288: 5_000 80 | 42161: 50_000 81 | 82 | # Only bridgoors who bridged to one of these chains/tokens receive rewards 83 | chains: ["mainnet", "optimism", "polygon", "boba", "arbitrum"] 84 | tokens: ["DAI", "USDC", "WBTC", "WETH"] 85 | 86 | v1_start_block: 13_576_190 # 2021-11-08T14:00+00:00 87 | v1_end_block: 14_987_809 # 2022-06-19T00:00+00:00 88 | 89 | v2_start_block: # 2022-05-24T14:00+00:00 90 | 1: 14_836_162 91 | 10: 8_915_780 92 | 137: 28_714_237 93 | 288: 622_100 94 | 42161: 12_862_573 95 | v2_end_block: # 2022-07-19T00:00+00:00 96 | 1: 15_169_695 97 | 10: 14_924_065 98 | 137: 30_878_164 99 | 288: 731_786 100 | 42161: 17_963_566 101 | 102 | # Shared parameters 103 | parameters: 104 | inclusion: 105 | # If you do this many transfers and a certain volume, you're included 106 | transfer_count: 2 107 | transfer_count_volume: 500 108 | 109 | # If you do this amount of volume, you're included 110 | volume_inclusion: 10_000 111 | 112 | score: 113 | # The power that the clipped volume is raised to 114 | power: 0.5 115 | # The upper bound of volume that counts for score 116 | ub: 5_000_000 117 | 118 | # Total rewards shared between bridgoors 119 | total_rewards: 15_000_000 120 | 121 | # `lp` parameters correspond to specifications on how liquidity providers 122 | # are included in the airdrop 123 | lp: 124 | # The number of blocks to request at a time for both v1/v2 liquidity events 125 | n_blocks: 500_000 126 | 127 | # LPs receive rewards for LPing for these tokens 128 | tokens: ["DAI", "USDC", "WBTC", "WETH"] 129 | 130 | # v1 start block picked by the v1 launch on 2021-11-08T14:00+00:00 131 | v1_start_block: 13_576_190 132 | # v1 end block picked by the v2 launch from 2022-05-24T14:00+00:00 133 | v1_end_block: 14_836_161 134 | 135 | # v2 launch block picked by the v2 launch on 2022-05-24T14:00+00:00 136 | v2_start_block: 14_836_162 137 | # v2 end block is 2022-11-28T06:00:00+00:00 138 | v2_end_block: 16_066_551 139 | 140 | v2_lp_token_creation_block: 141 | DAI: 14_828_021 142 | USDC: 14_824_012 143 | WBTC: 14_824_012 144 | WETH: 14_823_998 145 | 146 | v2_lp_token_creation_block: 147 | DAI: 14_828_021 148 | USDC: 14_824_012 149 | WBTC: 14_824_012 150 | WETH: 14_823_998 151 | 152 | # Shared parameters 153 | parameters: 154 | # Total rewards shared between LPs 155 | total_rewards: 70_000_000 156 | 157 | 158 | # `traveler` parameters correspond to specifications on which "bridge travelers" 159 | # should qualify for the "pre-drop" -- After they qualify, they still need 160 | # to accomplish their pre-determined Across tasks 161 | traveler: 162 | chains: ["mainnet", "optimism", "polygon", "boba", "arbitrum"] 163 | tokens: ["DAI", "USDC", "USDT", "ETH", "WETH", "WBTC"] 164 | 165 | n_blocks: 166 | 1: 25_000 167 | 10: 100_000 168 | 137: 3_500 169 | 288: 5_000 170 | 42161: 50_000 171 | 172 | travel_start_block: # 2022-10-11T00:00:00 173 | 1: 15_721_143 174 | 10: 28_581_865 175 | 137: 34_187_912 176 | 288: 835_877 177 | 42161: 29_474_892 178 | 179 | travel_end_block: # 2022-11-22T00:00:00 180 | 1: 16_021_829 181 | 10: 40_681_474 182 | 137: 35_904_127 183 | 288: 890_563 184 | 42161: 40_090_460 185 | 186 | # Cbridge 187 | cbridge: 188 | chains: ["mainnet", "optimism", "polygon", "arbitrum"] 189 | tokens: ["DAI", "USDC", "USDT", "ETH", "WETH"] 190 | 191 | contract_info: 192 | 1: 193 | address: "0x5427FEFA711Eff984124bFBB1AB6fbf5E3DA1820" 194 | first_block: 13_916_166 # 2022-01-01T00:00 195 | last_block: 15_449_618 # 2022-09-01T00:00 196 | 10: 197 | address: "0x9D39Fc627A6d9d9F8C831c16995b209548cc3401" 198 | first_block: 1_806_122 # 2022-01-01T00:00 199 | last_block: 21_406_456 # 2022-09-01T00:00 200 | 137: 201 | address: "0x88DCDC47D2f83a99CF0000FDF667A468bB958a78" 202 | first_block: 23_201_014 # 2022-01-01T00:00 203 | last_block: 32_534_499 # 2022-09-01T00:00 204 | 42161: 205 | address: "0x1619DE6B6B20eD217a58d00f37B9d47C7663feca" 206 | first_block: 4_221_290 # 2022-01-01T00:00 207 | last_block: 22_253_579 # 2022-09-01T00:00 208 | 209 | # Hop parameters 210 | hop: 211 | chains: ["mainnet", "optimism", "gnosis", "polygon", "arbitrum"] 212 | tokens: ["DAI", "USDC", "USDT", "ETH", "WETH"] 213 | first_block: # 2022-01-01T00:00 214 | 1: 13_916_166 215 | 10: 1_806_122 216 | 100: 19_872_632 217 | 137: 23_201_014 218 | 42161: 4_221_290 219 | last_block: # 2022-09-01T00:00 220 | 1: 15_449_618 221 | 10: 21_406_456 222 | 100: 23_980_828 223 | 137: 32_534_499 224 | 42161: 22_253_579 225 | 226 | # Stargate parameters 227 | stg: 228 | chains: ["mainnet", "optimism", "polygon", "arbitrum"] 229 | tokens: ["USDC", "USDT", "SGETH"] 230 | contract_info: 231 | 1: 232 | SGETH: 233 | address: "0x101816545F6bd2b1076434B54383a1E633390A2E" 234 | first_block: 15_035_701 # 2022-06-27T18:32 (deployment block) 235 | last_block: 15_449_618 # 2022-09-01T00:00 236 | USDC: 237 | address: "0xdf0770dF86a8034b3EFEf0A1Bb3c889B8332FF56" 238 | first_block: 14_403_393 # 2022-03-17T10:08 (deployment block) 239 | last_block: 15_449_618 # 2022-09-01T00:00 240 | 10: 241 | SGETH: 242 | address: "0xd22363e3762cA7339569F3d33EADe20127D5F98C" 243 | first_block: 13_332_734 # 2022-06-27T18:23 (deployment block) 244 | last_block: 21_406_456 # 2022-09-01T00:00 245 | USDC: 246 | address: "0xDecC0c09c3B5f6e92EF4184125D5648a66E35298" 247 | first_block: 4_535_509 # 2022-03-17T07:52 (deployment block) 248 | last_block: 21_406_456 # 2022-09-01T00:00 249 | 137: 250 | USDC: 251 | address: "0x1205f31718499dBf1fCa446663B532Ef87481fe1" 252 | first_block: 26_032_726 # 2022-03-17T08:05 (deployment block) 253 | last_block: 32_534_499 # 2022-09-01T00:00 254 | 42161: 255 | SGETH: 256 | address: "0x915A55e36A01285A14f05dE6e81ED9cE89772f8e" 257 | first_block: 16_112_680 # 2022-06-27T18:24 (deployment block) 258 | last_block: 22_535_579 # 2022-09-01T00:00 259 | USDC: 260 | address: "0x892785f33CdeE22A30AEF750F285E18c18040c3e" 261 | first_block: 8_041_115 # 2022-03-17T07:51 (deployment block) 262 | last_block: 22_535_579 # 2022-09-01T00:00 263 | 264 | # Synapse parameters 265 | synapse: 266 | chains: ["mainnet", "optimism", "polygon", "boba", "arbitrum"] 267 | tokens: ["USDC", "USDT", "nUSD", "ETH", "WETH", "nETH"] 268 | 269 | contract_info: 270 | 1: 271 | address: "0x2796317b0fF8538F253012862c06787Adfb8cEb6" 272 | first_block: 13_916_166 # 2022-01-01T00:00 273 | last_block: 15_449_618 # 2022-09-01T00:00 274 | 10: 275 | address: "0xAf41a65F786339e7911F4acDAD6BD49426F2Dc6b" 276 | first_block: 1_806_122 # 2022-01-01T00:00 277 | last_block: 21_406_456 # 2022-09-01T00:00 278 | 137: 279 | address: "0x8F5BBB2BB8c2Ee94639E55d5F41de9b4839C1280" 280 | first_block: 23_201_014 # 2022-01-01T00:00 281 | last_block: 32_534_499 # 2022-09-01T00:00 282 | 288: 283 | address: "0x432036208d2717394d2614d6697c46DF3Ed69540" 284 | first_block: 271_550 # 2022-01-01T00:00 285 | last_block: 731_786 # 2022-09-01T00:00 286 | 42161: 287 | address: "0x6F4e8eBa4D337f874Ab57478AcC2Cb5BACdc19c9" 288 | first_block: 4_221_290 # 2022-01-01T00:00 289 | last_block: 22_253_579 # 2022-09-01T00:00 290 | 291 | parameters: 292 | inclusion: 293 | # If you do this many transfers and a certain volume, you're included 294 | transfer_count: 5 295 | transfer_count_volume: 3_000 296 | 297 | # If you do this amount of volume, you're automatically included 298 | volume_inclusion: 25_000 299 | 300 | score: 301 | # The power that the clipped volume is raised to 302 | power: 0.5 303 | # The upper bound of volume that counts for score 304 | ub: 500_000 305 | 306 | rewards: 307 | tokens_lb: 10_000_000 308 | tokens_ub: 20_000_000 309 | bonus_threshold: 0.30 310 | clip_threshold: 25_000 311 | 312 | qualification: 313 | eth: 0 314 | usdc: 0.0000025 315 | 316 | misc: 317 | # Block data 318 | block: 319 | chains: ["mainnet", "optimism", "polygon", "boba", "arbitrum"] 320 | start_ts_mainnet: 1636329600 # 2021-11-08T00:00 321 | start_ts_nonmainnet: 1640995200 # 2022-01-01T00:00 322 | end_ts: 1669075200 # 2022-11-28T06:00 323 | 324 | # Price data 325 | price: 326 | start_ts: 1609459200 # 2021-01-01T00:00 327 | end_ts: 1669615200 # 2022-11-28T06:00 328 | tokens: ["DAI", "ETH", "USDC", "WBTC", "WETH"] 329 | -------------------------------------------------------------------------------- /acx/abis/v2SpokePool.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_hubPool", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "_wethAddress", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "timerAddress", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "uint256", 29 | "name": "rootBundleId", 30 | "type": "uint256" 31 | } 32 | ], 33 | "name": "EmergencyDeleteRootBundle", 34 | "type": "event" 35 | }, 36 | { 37 | "anonymous": false, 38 | "inputs": [ 39 | { 40 | "indexed": true, 41 | "internalType": "address", 42 | "name": "originToken", 43 | "type": "address" 44 | }, 45 | { 46 | "indexed": true, 47 | "internalType": "uint256", 48 | "name": "destinationChainId", 49 | "type": "uint256" 50 | }, 51 | { 52 | "indexed": false, 53 | "internalType": "bool", 54 | "name": "enabled", 55 | "type": "bool" 56 | } 57 | ], 58 | "name": "EnabledDepositRoute", 59 | "type": "event" 60 | }, 61 | { 62 | "anonymous": false, 63 | "inputs": [ 64 | { 65 | "indexed": false, 66 | "internalType": "uint256", 67 | "name": "amountToReturn", 68 | "type": "uint256" 69 | }, 70 | { 71 | "indexed": true, 72 | "internalType": "uint256", 73 | "name": "chainId", 74 | "type": "uint256" 75 | }, 76 | { 77 | "indexed": false, 78 | "internalType": "uint256[]", 79 | "name": "refundAmounts", 80 | "type": "uint256[]" 81 | }, 82 | { 83 | "indexed": true, 84 | "internalType": "uint32", 85 | "name": "rootBundleId", 86 | "type": "uint32" 87 | }, 88 | { 89 | "indexed": true, 90 | "internalType": "uint32", 91 | "name": "leafId", 92 | "type": "uint32" 93 | }, 94 | { 95 | "indexed": false, 96 | "internalType": "address", 97 | "name": "l2TokenAddress", 98 | "type": "address" 99 | }, 100 | { 101 | "indexed": false, 102 | "internalType": "address[]", 103 | "name": "refundAddresses", 104 | "type": "address[]" 105 | }, 106 | { 107 | "indexed": false, 108 | "internalType": "address", 109 | "name": "caller", 110 | "type": "address" 111 | } 112 | ], 113 | "name": "ExecutedRelayerRefundRoot", 114 | "type": "event" 115 | }, 116 | { 117 | "anonymous": false, 118 | "inputs": [ 119 | { 120 | "indexed": false, 121 | "internalType": "uint256", 122 | "name": "amount", 123 | "type": "uint256" 124 | }, 125 | { 126 | "indexed": false, 127 | "internalType": "uint256", 128 | "name": "totalFilledAmount", 129 | "type": "uint256" 130 | }, 131 | { 132 | "indexed": false, 133 | "internalType": "uint256", 134 | "name": "fillAmount", 135 | "type": "uint256" 136 | }, 137 | { 138 | "indexed": false, 139 | "internalType": "uint256", 140 | "name": "repaymentChainId", 141 | "type": "uint256" 142 | }, 143 | { 144 | "indexed": false, 145 | "internalType": "uint256", 146 | "name": "originChainId", 147 | "type": "uint256" 148 | }, 149 | { 150 | "indexed": false, 151 | "internalType": "uint256", 152 | "name": "destinationChainId", 153 | "type": "uint256" 154 | }, 155 | { 156 | "indexed": false, 157 | "internalType": "uint64", 158 | "name": "relayerFeePct", 159 | "type": "uint64" 160 | }, 161 | { 162 | "indexed": false, 163 | "internalType": "uint64", 164 | "name": "appliedRelayerFeePct", 165 | "type": "uint64" 166 | }, 167 | { 168 | "indexed": false, 169 | "internalType": "uint64", 170 | "name": "realizedLpFeePct", 171 | "type": "uint64" 172 | }, 173 | { 174 | "indexed": false, 175 | "internalType": "uint32", 176 | "name": "depositId", 177 | "type": "uint32" 178 | }, 179 | { 180 | "indexed": false, 181 | "internalType": "address", 182 | "name": "destinationToken", 183 | "type": "address" 184 | }, 185 | { 186 | "indexed": true, 187 | "internalType": "address", 188 | "name": "relayer", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": true, 193 | "internalType": "address", 194 | "name": "depositor", 195 | "type": "address" 196 | }, 197 | { 198 | "indexed": false, 199 | "internalType": "address", 200 | "name": "recipient", 201 | "type": "address" 202 | }, 203 | { 204 | "indexed": false, 205 | "internalType": "bool", 206 | "name": "isSlowRelay", 207 | "type": "bool" 208 | } 209 | ], 210 | "name": "FilledRelay", 211 | "type": "event" 212 | }, 213 | { 214 | "anonymous": false, 215 | "inputs": [ 216 | { 217 | "indexed": false, 218 | "internalType": "uint256", 219 | "name": "amount", 220 | "type": "uint256" 221 | }, 222 | { 223 | "indexed": false, 224 | "internalType": "uint256", 225 | "name": "originChainId", 226 | "type": "uint256" 227 | }, 228 | { 229 | "indexed": false, 230 | "internalType": "uint256", 231 | "name": "destinationChainId", 232 | "type": "uint256" 233 | }, 234 | { 235 | "indexed": false, 236 | "internalType": "uint64", 237 | "name": "relayerFeePct", 238 | "type": "uint64" 239 | }, 240 | { 241 | "indexed": true, 242 | "internalType": "uint32", 243 | "name": "depositId", 244 | "type": "uint32" 245 | }, 246 | { 247 | "indexed": false, 248 | "internalType": "uint32", 249 | "name": "quoteTimestamp", 250 | "type": "uint32" 251 | }, 252 | { 253 | "indexed": true, 254 | "internalType": "address", 255 | "name": "originToken", 256 | "type": "address" 257 | }, 258 | { 259 | "indexed": false, 260 | "internalType": "address", 261 | "name": "recipient", 262 | "type": "address" 263 | }, 264 | { 265 | "indexed": true, 266 | "internalType": "address", 267 | "name": "depositor", 268 | "type": "address" 269 | } 270 | ], 271 | "name": "FundsDeposited", 272 | "type": "event" 273 | }, 274 | { 275 | "anonymous": false, 276 | "inputs": [ 277 | { 278 | "indexed": true, 279 | "internalType": "address", 280 | "name": "previousOwner", 281 | "type": "address" 282 | }, 283 | { 284 | "indexed": true, 285 | "internalType": "address", 286 | "name": "newOwner", 287 | "type": "address" 288 | } 289 | ], 290 | "name": "OwnershipTransferred", 291 | "type": "event" 292 | }, 293 | { 294 | "anonymous": false, 295 | "inputs": [ 296 | { 297 | "indexed": true, 298 | "internalType": "uint32", 299 | "name": "rootBundleId", 300 | "type": "uint32" 301 | }, 302 | { 303 | "indexed": true, 304 | "internalType": "bytes32", 305 | "name": "relayerRefundRoot", 306 | "type": "bytes32" 307 | }, 308 | { 309 | "indexed": true, 310 | "internalType": "bytes32", 311 | "name": "slowRelayRoot", 312 | "type": "bytes32" 313 | } 314 | ], 315 | "name": "RelayedRootBundle", 316 | "type": "event" 317 | }, 318 | { 319 | "anonymous": false, 320 | "inputs": [ 321 | { 322 | "indexed": false, 323 | "internalType": "uint64", 324 | "name": "newRelayerFeePct", 325 | "type": "uint64" 326 | }, 327 | { 328 | "indexed": true, 329 | "internalType": "uint32", 330 | "name": "depositId", 331 | "type": "uint32" 332 | }, 333 | { 334 | "indexed": true, 335 | "internalType": "address", 336 | "name": "depositor", 337 | "type": "address" 338 | }, 339 | { 340 | "indexed": false, 341 | "internalType": "bytes", 342 | "name": "depositorSignature", 343 | "type": "bytes" 344 | } 345 | ], 346 | "name": "RequestedSpeedUpDeposit", 347 | "type": "event" 348 | }, 349 | { 350 | "anonymous": false, 351 | "inputs": [ 352 | { 353 | "indexed": false, 354 | "internalType": "uint32", 355 | "name": "newBuffer", 356 | "type": "uint32" 357 | } 358 | ], 359 | "name": "SetDepositQuoteTimeBuffer", 360 | "type": "event" 361 | }, 362 | { 363 | "anonymous": false, 364 | "inputs": [ 365 | { 366 | "indexed": true, 367 | "internalType": "address", 368 | "name": "newHubPool", 369 | "type": "address" 370 | } 371 | ], 372 | "name": "SetHubPool", 373 | "type": "event" 374 | }, 375 | { 376 | "anonymous": false, 377 | "inputs": [ 378 | { 379 | "indexed": true, 380 | "internalType": "address", 381 | "name": "newAdmin", 382 | "type": "address" 383 | } 384 | ], 385 | "name": "SetXDomainAdmin", 386 | "type": "event" 387 | }, 388 | { 389 | "anonymous": false, 390 | "inputs": [ 391 | { 392 | "indexed": false, 393 | "internalType": "uint256", 394 | "name": "amountToReturn", 395 | "type": "uint256" 396 | }, 397 | { 398 | "indexed": true, 399 | "internalType": "uint256", 400 | "name": "chainId", 401 | "type": "uint256" 402 | }, 403 | { 404 | "indexed": true, 405 | "internalType": "uint32", 406 | "name": "leafId", 407 | "type": "uint32" 408 | }, 409 | { 410 | "indexed": true, 411 | "internalType": "address", 412 | "name": "l2TokenAddress", 413 | "type": "address" 414 | }, 415 | { 416 | "indexed": false, 417 | "internalType": "address", 418 | "name": "caller", 419 | "type": "address" 420 | } 421 | ], 422 | "name": "TokensBridged", 423 | "type": "event" 424 | }, 425 | { 426 | "inputs": [], 427 | "name": "chainId", 428 | "outputs": [ 429 | { 430 | "internalType": "uint256", 431 | "name": "", 432 | "type": "uint256" 433 | } 434 | ], 435 | "stateMutability": "view", 436 | "type": "function" 437 | }, 438 | { 439 | "inputs": [], 440 | "name": "crossDomainAdmin", 441 | "outputs": [ 442 | { 443 | "internalType": "address", 444 | "name": "", 445 | "type": "address" 446 | } 447 | ], 448 | "stateMutability": "view", 449 | "type": "function" 450 | }, 451 | { 452 | "inputs": [ 453 | { 454 | "internalType": "address", 455 | "name": "recipient", 456 | "type": "address" 457 | }, 458 | { 459 | "internalType": "address", 460 | "name": "originToken", 461 | "type": "address" 462 | }, 463 | { 464 | "internalType": "uint256", 465 | "name": "amount", 466 | "type": "uint256" 467 | }, 468 | { 469 | "internalType": "uint256", 470 | "name": "destinationChainId", 471 | "type": "uint256" 472 | }, 473 | { 474 | "internalType": "uint64", 475 | "name": "relayerFeePct", 476 | "type": "uint64" 477 | }, 478 | { 479 | "internalType": "uint32", 480 | "name": "quoteTimestamp", 481 | "type": "uint32" 482 | } 483 | ], 484 | "name": "deposit", 485 | "outputs": [], 486 | "stateMutability": "payable", 487 | "type": "function" 488 | }, 489 | { 490 | "inputs": [], 491 | "name": "depositQuoteTimeBuffer", 492 | "outputs": [ 493 | { 494 | "internalType": "uint32", 495 | "name": "", 496 | "type": "uint32" 497 | } 498 | ], 499 | "stateMutability": "view", 500 | "type": "function" 501 | }, 502 | { 503 | "inputs": [ 504 | { 505 | "internalType": "uint256", 506 | "name": "rootBundleId", 507 | "type": "uint256" 508 | } 509 | ], 510 | "name": "emergencyDeleteRootBundle", 511 | "outputs": [], 512 | "stateMutability": "nonpayable", 513 | "type": "function" 514 | }, 515 | { 516 | "inputs": [ 517 | { 518 | "internalType": "address", 519 | "name": "", 520 | "type": "address" 521 | }, 522 | { 523 | "internalType": "uint256", 524 | "name": "", 525 | "type": "uint256" 526 | } 527 | ], 528 | "name": "enabledDepositRoutes", 529 | "outputs": [ 530 | { 531 | "internalType": "bool", 532 | "name": "", 533 | "type": "bool" 534 | } 535 | ], 536 | "stateMutability": "view", 537 | "type": "function" 538 | }, 539 | { 540 | "inputs": [ 541 | { 542 | "internalType": "uint32", 543 | "name": "rootBundleId", 544 | "type": "uint32" 545 | }, 546 | { 547 | "components": [ 548 | { 549 | "internalType": "uint256", 550 | "name": "amountToReturn", 551 | "type": "uint256" 552 | }, 553 | { 554 | "internalType": "uint256", 555 | "name": "chainId", 556 | "type": "uint256" 557 | }, 558 | { 559 | "internalType": "uint256[]", 560 | "name": "refundAmounts", 561 | "type": "uint256[]" 562 | }, 563 | { 564 | "internalType": "uint32", 565 | "name": "leafId", 566 | "type": "uint32" 567 | }, 568 | { 569 | "internalType": "address", 570 | "name": "l2TokenAddress", 571 | "type": "address" 572 | }, 573 | { 574 | "internalType": "address[]", 575 | "name": "refundAddresses", 576 | "type": "address[]" 577 | } 578 | ], 579 | "internalType": "struct SpokePoolInterface.RelayerRefundLeaf", 580 | "name": "relayerRefundLeaf", 581 | "type": "tuple" 582 | }, 583 | { 584 | "internalType": "bytes32[]", 585 | "name": "proof", 586 | "type": "bytes32[]" 587 | } 588 | ], 589 | "name": "executeRelayerRefundLeaf", 590 | "outputs": [], 591 | "stateMutability": "nonpayable", 592 | "type": "function" 593 | }, 594 | { 595 | "inputs": [ 596 | { 597 | "internalType": "address", 598 | "name": "depositor", 599 | "type": "address" 600 | }, 601 | { 602 | "internalType": "address", 603 | "name": "recipient", 604 | "type": "address" 605 | }, 606 | { 607 | "internalType": "address", 608 | "name": "destinationToken", 609 | "type": "address" 610 | }, 611 | { 612 | "internalType": "uint256", 613 | "name": "amount", 614 | "type": "uint256" 615 | }, 616 | { 617 | "internalType": "uint256", 618 | "name": "originChainId", 619 | "type": "uint256" 620 | }, 621 | { 622 | "internalType": "uint64", 623 | "name": "realizedLpFeePct", 624 | "type": "uint64" 625 | }, 626 | { 627 | "internalType": "uint64", 628 | "name": "relayerFeePct", 629 | "type": "uint64" 630 | }, 631 | { 632 | "internalType": "uint32", 633 | "name": "depositId", 634 | "type": "uint32" 635 | }, 636 | { 637 | "internalType": "uint32", 638 | "name": "rootBundleId", 639 | "type": "uint32" 640 | }, 641 | { 642 | "internalType": "bytes32[]", 643 | "name": "proof", 644 | "type": "bytes32[]" 645 | } 646 | ], 647 | "name": "executeSlowRelayLeaf", 648 | "outputs": [], 649 | "stateMutability": "nonpayable", 650 | "type": "function" 651 | }, 652 | { 653 | "inputs": [ 654 | { 655 | "internalType": "address", 656 | "name": "depositor", 657 | "type": "address" 658 | }, 659 | { 660 | "internalType": "address", 661 | "name": "recipient", 662 | "type": "address" 663 | }, 664 | { 665 | "internalType": "address", 666 | "name": "destinationToken", 667 | "type": "address" 668 | }, 669 | { 670 | "internalType": "uint256", 671 | "name": "amount", 672 | "type": "uint256" 673 | }, 674 | { 675 | "internalType": "uint256", 676 | "name": "maxTokensToSend", 677 | "type": "uint256" 678 | }, 679 | { 680 | "internalType": "uint256", 681 | "name": "repaymentChainId", 682 | "type": "uint256" 683 | }, 684 | { 685 | "internalType": "uint256", 686 | "name": "originChainId", 687 | "type": "uint256" 688 | }, 689 | { 690 | "internalType": "uint64", 691 | "name": "realizedLpFeePct", 692 | "type": "uint64" 693 | }, 694 | { 695 | "internalType": "uint64", 696 | "name": "relayerFeePct", 697 | "type": "uint64" 698 | }, 699 | { 700 | "internalType": "uint32", 701 | "name": "depositId", 702 | "type": "uint32" 703 | } 704 | ], 705 | "name": "fillRelay", 706 | "outputs": [], 707 | "stateMutability": "nonpayable", 708 | "type": "function" 709 | }, 710 | { 711 | "inputs": [ 712 | { 713 | "internalType": "address", 714 | "name": "depositor", 715 | "type": "address" 716 | }, 717 | { 718 | "internalType": "address", 719 | "name": "recipient", 720 | "type": "address" 721 | }, 722 | { 723 | "internalType": "address", 724 | "name": "destinationToken", 725 | "type": "address" 726 | }, 727 | { 728 | "internalType": "uint256", 729 | "name": "amount", 730 | "type": "uint256" 731 | }, 732 | { 733 | "internalType": "uint256", 734 | "name": "maxTokensToSend", 735 | "type": "uint256" 736 | }, 737 | { 738 | "internalType": "uint256", 739 | "name": "repaymentChainId", 740 | "type": "uint256" 741 | }, 742 | { 743 | "internalType": "uint256", 744 | "name": "originChainId", 745 | "type": "uint256" 746 | }, 747 | { 748 | "internalType": "uint64", 749 | "name": "realizedLpFeePct", 750 | "type": "uint64" 751 | }, 752 | { 753 | "internalType": "uint64", 754 | "name": "relayerFeePct", 755 | "type": "uint64" 756 | }, 757 | { 758 | "internalType": "uint64", 759 | "name": "newRelayerFeePct", 760 | "type": "uint64" 761 | }, 762 | { 763 | "internalType": "uint32", 764 | "name": "depositId", 765 | "type": "uint32" 766 | }, 767 | { 768 | "internalType": "bytes", 769 | "name": "depositorSignature", 770 | "type": "bytes" 771 | } 772 | ], 773 | "name": "fillRelayWithUpdatedFee", 774 | "outputs": [], 775 | "stateMutability": "nonpayable", 776 | "type": "function" 777 | }, 778 | { 779 | "inputs": [], 780 | "name": "getCurrentTime", 781 | "outputs": [ 782 | { 783 | "internalType": "uint256", 784 | "name": "", 785 | "type": "uint256" 786 | } 787 | ], 788 | "stateMutability": "view", 789 | "type": "function" 790 | }, 791 | { 792 | "inputs": [], 793 | "name": "hubPool", 794 | "outputs": [ 795 | { 796 | "internalType": "address", 797 | "name": "", 798 | "type": "address" 799 | } 800 | ], 801 | "stateMutability": "view", 802 | "type": "function" 803 | }, 804 | { 805 | "inputs": [ 806 | { 807 | "internalType": "bytes[]", 808 | "name": "data", 809 | "type": "bytes[]" 810 | } 811 | ], 812 | "name": "multicall", 813 | "outputs": [ 814 | { 815 | "internalType": "bytes[]", 816 | "name": "results", 817 | "type": "bytes[]" 818 | } 819 | ], 820 | "stateMutability": "payable", 821 | "type": "function" 822 | }, 823 | { 824 | "inputs": [], 825 | "name": "numberOfDeposits", 826 | "outputs": [ 827 | { 828 | "internalType": "uint32", 829 | "name": "", 830 | "type": "uint32" 831 | } 832 | ], 833 | "stateMutability": "view", 834 | "type": "function" 835 | }, 836 | { 837 | "inputs": [], 838 | "name": "owner", 839 | "outputs": [ 840 | { 841 | "internalType": "address", 842 | "name": "", 843 | "type": "address" 844 | } 845 | ], 846 | "stateMutability": "view", 847 | "type": "function" 848 | }, 849 | { 850 | "inputs": [ 851 | { 852 | "internalType": "bytes32", 853 | "name": "", 854 | "type": "bytes32" 855 | } 856 | ], 857 | "name": "relayFills", 858 | "outputs": [ 859 | { 860 | "internalType": "uint256", 861 | "name": "", 862 | "type": "uint256" 863 | } 864 | ], 865 | "stateMutability": "view", 866 | "type": "function" 867 | }, 868 | { 869 | "inputs": [ 870 | { 871 | "internalType": "bytes32", 872 | "name": "relayerRefundRoot", 873 | "type": "bytes32" 874 | }, 875 | { 876 | "internalType": "bytes32", 877 | "name": "slowRelayRoot", 878 | "type": "bytes32" 879 | } 880 | ], 881 | "name": "relayRootBundle", 882 | "outputs": [], 883 | "stateMutability": "nonpayable", 884 | "type": "function" 885 | }, 886 | { 887 | "inputs": [], 888 | "name": "renounceOwnership", 889 | "outputs": [], 890 | "stateMutability": "nonpayable", 891 | "type": "function" 892 | }, 893 | { 894 | "inputs": [ 895 | { 896 | "internalType": "uint256", 897 | "name": "", 898 | "type": "uint256" 899 | } 900 | ], 901 | "name": "rootBundles", 902 | "outputs": [ 903 | { 904 | "internalType": "bytes32", 905 | "name": "slowRelayRoot", 906 | "type": "bytes32" 907 | }, 908 | { 909 | "internalType": "bytes32", 910 | "name": "relayerRefundRoot", 911 | "type": "bytes32" 912 | } 913 | ], 914 | "stateMutability": "view", 915 | "type": "function" 916 | }, 917 | { 918 | "inputs": [ 919 | { 920 | "internalType": "address", 921 | "name": "newCrossDomainAdmin", 922 | "type": "address" 923 | } 924 | ], 925 | "name": "setCrossDomainAdmin", 926 | "outputs": [], 927 | "stateMutability": "nonpayable", 928 | "type": "function" 929 | }, 930 | { 931 | "inputs": [ 932 | { 933 | "internalType": "uint256", 934 | "name": "time", 935 | "type": "uint256" 936 | } 937 | ], 938 | "name": "setCurrentTime", 939 | "outputs": [], 940 | "stateMutability": "nonpayable", 941 | "type": "function" 942 | }, 943 | { 944 | "inputs": [ 945 | { 946 | "internalType": "uint32", 947 | "name": "newDepositQuoteTimeBuffer", 948 | "type": "uint32" 949 | } 950 | ], 951 | "name": "setDepositQuoteTimeBuffer", 952 | "outputs": [], 953 | "stateMutability": "nonpayable", 954 | "type": "function" 955 | }, 956 | { 957 | "inputs": [ 958 | { 959 | "internalType": "address", 960 | "name": "originToken", 961 | "type": "address" 962 | }, 963 | { 964 | "internalType": "uint256", 965 | "name": "destinationChainId", 966 | "type": "uint256" 967 | }, 968 | { 969 | "internalType": "bool", 970 | "name": "enabled", 971 | "type": "bool" 972 | } 973 | ], 974 | "name": "setEnableRoute", 975 | "outputs": [], 976 | "stateMutability": "nonpayable", 977 | "type": "function" 978 | }, 979 | { 980 | "inputs": [ 981 | { 982 | "internalType": "address", 983 | "name": "newHubPool", 984 | "type": "address" 985 | } 986 | ], 987 | "name": "setHubPool", 988 | "outputs": [], 989 | "stateMutability": "nonpayable", 990 | "type": "function" 991 | }, 992 | { 993 | "inputs": [ 994 | { 995 | "internalType": "address", 996 | "name": "depositor", 997 | "type": "address" 998 | }, 999 | { 1000 | "internalType": "uint64", 1001 | "name": "newRelayerFeePct", 1002 | "type": "uint64" 1003 | }, 1004 | { 1005 | "internalType": "uint32", 1006 | "name": "depositId", 1007 | "type": "uint32" 1008 | }, 1009 | { 1010 | "internalType": "bytes", 1011 | "name": "depositorSignature", 1012 | "type": "bytes" 1013 | } 1014 | ], 1015 | "name": "speedUpDeposit", 1016 | "outputs": [], 1017 | "stateMutability": "nonpayable", 1018 | "type": "function" 1019 | }, 1020 | { 1021 | "inputs": [], 1022 | "name": "timerAddress", 1023 | "outputs": [ 1024 | { 1025 | "internalType": "address", 1026 | "name": "", 1027 | "type": "address" 1028 | } 1029 | ], 1030 | "stateMutability": "view", 1031 | "type": "function" 1032 | }, 1033 | { 1034 | "inputs": [ 1035 | { 1036 | "internalType": "address", 1037 | "name": "newOwner", 1038 | "type": "address" 1039 | } 1040 | ], 1041 | "name": "transferOwnership", 1042 | "outputs": [], 1043 | "stateMutability": "nonpayable", 1044 | "type": "function" 1045 | }, 1046 | { 1047 | "inputs": [], 1048 | "name": "wrappedNativeToken", 1049 | "outputs": [ 1050 | { 1051 | "internalType": "contract WETH9", 1052 | "name": "", 1053 | "type": "address" 1054 | } 1055 | ], 1056 | "stateMutability": "view", 1057 | "type": "function" 1058 | }, 1059 | { 1060 | "stateMutability": "payable", 1061 | "type": "receive" 1062 | } 1063 | ] 1064 | -------------------------------------------------------------------------------- /acx/abis/SynapseBridge.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "address", 8 | "name": "account", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "Paused", 13 | "type": "event" 14 | }, 15 | { 16 | "anonymous": false, 17 | "inputs": [ 18 | { 19 | "indexed": true, 20 | "internalType": "bytes32", 21 | "name": "role", 22 | "type": "bytes32" 23 | }, 24 | { 25 | "indexed": true, 26 | "internalType": "bytes32", 27 | "name": "previousAdminRole", 28 | "type": "bytes32" 29 | }, 30 | { 31 | "indexed": true, 32 | "internalType": "bytes32", 33 | "name": "newAdminRole", 34 | "type": "bytes32" 35 | } 36 | ], 37 | "name": "RoleAdminChanged", 38 | "type": "event" 39 | }, 40 | { 41 | "anonymous": false, 42 | "inputs": [ 43 | { 44 | "indexed": true, 45 | "internalType": "bytes32", 46 | "name": "role", 47 | "type": "bytes32" 48 | }, 49 | { 50 | "indexed": true, 51 | "internalType": "address", 52 | "name": "account", 53 | "type": "address" 54 | }, 55 | { 56 | "indexed": true, 57 | "internalType": "address", 58 | "name": "sender", 59 | "type": "address" 60 | } 61 | ], 62 | "name": "RoleGranted", 63 | "type": "event" 64 | }, 65 | { 66 | "anonymous": false, 67 | "inputs": [ 68 | { 69 | "indexed": true, 70 | "internalType": "bytes32", 71 | "name": "role", 72 | "type": "bytes32" 73 | }, 74 | { 75 | "indexed": true, 76 | "internalType": "address", 77 | "name": "account", 78 | "type": "address" 79 | }, 80 | { 81 | "indexed": true, 82 | "internalType": "address", 83 | "name": "sender", 84 | "type": "address" 85 | } 86 | ], 87 | "name": "RoleRevoked", 88 | "type": "event" 89 | }, 90 | { 91 | "anonymous": false, 92 | "inputs": [ 93 | { 94 | "indexed": true, 95 | "internalType": "address", 96 | "name": "to", 97 | "type": "address" 98 | }, 99 | { 100 | "indexed": false, 101 | "internalType": "uint256", 102 | "name": "chainId", 103 | "type": "uint256" 104 | }, 105 | { 106 | "indexed": false, 107 | "internalType": "contract IERC20", 108 | "name": "token", 109 | "type": "address" 110 | }, 111 | { 112 | "indexed": false, 113 | "internalType": "uint256", 114 | "name": "amount", 115 | "type": "uint256" 116 | } 117 | ], 118 | "name": "TokenDeposit", 119 | "type": "event" 120 | }, 121 | { 122 | "anonymous": false, 123 | "inputs": [ 124 | { 125 | "indexed": true, 126 | "internalType": "address", 127 | "name": "to", 128 | "type": "address" 129 | }, 130 | { 131 | "indexed": false, 132 | "internalType": "uint256", 133 | "name": "chainId", 134 | "type": "uint256" 135 | }, 136 | { 137 | "indexed": false, 138 | "internalType": "contract IERC20", 139 | "name": "token", 140 | "type": "address" 141 | }, 142 | { 143 | "indexed": false, 144 | "internalType": "uint256", 145 | "name": "amount", 146 | "type": "uint256" 147 | }, 148 | { 149 | "indexed": false, 150 | "internalType": "uint8", 151 | "name": "tokenIndexFrom", 152 | "type": "uint8" 153 | }, 154 | { 155 | "indexed": false, 156 | "internalType": "uint8", 157 | "name": "tokenIndexTo", 158 | "type": "uint8" 159 | }, 160 | { 161 | "indexed": false, 162 | "internalType": "uint256", 163 | "name": "minDy", 164 | "type": "uint256" 165 | }, 166 | { 167 | "indexed": false, 168 | "internalType": "uint256", 169 | "name": "deadline", 170 | "type": "uint256" 171 | } 172 | ], 173 | "name": "TokenDepositAndSwap", 174 | "type": "event" 175 | }, 176 | { 177 | "anonymous": false, 178 | "inputs": [ 179 | { 180 | "indexed": true, 181 | "internalType": "address", 182 | "name": "to", 183 | "type": "address" 184 | }, 185 | { 186 | "indexed": false, 187 | "internalType": "contract IERC20Mintable", 188 | "name": "token", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "internalType": "uint256", 194 | "name": "amount", 195 | "type": "uint256" 196 | }, 197 | { 198 | "indexed": false, 199 | "internalType": "uint256", 200 | "name": "fee", 201 | "type": "uint256" 202 | }, 203 | { 204 | "indexed": true, 205 | "internalType": "bytes32", 206 | "name": "kappa", 207 | "type": "bytes32" 208 | } 209 | ], 210 | "name": "TokenMint", 211 | "type": "event" 212 | }, 213 | { 214 | "anonymous": false, 215 | "inputs": [ 216 | { 217 | "indexed": true, 218 | "internalType": "address", 219 | "name": "to", 220 | "type": "address" 221 | }, 222 | { 223 | "indexed": false, 224 | "internalType": "contract IERC20Mintable", 225 | "name": "token", 226 | "type": "address" 227 | }, 228 | { 229 | "indexed": false, 230 | "internalType": "uint256", 231 | "name": "amount", 232 | "type": "uint256" 233 | }, 234 | { 235 | "indexed": false, 236 | "internalType": "uint256", 237 | "name": "fee", 238 | "type": "uint256" 239 | }, 240 | { 241 | "indexed": false, 242 | "internalType": "uint8", 243 | "name": "tokenIndexFrom", 244 | "type": "uint8" 245 | }, 246 | { 247 | "indexed": false, 248 | "internalType": "uint8", 249 | "name": "tokenIndexTo", 250 | "type": "uint8" 251 | }, 252 | { 253 | "indexed": false, 254 | "internalType": "uint256", 255 | "name": "minDy", 256 | "type": "uint256" 257 | }, 258 | { 259 | "indexed": false, 260 | "internalType": "uint256", 261 | "name": "deadline", 262 | "type": "uint256" 263 | }, 264 | { 265 | "indexed": false, 266 | "internalType": "bool", 267 | "name": "swapSuccess", 268 | "type": "bool" 269 | }, 270 | { 271 | "indexed": true, 272 | "internalType": "bytes32", 273 | "name": "kappa", 274 | "type": "bytes32" 275 | } 276 | ], 277 | "name": "TokenMintAndSwap", 278 | "type": "event" 279 | }, 280 | { 281 | "anonymous": false, 282 | "inputs": [ 283 | { 284 | "indexed": true, 285 | "internalType": "address", 286 | "name": "to", 287 | "type": "address" 288 | }, 289 | { 290 | "indexed": false, 291 | "internalType": "uint256", 292 | "name": "chainId", 293 | "type": "uint256" 294 | }, 295 | { 296 | "indexed": false, 297 | "internalType": "contract IERC20", 298 | "name": "token", 299 | "type": "address" 300 | }, 301 | { 302 | "indexed": false, 303 | "internalType": "uint256", 304 | "name": "amount", 305 | "type": "uint256" 306 | } 307 | ], 308 | "name": "TokenRedeem", 309 | "type": "event" 310 | }, 311 | { 312 | "anonymous": false, 313 | "inputs": [ 314 | { 315 | "indexed": true, 316 | "internalType": "address", 317 | "name": "to", 318 | "type": "address" 319 | }, 320 | { 321 | "indexed": false, 322 | "internalType": "uint256", 323 | "name": "chainId", 324 | "type": "uint256" 325 | }, 326 | { 327 | "indexed": false, 328 | "internalType": "contract IERC20", 329 | "name": "token", 330 | "type": "address" 331 | }, 332 | { 333 | "indexed": false, 334 | "internalType": "uint256", 335 | "name": "amount", 336 | "type": "uint256" 337 | }, 338 | { 339 | "indexed": false, 340 | "internalType": "uint8", 341 | "name": "swapTokenIndex", 342 | "type": "uint8" 343 | }, 344 | { 345 | "indexed": false, 346 | "internalType": "uint256", 347 | "name": "swapMinAmount", 348 | "type": "uint256" 349 | }, 350 | { 351 | "indexed": false, 352 | "internalType": "uint256", 353 | "name": "swapDeadline", 354 | "type": "uint256" 355 | } 356 | ], 357 | "name": "TokenRedeemAndRemove", 358 | "type": "event" 359 | }, 360 | { 361 | "anonymous": false, 362 | "inputs": [ 363 | { 364 | "indexed": true, 365 | "internalType": "address", 366 | "name": "to", 367 | "type": "address" 368 | }, 369 | { 370 | "indexed": false, 371 | "internalType": "uint256", 372 | "name": "chainId", 373 | "type": "uint256" 374 | }, 375 | { 376 | "indexed": false, 377 | "internalType": "contract IERC20", 378 | "name": "token", 379 | "type": "address" 380 | }, 381 | { 382 | "indexed": false, 383 | "internalType": "uint256", 384 | "name": "amount", 385 | "type": "uint256" 386 | }, 387 | { 388 | "indexed": false, 389 | "internalType": "uint8", 390 | "name": "tokenIndexFrom", 391 | "type": "uint8" 392 | }, 393 | { 394 | "indexed": false, 395 | "internalType": "uint8", 396 | "name": "tokenIndexTo", 397 | "type": "uint8" 398 | }, 399 | { 400 | "indexed": false, 401 | "internalType": "uint256", 402 | "name": "minDy", 403 | "type": "uint256" 404 | }, 405 | { 406 | "indexed": false, 407 | "internalType": "uint256", 408 | "name": "deadline", 409 | "type": "uint256" 410 | } 411 | ], 412 | "name": "TokenRedeemAndSwap", 413 | "type": "event" 414 | }, 415 | { 416 | "anonymous": false, 417 | "inputs": [ 418 | { 419 | "indexed": true, 420 | "internalType": "bytes32", 421 | "name": "to", 422 | "type": "bytes32" 423 | }, 424 | { 425 | "indexed": false, 426 | "internalType": "uint256", 427 | "name": "chainId", 428 | "type": "uint256" 429 | }, 430 | { 431 | "indexed": false, 432 | "internalType": "contract IERC20", 433 | "name": "token", 434 | "type": "address" 435 | }, 436 | { 437 | "indexed": false, 438 | "internalType": "uint256", 439 | "name": "amount", 440 | "type": "uint256" 441 | } 442 | ], 443 | "name": "TokenRedeemV2", 444 | "type": "event" 445 | }, 446 | { 447 | "anonymous": false, 448 | "inputs": [ 449 | { 450 | "indexed": true, 451 | "internalType": "address", 452 | "name": "to", 453 | "type": "address" 454 | }, 455 | { 456 | "indexed": false, 457 | "internalType": "contract IERC20", 458 | "name": "token", 459 | "type": "address" 460 | }, 461 | { 462 | "indexed": false, 463 | "internalType": "uint256", 464 | "name": "amount", 465 | "type": "uint256" 466 | }, 467 | { 468 | "indexed": false, 469 | "internalType": "uint256", 470 | "name": "fee", 471 | "type": "uint256" 472 | }, 473 | { 474 | "indexed": true, 475 | "internalType": "bytes32", 476 | "name": "kappa", 477 | "type": "bytes32" 478 | } 479 | ], 480 | "name": "TokenWithdraw", 481 | "type": "event" 482 | }, 483 | { 484 | "anonymous": false, 485 | "inputs": [ 486 | { 487 | "indexed": true, 488 | "internalType": "address", 489 | "name": "to", 490 | "type": "address" 491 | }, 492 | { 493 | "indexed": false, 494 | "internalType": "contract IERC20", 495 | "name": "token", 496 | "type": "address" 497 | }, 498 | { 499 | "indexed": false, 500 | "internalType": "uint256", 501 | "name": "amount", 502 | "type": "uint256" 503 | }, 504 | { 505 | "indexed": false, 506 | "internalType": "uint256", 507 | "name": "fee", 508 | "type": "uint256" 509 | }, 510 | { 511 | "indexed": false, 512 | "internalType": "uint8", 513 | "name": "swapTokenIndex", 514 | "type": "uint8" 515 | }, 516 | { 517 | "indexed": false, 518 | "internalType": "uint256", 519 | "name": "swapMinAmount", 520 | "type": "uint256" 521 | }, 522 | { 523 | "indexed": false, 524 | "internalType": "uint256", 525 | "name": "swapDeadline", 526 | "type": "uint256" 527 | }, 528 | { 529 | "indexed": false, 530 | "internalType": "bool", 531 | "name": "swapSuccess", 532 | "type": "bool" 533 | }, 534 | { 535 | "indexed": true, 536 | "internalType": "bytes32", 537 | "name": "kappa", 538 | "type": "bytes32" 539 | } 540 | ], 541 | "name": "TokenWithdrawAndRemove", 542 | "type": "event" 543 | }, 544 | { 545 | "anonymous": false, 546 | "inputs": [ 547 | { 548 | "indexed": false, 549 | "internalType": "address", 550 | "name": "account", 551 | "type": "address" 552 | } 553 | ], 554 | "name": "Unpaused", 555 | "type": "event" 556 | }, 557 | { 558 | "inputs": [], 559 | "name": "DEFAULT_ADMIN_ROLE", 560 | "outputs": [ 561 | { 562 | "internalType": "bytes32", 563 | "name": "", 564 | "type": "bytes32" 565 | } 566 | ], 567 | "stateMutability": "view", 568 | "type": "function" 569 | }, 570 | { 571 | "inputs": [], 572 | "name": "GOVERNANCE_ROLE", 573 | "outputs": [ 574 | { 575 | "internalType": "bytes32", 576 | "name": "", 577 | "type": "bytes32" 578 | } 579 | ], 580 | "stateMutability": "view", 581 | "type": "function" 582 | }, 583 | { 584 | "inputs": [], 585 | "name": "NODEGROUP_ROLE", 586 | "outputs": [ 587 | { 588 | "internalType": "bytes32", 589 | "name": "", 590 | "type": "bytes32" 591 | } 592 | ], 593 | "stateMutability": "view", 594 | "type": "function" 595 | }, 596 | { 597 | "inputs": [], 598 | "name": "WETH_ADDRESS", 599 | "outputs": [ 600 | { 601 | "internalType": "address payable", 602 | "name": "", 603 | "type": "address" 604 | } 605 | ], 606 | "stateMutability": "view", 607 | "type": "function" 608 | }, 609 | { 610 | "inputs": [ 611 | { 612 | "internalType": "bytes32[]", 613 | "name": "kappas", 614 | "type": "bytes32[]" 615 | } 616 | ], 617 | "name": "addKappas", 618 | "outputs": [], 619 | "stateMutability": "nonpayable", 620 | "type": "function" 621 | }, 622 | { 623 | "inputs": [], 624 | "name": "bridgeVersion", 625 | "outputs": [ 626 | { 627 | "internalType": "uint256", 628 | "name": "", 629 | "type": "uint256" 630 | } 631 | ], 632 | "stateMutability": "view", 633 | "type": "function" 634 | }, 635 | { 636 | "inputs": [], 637 | "name": "chainGasAmount", 638 | "outputs": [ 639 | { 640 | "internalType": "uint256", 641 | "name": "", 642 | "type": "uint256" 643 | } 644 | ], 645 | "stateMutability": "view", 646 | "type": "function" 647 | }, 648 | { 649 | "inputs": [ 650 | { 651 | "internalType": "address", 652 | "name": "to", 653 | "type": "address" 654 | }, 655 | { 656 | "internalType": "uint256", 657 | "name": "chainId", 658 | "type": "uint256" 659 | }, 660 | { 661 | "internalType": "contract IERC20", 662 | "name": "token", 663 | "type": "address" 664 | }, 665 | { 666 | "internalType": "uint256", 667 | "name": "amount", 668 | "type": "uint256" 669 | } 670 | ], 671 | "name": "deposit", 672 | "outputs": [], 673 | "stateMutability": "nonpayable", 674 | "type": "function" 675 | }, 676 | { 677 | "inputs": [ 678 | { 679 | "internalType": "address", 680 | "name": "to", 681 | "type": "address" 682 | }, 683 | { 684 | "internalType": "uint256", 685 | "name": "chainId", 686 | "type": "uint256" 687 | }, 688 | { 689 | "internalType": "contract IERC20", 690 | "name": "token", 691 | "type": "address" 692 | }, 693 | { 694 | "internalType": "uint256", 695 | "name": "amount", 696 | "type": "uint256" 697 | }, 698 | { 699 | "internalType": "uint8", 700 | "name": "tokenIndexFrom", 701 | "type": "uint8" 702 | }, 703 | { 704 | "internalType": "uint8", 705 | "name": "tokenIndexTo", 706 | "type": "uint8" 707 | }, 708 | { 709 | "internalType": "uint256", 710 | "name": "minDy", 711 | "type": "uint256" 712 | }, 713 | { 714 | "internalType": "uint256", 715 | "name": "deadline", 716 | "type": "uint256" 717 | } 718 | ], 719 | "name": "depositAndSwap", 720 | "outputs": [], 721 | "stateMutability": "nonpayable", 722 | "type": "function" 723 | }, 724 | { 725 | "inputs": [ 726 | { 727 | "internalType": "address", 728 | "name": "tokenAddress", 729 | "type": "address" 730 | } 731 | ], 732 | "name": "getFeeBalance", 733 | "outputs": [ 734 | { 735 | "internalType": "uint256", 736 | "name": "", 737 | "type": "uint256" 738 | } 739 | ], 740 | "stateMutability": "view", 741 | "type": "function" 742 | }, 743 | { 744 | "inputs": [ 745 | { 746 | "internalType": "bytes32", 747 | "name": "role", 748 | "type": "bytes32" 749 | } 750 | ], 751 | "name": "getRoleAdmin", 752 | "outputs": [ 753 | { 754 | "internalType": "bytes32", 755 | "name": "", 756 | "type": "bytes32" 757 | } 758 | ], 759 | "stateMutability": "view", 760 | "type": "function" 761 | }, 762 | { 763 | "inputs": [ 764 | { 765 | "internalType": "bytes32", 766 | "name": "role", 767 | "type": "bytes32" 768 | }, 769 | { 770 | "internalType": "uint256", 771 | "name": "index", 772 | "type": "uint256" 773 | } 774 | ], 775 | "name": "getRoleMember", 776 | "outputs": [ 777 | { 778 | "internalType": "address", 779 | "name": "", 780 | "type": "address" 781 | } 782 | ], 783 | "stateMutability": "view", 784 | "type": "function" 785 | }, 786 | { 787 | "inputs": [ 788 | { 789 | "internalType": "bytes32", 790 | "name": "role", 791 | "type": "bytes32" 792 | } 793 | ], 794 | "name": "getRoleMemberCount", 795 | "outputs": [ 796 | { 797 | "internalType": "uint256", 798 | "name": "", 799 | "type": "uint256" 800 | } 801 | ], 802 | "stateMutability": "view", 803 | "type": "function" 804 | }, 805 | { 806 | "inputs": [ 807 | { 808 | "internalType": "bytes32", 809 | "name": "role", 810 | "type": "bytes32" 811 | }, 812 | { 813 | "internalType": "address", 814 | "name": "account", 815 | "type": "address" 816 | } 817 | ], 818 | "name": "grantRole", 819 | "outputs": [], 820 | "stateMutability": "nonpayable", 821 | "type": "function" 822 | }, 823 | { 824 | "inputs": [ 825 | { 826 | "internalType": "bytes32", 827 | "name": "role", 828 | "type": "bytes32" 829 | }, 830 | { 831 | "internalType": "address", 832 | "name": "account", 833 | "type": "address" 834 | } 835 | ], 836 | "name": "hasRole", 837 | "outputs": [ 838 | { 839 | "internalType": "bool", 840 | "name": "", 841 | "type": "bool" 842 | } 843 | ], 844 | "stateMutability": "view", 845 | "type": "function" 846 | }, 847 | { 848 | "inputs": [], 849 | "name": "initialize", 850 | "outputs": [], 851 | "stateMutability": "nonpayable", 852 | "type": "function" 853 | }, 854 | { 855 | "inputs": [ 856 | { 857 | "internalType": "bytes32", 858 | "name": "kappa", 859 | "type": "bytes32" 860 | } 861 | ], 862 | "name": "kappaExists", 863 | "outputs": [ 864 | { 865 | "internalType": "bool", 866 | "name": "", 867 | "type": "bool" 868 | } 869 | ], 870 | "stateMutability": "view", 871 | "type": "function" 872 | }, 873 | { 874 | "inputs": [ 875 | { 876 | "internalType": "address payable", 877 | "name": "to", 878 | "type": "address" 879 | }, 880 | { 881 | "internalType": "contract IERC20Mintable", 882 | "name": "token", 883 | "type": "address" 884 | }, 885 | { 886 | "internalType": "uint256", 887 | "name": "amount", 888 | "type": "uint256" 889 | }, 890 | { 891 | "internalType": "uint256", 892 | "name": "fee", 893 | "type": "uint256" 894 | }, 895 | { 896 | "internalType": "bytes32", 897 | "name": "kappa", 898 | "type": "bytes32" 899 | } 900 | ], 901 | "name": "mint", 902 | "outputs": [], 903 | "stateMutability": "nonpayable", 904 | "type": "function" 905 | }, 906 | { 907 | "inputs": [ 908 | { 909 | "internalType": "address payable", 910 | "name": "to", 911 | "type": "address" 912 | }, 913 | { 914 | "internalType": "contract IERC20Mintable", 915 | "name": "token", 916 | "type": "address" 917 | }, 918 | { 919 | "internalType": "uint256", 920 | "name": "amount", 921 | "type": "uint256" 922 | }, 923 | { 924 | "internalType": "uint256", 925 | "name": "fee", 926 | "type": "uint256" 927 | }, 928 | { 929 | "internalType": "contract ISwap", 930 | "name": "pool", 931 | "type": "address" 932 | }, 933 | { 934 | "internalType": "uint8", 935 | "name": "tokenIndexFrom", 936 | "type": "uint8" 937 | }, 938 | { 939 | "internalType": "uint8", 940 | "name": "tokenIndexTo", 941 | "type": "uint8" 942 | }, 943 | { 944 | "internalType": "uint256", 945 | "name": "minDy", 946 | "type": "uint256" 947 | }, 948 | { 949 | "internalType": "uint256", 950 | "name": "deadline", 951 | "type": "uint256" 952 | }, 953 | { 954 | "internalType": "bytes32", 955 | "name": "kappa", 956 | "type": "bytes32" 957 | } 958 | ], 959 | "name": "mintAndSwap", 960 | "outputs": [], 961 | "stateMutability": "nonpayable", 962 | "type": "function" 963 | }, 964 | { 965 | "inputs": [], 966 | "name": "pause", 967 | "outputs": [], 968 | "stateMutability": "nonpayable", 969 | "type": "function" 970 | }, 971 | { 972 | "inputs": [], 973 | "name": "paused", 974 | "outputs": [ 975 | { 976 | "internalType": "bool", 977 | "name": "", 978 | "type": "bool" 979 | } 980 | ], 981 | "stateMutability": "view", 982 | "type": "function" 983 | }, 984 | { 985 | "inputs": [ 986 | { 987 | "internalType": "address", 988 | "name": "to", 989 | "type": "address" 990 | }, 991 | { 992 | "internalType": "uint256", 993 | "name": "chainId", 994 | "type": "uint256" 995 | }, 996 | { 997 | "internalType": "contract ERC20Burnable", 998 | "name": "token", 999 | "type": "address" 1000 | }, 1001 | { 1002 | "internalType": "uint256", 1003 | "name": "amount", 1004 | "type": "uint256" 1005 | } 1006 | ], 1007 | "name": "redeem", 1008 | "outputs": [], 1009 | "stateMutability": "nonpayable", 1010 | "type": "function" 1011 | }, 1012 | { 1013 | "inputs": [ 1014 | { 1015 | "internalType": "address", 1016 | "name": "to", 1017 | "type": "address" 1018 | }, 1019 | { 1020 | "internalType": "uint256", 1021 | "name": "chainId", 1022 | "type": "uint256" 1023 | }, 1024 | { 1025 | "internalType": "contract ERC20Burnable", 1026 | "name": "token", 1027 | "type": "address" 1028 | }, 1029 | { 1030 | "internalType": "uint256", 1031 | "name": "amount", 1032 | "type": "uint256" 1033 | }, 1034 | { 1035 | "internalType": "uint8", 1036 | "name": "swapTokenIndex", 1037 | "type": "uint8" 1038 | }, 1039 | { 1040 | "internalType": "uint256", 1041 | "name": "swapMinAmount", 1042 | "type": "uint256" 1043 | }, 1044 | { 1045 | "internalType": "uint256", 1046 | "name": "swapDeadline", 1047 | "type": "uint256" 1048 | } 1049 | ], 1050 | "name": "redeemAndRemove", 1051 | "outputs": [], 1052 | "stateMutability": "nonpayable", 1053 | "type": "function" 1054 | }, 1055 | { 1056 | "inputs": [ 1057 | { 1058 | "internalType": "address", 1059 | "name": "to", 1060 | "type": "address" 1061 | }, 1062 | { 1063 | "internalType": "uint256", 1064 | "name": "chainId", 1065 | "type": "uint256" 1066 | }, 1067 | { 1068 | "internalType": "contract ERC20Burnable", 1069 | "name": "token", 1070 | "type": "address" 1071 | }, 1072 | { 1073 | "internalType": "uint256", 1074 | "name": "amount", 1075 | "type": "uint256" 1076 | }, 1077 | { 1078 | "internalType": "uint8", 1079 | "name": "tokenIndexFrom", 1080 | "type": "uint8" 1081 | }, 1082 | { 1083 | "internalType": "uint8", 1084 | "name": "tokenIndexTo", 1085 | "type": "uint8" 1086 | }, 1087 | { 1088 | "internalType": "uint256", 1089 | "name": "minDy", 1090 | "type": "uint256" 1091 | }, 1092 | { 1093 | "internalType": "uint256", 1094 | "name": "deadline", 1095 | "type": "uint256" 1096 | } 1097 | ], 1098 | "name": "redeemAndSwap", 1099 | "outputs": [], 1100 | "stateMutability": "nonpayable", 1101 | "type": "function" 1102 | }, 1103 | { 1104 | "inputs": [ 1105 | { 1106 | "internalType": "bytes32", 1107 | "name": "to", 1108 | "type": "bytes32" 1109 | }, 1110 | { 1111 | "internalType": "uint256", 1112 | "name": "chainId", 1113 | "type": "uint256" 1114 | }, 1115 | { 1116 | "internalType": "contract ERC20Burnable", 1117 | "name": "token", 1118 | "type": "address" 1119 | }, 1120 | { 1121 | "internalType": "uint256", 1122 | "name": "amount", 1123 | "type": "uint256" 1124 | } 1125 | ], 1126 | "name": "redeemV2", 1127 | "outputs": [], 1128 | "stateMutability": "nonpayable", 1129 | "type": "function" 1130 | }, 1131 | { 1132 | "inputs": [ 1133 | { 1134 | "internalType": "bytes32", 1135 | "name": "role", 1136 | "type": "bytes32" 1137 | }, 1138 | { 1139 | "internalType": "address", 1140 | "name": "account", 1141 | "type": "address" 1142 | } 1143 | ], 1144 | "name": "renounceRole", 1145 | "outputs": [], 1146 | "stateMutability": "nonpayable", 1147 | "type": "function" 1148 | }, 1149 | { 1150 | "inputs": [ 1151 | { 1152 | "internalType": "bytes32", 1153 | "name": "role", 1154 | "type": "bytes32" 1155 | }, 1156 | { 1157 | "internalType": "address", 1158 | "name": "account", 1159 | "type": "address" 1160 | } 1161 | ], 1162 | "name": "revokeRole", 1163 | "outputs": [], 1164 | "stateMutability": "nonpayable", 1165 | "type": "function" 1166 | }, 1167 | { 1168 | "inputs": [ 1169 | { 1170 | "internalType": "uint256", 1171 | "name": "amount", 1172 | "type": "uint256" 1173 | } 1174 | ], 1175 | "name": "setChainGasAmount", 1176 | "outputs": [], 1177 | "stateMutability": "nonpayable", 1178 | "type": "function" 1179 | }, 1180 | { 1181 | "inputs": [ 1182 | { 1183 | "internalType": "address payable", 1184 | "name": "_wethAddress", 1185 | "type": "address" 1186 | } 1187 | ], 1188 | "name": "setWethAddress", 1189 | "outputs": [], 1190 | "stateMutability": "nonpayable", 1191 | "type": "function" 1192 | }, 1193 | { 1194 | "inputs": [], 1195 | "name": "startBlockNumber", 1196 | "outputs": [ 1197 | { 1198 | "internalType": "uint256", 1199 | "name": "", 1200 | "type": "uint256" 1201 | } 1202 | ], 1203 | "stateMutability": "view", 1204 | "type": "function" 1205 | }, 1206 | { 1207 | "inputs": [], 1208 | "name": "unpause", 1209 | "outputs": [], 1210 | "stateMutability": "nonpayable", 1211 | "type": "function" 1212 | }, 1213 | { 1214 | "inputs": [ 1215 | { 1216 | "internalType": "address", 1217 | "name": "to", 1218 | "type": "address" 1219 | }, 1220 | { 1221 | "internalType": "contract IERC20", 1222 | "name": "token", 1223 | "type": "address" 1224 | }, 1225 | { 1226 | "internalType": "uint256", 1227 | "name": "amount", 1228 | "type": "uint256" 1229 | }, 1230 | { 1231 | "internalType": "uint256", 1232 | "name": "fee", 1233 | "type": "uint256" 1234 | }, 1235 | { 1236 | "internalType": "bytes32", 1237 | "name": "kappa", 1238 | "type": "bytes32" 1239 | } 1240 | ], 1241 | "name": "withdraw", 1242 | "outputs": [], 1243 | "stateMutability": "nonpayable", 1244 | "type": "function" 1245 | }, 1246 | { 1247 | "inputs": [ 1248 | { 1249 | "internalType": "address", 1250 | "name": "to", 1251 | "type": "address" 1252 | }, 1253 | { 1254 | "internalType": "contract IERC20", 1255 | "name": "token", 1256 | "type": "address" 1257 | }, 1258 | { 1259 | "internalType": "uint256", 1260 | "name": "amount", 1261 | "type": "uint256" 1262 | }, 1263 | { 1264 | "internalType": "uint256", 1265 | "name": "fee", 1266 | "type": "uint256" 1267 | }, 1268 | { 1269 | "internalType": "contract ISwap", 1270 | "name": "pool", 1271 | "type": "address" 1272 | }, 1273 | { 1274 | "internalType": "uint8", 1275 | "name": "swapTokenIndex", 1276 | "type": "uint8" 1277 | }, 1278 | { 1279 | "internalType": "uint256", 1280 | "name": "swapMinAmount", 1281 | "type": "uint256" 1282 | }, 1283 | { 1284 | "internalType": "uint256", 1285 | "name": "swapDeadline", 1286 | "type": "uint256" 1287 | }, 1288 | { 1289 | "internalType": "bytes32", 1290 | "name": "kappa", 1291 | "type": "bytes32" 1292 | } 1293 | ], 1294 | "name": "withdrawAndRemove", 1295 | "outputs": [], 1296 | "stateMutability": "nonpayable", 1297 | "type": "function" 1298 | }, 1299 | { 1300 | "inputs": [ 1301 | { 1302 | "internalType": "contract IERC20", 1303 | "name": "token", 1304 | "type": "address" 1305 | }, 1306 | { 1307 | "internalType": "address", 1308 | "name": "to", 1309 | "type": "address" 1310 | } 1311 | ], 1312 | "name": "withdrawFees", 1313 | "outputs": [], 1314 | "stateMutability": "nonpayable", 1315 | "type": "function" 1316 | }, 1317 | { 1318 | "stateMutability": "payable", 1319 | "type": "receive" 1320 | } 1321 | ] 1322 | -------------------------------------------------------------------------------- /acx/abis/v2HubPool.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract LpTokenFactoryInterface", 6 | "name": "_lpTokenFactory", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "contract FinderInterface", 11 | "name": "_finder", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "contract WETH9", 16 | "name": "_weth", 17 | "type": "address" 18 | }, 19 | { 20 | "internalType": "address", 21 | "name": "_timer", 22 | "type": "address" 23 | } 24 | ], 25 | "stateMutability": "nonpayable", 26 | "type": "constructor" 27 | }, 28 | { 29 | "anonymous": false, 30 | "inputs": [ 31 | { 32 | "indexed": true, 33 | "internalType": "address", 34 | "name": "newBondToken", 35 | "type": "address" 36 | }, 37 | { 38 | "indexed": false, 39 | "internalType": "uint256", 40 | "name": "newBondAmount", 41 | "type": "uint256" 42 | } 43 | ], 44 | "name": "BondSet", 45 | "type": "event" 46 | }, 47 | { 48 | "anonymous": false, 49 | "inputs": [ 50 | { 51 | "indexed": false, 52 | "internalType": "uint256", 53 | "name": "l2ChainId", 54 | "type": "uint256" 55 | }, 56 | { 57 | "indexed": false, 58 | "internalType": "address", 59 | "name": "adapter", 60 | "type": "address" 61 | }, 62 | { 63 | "indexed": false, 64 | "internalType": "address", 65 | "name": "spokePool", 66 | "type": "address" 67 | } 68 | ], 69 | "name": "CrossChainContractsSet", 70 | "type": "event" 71 | }, 72 | { 73 | "anonymous": false, 74 | "inputs": [ 75 | { 76 | "indexed": true, 77 | "internalType": "bytes32", 78 | "name": "poolRebalanceRoot", 79 | "type": "bytes32" 80 | }, 81 | { 82 | "indexed": true, 83 | "internalType": "bytes32", 84 | "name": "relayerRefundRoot", 85 | "type": "bytes32" 86 | }, 87 | { 88 | "indexed": false, 89 | "internalType": "bytes32", 90 | "name": "slowRelayRoot", 91 | "type": "bytes32" 92 | }, 93 | { 94 | "indexed": true, 95 | "internalType": "address", 96 | "name": "proposer", 97 | "type": "address" 98 | } 99 | ], 100 | "name": "EmergencyRootBundleDeleted", 101 | "type": "event" 102 | }, 103 | { 104 | "anonymous": false, 105 | "inputs": [ 106 | { 107 | "indexed": false, 108 | "internalType": "bytes32", 109 | "name": "newIdentifier", 110 | "type": "bytes32" 111 | } 112 | ], 113 | "name": "IdentifierSet", 114 | "type": "event" 115 | }, 116 | { 117 | "anonymous": false, 118 | "inputs": [ 119 | { 120 | "indexed": false, 121 | "internalType": "address", 122 | "name": "l1Token", 123 | "type": "address" 124 | }, 125 | { 126 | "indexed": false, 127 | "internalType": "address", 128 | "name": "lpToken", 129 | "type": "address" 130 | } 131 | ], 132 | "name": "L1TokenEnabledForLiquidityProvision", 133 | "type": "event" 134 | }, 135 | { 136 | "anonymous": false, 137 | "inputs": [ 138 | { 139 | "indexed": false, 140 | "internalType": "address", 141 | "name": "l1Token", 142 | "type": "address" 143 | }, 144 | { 145 | "indexed": false, 146 | "internalType": "address", 147 | "name": "lpToken", 148 | "type": "address" 149 | } 150 | ], 151 | "name": "L2TokenDisabledForLiquidityProvision", 152 | "type": "event" 153 | }, 154 | { 155 | "anonymous": false, 156 | "inputs": [ 157 | { 158 | "indexed": true, 159 | "internalType": "address", 160 | "name": "l1Token", 161 | "type": "address" 162 | }, 163 | { 164 | "indexed": false, 165 | "internalType": "uint256", 166 | "name": "amount", 167 | "type": "uint256" 168 | }, 169 | { 170 | "indexed": false, 171 | "internalType": "uint256", 172 | "name": "lpTokensMinted", 173 | "type": "uint256" 174 | }, 175 | { 176 | "indexed": true, 177 | "internalType": "address", 178 | "name": "liquidityProvider", 179 | "type": "address" 180 | } 181 | ], 182 | "name": "LiquidityAdded", 183 | "type": "event" 184 | }, 185 | { 186 | "anonymous": false, 187 | "inputs": [ 188 | { 189 | "indexed": true, 190 | "internalType": "address", 191 | "name": "l1Token", 192 | "type": "address" 193 | }, 194 | { 195 | "indexed": false, 196 | "internalType": "uint256", 197 | "name": "amount", 198 | "type": "uint256" 199 | }, 200 | { 201 | "indexed": false, 202 | "internalType": "uint256", 203 | "name": "lpTokensBurnt", 204 | "type": "uint256" 205 | }, 206 | { 207 | "indexed": true, 208 | "internalType": "address", 209 | "name": "liquidityProvider", 210 | "type": "address" 211 | } 212 | ], 213 | "name": "LiquidityRemoved", 214 | "type": "event" 215 | }, 216 | { 217 | "anonymous": false, 218 | "inputs": [ 219 | { 220 | "indexed": false, 221 | "internalType": "uint256", 222 | "name": "newLiveness", 223 | "type": "uint256" 224 | } 225 | ], 226 | "name": "LivenessSet", 227 | "type": "event" 228 | }, 229 | { 230 | "anonymous": false, 231 | "inputs": [ 232 | { 233 | "indexed": true, 234 | "internalType": "address", 235 | "name": "previousOwner", 236 | "type": "address" 237 | }, 238 | { 239 | "indexed": true, 240 | "internalType": "address", 241 | "name": "newOwner", 242 | "type": "address" 243 | } 244 | ], 245 | "name": "OwnershipTransferred", 246 | "type": "event" 247 | }, 248 | { 249 | "anonymous": false, 250 | "inputs": [ 251 | { 252 | "indexed": true, 253 | "internalType": "bool", 254 | "name": "isPaused", 255 | "type": "bool" 256 | } 257 | ], 258 | "name": "Paused", 259 | "type": "event" 260 | }, 261 | { 262 | "anonymous": false, 263 | "inputs": [ 264 | { 265 | "indexed": false, 266 | "internalType": "uint32", 267 | "name": "challengePeriodEndTimestamp", 268 | "type": "uint32" 269 | }, 270 | { 271 | "indexed": false, 272 | "internalType": "uint8", 273 | "name": "poolRebalanceLeafCount", 274 | "type": "uint8" 275 | }, 276 | { 277 | "indexed": false, 278 | "internalType": "uint256[]", 279 | "name": "bundleEvaluationBlockNumbers", 280 | "type": "uint256[]" 281 | }, 282 | { 283 | "indexed": true, 284 | "internalType": "bytes32", 285 | "name": "poolRebalanceRoot", 286 | "type": "bytes32" 287 | }, 288 | { 289 | "indexed": true, 290 | "internalType": "bytes32", 291 | "name": "relayerRefundRoot", 292 | "type": "bytes32" 293 | }, 294 | { 295 | "indexed": false, 296 | "internalType": "bytes32", 297 | "name": "slowRelayRoot", 298 | "type": "bytes32" 299 | }, 300 | { 301 | "indexed": true, 302 | "internalType": "address", 303 | "name": "proposer", 304 | "type": "address" 305 | } 306 | ], 307 | "name": "ProposeRootBundle", 308 | "type": "event" 309 | }, 310 | { 311 | "anonymous": false, 312 | "inputs": [ 313 | { 314 | "indexed": true, 315 | "internalType": "address", 316 | "name": "newProtocolFeeCaptureAddress", 317 | "type": "address" 318 | }, 319 | { 320 | "indexed": true, 321 | "internalType": "uint256", 322 | "name": "newProtocolFeeCapturePct", 323 | "type": "uint256" 324 | } 325 | ], 326 | "name": "ProtocolFeeCaptureSet", 327 | "type": "event" 328 | }, 329 | { 330 | "anonymous": false, 331 | "inputs": [ 332 | { 333 | "indexed": true, 334 | "internalType": "address", 335 | "name": "l1Token", 336 | "type": "address" 337 | }, 338 | { 339 | "indexed": true, 340 | "internalType": "uint256", 341 | "name": "accumulatedFees", 342 | "type": "uint256" 343 | } 344 | ], 345 | "name": "ProtocolFeesCapturedClaimed", 346 | "type": "event" 347 | }, 348 | { 349 | "anonymous": false, 350 | "inputs": [ 351 | { 352 | "indexed": true, 353 | "internalType": "address", 354 | "name": "disputer", 355 | "type": "address" 356 | }, 357 | { 358 | "indexed": false, 359 | "internalType": "uint256", 360 | "name": "requestTime", 361 | "type": "uint256" 362 | } 363 | ], 364 | "name": "RootBundleCanceled", 365 | "type": "event" 366 | }, 367 | { 368 | "anonymous": false, 369 | "inputs": [ 370 | { 371 | "indexed": true, 372 | "internalType": "address", 373 | "name": "disputer", 374 | "type": "address" 375 | }, 376 | { 377 | "indexed": false, 378 | "internalType": "uint256", 379 | "name": "requestTime", 380 | "type": "uint256" 381 | } 382 | ], 383 | "name": "RootBundleDisputed", 384 | "type": "event" 385 | }, 386 | { 387 | "anonymous": false, 388 | "inputs": [ 389 | { 390 | "indexed": false, 391 | "internalType": "uint256", 392 | "name": "groupIndex", 393 | "type": "uint256" 394 | }, 395 | { 396 | "indexed": true, 397 | "internalType": "uint256", 398 | "name": "leafId", 399 | "type": "uint256" 400 | }, 401 | { 402 | "indexed": true, 403 | "internalType": "uint256", 404 | "name": "chainId", 405 | "type": "uint256" 406 | }, 407 | { 408 | "indexed": false, 409 | "internalType": "address[]", 410 | "name": "l1Tokens", 411 | "type": "address[]" 412 | }, 413 | { 414 | "indexed": false, 415 | "internalType": "uint256[]", 416 | "name": "bundleLpFees", 417 | "type": "uint256[]" 418 | }, 419 | { 420 | "indexed": false, 421 | "internalType": "int256[]", 422 | "name": "netSendAmounts", 423 | "type": "int256[]" 424 | }, 425 | { 426 | "indexed": false, 427 | "internalType": "int256[]", 428 | "name": "runningBalances", 429 | "type": "int256[]" 430 | }, 431 | { 432 | "indexed": true, 433 | "internalType": "address", 434 | "name": "caller", 435 | "type": "address" 436 | } 437 | ], 438 | "name": "RootBundleExecuted", 439 | "type": "event" 440 | }, 441 | { 442 | "anonymous": false, 443 | "inputs": [ 444 | { 445 | "indexed": true, 446 | "internalType": "uint256", 447 | "name": "originChainId", 448 | "type": "uint256" 449 | }, 450 | { 451 | "indexed": true, 452 | "internalType": "uint256", 453 | "name": "destinationChainId", 454 | "type": "uint256" 455 | }, 456 | { 457 | "indexed": true, 458 | "internalType": "address", 459 | "name": "originToken", 460 | "type": "address" 461 | }, 462 | { 463 | "indexed": false, 464 | "internalType": "bool", 465 | "name": "depositsEnabled", 466 | "type": "bool" 467 | } 468 | ], 469 | "name": "SetEnableDepositRoute", 470 | "type": "event" 471 | }, 472 | { 473 | "anonymous": false, 474 | "inputs": [ 475 | { 476 | "indexed": true, 477 | "internalType": "uint256", 478 | "name": "destinationChainId", 479 | "type": "uint256" 480 | }, 481 | { 482 | "indexed": true, 483 | "internalType": "address", 484 | "name": "l1Token", 485 | "type": "address" 486 | }, 487 | { 488 | "indexed": true, 489 | "internalType": "address", 490 | "name": "destinationToken", 491 | "type": "address" 492 | } 493 | ], 494 | "name": "SetPoolRebalanceRoute", 495 | "type": "event" 496 | }, 497 | { 498 | "anonymous": false, 499 | "inputs": [ 500 | { 501 | "indexed": true, 502 | "internalType": "uint256", 503 | "name": "chainId", 504 | "type": "uint256" 505 | }, 506 | { 507 | "indexed": false, 508 | "internalType": "bytes", 509 | "name": "message", 510 | "type": "bytes" 511 | } 512 | ], 513 | "name": "SpokePoolAdminFunctionTriggered", 514 | "type": "event" 515 | }, 516 | { 517 | "stateMutability": "payable", 518 | "type": "fallback" 519 | }, 520 | { 521 | "inputs": [ 522 | { 523 | "internalType": "address", 524 | "name": "l1Token", 525 | "type": "address" 526 | }, 527 | { 528 | "internalType": "uint256", 529 | "name": "l1TokenAmount", 530 | "type": "uint256" 531 | } 532 | ], 533 | "name": "addLiquidity", 534 | "outputs": [], 535 | "stateMutability": "payable", 536 | "type": "function" 537 | }, 538 | { 539 | "inputs": [], 540 | "name": "bondAmount", 541 | "outputs": [ 542 | { 543 | "internalType": "uint256", 544 | "name": "", 545 | "type": "uint256" 546 | } 547 | ], 548 | "stateMutability": "view", 549 | "type": "function" 550 | }, 551 | { 552 | "inputs": [], 553 | "name": "bondToken", 554 | "outputs": [ 555 | { 556 | "internalType": "contract IERC20", 557 | "name": "", 558 | "type": "address" 559 | } 560 | ], 561 | "stateMutability": "view", 562 | "type": "function" 563 | }, 564 | { 565 | "inputs": [ 566 | { 567 | "internalType": "address", 568 | "name": "l1Token", 569 | "type": "address" 570 | } 571 | ], 572 | "name": "claimProtocolFeesCaptured", 573 | "outputs": [], 574 | "stateMutability": "nonpayable", 575 | "type": "function" 576 | }, 577 | { 578 | "inputs": [ 579 | { 580 | "internalType": "uint256", 581 | "name": "", 582 | "type": "uint256" 583 | } 584 | ], 585 | "name": "crossChainContracts", 586 | "outputs": [ 587 | { 588 | "internalType": "address", 589 | "name": "adapter", 590 | "type": "address" 591 | }, 592 | { 593 | "internalType": "address", 594 | "name": "spokePool", 595 | "type": "address" 596 | } 597 | ], 598 | "stateMutability": "view", 599 | "type": "function" 600 | }, 601 | { 602 | "inputs": [ 603 | { 604 | "internalType": "address", 605 | "name": "l1Token", 606 | "type": "address" 607 | } 608 | ], 609 | "name": "disableL1TokenForLiquidityProvision", 610 | "outputs": [], 611 | "stateMutability": "nonpayable", 612 | "type": "function" 613 | }, 614 | { 615 | "inputs": [], 616 | "name": "disputeRootBundle", 617 | "outputs": [], 618 | "stateMutability": "nonpayable", 619 | "type": "function" 620 | }, 621 | { 622 | "inputs": [], 623 | "name": "emergencyDeleteProposal", 624 | "outputs": [], 625 | "stateMutability": "nonpayable", 626 | "type": "function" 627 | }, 628 | { 629 | "inputs": [ 630 | { 631 | "internalType": "address", 632 | "name": "l1Token", 633 | "type": "address" 634 | } 635 | ], 636 | "name": "enableL1TokenForLiquidityProvision", 637 | "outputs": [], 638 | "stateMutability": "nonpayable", 639 | "type": "function" 640 | }, 641 | { 642 | "inputs": [ 643 | { 644 | "internalType": "address", 645 | "name": "l1Token", 646 | "type": "address" 647 | } 648 | ], 649 | "name": "exchangeRateCurrent", 650 | "outputs": [ 651 | { 652 | "internalType": "uint256", 653 | "name": "", 654 | "type": "uint256" 655 | } 656 | ], 657 | "stateMutability": "nonpayable", 658 | "type": "function" 659 | }, 660 | { 661 | "inputs": [ 662 | { 663 | "internalType": "uint256", 664 | "name": "chainId", 665 | "type": "uint256" 666 | }, 667 | { 668 | "internalType": "uint256", 669 | "name": "groupIndex", 670 | "type": "uint256" 671 | }, 672 | { 673 | "internalType": "uint256[]", 674 | "name": "bundleLpFees", 675 | "type": "uint256[]" 676 | }, 677 | { 678 | "internalType": "int256[]", 679 | "name": "netSendAmounts", 680 | "type": "int256[]" 681 | }, 682 | { 683 | "internalType": "int256[]", 684 | "name": "runningBalances", 685 | "type": "int256[]" 686 | }, 687 | { 688 | "internalType": "uint8", 689 | "name": "leafId", 690 | "type": "uint8" 691 | }, 692 | { 693 | "internalType": "address[]", 694 | "name": "l1Tokens", 695 | "type": "address[]" 696 | }, 697 | { 698 | "internalType": "bytes32[]", 699 | "name": "proof", 700 | "type": "bytes32[]" 701 | } 702 | ], 703 | "name": "executeRootBundle", 704 | "outputs": [], 705 | "stateMutability": "nonpayable", 706 | "type": "function" 707 | }, 708 | { 709 | "inputs": [], 710 | "name": "finder", 711 | "outputs": [ 712 | { 713 | "internalType": "contract FinderInterface", 714 | "name": "", 715 | "type": "address" 716 | } 717 | ], 718 | "stateMutability": "view", 719 | "type": "function" 720 | }, 721 | { 722 | "inputs": [], 723 | "name": "getCurrentTime", 724 | "outputs": [ 725 | { 726 | "internalType": "uint256", 727 | "name": "", 728 | "type": "uint256" 729 | } 730 | ], 731 | "stateMutability": "view", 732 | "type": "function" 733 | }, 734 | { 735 | "inputs": [ 736 | { 737 | "internalType": "address", 738 | "name": "l1Token", 739 | "type": "address" 740 | }, 741 | { 742 | "internalType": "int256", 743 | "name": "haircutAmount", 744 | "type": "int256" 745 | } 746 | ], 747 | "name": "haircutReserves", 748 | "outputs": [], 749 | "stateMutability": "nonpayable", 750 | "type": "function" 751 | }, 752 | { 753 | "inputs": [], 754 | "name": "identifier", 755 | "outputs": [ 756 | { 757 | "internalType": "bytes32", 758 | "name": "", 759 | "type": "bytes32" 760 | } 761 | ], 762 | "stateMutability": "view", 763 | "type": "function" 764 | }, 765 | { 766 | "inputs": [ 767 | { 768 | "internalType": "address", 769 | "name": "l1Token", 770 | "type": "address" 771 | } 772 | ], 773 | "name": "liquidityUtilizationCurrent", 774 | "outputs": [ 775 | { 776 | "internalType": "uint256", 777 | "name": "", 778 | "type": "uint256" 779 | } 780 | ], 781 | "stateMutability": "nonpayable", 782 | "type": "function" 783 | }, 784 | { 785 | "inputs": [ 786 | { 787 | "internalType": "address", 788 | "name": "l1Token", 789 | "type": "address" 790 | }, 791 | { 792 | "internalType": "uint256", 793 | "name": "relayedAmount", 794 | "type": "uint256" 795 | } 796 | ], 797 | "name": "liquidityUtilizationPostRelay", 798 | "outputs": [ 799 | { 800 | "internalType": "uint256", 801 | "name": "", 802 | "type": "uint256" 803 | } 804 | ], 805 | "stateMutability": "nonpayable", 806 | "type": "function" 807 | }, 808 | { 809 | "inputs": [], 810 | "name": "liveness", 811 | "outputs": [ 812 | { 813 | "internalType": "uint32", 814 | "name": "", 815 | "type": "uint32" 816 | } 817 | ], 818 | "stateMutability": "view", 819 | "type": "function" 820 | }, 821 | { 822 | "inputs": [], 823 | "name": "loadEthForL2Calls", 824 | "outputs": [], 825 | "stateMutability": "payable", 826 | "type": "function" 827 | }, 828 | { 829 | "inputs": [], 830 | "name": "lpFeeRatePerSecond", 831 | "outputs": [ 832 | { 833 | "internalType": "uint256", 834 | "name": "", 835 | "type": "uint256" 836 | } 837 | ], 838 | "stateMutability": "view", 839 | "type": "function" 840 | }, 841 | { 842 | "inputs": [], 843 | "name": "lpTokenFactory", 844 | "outputs": [ 845 | { 846 | "internalType": "contract LpTokenFactoryInterface", 847 | "name": "", 848 | "type": "address" 849 | } 850 | ], 851 | "stateMutability": "view", 852 | "type": "function" 853 | }, 854 | { 855 | "inputs": [ 856 | { 857 | "internalType": "bytes[]", 858 | "name": "data", 859 | "type": "bytes[]" 860 | } 861 | ], 862 | "name": "multicall", 863 | "outputs": [ 864 | { 865 | "internalType": "bytes[]", 866 | "name": "results", 867 | "type": "bytes[]" 868 | } 869 | ], 870 | "stateMutability": "payable", 871 | "type": "function" 872 | }, 873 | { 874 | "inputs": [], 875 | "name": "owner", 876 | "outputs": [ 877 | { 878 | "internalType": "address", 879 | "name": "", 880 | "type": "address" 881 | } 882 | ], 883 | "stateMutability": "view", 884 | "type": "function" 885 | }, 886 | { 887 | "inputs": [], 888 | "name": "paused", 889 | "outputs": [ 890 | { 891 | "internalType": "bool", 892 | "name": "", 893 | "type": "bool" 894 | } 895 | ], 896 | "stateMutability": "view", 897 | "type": "function" 898 | }, 899 | { 900 | "inputs": [ 901 | { 902 | "internalType": "uint256", 903 | "name": "destinationChainId", 904 | "type": "uint256" 905 | }, 906 | { 907 | "internalType": "address", 908 | "name": "l1Token", 909 | "type": "address" 910 | } 911 | ], 912 | "name": "poolRebalanceRoute", 913 | "outputs": [ 914 | { 915 | "internalType": "address", 916 | "name": "destinationToken", 917 | "type": "address" 918 | } 919 | ], 920 | "stateMutability": "view", 921 | "type": "function" 922 | }, 923 | { 924 | "inputs": [ 925 | { 926 | "internalType": "address", 927 | "name": "", 928 | "type": "address" 929 | } 930 | ], 931 | "name": "pooledTokens", 932 | "outputs": [ 933 | { 934 | "internalType": "address", 935 | "name": "lpToken", 936 | "type": "address" 937 | }, 938 | { 939 | "internalType": "bool", 940 | "name": "isEnabled", 941 | "type": "bool" 942 | }, 943 | { 944 | "internalType": "uint32", 945 | "name": "lastLpFeeUpdate", 946 | "type": "uint32" 947 | }, 948 | { 949 | "internalType": "int256", 950 | "name": "utilizedReserves", 951 | "type": "int256" 952 | }, 953 | { 954 | "internalType": "uint256", 955 | "name": "liquidReserves", 956 | "type": "uint256" 957 | }, 958 | { 959 | "internalType": "uint256", 960 | "name": "undistributedLpFees", 961 | "type": "uint256" 962 | } 963 | ], 964 | "stateMutability": "view", 965 | "type": "function" 966 | }, 967 | { 968 | "inputs": [ 969 | { 970 | "internalType": "uint256[]", 971 | "name": "bundleEvaluationBlockNumbers", 972 | "type": "uint256[]" 973 | }, 974 | { 975 | "internalType": "uint8", 976 | "name": "poolRebalanceLeafCount", 977 | "type": "uint8" 978 | }, 979 | { 980 | "internalType": "bytes32", 981 | "name": "poolRebalanceRoot", 982 | "type": "bytes32" 983 | }, 984 | { 985 | "internalType": "bytes32", 986 | "name": "relayerRefundRoot", 987 | "type": "bytes32" 988 | }, 989 | { 990 | "internalType": "bytes32", 991 | "name": "slowRelayRoot", 992 | "type": "bytes32" 993 | } 994 | ], 995 | "name": "proposeRootBundle", 996 | "outputs": [], 997 | "stateMutability": "nonpayable", 998 | "type": "function" 999 | }, 1000 | { 1001 | "inputs": [], 1002 | "name": "protocolFeeCaptureAddress", 1003 | "outputs": [ 1004 | { 1005 | "internalType": "address", 1006 | "name": "", 1007 | "type": "address" 1008 | } 1009 | ], 1010 | "stateMutability": "view", 1011 | "type": "function" 1012 | }, 1013 | { 1014 | "inputs": [], 1015 | "name": "protocolFeeCapturePct", 1016 | "outputs": [ 1017 | { 1018 | "internalType": "uint256", 1019 | "name": "", 1020 | "type": "uint256" 1021 | } 1022 | ], 1023 | "stateMutability": "view", 1024 | "type": "function" 1025 | }, 1026 | { 1027 | "inputs": [ 1028 | { 1029 | "internalType": "uint256", 1030 | "name": "chainId", 1031 | "type": "uint256" 1032 | }, 1033 | { 1034 | "internalType": "bytes", 1035 | "name": "functionData", 1036 | "type": "bytes" 1037 | } 1038 | ], 1039 | "name": "relaySpokePoolAdminFunction", 1040 | "outputs": [], 1041 | "stateMutability": "nonpayable", 1042 | "type": "function" 1043 | }, 1044 | { 1045 | "inputs": [ 1046 | { 1047 | "internalType": "address", 1048 | "name": "l1Token", 1049 | "type": "address" 1050 | }, 1051 | { 1052 | "internalType": "uint256", 1053 | "name": "lpTokenAmount", 1054 | "type": "uint256" 1055 | }, 1056 | { 1057 | "internalType": "bool", 1058 | "name": "sendEth", 1059 | "type": "bool" 1060 | } 1061 | ], 1062 | "name": "removeLiquidity", 1063 | "outputs": [], 1064 | "stateMutability": "nonpayable", 1065 | "type": "function" 1066 | }, 1067 | { 1068 | "inputs": [], 1069 | "name": "renounceOwnership", 1070 | "outputs": [], 1071 | "stateMutability": "nonpayable", 1072 | "type": "function" 1073 | }, 1074 | { 1075 | "inputs": [], 1076 | "name": "rootBundleProposal", 1077 | "outputs": [ 1078 | { 1079 | "internalType": "bytes32", 1080 | "name": "poolRebalanceRoot", 1081 | "type": "bytes32" 1082 | }, 1083 | { 1084 | "internalType": "bytes32", 1085 | "name": "relayerRefundRoot", 1086 | "type": "bytes32" 1087 | }, 1088 | { 1089 | "internalType": "bytes32", 1090 | "name": "slowRelayRoot", 1091 | "type": "bytes32" 1092 | }, 1093 | { 1094 | "internalType": "uint256", 1095 | "name": "claimedBitMap", 1096 | "type": "uint256" 1097 | }, 1098 | { 1099 | "internalType": "address", 1100 | "name": "proposer", 1101 | "type": "address" 1102 | }, 1103 | { 1104 | "internalType": "uint8", 1105 | "name": "unclaimedPoolRebalanceLeafCount", 1106 | "type": "uint8" 1107 | }, 1108 | { 1109 | "internalType": "uint32", 1110 | "name": "challengePeriodEndTimestamp", 1111 | "type": "uint32" 1112 | } 1113 | ], 1114 | "stateMutability": "view", 1115 | "type": "function" 1116 | }, 1117 | { 1118 | "inputs": [ 1119 | { 1120 | "internalType": "contract IERC20", 1121 | "name": "newBondToken", 1122 | "type": "address" 1123 | }, 1124 | { 1125 | "internalType": "uint256", 1126 | "name": "newBondAmount", 1127 | "type": "uint256" 1128 | } 1129 | ], 1130 | "name": "setBond", 1131 | "outputs": [], 1132 | "stateMutability": "nonpayable", 1133 | "type": "function" 1134 | }, 1135 | { 1136 | "inputs": [ 1137 | { 1138 | "internalType": "uint256", 1139 | "name": "l2ChainId", 1140 | "type": "uint256" 1141 | }, 1142 | { 1143 | "internalType": "address", 1144 | "name": "adapter", 1145 | "type": "address" 1146 | }, 1147 | { 1148 | "internalType": "address", 1149 | "name": "spokePool", 1150 | "type": "address" 1151 | } 1152 | ], 1153 | "name": "setCrossChainContracts", 1154 | "outputs": [], 1155 | "stateMutability": "nonpayable", 1156 | "type": "function" 1157 | }, 1158 | { 1159 | "inputs": [ 1160 | { 1161 | "internalType": "uint256", 1162 | "name": "time", 1163 | "type": "uint256" 1164 | } 1165 | ], 1166 | "name": "setCurrentTime", 1167 | "outputs": [], 1168 | "stateMutability": "nonpayable", 1169 | "type": "function" 1170 | }, 1171 | { 1172 | "inputs": [ 1173 | { 1174 | "internalType": "uint256", 1175 | "name": "originChainId", 1176 | "type": "uint256" 1177 | }, 1178 | { 1179 | "internalType": "uint256", 1180 | "name": "destinationChainId", 1181 | "type": "uint256" 1182 | }, 1183 | { 1184 | "internalType": "address", 1185 | "name": "originToken", 1186 | "type": "address" 1187 | }, 1188 | { 1189 | "internalType": "bool", 1190 | "name": "depositsEnabled", 1191 | "type": "bool" 1192 | } 1193 | ], 1194 | "name": "setDepositRoute", 1195 | "outputs": [], 1196 | "stateMutability": "nonpayable", 1197 | "type": "function" 1198 | }, 1199 | { 1200 | "inputs": [ 1201 | { 1202 | "internalType": "bytes32", 1203 | "name": "newIdentifier", 1204 | "type": "bytes32" 1205 | } 1206 | ], 1207 | "name": "setIdentifier", 1208 | "outputs": [], 1209 | "stateMutability": "nonpayable", 1210 | "type": "function" 1211 | }, 1212 | { 1213 | "inputs": [ 1214 | { 1215 | "internalType": "uint32", 1216 | "name": "newLiveness", 1217 | "type": "uint32" 1218 | } 1219 | ], 1220 | "name": "setLiveness", 1221 | "outputs": [], 1222 | "stateMutability": "nonpayable", 1223 | "type": "function" 1224 | }, 1225 | { 1226 | "inputs": [ 1227 | { 1228 | "internalType": "bool", 1229 | "name": "pause", 1230 | "type": "bool" 1231 | } 1232 | ], 1233 | "name": "setPaused", 1234 | "outputs": [], 1235 | "stateMutability": "nonpayable", 1236 | "type": "function" 1237 | }, 1238 | { 1239 | "inputs": [ 1240 | { 1241 | "internalType": "uint256", 1242 | "name": "destinationChainId", 1243 | "type": "uint256" 1244 | }, 1245 | { 1246 | "internalType": "address", 1247 | "name": "l1Token", 1248 | "type": "address" 1249 | }, 1250 | { 1251 | "internalType": "address", 1252 | "name": "destinationToken", 1253 | "type": "address" 1254 | } 1255 | ], 1256 | "name": "setPoolRebalanceRoute", 1257 | "outputs": [], 1258 | "stateMutability": "nonpayable", 1259 | "type": "function" 1260 | }, 1261 | { 1262 | "inputs": [ 1263 | { 1264 | "internalType": "address", 1265 | "name": "newProtocolFeeCaptureAddress", 1266 | "type": "address" 1267 | }, 1268 | { 1269 | "internalType": "uint256", 1270 | "name": "newProtocolFeeCapturePct", 1271 | "type": "uint256" 1272 | } 1273 | ], 1274 | "name": "setProtocolFeeCapture", 1275 | "outputs": [], 1276 | "stateMutability": "nonpayable", 1277 | "type": "function" 1278 | }, 1279 | { 1280 | "inputs": [ 1281 | { 1282 | "internalType": "address", 1283 | "name": "l1Token", 1284 | "type": "address" 1285 | } 1286 | ], 1287 | "name": "sync", 1288 | "outputs": [], 1289 | "stateMutability": "nonpayable", 1290 | "type": "function" 1291 | }, 1292 | { 1293 | "inputs": [], 1294 | "name": "timerAddress", 1295 | "outputs": [ 1296 | { 1297 | "internalType": "address", 1298 | "name": "", 1299 | "type": "address" 1300 | } 1301 | ], 1302 | "stateMutability": "view", 1303 | "type": "function" 1304 | }, 1305 | { 1306 | "inputs": [ 1307 | { 1308 | "internalType": "address", 1309 | "name": "newOwner", 1310 | "type": "address" 1311 | } 1312 | ], 1313 | "name": "transferOwnership", 1314 | "outputs": [], 1315 | "stateMutability": "nonpayable", 1316 | "type": "function" 1317 | }, 1318 | { 1319 | "inputs": [ 1320 | { 1321 | "internalType": "address", 1322 | "name": "", 1323 | "type": "address" 1324 | } 1325 | ], 1326 | "name": "unclaimedAccumulatedProtocolFees", 1327 | "outputs": [ 1328 | { 1329 | "internalType": "uint256", 1330 | "name": "", 1331 | "type": "uint256" 1332 | } 1333 | ], 1334 | "stateMutability": "view", 1335 | "type": "function" 1336 | }, 1337 | { 1338 | "inputs": [], 1339 | "name": "weth", 1340 | "outputs": [ 1341 | { 1342 | "internalType": "contract WETH9", 1343 | "name": "", 1344 | "type": "address" 1345 | } 1346 | ], 1347 | "stateMutability": "view", 1348 | "type": "function" 1349 | }, 1350 | { 1351 | "stateMutability": "payable", 1352 | "type": "receive" 1353 | } 1354 | ] 1355 | --------------------------------------------------------------------------------