├── .dockerignore ├── .env.example ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── Dockerfile ├── LICENSE ├── README.md ├── app ├── __init__.py ├── config.yaml └── liquidation │ ├── __init__.py │ ├── bot_manager.py │ ├── config_loader.py │ ├── liquidation_bot.py │ ├── routes.py │ └── utils.py ├── application.py ├── broadcast ├── DeployLiquidator.sol │ ├── 41337 │ │ ├── run-1721912164.json │ │ └── run-latest.json │ └── 42161 │ │ ├── run-1722278799.json │ │ ├── run-1722849403.json │ │ ├── run-1722943201.json │ │ ├── run-1722944027.json │ │ ├── run-1722945806.json │ │ └── run-latest.json └── LiquidationSetupWithVaultCreated.sol │ └── 42161 │ ├── run-1722942017.json │ ├── run-1722942330.json │ ├── run-1722942413.json │ ├── run-1722945742.json │ ├── run-1722945872.json │ └── run-latest.json ├── compose.yaml ├── contracts ├── DeployLiquidator.sol ├── EVault.json ├── EthereumVaultConnector.json ├── EulerRouter.json ├── IEVC.sol ├── IEVault.sol ├── IOracle.json ├── IPyth.json ├── IPyth.sol ├── ISwapper.sol ├── IVault.sol ├── Liquidator.sol ├── MockPriceOracle.sol └── SwapVerifier.sol ├── foundry.toml ├── pylintrc ├── remappings.txt ├── requirements.txt ├── state ├── Base_state.json ├── Berachain_state.json └── Swell_state.json └── test ├── LiquidationSetupWithVaultCreated.sol ├── TestLiquidator.t.sol ├── get_ids.py ├── oracle_test.py ├── pyth_test.py └── swap_api_test.py /.dockerignore: -------------------------------------------------------------------------------- 1 | # Include any files or directories that you don't want to be copied to your 2 | # container here (e.g., local build artifacts, temporary files, etc.). 3 | # 4 | # For more help, visit the .dockerignore file reference guide at 5 | # https://docs.docker.com/go/build-context-dockerignore/ 6 | 7 | **/.DS_Store 8 | **/__pycache__ 9 | **/.venv 10 | **/.classpath 11 | **/.dockerignore 12 | **/.env 13 | **/.git 14 | **/.gitignore 15 | **/.project 16 | **/.settings 17 | **/.toolstarget 18 | **/.vs 19 | **/.vscode 20 | **/*.*proj.user 21 | **/*.dbmdl 22 | **/*.jfm 23 | **/bin 24 | **/charts 25 | **/docker-compose* 26 | **/compose.y*ml 27 | **/Dockerfile* 28 | **/node_modules 29 | **/npm-debug.log 30 | **/obj 31 | **/secrets.dev.yaml 32 | **/values.dev.yaml 33 | LICENSE 34 | README.md 35 | **/lib -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # EOA that holds the gas that should be used for liquidation 2 | LIQUIDATOR_EOA=0x0001 3 | LIQUIDATOR_PRIVATE_KEY=0x0002 4 | 5 | # RPC URLs 6 | MAINNET_RPC_URL=https://example.rpc.url.com 7 | BASE_RPC_URL=https://example.base_rpc.url.com 8 | ARBITRUM_RPC_URL=https://example.arbitrum_rpc.url.com 9 | 10 | # Swap API URL 11 | SWAP_API_URL=https://example.api.url.com 12 | 13 | ### OPTIONAL ### 14 | 15 | # Slack webhook URL for sending notifications 16 | SLACK_WEBHOOK_URL=https://hooks.slack.com/services/SLACK_KEY 17 | 18 | # URL for the liquidation UI, if including in the slack notification 19 | RISK_DASHBOARD_URL=http://127.0.0.1:8080 -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | broadcast/ 10 | 11 | # Docs 12 | docs/ 13 | 14 | # Dotenv file 15 | .env 16 | .env_local 17 | .copy_env 18 | .vscode 19 | lcov.info 20 | 21 | # Virtual env 22 | python-venv/ 23 | venv/ 24 | 25 | # Logs and save state 26 | logs/ 27 | 28 | # Python cache files 29 | __pycache__/ 30 | *.pyc 31 | *.pyo 32 | *.pyd 33 | 34 | /redstone_script/node_modules -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ARG PYTHON_VERSION=3.12.5 4 | FROM 310118226683.dkr.ecr.eu-west-1.amazonaws.com/python:${PYTHON_VERSION} as base 5 | 6 | # Copy the project files 7 | COPY . . 8 | 9 | RUN apt-get update && apt-get install -y nodejs npm 10 | 11 | # Initialize git repository 12 | RUN git init && \ 13 | git add -A && \ 14 | git commit -m "Initial commit" 15 | 16 | # Manually clone submodules 17 | RUN mkdir -p lib/forge-std && \ 18 | git clone https://github.com/foundry-rs/forge-std.git lib/forge-std 19 | 20 | # Run Forge commands 21 | RUN forge install --no-commit 22 | RUN forge update 23 | RUN forge build 24 | 25 | # Create a non-privileged user 26 | ARG UID=10001 27 | RUN adduser \ 28 | --disabled-password \ 29 | --gecos "" \ 30 | --home "/nonexistent" \ 31 | --shell "/sbin/nologin" \ 32 | --no-create-home \ 33 | --uid "${UID}" \ 34 | appuser 35 | 36 | RUN mkdir -p /app/logs /app/state 37 | 38 | # Install Python dependencies 39 | RUN --mount=type=cache,target=/root/.cache/pip \ 40 | --mount=type=bind,source=requirements.txt,target=requirements.txt \ 41 | python -m pip install -r requirements.txt 42 | 43 | # Set correct permissions 44 | RUN chown -R appuser:appuser /app && \ 45 | chmod -R 755 /app && \ 46 | chmod 777 /app/logs /app/state 47 | 48 | USER appuser 49 | 50 | EXPOSE 8080 51 | 52 | # CMD ["python", "python/liquidation_bot.py"] 53 | # Run the application 54 | CMD ["gunicorn", "--bind", "0.0.0.0:8080", "application:application"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Euler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Euler Liquidation Bot 2 | 3 | Bot to perform liquidations on the Euler platform. [Liquidation docs.](https://docs.euler.finance/euler-vault-kit-white-paper/#liquidation) 4 | 5 | ## How it works 6 | 7 | 1. **Account Monitoring**: 8 | - The primary way of finding new accounts is [scanning](app/liquidation/liquidation_bot.py#L950) for `AccountStatusCheck` events emitted by the EVC contract to check for new & modified positions. 9 | - This event is emitted every time a borrow is created or modified, and contains both the account address and vault address. 10 | - Health scores are calculated using the `accountLiquidity` [function](app/liqiudation/liquidation_bot.py#L101) implemented by the vaults themselves. 11 | - Accounts are added to a priority queue based on their health score with a time of next update, with low health accounts being checked most frequently. 12 | - EVC logs are batched on bot startup to catch up to the current block, then scanned for new events at a regular interval. 13 | 14 | 2. **Liquidation Opportunity Detection**: 15 | - When an account's health score falls below 1, the bot simulates a liquidation transaction across each collateral asset. 16 | - The bot gets a quote for how much collateral is needed to swap into the debt repay amount, and simulates a liquidation transaction on the Liquidator.sol contract. 17 | - Gas cost is estimated for the liquidation transaction, then checks if the leftover collateral after repaying debt is greater than the gas cost when converted to ETH terms. 18 | - If this is the case, the liquidation is profitable and the bot will attempt to execute the transaction. 19 | 20 | 3. **Liquidation Execution - [Liquidator.sol](contracts/Liquidator.sol)**: 21 | - If profitable, the bot constructs a transaction to call the `liquidateSingleCollateral` [function](contracts/Liquidator.sol#L70) on the Liquidator contract. 22 | - The Liquidator contract then executes a batch of actions via the EVC containing the following steps: 23 | 1. Enables borrow vault as a controller. 24 | 2. Enable collateral vault as a collateral. 25 | 3. Call liquidate() on the violator's position in the borrow vault, which seizes both the collateral and debt position. 26 | 4. Withdraws specified amount of collateral from the collateral vault to the swapper contract. 27 | 5. Calls the swapper contract with a multicall batch to swap the seized collateral, repay the debt, and sweep any remaining dust from the swapper contract. 28 | 6. Transfers remaining collateral to the profit receiver. 29 | 7. Submit batch to EVC. 30 | 31 | 32 | - There is a secondary flow still being developed to use the liquidator contract as an EVC operator, which would allow the bot to operate on behalf of another account and pull the debt position alongside the collateral to the account directly. This flow will be particularly useful for liquidating positions without swapping the collateral to the debt asset, for things such as permissioned RWA liquidations. 33 | 34 | 4. **Swap Quotation**: 35 | - The bot currently uses 1inch API to get quotes for swapping seized collateral to repay debt. 36 | - 1inch unfortunatley does not support exact output swaps, so we perform a binary search to find the optimal swap amount resulting in swapping slightly more collateral than needed to repay debt. 37 | - The bot will eventually have a fallback to uniswap swapping if 1inch is unable to provide a quote, which would also allow for more precise exact output swaps. 38 | 39 | 5. **Profit Handling**: 40 | - Any profit (excess collateral after repayment) is sent to a designated receiver address. 41 | - Profit is sent in the form of ETokens of the collateral asset, and is not withdrawn from the vault or converted to any other asset. 42 | 43 | 6. **Slack Notifications**: 44 | - The bot can send notifications to a slack channel when unhealthy accounts are detected, when liquidations are performed, and when errors occur. 45 | - The bot also sends a report of all low health accounts at regularly scheduled intervals, which can be configured in the config.yaml file. 46 | - In order to receive notifications, a slack channel must be set up and a webhook URL must be provided in the .env file. 47 | 48 | #### Improvement Notes 49 | There are quite a few optimizations/improvements that likely could be made with more time, for instance: 50 | - Storing enabled collateral/controller within the liquidator contract itself to avoid calls to EVC to check & enable already enabled collaterals 51 | - Reducing the number of calls made to the RPC with smarter caching 52 | - Smarter gas price & slippage profitability checks 53 | - Potentially skipping interaction with Liquidator contract entirely and constructing batch off chain 54 | - More precise swap calculations in tandem with Uniswap swaps to avoid overswapping 55 | - Additional safety checks on amounts in Liquidator contract 56 | - Deconstruction of Pull oracle batches to avoid unnecessary updates on oracles that aren't being used 57 | - Secure routing via flashbots/bundling/etc 58 | 59 | 60 | ## How to run the bot 61 | 62 | 63 | ### Installation 64 | 65 | The bot can be run either via building a docker container or manually. In both instances, it runs via a flask app to expose some endpoints for account health dashboards & metrics. 66 | 67 | Before running either, setup a .env file by copying the .env.example file and updating with the relevant contract addresses, an EOA private key, & API keys. Then, check config.yaml to make sure parameters, contracts, and ABI paths have been set up correctly. 68 | 69 | #### Running locally 70 | To run locally, we need to install some dependencies and build the contracts. This will setup a python virtual environment for installing dependencies. The below command assumes we have foundry installed, which can installed from the [Foundry Book](https://book.getfoundry.sh/). 71 | 72 | Setup: 73 | ```bash 74 | foundryup 75 | python3 -m venv venv 76 | source venv/bin/activate 77 | pip install -r requirements.txt 78 | forge install && forge build 79 | cd lib/evk-periphery && forge build && cd ../.. 80 | mkdir logs state 81 | ``` 82 | 83 | **Run**: 84 | ```bash 85 | python flask run --port 8080 86 | ``` 87 | Change the Port number to whatever port is desired for exposing the relevant endpoints from the [routes.py](app/liquidation/routes.py) file. 88 | 89 | #### Docker 90 | After creating the .env file, the below command will create a container, install all dependencies, and start the liquidation bot: 91 | `docker compose build --progress=plain && docker compose up` 92 | 93 | This may require some configuration changes on the Docker image to a basic Python enabled container. 94 | 95 | ### Configuration 96 | 97 | - The bot uses variables from both the [config.yaml](config.yaml) file and the [.env](.env.example) file to configure settings and private keys. 98 | - The startup code is contained at the end of the [python/liquidation_bot.py](python/liquidation_bot.py#L1311) file, which also has two variable to set for the bot - `notify` & `execute_liquidation`, which determine if the bot will post to slack and if it will execute the liquidations found. 99 | 100 | Make sure to build the contracts in both src and lib to have the correct ABIs loaded from the evk-periphery installation 101 | 102 | Configuration through `.env` file: 103 | 104 | REQUIRED: 105 | - `LIQUIDATOR_EOA, LIQUIDATOR_PRIVATE_KEY` - public/private key of EOA that will be used to liquidate 106 | 107 | - `{CHAIN}_RPC_URL` - RPC provider endpoint (Infura, Rivet, Alchemy etc.) 108 | 109 | OPTIONAL: 110 | - `SLACK_WEBHOOK_URL` - Optional URL to post notifications to slack 111 | - `RISK_DASHBOARD_URL` - Optional, can include a link in slack notifications to manually liquidate a position 112 | - `DEPOSITOR_ADDRESS, DEPOSITOR_PRIVATE_KEY, BORROWER_ADDRESS, BORROWER_PRIVATE_KEY` - Optional, for running 113 | 114 | 115 | Configuration in `config.yaml` file: 116 | 117 | - `LOGS_PATH, SAVE_STATE_PATH` - Path directing to save location for Logs & Save State 118 | - `SAVE_INTERVAL` - How often state should be saved 119 | 120 | - `HS_LOWER_BOUND, HS_UPPER_BOUND` - Bounds below and above which an account should be updated at the min/max update interval 121 | - `MIN_UPDATE_INTERVAL, MAX_UPDATE_INTERVAL` - Min/Max time between account updates 122 | 123 | - `LOW_HEALTH_REPORT_INTERVAL` - Interval between low health reports 124 | - `SLACK_REPORT_HEALTH_SCORE` - Threshold to include an account on the low health report 125 | 126 | - `BATCH_SIZE, BATCH_INTERVAL` - Configuration batching logs on bot startup 127 | 128 | - `SCAN_INTERVAL` - How often to scan for new events during regular operation 129 | 130 | - `NUM_RETRIES, RETRY_DELAY` - Config for how often to retry failing API requests 131 | 132 | - `SWAP_DELTA, MAX_SEARCH_ITERATIONS` - Used to define how much overswapping is accetable when searching 1Inch swaps 133 | 134 | - `EVC_DEPLOYMENT_BLOCK` - Block that the contracs were deployed 135 | 136 | - `WETH, EVC, SWAPPER, SWAP_VERIFIER, LIQUIDATOR_CONTRACT, ORACLE_LENS` - Relevant deployed contract addresses. The liquidator contract has been deployed on Mainnet, but feel free to redeploy. 137 | 138 | - `PROFIT_RECEIVER` - Targeted receiver of any profits from liquidations 139 | 140 | - `EVAULT_ABI_PATH, EVC_ABI_PATH, LIQUIDATOR_ABI_PATH, ORACLE_LENS_ABI_PATH` - Paths to compiled contracts 141 | 142 | - `CHAIN_ID` - Chain ID to run the bot on, Mainnet: 1, Arbitrum: 42161 143 | 144 | 145 | ### Deploying 146 | 147 | If you want to deploy your own version of the liquidator contract, you can run the command below: 148 | 149 | ```bash 150 | forge script contracts/DeployLiquidator.sol --rpc-url $RPC_URL --broadcast --ffi -vvv --slow 151 | ``` 152 | 153 | To run the basic test script & broadcast to the configured RPC, modify the [LiquidationSetupWithVaultCreated.sol test](test/LiquidationSetupWithVaultCreated.sol) with the correct contract addresses and uncomment the various steps of setting up a position, then run the below commmand: 154 | 155 | ```bash 156 | forge script test/LiquidationSetupWithVaultCreated.sol --rpc-url $RPC_URL --broadcast --ffi -vvv --slow --evm-version shanghai 157 | ``` 158 | 159 | This test is intended to create a position on an existing vault. To test a liquitation, you can either wait for price fluctuations to happen or manually change the LTV of the vault using the create.euler.finance UI if it is a governed vault that you control. -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Creates and returns main flask app 3 | """ 4 | from flask import Flask, jsonify 5 | from flask_cors import CORS 6 | import threading 7 | from .liquidation.routes import liquidation, start_monitor 8 | 9 | def create_app(): 10 | """Create Flask app with specified chain IDs""" 11 | app = Flask(__name__) 12 | CORS(app) 13 | 14 | @app.route("/health", methods=["GET"]) 15 | def health_check(): 16 | return jsonify({"status": "healthy"}), 200 17 | 18 | chain_ids = [1] 19 | # chain_ids = [80094] 20 | monitor_thread = threading.Thread(target=start_monitor, args=(chain_ids,)) 21 | monitor_thread.start() 22 | 23 | # Register the rewards blueprint after starting the monitor 24 | app.register_blueprint(liquidation, url_prefix="/liquidation") 25 | 26 | return app 27 | -------------------------------------------------------------------------------- /app/config.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | ## RISK PARAMETERS ## 3 | # Health score bounds for update interval frequency 4 | HS_LIQUIDATION: 1.0 5 | HS_HIGH_RISK: 1.02 6 | HS_SAFE: 1.25 7 | 8 | # Position size bounds for update interval frequency 9 | TEENY: 10000000000000000000 # $10 10 | MINI: 100000000000000000000 # $100 11 | SMALL: 1000000000000000000000 # $1000 12 | MEDIUM: 10000000000000000000000 # $10000 13 | 14 | 15 | # Interval Update Frequency Matrix 16 | TEENY_LIQ: 86400 17 | TEENY_HIGH: 86400 18 | TEENY_LOW: 86400 19 | TEENY_SAFE: 86400 20 | 21 | MINI_LIQ: 900 22 | MINI_HIGH: 14400 23 | MINI_LOW: 43200 24 | MINI_SAFE: 86400 25 | 26 | SMALL_LIQ: 300 27 | SMALL_HIGH: 3600 28 | SMALL_LOW: 21600 29 | SMALL_SAFE: 43200 30 | 31 | MEDIUM_LIQ: 120 32 | MEDIUM_HIGH: 900 33 | MEDIUM_LOW: 14400 34 | MEDIUM_SAFE: 21600 35 | 36 | LARGE_LIQ: 30 37 | LARGE_HIGH: 900 38 | LARGE_LOW: 3600 39 | LARGE_SAFE: 21600 40 | 41 | # Update interval frequency (in seconds) 42 | MIN_UPDATE_INTERVAL_SMALL: 300 43 | HIGH_RISK_UPDATE_INTERVAL: 600 44 | MAX_UPDATE_INTERVAL: 3600 # 60 minutes 45 | 46 | ## REPORTING PARAMETERS ## 47 | # Interval for reporting low health accounts 48 | LOW_HEALTH_REPORT_INTERVAL: 43200 # 12 hours 49 | SLACK_REPORT_HEALTH_SCORE: 1.05 50 | BORROW_VALUE_THRESHOLD: 10000 # $1000 minimum for reporting 51 | # Threshold for excluding small positions from frequent notifications, in USD terms 52 | SMALL_POSITION_THRESHOLD: 1000000000000000000000 # 1000 USD 53 | SMALL_POSITION_REPORT_INTERVAL: 43200 # 2 hours 54 | # Cooldown for reporting errors 55 | ERROR_COOLDOWN: 900 56 | 57 | ## MONITORING PARAMETERS ## 58 | # Batch size for scanning blocks on startup 59 | BATCH_SIZE: 10000 60 | BATCH_INTERVAL: 0.1 61 | # Time to wait between scanning on regular intervals 62 | SCAN_INTERVAL: 600 # 2 minutes 63 | 64 | ## PATHS ## 65 | EVAULT_ABI_PATH: "contracts/EVault.json" 66 | EVC_ABI_PATH: "contracts/EthereumVaultConnector.json" 67 | LIQUIDATOR_ABI_PATH: "out/Liquidator.sol/Liquidator.json" 68 | ORACLE_ABI_PATH: "contracts/IOracle.json" 69 | PYTH_ABI_PATH: "contracts/IPyth.json" 70 | ERC20_ABI_PATH: "out/IERC20.sol/IERC20.json" 71 | ROUTER_ABI_PATH: "contracts/EulerRouter.json" 72 | LOGS_PATH: "logs/account_monitor_logs.log" 73 | SAVE_STATE_PATH: "state" 74 | SAVE_INTERVAL: 1800 # 30 minutes 75 | 76 | ## API CALL PARAMETERS ## 77 | # API Retry 78 | NUM_RETRIES: 3 79 | RETRY_DELAY: 10 80 | # Acceptable amound of overswapping of collateral for 1INCH binary search 81 | API_REQUEST_DELAY: .25 82 | SWAP_SLIPPAGE: 1.0 # 1% 83 | SWAP_DEADLINE: 300 # 5 minutes 84 | 85 | ## PYTH FEED ID CACHE ## 86 | PYTH_CACHE_REFRESH: 86400 87 | 88 | ## EOA TO RECEIVE LIQUIDATION PROCEEDS ## 89 | PROFIT_RECEIVER: "0x8cbB534874bab83e44a7325973D2F04493359dF8" 90 | 91 | MAINNET_ETH_ADAPTER: "0x10674C8C1aE2072d4a75FE83f1E159425fd84E1D" 92 | MAINNET_ETH_ADDRESS: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" 93 | MAINNET_BTC_ADAPTER: "0x0484Df76f561443d93548D86740b5C4A826e5A33" 94 | 95 | chains: 96 | # ETH Mainnet 97 | 1: 98 | # Config 99 | name: "Ethereum" 100 | EVC_DEPLOYMENT_BLOCK: 20529207 101 | EXPLORER_URL: "https://etherscan.io" 102 | RPC_NAME: "MAINNET_RPC_URL" 103 | 104 | # Deployed contract addresses 105 | contracts: 106 | LIQUIDATOR_CONTRACT: "0xAAF93d5475d092EA68a748137eE19D8130918392" 107 | 108 | #EVK Addresses 109 | EVC: "0x0C9a3dd6b8F28529d72d7f9cE918D493519EE383" 110 | SWAPPER: "0x2Bba09866b6F1025258542478C39720A09B728bF" 111 | SWAP_VERIFIER: "0xae26485ACDDeFd486Fe9ad7C2b34169d360737c7" 112 | 113 | # Other relevant contracts & Units of Account 114 | WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" 115 | USD: "0x0000000000000000000000000000000000000348" 116 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 117 | 118 | # PYTH address 119 | PYTH: "0x4305FB66699C3B2702D4d05CF36551390A4c69C6" 120 | 121 | # Base 122 | 8453: 123 | # Config 124 | name: "Base" 125 | EVC_DEPLOYMENT_BLOCK: 22282342 126 | EXPLORER_URL: "https://basescan.org" 127 | RPC_NAME: "BASE_RPC_URL" 128 | 129 | # Deployed contract addresses 130 | contracts: 131 | LIQUIDATOR_CONTRACT: "0x7608926d200d2a85dDB3a034ADb7D18fD2D5F3Cf" 132 | 133 | #EVK Addresses 134 | EVC: "0x5301c7dD20bD945D2013b48ed0DEE3A284ca8989" 135 | SWAPPER: "0x0D3d0F97eD816Ca3350D627AD8e57B6AD41774df" 136 | SWAP_VERIFIER: "0x30660764A7a05B84608812C8AFC0Cb4845439EEe" 137 | 138 | # Other relevant contracts & Units of Account 139 | WETH: "0x4200000000000000000000000000000000000006" 140 | USD: "0x0000000000000000000000000000000000000348" 141 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 142 | 143 | # PYTH address 144 | PYTH: "0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a" 145 | 146 | # Swell 147 | 1923: 148 | # Config 149 | name: "Swell" 150 | EVC_DEPLOYMENT_BLOCK: 485320 151 | EXPLORER_URL: "https://explorer.swellnetwork.io" 152 | RPC_NAME: "SWELL_RPC_URL" 153 | 154 | # Deployed contract addresses 155 | contracts: 156 | LIQUIDATOR_CONTRACT: "0xA8A46596a7B17542d2cf6993FC61Ea0CBb4474c1" 157 | 158 | #EVK Addresses 159 | EVC: "0x08739CBede6E28E387685ba20e6409bD16969Cde" 160 | SWAPPER: "0x05Eb1A647265D974a1B0A57206048312604Ac6C3" 161 | SWAP_VERIFIER: "0x392C1570b3Bf29B113944b759cAa9a9282DA12Fe" 162 | 163 | # Other relevant contracts & Units of Account 164 | WETH: "0x4200000000000000000000000000000000000006" 165 | USD: "0x0000000000000000000000000000000000000348" 166 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 167 | 168 | # PYTH address 169 | PYTH: "" 170 | 171 | # Sonic 172 | 146: 173 | # Config 174 | name: "Sonic" 175 | EVC_DEPLOYMENT_BLOCK: 5324624 176 | EXPLORER_URL: "https://sonicscan.org" 177 | RPC_NAME: "SONIC_RPC_URL" 178 | 179 | # Deployed contract addresses 180 | contracts: 181 | LIQUIDATOR_CONTRACT: "0x431e0a2768de070E860F33653C4634BD69aa4c6a" 182 | 183 | #EVK Addresses 184 | EVC: "0x4860C903f6Ad709c3eDA46D3D502943f184D4315" 185 | SWAPPER: "0xbAf5B12c92711a3657DD4adA6b3C7801e83Bb56a" 186 | SWAP_VERIFIER: "0x003ef4048b45a5A79D4499aaBd52108B3Bc9209f" 187 | 188 | # Other relevant contracts & Units of Account 189 | WETH: "0x4200000000000000000000000000000000000006" 190 | USD: "0x0000000000000000000000000000000000000348" 191 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 192 | 193 | # PYTH address 194 | PYTH: "0x2880aB155794e7179c9eE2e38200202908C17B43" 195 | 196 | 60808: 197 | name: "BOB" 198 | EVC_DEPLOYMENT_BLOCK: 11481883 199 | EXPLORER_URL: "https://explorer.gobob.xyz/" 200 | RPC_NAME: "BOB_RPC_URL" 201 | 202 | # Deployed contract addresses 203 | contracts: 204 | LIQUIDATOR_CONTRACT: "0x431e0a2768de070E860F33653C4634BD69aa4c6a" 205 | 206 | #EVK Addresses 207 | EVC: "0x59f0FeEc4fA474Ad4ffC357cC8d8595B68abE47d" 208 | SWAPPER: "0x697Ca30D765c1603890D88AAffBa3BeCCe72059d" 209 | SWAP_VERIFIER: "0x296041DbdBC92171293F23c0a31e1574b791060d" 210 | 211 | # Other relevant contracts & Units of Account 212 | WETH: "0x4200000000000000000000000000000000000006" 213 | USD: "0x0000000000000000000000000000000000000348" 214 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 215 | 216 | # PYTH address 217 | PYTH: "0x2880aB155794e7179c9eE2e38200202908C17B43" 218 | 219 | 80094: 220 | name: "Berachain" 221 | EVC_DEPLOYMENT_BLOCK: 786266 222 | EXPLORER_URL: "https://berascan.com/" 223 | RPC_NAME: "BERA_RPC_URL" 224 | 225 | contracts: 226 | LIQUIDATOR_CONTRACT: "0xA8A46596a7B17542d2cf6993FC61Ea0CBb4474c1" 227 | 228 | #EVK Addresses 229 | EVC: "0x45334608ECE7B2775136bC847EB92B5D332806A9" 230 | SWAPPER: "0x4A35e6A872cf35623cd3fD07ebECEDFc0170D705" 231 | SWAP_VERIFIER: "0x6fFf8Ac4AB123B62FF5e92aBb9fF702DCBD6C939" 232 | 233 | # Other relevant contracts & Units of Account 234 | WETH: "0x4200000000000000000000000000000000000006" 235 | USD: "0x0000000000000000000000000000000000000348" 236 | BTC: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 237 | 238 | # PYTH address 239 | PYTH: "0x2880aB155794e7179c9eE2e38200202908C17B43" 240 | -------------------------------------------------------------------------------- /app/liquidation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euler-xyz/liquidation-bot-v2/f575ab7ced4baaede70a2a1995c87bc4f953c4b7/app/liquidation/__init__.py -------------------------------------------------------------------------------- /app/liquidation/bot_manager.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | from concurrent.futures import ThreadPoolExecutor 3 | from web3 import Web3 4 | 5 | from .liquidation_bot import AccountMonitor, EVCListener, logger 6 | from .config_loader import load_chain_config, ChainConfig 7 | 8 | class ChainManager: 9 | """Manages multiple chain instances of the liquidation bot""" 10 | def __init__(self, chain_ids: List[int], notify: bool = True, execute_liquidation: bool = True): 11 | self.chain_ids = chain_ids 12 | self.notify = notify 13 | self.execute_liquidation = execute_liquidation 14 | 15 | # Initialize configs, monitors, and evc_listeners for each chain 16 | self.configs: Dict[int, ChainConfig] = {} 17 | self.monitors: Dict[int, AccountMonitor] = {} 18 | self.evc_listeners: Dict[int, EVCListener] = {} 19 | self.web3s: Dict[int, Web3] = {} 20 | 21 | self._initialize_chains() 22 | 23 | def _initialize_chains(self): 24 | """Initialize components for each chain""" 25 | print(self.chain_ids) 26 | for chain_id in self.chain_ids: 27 | # Load chain-specific config 28 | config = load_chain_config(chain_id) 29 | self.configs[chain_id] = config 30 | 31 | # Create monitor instance 32 | monitor = AccountMonitor( 33 | chain_id=chain_id, 34 | config=config, 35 | notify=self.notify, 36 | execute_liquidation=self.execute_liquidation 37 | ) 38 | monitor.load_state(config.SAVE_STATE_PATH) 39 | self.monitors[chain_id] = monitor 40 | 41 | # Create listener instance 42 | listener = EVCListener(monitor, config) 43 | self.evc_listeners[chain_id] = listener 44 | 45 | def start(self): 46 | """Start all chain monitors and evc_listeners""" 47 | with ThreadPoolExecutor() as executor: 48 | # First batch process historical logs 49 | for chain_id in self.chain_ids: 50 | self.evc_listeners[chain_id].batch_account_logs_on_startup() 51 | 52 | # Start monitors 53 | monitor_futures = [ 54 | executor.submit(self._run_monitor, chain_id) 55 | for chain_id in self.chain_ids 56 | ] 57 | 58 | # Start evc_listeners 59 | listener_futures = [ 60 | executor.submit(self._run_listener, chain_id) 61 | for chain_id in self.chain_ids 62 | ] 63 | 64 | # Wait for all to complete (they shouldn't unless there's an error) 65 | for future in monitor_futures + listener_futures: 66 | try: 67 | future.result() 68 | except Exception as e: # pylint: disable=broad-except 69 | logger.error("Chain instance failed: %s", e, exc_info=True) 70 | 71 | def _run_monitor(self, chain_id: int): 72 | """Run a single chain's monitor""" 73 | monitor = self.monitors[chain_id] 74 | monitor.start_queue_monitoring() 75 | 76 | def _run_listener(self, chain_id: int): 77 | """Run a single chain's listener""" 78 | listener = self.evc_listeners[chain_id] 79 | listener.start_event_monitoring() 80 | 81 | def stop(self): 82 | """Stop all chain instances""" 83 | for monitor in self.monitors.values(): 84 | monitor.stop() -------------------------------------------------------------------------------- /app/liquidation/config_loader.py: -------------------------------------------------------------------------------- 1 | """ 2 | Config Loader module - part of multi chain refactor 3 | """ 4 | import os 5 | import yaml 6 | import json 7 | from typing import Dict, Any, Optional 8 | from dotenv import load_dotenv 9 | from web3 import Web3 10 | 11 | 12 | class Web3Singleton: 13 | """ 14 | Singleton class to manage w3 object creation per RPC URL 15 | """ 16 | _instances = {} 17 | 18 | @staticmethod 19 | def get_instance(rpc_url: Optional[str] = None): 20 | """ 21 | Set up a Web3 instance using the RPC URL from environment variables or passed parameter. 22 | Maintains separate instances per unique RPC URL. 23 | """ 24 | load_dotenv(override=True) 25 | default_url = os.getenv("RPC_URL") 26 | url = default_url if rpc_url is None else rpc_url 27 | 28 | if url not in Web3Singleton._instances: 29 | Web3Singleton._instances[url] = Web3(Web3.HTTPProvider(url)) 30 | 31 | return Web3Singleton._instances[url] 32 | 33 | def setup_w3(rpc_url: Optional[str] = None) -> Web3: 34 | """ 35 | Get the Web3 instance from the singleton class 36 | 37 | Args: 38 | rpc_url (Optional[str]): Optional RPC URL to override environment variable 39 | 40 | Returns: 41 | Web3: Web3 instance. 42 | """ 43 | return Web3Singleton.get_instance(rpc_url) 44 | 45 | 46 | class ChainConfig: 47 | """ 48 | Chain Config object to access config variables 49 | """ 50 | def __init__(self, chain_id: int, global_config: Dict[str, Any], chain_config: Dict[str, Any]): 51 | self.CHAIN_ID = chain_id 52 | self.CHAIN_NAME = chain_config["name"] 53 | self._global = global_config 54 | self._chain = chain_config 55 | 56 | # Load global EOA settings 57 | self.LIQUIDATOR_EOA = os.getenv("LIQUIDATOR_EOA") 58 | self.LIQUIDATOR_EOA_PRIVATE_KEY = os.getenv("LIQUIDATOR_PRIVATE_KEY") 59 | self.SWAP_API_URL = os.getenv("SWAP_API_URL") 60 | self.SLACK_URL = os.getenv("SLACK_WEBHOOK_URL") 61 | self.RISK_DASHBOARD_URL = os.getenv("RISK_DASHBOARD_URL") 62 | 63 | # Load chain-specific RPC from env using RPC_NAME from config 64 | self.RPC_URL = os.getenv(self._chain["RPC_NAME"]) 65 | if not self.RPC_URL: 66 | raise ValueError(f"Missing RPC URL for {self._chain["name"]}. " 67 | f"Env var {self._chain["RPC_NAME"]} not found") 68 | 69 | self.w3 = setup_w3(self.RPC_URL) 70 | self.mainnet_w3 = setup_w3(os.getenv("MAINNET_RPC_URL")) 71 | 72 | # Set chain-specific paths 73 | self.LOGS_PATH = f"{self._global["LOGS_PATH"]}/{self._chain["name"]}_monitor.log" 74 | self.SAVE_STATE_PATH = f"{self._global["SAVE_STATE_PATH"]}/{self._chain["name"]}_state.json" 75 | 76 | with open(self._global["EVC_ABI_PATH"], "r", encoding="utf-8") as file: 77 | interface = json.load(file) 78 | abi = interface["abi"] 79 | 80 | self.evc = self.w3.eth.contract(address=self.EVC, abi=abi) 81 | 82 | with open(self._global["ORACLE_ABI_PATH"], "r", encoding="utf-8") as file: 83 | interface = json.load(file) 84 | abi = interface["abi"] 85 | 86 | self.eth_oracle = self.mainnet_w3.eth.contract(address=self._global["MAINNET_ETH_ADAPTER"], abi=abi) 87 | self.btc_oracle = self.mainnet_w3.eth.contract(address=self._global["MAINNET_BTC_ADAPTER"], abi=abi) 88 | 89 | with open(global_config["LIQUIDATOR_ABI_PATH"], "r", encoding="utf-8") as file: 90 | interface = json.load(file) 91 | abi = interface["abi"] 92 | 93 | self.liquidator = self.w3.eth.contract(address=self._chain["contracts"]["LIQUIDATOR_CONTRACT"], abi=abi) 94 | 95 | def __getattr__(self, name: str) -> Any: 96 | if name in self._chain: 97 | return self._chain[name] 98 | if name in self._chain.get("contracts", {}): 99 | return self._chain["contracts"][name] 100 | if name in self._global: 101 | return self._global[name] 102 | raise AttributeError(f"Config has no attribute '{name}'") 103 | 104 | 105 | 106 | def load_chain_config(chain_id: int) -> ChainConfig: 107 | load_dotenv() 108 | 109 | current_dir = os.path.dirname(os.path.abspath(__file__)) 110 | config_path = os.path.join(os.path.dirname(current_dir), "config.yaml") 111 | 112 | try: 113 | with open(config_path, "r", encoding="utf-8") as f: 114 | config = yaml.safe_load(f) 115 | except FileNotFoundError as exc: 116 | raise FileNotFoundError(f"Config file not found at {config_path}") from exc 117 | except yaml.YAMLError as e: 118 | raise ValueError(f"Error parsing YAML file: {e}") from e 119 | 120 | if chain_id not in config["chains"]: 121 | raise ValueError(f"No configuration found for chain ID {chain_id}") 122 | 123 | return ChainConfig( 124 | chain_id=chain_id, 125 | global_config=config["global"], 126 | chain_config=config["chains"][chain_id] 127 | ) 128 | -------------------------------------------------------------------------------- /app/liquidation/routes.py: -------------------------------------------------------------------------------- 1 | """Module for handling API routes""" 2 | from flask import Blueprint, make_response, jsonify, request 3 | import math 4 | 5 | from .liquidation_bot import logger 6 | from .bot_manager import ChainManager 7 | 8 | liquidation = Blueprint("liquidation", __name__) 9 | 10 | chain_manager = None 11 | 12 | def start_monitor(chain_ids=None): 13 | """Start monitoring for specified chains, defaults to mainnet if none specified""" 14 | global chain_manager 15 | if chain_ids is None: 16 | chain_ids = [1] # Default to Ethereum mainnet 17 | 18 | chain_manager = ChainManager(chain_ids, notify=True) 19 | 20 | chain_manager.start() 21 | 22 | return chain_manager 23 | 24 | @liquidation.route("/allPositions", methods=["GET"]) 25 | def get_all_positions(): 26 | chain_id = int(request.args.get("chainId", 1)) # Default to mainnet if not specified 27 | 28 | if not chain_manager or chain_id not in chain_manager.monitors: 29 | return jsonify({"error": f"Monitor not initialized for chain {chain_id}"}), 500 30 | 31 | logger.info("API: Getting all positions for chain %s", chain_id) 32 | monitor = chain_manager.monitors[chain_id] 33 | sorted_accounts = monitor.get_accounts_by_health_score() 34 | 35 | response = [] 36 | for (address, owner, sub_account, health_score, value_borrowed, vault_name, vault_symbol) in sorted_accounts: 37 | if math.isinf(health_score): 38 | continue 39 | response.append({ 40 | "address": owner, 41 | "account_address": address, 42 | "sub_account": sub_account, 43 | "health_score": health_score, 44 | "value_borrowed": value_borrowed, 45 | "vault_name": vault_name, 46 | "vault_symbol": vault_symbol 47 | }) 48 | 49 | return make_response(jsonify(response)) 50 | -------------------------------------------------------------------------------- /app/liquidation/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility functions for the liquidation bot. 3 | """ 4 | import logging 5 | import json 6 | import functools 7 | import time 8 | import traceback 9 | import requests 10 | 11 | from typing import Any, Callable, Dict, Optional 12 | 13 | from web3 import Web3 14 | from web3.contract import Contract 15 | from urllib.parse import urlencode 16 | 17 | from .config_loader import ChainConfig 18 | 19 | LOGS_PATH = "logs/account_monitor_logs.log" 20 | 21 | def setup_logger() -> logging.Logger: 22 | """ 23 | Set up and configure a logger for the liquidation bot. 24 | 25 | Args: 26 | logs_path (str): Path to the log output file. 27 | 28 | Returns: 29 | logging.Logger: Configured logger instance. 30 | """ 31 | logger = logging.getLogger("liquidation_bot") 32 | logger.setLevel(logging.DEBUG) 33 | 34 | console_handler = logging.StreamHandler() 35 | file_handler = logging.FileHandler(LOGS_PATH, mode="a") 36 | 37 | detailed_formatter = logging.Formatter( 38 | "%(asctime)s - %(levelname)s - %(message)s\n%(exc_info)s") 39 | 40 | # Create a standard formatter for other log levels 41 | standard_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") 42 | 43 | class DetailedExceptionFormatter(logging.Formatter): 44 | def format(self, record): 45 | if record.levelno >= logging.ERROR: 46 | record.exc_text = "".join( 47 | traceback.format_exception(*record.exc_info)) if record.exc_info else "" 48 | return detailed_formatter.format(record) 49 | else: 50 | return standard_formatter.format(record) 51 | 52 | console_handler.setFormatter(DetailedExceptionFormatter()) 53 | file_handler.setFormatter(DetailedExceptionFormatter()) 54 | 55 | logger.addHandler(console_handler) 56 | logger.addHandler(file_handler) 57 | 58 | 59 | return logger 60 | 61 | def create_contract_instance(address: str, abi_path: str, config: ChainConfig) -> Contract: 62 | """ 63 | Create and return a contract instance. 64 | 65 | Args: 66 | address (str): The address of the contract. 67 | abi_path (str): Path to the ABI JSON file. 68 | 69 | Returns: 70 | Contract: Web3 contract instance. 71 | """ 72 | with open(abi_path, "r", encoding="utf-8") as file: 73 | interface = json.load(file) 74 | abi = interface["abi"] 75 | 76 | return config.w3.eth.contract(address=address, abi=abi) 77 | 78 | def retry_request(logger: logging.Logger, 79 | max_retries: int = 3, 80 | delay: int = 10) -> Callable: 81 | """ 82 | Decorator to retry a function in case of RequestException. 83 | 84 | Args: 85 | logger (logging.Logger): Logger instance to log retry attempts. 86 | max_retries (int, optional): Maximum number of retry attempts. 87 | Defaults to config.NUM_RETRIES. 88 | delay (int, optional): Delay between retry attempts in seconds. 89 | Defaults to config.RETRY_DELAY. 90 | 91 | Returns: 92 | Callable: Decorated function. 93 | """ 94 | def decorator(func): 95 | @functools.wraps(func) 96 | def wrapper(*args, **kwargs): 97 | for attempt in range(1, max_retries + 1): 98 | try: 99 | return func(*args, **kwargs) 100 | except requests.RequestException as e: 101 | logger.error(f"Error in API request, waiting {delay} seconds before retrying. " 102 | f"Attempt {attempt}/{max_retries}") 103 | logger.error(f"Error: {e}") 104 | 105 | if attempt == max_retries: 106 | logger.error(f"Failed after {max_retries} attempts.") 107 | return None 108 | 109 | time.sleep(delay) 110 | return wrapper 111 | return decorator 112 | 113 | def get_spy_link(account, config: ChainConfig): 114 | """ 115 | Get account owner from EVC 116 | """ 117 | owner = config.evc.functions.getAccountOwner(account).call() 118 | if owner == "0x0000000000000000000000000000000000000000": 119 | owner = account 120 | 121 | subaccount_number = int(int(account, 16) ^ int(owner, 16)) 122 | 123 | spy_link = f"https://app.euler.finance/account/{subaccount_number}?spy={owner}&chainId={config.CHAIN_ID}" 124 | 125 | return spy_link 126 | 127 | @retry_request(logging.getLogger("liquidation_bot")) 128 | def make_api_request(url: str, 129 | headers: Dict[str, str], 130 | params: Dict[str, Any]) -> Optional[Dict[str, Any]]: 131 | """ 132 | Make an API request with retry functionality. 133 | 134 | Args: 135 | url (str): The URL for the API request. 136 | headers (Dict[str, str]): Headers for the request. 137 | params (Dict[str, Any]): Parameters for the request. 138 | 139 | Returns: 140 | Optional[Dict[str, Any]]: JSON response if successful, None otherwise. 141 | """ 142 | response = requests.get(url, headers=headers, params=params, timeout=10) 143 | response.raise_for_status() 144 | return response.json() 145 | 146 | def get_eth_usd_quote(amount: int = 10**18, config: ChainConfig = None): 147 | return config.eth_oracle.functions.getQuote(amount, config.MAINNET_ETH_ADDRESS, config.USD).call() 148 | 149 | def get_btc_usd_quote(amount: int = 10**18, config: ChainConfig = None): 150 | return config.btc_oracle.functions.getQuote(amount, config.BTC, config.USD).call() 151 | 152 | 153 | def global_exception_handler(exctype: type, value: BaseException, tb: Any) -> None: 154 | """ 155 | Global exception handler to log uncaught exceptions. 156 | 157 | Args: 158 | exctype (type): The type of the exception. 159 | value (BaseException): The exception instance. 160 | tb (Any): A traceback object encapsulating the call stack 161 | at the point where the exception occurred. 162 | """ 163 | logger = logging.getLogger("liquidation_bot") 164 | 165 | # Get the full traceback as a string 166 | trace_str = "".join(traceback.format_exception(exctype, value, tb)) 167 | 168 | # Log the full exception information 169 | logger.critical("Uncaught exception:\n %s", trace_str) 170 | 171 | def post_unhealthy_account_on_slack(account_address: str, vault_address: str, 172 | health_score: float, value_borrowed: int, config: ChainConfig) -> None: 173 | """ 174 | Post a message on Slack about an unhealthy account. 175 | """ 176 | spy_link = get_spy_link(account_address, config) 177 | 178 | message = ( 179 | ":warning: *Unhealthy Account Detected* :warning:\n\n" 180 | f"*Account*: `{account_address}`, <{spy_link}|Spy Mode>\n" 181 | f"*Vault*: `{vault_address}`\n" 182 | f"*Health Score*: `{health_score:.4f}`\n" 183 | f"*Value Borrowed*: `${value_borrowed / 10 ** 18:,.2f}`\n" 184 | f"Time of detection: {time.strftime("%Y-%m-%d %H:%M:%S")}\n" 185 | f"Network: `{config.CHAIN_NAME}`\n\n" 186 | ) 187 | 188 | slack_payload = { 189 | "text": message, 190 | "username": "Liquidation Bot", 191 | "icon_emoji": ":robot_face:" 192 | } 193 | requests.post(config.SLACK_URL, json=slack_payload, timeout=10) 194 | 195 | 196 | def post_liquidation_opportunity_on_slack(account_address: str, vault_address: str, 197 | liquidation_data: Optional[Dict[str, Any]], 198 | params: Optional[Dict[str, Any]], config: ChainConfig) -> None: 199 | """ 200 | Post a message on Slack. 201 | 202 | Args: 203 | message (str): The main message to post. 204 | liquidation_data (Optional[Dict[str, Any]]): Additional liquidation data to format. 205 | """ 206 | RISK_DASHBOARD_URL = config.RISK_DASHBOARD_URL 207 | 208 | if liquidation_data and params: 209 | 210 | # Unpack params 211 | violator_address, vault, borrowed_asset, collateral_vault, collateral_asset, \ 212 | max_repay, seized_collateral_shares, receiver = params 213 | 214 | spy_link = get_spy_link(account_address, config) 215 | 216 | # Build URL parameters 217 | url_params = urlencode({ 218 | "violator": violator_address, 219 | "vault": vault, 220 | "borrowed_asset": borrowed_asset, 221 | "collateral_vault": collateral_vault, 222 | "collateral_asset": collateral_asset, 223 | "max_repay": max_repay, 224 | "seized_collateral_shares": seized_collateral_shares, 225 | "receiver": receiver 226 | }) 227 | 228 | # Construct the full URL 229 | execution_url = f"{RISK_DASHBOARD_URL}/liquidation/execute?{url_params}" 230 | 231 | 232 | message = ( 233 | ":rotating_light: *Profitable Liquidation Opportunity Detected* :rotating_light:\n\n" 234 | f"*Account*: `{account_address}`, <{spy_link}|Spy Mode>\n" 235 | f"*Vault*: `{vault_address}`" 236 | ) 237 | 238 | formatted_data = ( 239 | f"*Liquidation Opportunity Details:*\n" 240 | f"• Profit: {Web3.from_wei(liquidation_data["profit"], "ether")} ETH\n" 241 | f"• Collateral Vault Address: `{liquidation_data["collateral_address"]}`\n" 242 | f"• Collateral Asset: `{liquidation_data["collateral_asset"]}`\n" 243 | f"• Leftover Borrow Asset: {Web3.from_wei(liquidation_data["leftover_borrow"], 244 | "ether")}\n" 245 | f"• Leftover Borrow Asset in ETH terms (excluding gas): {Web3.from_wei( 246 | liquidation_data["leftover_borrow_in_eth"], "ether")} ETH\n\n" 247 | f"<{execution_url}|Click here to execute this liquidation manually>\n\n" 248 | f"Time of detection: {time.strftime("%Y-%m-%d %H:%M:%S")}\n\n" 249 | f"Network: `{config.CHAIN_NAME}`" 250 | ) 251 | message += f"\n\n{formatted_data}" 252 | 253 | slack_payload = { 254 | "text": message, 255 | "username": "Liquidation Bot", 256 | "icon_emoji": ":robot_face:" 257 | } 258 | requests.post(config.SLACK_URL, json=slack_payload, timeout=10) 259 | 260 | 261 | def post_liquidation_result_on_slack(account_address: str, vault_address: str, 262 | liquidation_data: Optional[Dict[str, Any]], 263 | tx_hash: Optional[str], config: ChainConfig) -> None: 264 | """ 265 | Post a message on Slack. 266 | 267 | Args: 268 | message (str): The main message to post. 269 | liquidation_data (Optional[Dict[str, Any]]): Additional liquidation data to format. 270 | """ 271 | 272 | spy_link = get_spy_link(account_address, config) 273 | 274 | message = ( 275 | ":moneybag: *Liquidation Completed* :moneybag:\n\n" 276 | f"*Liquidated Account*: `{account_address}`, <{spy_link}|Spy Mode>\n" 277 | f"*Vault*: `{vault_address}`" 278 | ) 279 | 280 | tx_url = f"{config.EXPLORER_URL}/tx/{tx_hash}" 281 | 282 | formatted_data = ( 283 | f"*Liquidation Details:*\n" 284 | f"• Profit: {Web3.from_wei(liquidation_data["profit"], "ether")} ETH\n" 285 | f"• Collateral Vault Address: `{liquidation_data["collateral_address"]}`\n" 286 | f"• Collateral Asset: `{liquidation_data["collateral_asset"]}`\n" 287 | f"• Leftover Collateral: {Web3.from_wei(liquidation_data["leftover_borrow"], "ether")} {liquidation_data["collateral_asset"]}\n" 288 | f"• Leftover Collateral in ETH terms: {Web3.from_wei(liquidation_data["leftover_borrow_in_eth"], "ether")} ETH\n\n" 289 | f"• Transaction: <{tx_url}|View Transaction on Explorer>\n\n" 290 | f"Time of liquidation: {time.strftime("%Y-%m-%d %H:%M:%S")}\n\n" 291 | f"Network: `{config.CHAIN_NAME}`" 292 | ) 293 | message += f"\n\n{formatted_data}" 294 | 295 | slack_payload = { 296 | "text": message, 297 | "username": "Liquidation Bot", 298 | "icon_emoji": ":robot_face:" 299 | } 300 | requests.post(config.SLACK_URL, json=slack_payload, timeout=10) 301 | 302 | def post_low_health_account_report(sorted_accounts, config: ChainConfig) -> None: 303 | """ 304 | Post a report of accounts with low health scores to Slack. 305 | 306 | Args: 307 | sorted_accounts (List[Tuple[str, float]]): A list of tuples 308 | containing account addresses and their health scores, 309 | sorted by health score in ascending order. 310 | """ 311 | # Filter accounts below the threshold 312 | low_health_accounts = [ 313 | (address, owner, subaccount, score, value, _, _) for address, owner, subaccount, score, value, _, _ in sorted_accounts 314 | if (score < config.SLACK_REPORT_HEALTH_SCORE and value > (config.BORROW_VALUE_THRESHOLD * 10**18)) or score < 1.0 315 | ] 316 | 317 | total_value = sum(value / 10**18 for _, _, _, _, value, _, _ in sorted_accounts) 318 | 319 | message = ":warning: *Account Health Report* :warning:\n\n" 320 | 321 | if not low_health_accounts: 322 | message += f"No accounts with health score below `{config.SLACK_REPORT_HEALTH_SCORE}` detected.\n" 323 | else: 324 | for i, (address, _, _, score, value, _, _) in enumerate(low_health_accounts, start=1): 325 | 326 | # Format score to 4 decimal places 327 | formatted_score = f"{score:.4f}" 328 | formatted_value = value / 10 ** 18 329 | 330 | formatted_value = f"{formatted_value:,.2f}" 331 | 332 | spy_link = get_spy_link(address, config) 333 | 334 | message += f"{i}. `{address}` Health Score: `{formatted_score}`, Value Borrowed: `${formatted_value}`, <{spy_link}|Spy Mode>\n" 335 | 336 | if i >= 50: 337 | break 338 | 339 | message += f"\nTotal accounts with health score below `{config.SLACK_REPORT_HEALTH_SCORE}` larger than `${config.BORROW_VALUE_THRESHOLD:,.2f}`: `{len(low_health_accounts)}`" 340 | message += f"\nTotal borrow amount in USD: `${total_value:,.2f}`" 341 | 342 | RISK_DASHBOARD_URL = config.RISK_DASHBOARD_URL 343 | message += f"\n<{RISK_DASHBOARD_URL}|Risk Dashboard>" 344 | message += f"\nTime of report: `{time.strftime("%Y-%m-%d %H:%M:%S")}`" 345 | message += f"\nNetwork: `{config.CHAIN_NAME}`" 346 | 347 | slack_payload = { 348 | "text": message, 349 | "username": "Liquidation Bot", 350 | "icon_emoji": ":robot_face:" 351 | } 352 | 353 | try: 354 | response = requests.post(config.SLACK_URL, json=slack_payload, timeout=10) 355 | response.raise_for_status() 356 | print("Low health account report posted to Slack successfully.") 357 | except requests.RequestException as e: 358 | print(f"Failed to post low health account report to Slack: {e}") 359 | 360 | def post_error_notification(message, config: ChainConfig = None) -> None: 361 | """ 362 | Post an error notification to Slack. 363 | 364 | Args: 365 | message (str): The error message to be posted. 366 | """ 367 | 368 | error_message = f":rotating_light: *Error Notification* :rotating_light:\n\n{message}\n\n" 369 | error_message += f"Time: {time.strftime("%Y-%m-%d %H:%M:%S")}\n" 370 | if config: 371 | error_message += f"Network: `{config.CHAIN_NAME}`" 372 | 373 | slack_payload = { 374 | "text": error_message, 375 | "username": "Liquidation Bot", 376 | "icon_emoji": ":warning:" 377 | } 378 | 379 | try: 380 | response = requests.post(config.SLACK_URL, json=slack_payload, timeout=10) 381 | response.raise_for_status() 382 | print("Error notification posted to Slack successfully.") 383 | except requests.RequestException as e: 384 | print("Failed to post error notification to Slack: %s", e) 385 | -------------------------------------------------------------------------------- /application.py: -------------------------------------------------------------------------------- 1 | """ 2 | Start point for running flask app 3 | """ 4 | from app import create_app 5 | 6 | # List of chain IDs to monitor 7 | 8 | application = create_app() 9 | 10 | if __name__ == "__main__": 11 | application.run(host="0.0.0.0", port=8080, debug=True) 12 | -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/41337/run-1721912164.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xcfc8a88739639ecd3677b42253ba18952d700f3b85a504147116e3430ce82556", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0xf165a31dcbb4d2f00cb31532d1d0a27bb80aa49d", 8 | "function": null, 9 | "arguments": [ 10 | "0xfA898de6CcE1715a14F579c316C6cfd7F869655B", 11 | "0x4c0bF4C73f2Cf53259C84694b2F26Adc4916921e", 12 | "0xB8d6D6b01bFe81784BE46e5771eF017Fa3c906d8" 13 | ], 14 | "transaction": { 15 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 16 | "gas": "0x103006", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610e13380380610e1383398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610cf1610122600039600061010a01526000818161017a015261073901526000818160cb015281816105fe015261068c015260006101310152610cf16000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa3660046109aa565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b0316815260200184608001602081019061024791906109ed565b6001600160a01b0316815260200161026560608601604087016109ed565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610a16565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610aaa565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610b5e565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b19189019089016109ed565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610b5e565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b03168152602001600081526020013086606001602081019061047291906109ed565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610b5e565b602002602001018190525060405180608001604052808560200160208101906104f991906109ed565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185600001602081019061053091906109ed565b61054060808801606089016109ed565b60a0880135610554600160c08b0135610b74565b6040516024016105679493929190610b9b565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b17905290528151829060029081106105a8576105a8610b5e565b602002602001018190525060405180608001604052808560600160208101906105d191906109ed565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061067457610674610b5e565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106e09190610bc4565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061072157610721610b5e565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061078f91906109ed565b3060016000196040516024016107a89493929190610b9b565b60408051601f198184030181529190526020810180516001600160e01b031663146ad81760e21b17905290528151829060059081106107e9576107e9610b5e565b6020026020010181905250604051806080016040528085602001602081019061081291906109ed565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a001353060405160240161085f9291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b17905290528151829060069081106108a0576108a0610b5e565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108db908490600401610c29565b600060405180830381600087803b1580156108f557600080fd5b505af1158015610909573d6000803e3d6000fd5b5061091e9250505060408501602086016109ed565b6001600160a01b031661093460208601866109ed565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d61096e60608801604089016109ed565b61097e60a0890160808a016109ed565b8860a001358960c001356040516109989493929190610b9b565b60405180910390a35060019392505050565b6000602082840312156109bc57600080fd5b813567ffffffffffffffff8111156109d357600080fd5b820161014081850312156109e657600080fd5b9392505050565b6000602082840312156109ff57600080fd5b81356001600160a01b03811681146109e657600080fd5b6000808335601e19843603018112610a2d57600080fd5b83018035915067ffffffffffffffff821115610a4857600080fd5b602001915036819003821315610a5d57600080fd5b9250929050565b6000815180845260005b81811015610a8a57602081850181015186830182015201610a6e565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610adb60608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610b56610140840182610a64565b949350505050565b634e487b7160e01b600052603260045260246000fd5b81810381811115610b9557634e487b7160e01b600052601160045260246000fd5b92915050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610c1d57603f19878603018452610c08858351610a64565b94506020938401939190910190600101610bec565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610c1d57868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610ca590870182610a64565b9550506020938401939190910190600101610c5156fea2646970667358221220f92a70823ca79eac09fcc38850177722504ff9a199fa82abaeae742d4f57c80e64736f6c634300081a0033000000000000000000000000fa898de6cce1715a14f579c316c6cfd7f869655b0000000000000000000000004c0bf4c73f2cf53259c84694b2f26adc4916921e000000000000000000000000b8d6d6b01bfe81784be46e5771ef017fa3c906d8", 19 | "nonce": "0x456", 20 | "chainId": "0xa179" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0xc749e", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0xcfc8a88739639ecd3677b42253ba18952d700f3b85a504147116e3430ce82556", 34 | "transactionIndex": "0x0", 35 | "blockHash": "0xdbed06be6e656189c8c4a7c12f905d49b0a936e304aba5e9440e255145a68062", 36 | "blockNumber": "0x136f0b1", 37 | "gasUsed": "0xc749e", 38 | "effectiveGasPrice": "0x3b9aca01", 39 | "blobGasPrice": "0x1", 40 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 41 | "to": null, 42 | "contractAddress": "0xf165a31dcbb4d2f00cb31532d1d0a27bb80aa49d", 43 | "root": "0x0000000000000000000000000000000000000000000000000000000000000000" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1721912164, 50 | "chain": 41337, 51 | "commit": "bda79d3" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/41337/run-latest.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xcfc8a88739639ecd3677b42253ba18952d700f3b85a504147116e3430ce82556", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0xf165a31dcbb4d2f00cb31532d1d0a27bb80aa49d", 8 | "function": null, 9 | "arguments": [ 10 | "0xfA898de6CcE1715a14F579c316C6cfd7F869655B", 11 | "0x4c0bF4C73f2Cf53259C84694b2F26Adc4916921e", 12 | "0xB8d6D6b01bFe81784BE46e5771eF017Fa3c906d8" 13 | ], 14 | "transaction": { 15 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 16 | "gas": "0x103006", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610e13380380610e1383398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610cf1610122600039600061010a01526000818161017a015261073901526000818160cb015281816105fe015261068c015260006101310152610cf16000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa3660046109aa565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b0316815260200184608001602081019061024791906109ed565b6001600160a01b0316815260200161026560608601604087016109ed565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610a16565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610aaa565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610b5e565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b19189019089016109ed565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610b5e565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b03168152602001600081526020013086606001602081019061047291906109ed565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610b5e565b602002602001018190525060405180608001604052808560200160208101906104f991906109ed565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185600001602081019061053091906109ed565b61054060808801606089016109ed565b60a0880135610554600160c08b0135610b74565b6040516024016105679493929190610b9b565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b17905290528151829060029081106105a8576105a8610b5e565b602002602001018190525060405180608001604052808560600160208101906105d191906109ed565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061067457610674610b5e565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106e09190610bc4565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061072157610721610b5e565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061078f91906109ed565b3060016000196040516024016107a89493929190610b9b565b60408051601f198184030181529190526020810180516001600160e01b031663146ad81760e21b17905290528151829060059081106107e9576107e9610b5e565b6020026020010181905250604051806080016040528085602001602081019061081291906109ed565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a001353060405160240161085f9291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b17905290528151829060069081106108a0576108a0610b5e565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108db908490600401610c29565b600060405180830381600087803b1580156108f557600080fd5b505af1158015610909573d6000803e3d6000fd5b5061091e9250505060408501602086016109ed565b6001600160a01b031661093460208601866109ed565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d61096e60608801604089016109ed565b61097e60a0890160808a016109ed565b8860a001358960c001356040516109989493929190610b9b565b60405180910390a35060019392505050565b6000602082840312156109bc57600080fd5b813567ffffffffffffffff8111156109d357600080fd5b820161014081850312156109e657600080fd5b9392505050565b6000602082840312156109ff57600080fd5b81356001600160a01b03811681146109e657600080fd5b6000808335601e19843603018112610a2d57600080fd5b83018035915067ffffffffffffffff821115610a4857600080fd5b602001915036819003821315610a5d57600080fd5b9250929050565b6000815180845260005b81811015610a8a57602081850181015186830182015201610a6e565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610adb60608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610b56610140840182610a64565b949350505050565b634e487b7160e01b600052603260045260246000fd5b81810381811115610b9557634e487b7160e01b600052601160045260246000fd5b92915050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610c1d57603f19878603018452610c08858351610a64565b94506020938401939190910190600101610bec565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610c1d57868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610ca590870182610a64565b9550506020938401939190910190600101610c5156fea2646970667358221220f92a70823ca79eac09fcc38850177722504ff9a199fa82abaeae742d4f57c80e64736f6c634300081a0033000000000000000000000000fa898de6cce1715a14f579c316c6cfd7f869655b0000000000000000000000004c0bf4c73f2cf53259c84694b2f26adc4916921e000000000000000000000000b8d6d6b01bfe81784be46e5771ef017fa3c906d8", 19 | "nonce": "0x456", 20 | "chainId": "0xa179" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0xc749e", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0xcfc8a88739639ecd3677b42253ba18952d700f3b85a504147116e3430ce82556", 34 | "transactionIndex": "0x0", 35 | "blockHash": "0xdbed06be6e656189c8c4a7c12f905d49b0a936e304aba5e9440e255145a68062", 36 | "blockNumber": "0x136f0b1", 37 | "gasUsed": "0xc749e", 38 | "effectiveGasPrice": "0x3b9aca01", 39 | "blobGasPrice": "0x1", 40 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 41 | "to": null, 42 | "contractAddress": "0xf165a31dcbb4d2f00cb31532d1d0a27bb80aa49d", 43 | "root": "0x0000000000000000000000000000000000000000000000000000000000000000" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1721912164, 50 | "chain": 41337, 51 | "commit": "bda79d3" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/42161/run-1722278799.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xd37ba96a568ae371909404ddfe7a9922c09428a18252e59773f63c0527dc7885", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0x22c317403d468585bc6262b9d80b45de1edde5e0", 8 | "function": null, 9 | "arguments": [ 10 | "0xf2FE32e706c849E7b049AC7B75F82E98225969d7", 11 | "0x3f2d64E717A74B564664B2e7B237f3AD42D76D5A", 12 | "0xc860d644A514d0626c8B87ACFA63fE12644Ce3cd" 13 | ], 14 | "transaction": { 15 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 16 | "gas": "0x16ae4c", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610de2380380610de283398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610cc0610122600039600061010a01526000818161017a015261072f01526000818160cb015281816105f40152610682015260006101310152610cc06000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa3660046109a0565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b0316815260200184608001602081019061024791906109e3565b6001600160a01b0316815260200161026560608601604087016109e3565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610a0c565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610aa0565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610b54565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b19189019089016109e3565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610b54565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b03168152602001600081526020013086606001602081019061047291906109e3565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610b54565b602002602001018190525060405180608001604052808560200160208101906104f991906109e3565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185600001602081019061053091906109e3565b61054060808801606089016109e3565b8760a001358860c0013560405160240161055d9493929190610b6a565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b179052905281518290600290811061059e5761059e610b54565b602002602001018190525060405180608001604052808560600160208101906105c791906109e3565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061066a5761066a610b54565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106d69190610b93565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061071757610717610b54565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061078591906109e3565b30600160001960405160240161079e9493929190610b6a565b60408051601f198184030181529190526020810180516001600160e01b031663146ad81760e21b17905290528151829060059081106107df576107df610b54565b6020026020010181905250604051806080016040528085602001602081019061080891906109e3565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a00135306040516024016108559291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b179052905281518290600690811061089657610896610b54565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108d1908490600401610bf8565b600060405180830381600087803b1580156108eb57600080fd5b505af11580156108ff573d6000803e3d6000fd5b506109149250505060408501602086016109e3565b6001600160a01b031661092a60208601866109e3565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d61096460608801604089016109e3565b61097460a0890160808a016109e3565b8860a001358960c0013560405161098e9493929190610b6a565b60405180910390a35060019392505050565b6000602082840312156109b257600080fd5b813567ffffffffffffffff8111156109c957600080fd5b820161014081850312156109dc57600080fd5b9392505050565b6000602082840312156109f557600080fd5b81356001600160a01b03811681146109dc57600080fd5b6000808335601e19843603018112610a2357600080fd5b83018035915067ffffffffffffffff821115610a3e57600080fd5b602001915036819003821315610a5357600080fd5b9250929050565b6000815180845260005b81811015610a8057602081850181015186830182015201610a64565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610ad160608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610b4c610140840182610a5a565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610bec57603f19878603018452610bd7858351610a5a565b94506020938401939190910190600101610bbb565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610bec57868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610c7490870182610a5a565b9550506020938401939190910190600101610c2056fea2646970667358221220a8d5f2af696debe6f1f2e5efd38d0323317e783879c02e8f17aa598ac7ad3a4564736f6c634300081a0033000000000000000000000000f2fe32e706c849e7b049ac7b75f82e98225969d70000000000000000000000003f2d64e717a74b564664b2e7b237f3ad42d76d5a000000000000000000000000c860d644a514d0626c8b87acfa63fe12644ce3cd", 19 | "nonce": "0x0", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x10bf48", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0xd37ba96a568ae371909404ddfe7a9922c09428a18252e59773f63c0527dc7885", 34 | "transactionIndex": "0x1", 35 | "blockHash": "0x789c307df96780db0f93951bf5fe8034442e0725c5de7604e0dec4e1e064a7a2", 36 | "blockNumber": "0xe25f689", 37 | "gasUsed": "0x10bf48", 38 | "effectiveGasPrice": "0x989680", 39 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 40 | "to": null, 41 | "contractAddress": "0x22c317403d468585bc6262b9d80b45de1edde5e0", 42 | "gasUsedForL1": "0x473f9", 43 | "l1BlockNumber": "0x1377e9a" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1722278799, 50 | "chain": 42161, 51 | "commit": "d5548cb" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/42161/run-1722849403.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x3a740148665f38f48c2894dbb7e45100e9142b7a654a0c0a968159db9ceb0dda", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0x956810cc3e5098e48cdb9409f48819c1eafaaa69", 8 | "function": null, 9 | "arguments": [ 10 | "0xf11A61f808526B45ba797777Ab7B1DB5CC65DE0F", 11 | "0x8aAA2CaEca30AB50d48EB0EA71b83c49A2f49791", 12 | "0xE45Ee4046bD755330D555dFe4aDA7839a3eEb926" 13 | ], 14 | "transaction": { 15 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 16 | "gas": "0x11a6e8", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610de2380380610de283398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610cc0610122600039600061010a01526000818161017a015261072f01526000818160cb015281816105f40152610682015260006101310152610cc06000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa3660046109a0565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b0316815260200184608001602081019061024791906109e3565b6001600160a01b0316815260200161026560608601604087016109e3565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610a0c565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610aa0565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610b54565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b19189019089016109e3565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610b54565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b03168152602001600081526020013086606001602081019061047291906109e3565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610b54565b602002602001018190525060405180608001604052808560200160208101906104f991906109e3565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185600001602081019061053091906109e3565b61054060808801606089016109e3565b8760a001358860c0013560405160240161055d9493929190610b6a565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b179052905281518290600290811061059e5761059e610b54565b602002602001018190525060405180608001604052808560600160208101906105c791906109e3565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061066a5761066a610b54565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106d69190610b93565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061071757610717610b54565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061078591906109e3565b30600160001960405160240161079e9493929190610b6a565b60408051601f198184030181529190526020810180516001600160e01b031663146ad81760e21b17905290528151829060059081106107df576107df610b54565b6020026020010181905250604051806080016040528085602001602081019061080891906109e3565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a00135306040516024016108559291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b179052905281518290600690811061089657610896610b54565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108d1908490600401610bf8565b600060405180830381600087803b1580156108eb57600080fd5b505af11580156108ff573d6000803e3d6000fd5b506109149250505060408501602086016109e3565b6001600160a01b031661092a60208601866109e3565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d61096460608801604089016109e3565b61097460a0890160808a016109e3565b8860a001358960c0013560405161098e9493929190610b6a565b60405180910390a35060019392505050565b6000602082840312156109b257600080fd5b813567ffffffffffffffff8111156109c957600080fd5b820161014081850312156109dc57600080fd5b9392505050565b6000602082840312156109f557600080fd5b81356001600160a01b03811681146109dc57600080fd5b6000808335601e19843603018112610a2357600080fd5b83018035915067ffffffffffffffff821115610a3e57600080fd5b602001915036819003821315610a5357600080fd5b9250929050565b6000815180845260005b81811015610a8057602081850181015186830182015201610a64565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610ad160608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610b4c610140840182610a5a565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610bec57603f19878603018452610bd7858351610a5a565b94506020938401939190910190600101610bbb565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610bec57868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610c7490870182610a5a565b9550506020938401939190910190600101610c2056fea2646970667358221220a8d5f2af696debe6f1f2e5efd38d0323317e783879c02e8f17aa598ac7ad3a4564736f6c634300081a0033000000000000000000000000f11a61f808526b45ba797777ab7b1db5cc65de0f0000000000000000000000008aaa2caeca30ab50d48eb0ea71b83c49a2f49791000000000000000000000000e45ee4046bd755330d555dfe4ada7839a3eeb926", 19 | "nonce": "0x1", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x15eeed", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0x3a740148665f38f48c2894dbb7e45100e9142b7a654a0c0a968159db9ceb0dda", 34 | "transactionIndex": "0x6", 35 | "blockHash": "0xbfe0a3bf3215a0702c42df82c642378cdbe852f306358f6e8951d2ed6571758c", 36 | "blockNumber": "0xe48a4b3", 37 | "gasUsed": "0xd324f", 38 | "effectiveGasPrice": "0x8a04850", 39 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 40 | "to": null, 41 | "contractAddress": "0x956810cc3e5098e48cdb9409f48819c1eafaaa69", 42 | "gasUsedForL1": "0xe700", 43 | "l1BlockNumber": "0x1383763" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1722849403, 50 | "chain": 42161, 51 | "commit": "8b6128a" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/42161/run-1722943201.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x0b0543b22b834f632d0f4678a932fd1f4ead2345b800916c42282ee858648cd5", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0xfcab30d2559e9984b341d290f2aeb60d74abcf40", 8 | "function": null, 9 | "arguments": [ 10 | "0xf11A61f808526B45ba797777Ab7B1DB5CC65DE0F", 11 | "0x8aAA2CaEca30AB50d48EB0EA71b83c49A2f49791", 12 | "0xE45Ee4046bD755330D555dFe4aDA7839a3eEb926" 13 | ], 14 | "transaction": { 15 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 16 | "gas": "0x140cdf", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610ea3380380610ea383398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610d81610122600039600061010a01526000818161017a015261072f01526000818160cb015281816105f40152610682015260006101310152610d816000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa366004610a61565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b031681526020018460800160208101906102479190610aa4565b6001600160a01b031681526020016102656060860160408701610aa4565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610acd565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610b61565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610c15565b60209081029190910101526040805160088082526101208201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b1918901908901610aa4565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610c15565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b0316815260200160008152602001308660600160208101906104729190610aa4565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610c15565b602002602001018190525060405180608001604052808560200160208101906104f99190610aa4565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560000160208101906105309190610aa4565b6105406080880160608901610aa4565b8760a001358860c0013560405160240161055d9493929190610c2b565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b179052905281518290600290811061059e5761059e610c15565b602002602001018190525060405180608001604052808560600160208101906105c79190610aa4565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061066a5761066a610c15565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106d69190610c54565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061071757610717610c15565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b03168152602001600081526020018560200160208101906107859190610aa4565b30600160001960405160240161079e9493929190610c2b565b60408051601f198184030181529190526020810180516001600160e01b031663146ad81760e21b17905290528151829060059081106107df576107df610c15565b602002602001018190525060405180608001604052808560400160208101906108089190610aa4565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061083f9190610aa4565b6040516001600160a01b03909116602482015260a0870135604482015260640160408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b17905290528151829060069081106108a0576108a0610c15565b602002602001018190525060405180608001604052808560200160208101906108c99190610aa4565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a00135306040516024016109169291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b179052905281518290600790811061095757610957610c15565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a490610992908490600401610cb9565b600060405180830381600087803b1580156109ac57600080fd5b505af11580156109c0573d6000803e3d6000fd5b506109d5925050506040850160208601610aa4565b6001600160a01b03166109eb6020860186610aa4565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d610a256060880160408901610aa4565b610a3560a0890160808a01610aa4565b8860a001358960c00135604051610a4f9493929190610c2b565b60405180910390a35060019392505050565b600060208284031215610a7357600080fd5b813567ffffffffffffffff811115610a8a57600080fd5b82016101408185031215610a9d57600080fd5b9392505050565b600060208284031215610ab657600080fd5b81356001600160a01b0381168114610a9d57600080fd5b6000808335601e19843603018112610ae457600080fd5b83018035915067ffffffffffffffff821115610aff57600080fd5b602001915036819003821315610b1457600080fd5b9250929050565b6000815180845260005b81811015610b4157602081850181015186830182015201610b25565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610b9260608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610c0d610140840182610b1b565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610cad57603f19878603018452610c98858351610b1b565b94506020938401939190910190600101610c7c565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610cad57868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610d3590870182610b1b565b9550506020938401939190910190600101610ce156fea2646970667358221220394202cf126c90a20f2d95ee7fefa13e2869991d696a5cc196255be7c0eab0f264736f6c634300081a0033000000000000000000000000f11a61f808526b45ba797777ab7b1db5cc65de0f0000000000000000000000008aaa2caeca30ab50d48eb0ea71b83c49a2f49791000000000000000000000000e45ee4046bd755330d555dfe4ada7839a3eeb926", 19 | "nonce": "0x2", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0xf0171", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0x0b0543b22b834f632d0f4678a932fd1f4ead2345b800916c42282ee858648cd5", 34 | "transactionIndex": "0x1", 35 | "blockHash": "0x9612578858fb02a3178ce4c6be7a49c338d315ca9d6da5055852e04dd4978988", 36 | "blockNumber": "0xe4e534d", 37 | "gasUsed": "0xf0171", 38 | "effectiveGasPrice": "0x989680", 39 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 40 | "to": null, 41 | "contractAddress": "0xfcab30d2559e9984b341d290f2aeb60d74abcf40", 42 | "gasUsedForL1": "0x21311", 43 | "l1BlockNumber": "0x13855c4" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1722943201, 50 | "chain": 42161, 51 | "commit": "ea47789" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/42161/run-1722944027.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xf3b6e4de42a61d4c2adeddb9424afbb34005c720ed35ece2c589bd5c6110763b", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0xd20c2892e9cf9248c2561581f9f037b80d79a69d", 8 | "function": null, 9 | "arguments": [ 10 | "0xf11A61f808526B45ba797777Ab7B1DB5CC65DE0F", 11 | "0x8aAA2CaEca30AB50d48EB0EA71b83c49A2f49791", 12 | "0xE45Ee4046bD755330D555dFe4aDA7839a3eEb926" 13 | ], 14 | "transaction": { 15 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 16 | "gas": "0x1382f3", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b50604051610dd5380380610dd583398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e051610cba61011b600039600061010a0152600061017a01526000818160cb015281816106080152610696015260006101310152610cba6000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639e3f7432116100665780639e3f743214610153578063a55f08d314610162578063b0643a2f14610175578063b2e45fdc1461019c578063c4d88adf146101bf57600080fd5b806335b96ca41461009857806335c1d701146100c6578063512dd8ba146101055780638da5cb5b1461012c575b600080fd5b6100b3702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100bd565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6100b36406292dcc6d60db1b81565b6100b3682ab734b9bbb0b82b1960b91b81565b6100ed7f000000000000000000000000000000000000000000000000000000000000000081565b6101af6101aa3660046109c3565b6101d2565b60405190151581526020016100bd565b6100b368556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b60608152602001906001900390816101ec5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b031681526020018460800160208101906102479190610a06565b6001600160a01b031681526020016102656060860160408701610a06565b6001600160a01b03168152600060208201819052604082018190526060820152608001610296610120860186610a2f565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102dc9190602401610ac3565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061031957610319610b77565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161033d575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103b1918901908901610a06565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061040d5761040d610b77565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b0316815260200160008152602001308660600160208101906104729190610a06565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104d0576104d0610b77565b602002602001018190525060405180608001604052808560200160208101906104f99190610a06565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560000160208101906105309190610a06565b6105406080880160608901610a06565b6040516001600160a01b0392831660248201529116604482015260a0870135606482015260c0870135608482015260a40160408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b17905290528151829060029081106105b2576105b2610b77565b602002602001018190525060405180608001604052808560600160208101906105db9190610a06565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061067e5761067e610b77565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106ea9190610b8d565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061072b5761072b610b77565b602002602001018190525060405180608001604052808560400160208101906107549190610a06565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185602001602081019061078b9190610a06565b6040516001600160a01b03909116602482015260a0870135604482015260640160408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b17905290528151829060059081106107ec576107ec610b77565b602002602001018190525060405180608001604052808560200160208101906108159190610a06565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a00135306040516024016108629291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b17905290528151829060069081106108a3576108a3610b77565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108de908490600401610bf2565b600060405180830381600087803b1580156108f857600080fd5b505af115801561090c573d6000803e3d6000fd5b50610921925050506040850160208601610a06565b6001600160a01b03166109376020860186610a06565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d6109716060880160408901610a06565b61098160a0890160808a01610a06565b604080516001600160a01b03938416815292909116602083015260a08901359082015260c0880135606082015260800160405180910390a35060019392505050565b6000602082840312156109d557600080fd5b813567ffffffffffffffff8111156109ec57600080fd5b820161014081850312156109ff57600080fd5b9392505050565b600060208284031215610a1857600080fd5b81356001600160a01b03811681146109ff57600080fd5b6000808335601e19843603018112610a4657600080fd5b83018035915067ffffffffffffffff821115610a6157600080fd5b602001915036819003821315610a7657600080fd5b9250929050565b6000815180845260005b81811015610aa357602081850181015186830182015201610a87565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610af460608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610b6f610140840182610a7d565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610be657603f19878603018452610bd1858351610a7d565b94506020938401939190910190600101610bb5565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610be657868503603f19018452815180516001600160a01b0390811687526020808301519091169087015260408082015190870152606090810151608091870182905290610c6e90870182610a7d565b9550506020938401939190910190600101610c1a56fea26469706673582212209eb11d55443fbb06b6d5eeb30fba0313de62b9e62ca73f6a7606755c7c61a62464736f6c634300081a0033000000000000000000000000f11a61f808526b45ba797777ab7b1db5cc65de0f0000000000000000000000008aaa2caeca30ab50d48eb0ea71b83c49a2f49791000000000000000000000000e45ee4046bd755330d555dfe4ada7839a3eeb926", 19 | "nonce": "0x3", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x107891", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0xf3b6e4de42a61d4c2adeddb9424afbb34005c720ed35ece2c589bd5c6110763b", 34 | "transactionIndex": "0x4", 35 | "blockHash": "0xe0d6e3efb9fae1acb87d2c9bb050a89744a09ddc62ae40e59c3a7ee2142f0d4a", 36 | "blockNumber": "0xe4e6037", 37 | "gasUsed": "0xe94ca", 38 | "effectiveGasPrice": "0x989680", 39 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 40 | "to": null, 41 | "contractAddress": "0xd20c2892e9cf9248c2561581f9f037b80d79a69d", 42 | "gasUsedForL1": "0x24d80", 43 | "l1BlockNumber": "0x1385609" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1722944027, 50 | "chain": 42161, 51 | "commit": "ea47789" 52 | } -------------------------------------------------------------------------------- /broadcast/DeployLiquidator.sol/42161/run-1722945806.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xf5c3f126ea29d92560403ca5786befce51a9faf6c630fe2a58a90b4fd5340fec", 5 | "transactionType": "CREATE", 6 | "contractName": "Liquidator", 7 | "contractAddress": "0xe95e012038d78c3582adfba4691beba3e62a4c65", 8 | "function": null, 9 | "arguments": [ 10 | "0xf11A61f808526B45ba797777Ab7B1DB5CC65DE0F", 11 | "0x8aAA2CaEca30AB50d48EB0EA71b83c49A2f49791", 12 | "0xE45Ee4046bD755330D555dFe4aDA7839a3eEb926" 13 | ], 14 | "transaction": { 15 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 16 | "gas": "0x183f4d", 17 | "value": "0x0", 18 | "input": "0x61010060405234801561001157600080fd5b5060405161117738038061117783398101604081905261003091610092565b336080526001600160a01b0392831660a081905291831660c05290911660e0819052600080546001600160a01b03199081169093179055600180549092161790556100d5565b80516001600160a01b038116811461008d57600080fd5b919050565b6000806000606084860312156100a757600080fd5b6100b084610076565b92506100be60208501610076565b91506100cc60408501610076565b90509250925092565b60805160a05160c05160e05161105c61011b60003960006101150152600061018501526000818160d60152818161061201526106a00152600061013c015261105c6000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063a55f08d311610066578063a55f08d31461016d578063b0643a2f14610180578063b2e45fdc146101a7578063c37be663146101ca578063c4d88adf146101dd57600080fd5b806335b96ca4146100a357806335c1d701146100d1578063512dd8ba146101105780638da5cb5b146101375780639e3f74321461015e575b600080fd5b6100be702ab734b9bbb0b820baba37a937baba32b960791b81565b6040519081526020015b60405180910390f35b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100c8565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6100be6406292dcc6d60db1b81565b6100be682ab734b9bbb0b82b1960b91b81565b6100f87f000000000000000000000000000000000000000000000000000000000000000081565b6101ba6101b5366004610d3c565b6101f0565b60405190151581526020016100c8565b6101ba6101d8366004610d3c565b6109b7565b6100be68556e6973776170563360b81b81565b604080516001808252818301909252600091829190816020015b606081526020019060019003908161020a5790505090506040518061012001604052806406292dcc6d60db1b81526020016000815260200160006001600160a01b031681526020018460800160208101906102659190610d7f565b6001600160a01b031681526020016102836060860160408701610d7f565b6001600160a01b031681526000602082018190526040820181905260608201526080016102b4610120860186610da8565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040516102fa9190602401610e3c565b60408051601f198184030181529190526020810180516001600160e01b03166351915cd760e01b1790528151829060009061033757610337610ef0565b60209081029190910101526040805160078082526101008201909252600091816020015b604080516080810182526000808252602080830182905292820152606080820152825260001990920191018161035b575050604080516080810182526001546001600160a01b03168152600060208083018290528284019190915292935091606083019130916103cf918901908901610d7f565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b17905290528151829060009061042b5761042b610ef0565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b0316815260200160008152602001308660600160208101906104909190610d7f565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b17905290528151829060019081106104ee576104ee610ef0565b602002602001018190525060405180608001604052808560200160208101906105179190610d7f565b6001600160a01b03168152602001306001600160a01b031681526020016000815260200185600001602081019061054e9190610d7f565b61055e6080880160608901610d7f565b8760a001358860c0013560405160240161057b9493929190610f06565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b17905290528151829060029081106105bc576105bc610ef0565b602002602001018190525060405180608001604052808560600160208101906105e59190610d7f565b6001600160a01b039081168252306020830181905260006040808501919091525160e089013560248201527f00000000000000000000000000000000000000000000000000000000000000009092166044830152606482015260609091019060840160408051601f198184030181529190526020810180516001600160e01b0316632d182be560e21b179052905281518290600390811061068857610688610ef0565b602002602001018190525060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200160008152602001836040516024016106f49190610f2f565b60408051601f198184030181529190526020810180516001600160e01b0316631592ca1b60e31b179052905281518290600490811061073557610735610ef0565b6020026020010181905250604051806080016040528085604001602081019061075e9190610d7f565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560200160208101906107959190610d7f565b6040516001600160a01b03909116602482015260a0870135604482015260640160408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b17905290528151829060059081106107f6576107f6610ef0565b6020026020010181905250604051806080016040528085602001602081019061081f9190610d7f565b6001600160a01b03168152602001306001600160a01b03168152602001600081526020018560a001353060405160240161086c9291909182526001600160a01b0316602082015260400190565b60408051601f198184030181529190526020810180516001600160e01b031663acb7081560e01b17905290528151829060069081106108ad576108ad610ef0565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a4906108e8908490600401610f94565b600060405180830381600087803b15801561090257600080fd5b505af1158015610916573d6000803e3d6000fd5b5061092b925050506040850160208601610d7f565b6001600160a01b03166109416020860186610d7f565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d61097b6060880160408901610d7f565b61098b60a0890160808a01610d7f565b8860a001358960c001356040516109a59493929190610f06565b60405180910390a35060019392505050565b60408051600380825260808201909252600091829190816020015b60408051608081018252600080825260208083018290529282015260608082015282526000199092019101816109d2575050604080516080810182526001546001600160a01b0316815260006020808301829052828401919091529293509160608301913091610a46918801908801610d7f565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b03166330da145b60e21b179052905281518290600090610aa257610aa2610ef0565b60200260200101819052506040518060800160405280600160009054906101000a90046001600160a01b03166001600160a01b0316815260200160006001600160a01b031681526020016000815260200130856060016020810190610b079190610d7f565b6040516001600160a01b0392831660248201529116604482015260640160408051601f198184030181529190526020810180516001600160e01b0316636a27f72d60e11b1790529052815182906001908110610b6557610b65610ef0565b60200260200101819052506040518060800160405280846020016020810190610b8e9190610d7f565b6001600160a01b03168152602001306001600160a01b0316815260200160008152602001846000016020810190610bc59190610d7f565b610bd56080870160608801610d7f565b8660a001358760c00135604051602401610bf29493929190610f06565b60408051601f198184030181529190526020810180516001600160e01b031663304d095d60e21b1790529052815182906002908110610c3357610c33610ef0565b602090810291909101015260015460405163305ab9e960e21b81526001600160a01b039091169063c16ae7a490610c6e908490600401610f94565b600060405180830381600087803b158015610c8857600080fd5b505af1158015610c9c573d6000803e3d6000fd5b50610cb1925050506040840160208501610d7f565b6001600160a01b0316610cc76020850185610d7f565b6001600160a01b03167f64f7c2c46814e079964a1934953e50adc025dc52cdbeb7d8e478e9fb9bfd2c2d610d016060870160408801610d7f565b610d1160a0880160808901610d7f565b8760a001358860c00135604051610d2b9493929190610f06565b60405180910390a350600192915050565b600060208284031215610d4e57600080fd5b813567ffffffffffffffff811115610d6557600080fd5b82016101408185031215610d7857600080fd5b9392505050565b600060208284031215610d9157600080fd5b81356001600160a01b0381168114610d7857600080fd5b6000808335601e19843603018112610dbf57600080fd5b83018035915067ffffffffffffffff821115610dda57600080fd5b602001915036819003821315610def57600080fd5b9250929050565b6000815180845260005b81811015610e1c57602081850181015186830182015201610e00565b506000602082860101526020601f19601f83011685010191505092915050565b60208152815160208201526020820151604082015260006040830151610e6d60608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083015261010083015161012080840152610ee8610140840182610df6565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610f8857603f19878603018452610f73858351610df6565b94506020938401939190910190600101610f57565b50929695505050505050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015610f8857868503603f19018452815180516001600160a01b039081168752602080830151909116908701526040808201519087015260609081015160809187018290529061101090870182610df6565b9550506020938401939190910190600101610fbc56fea264697066735822122070fed032132792f705487ac7e1c74ffccbc92045bc31d0fa36475678e4e8197e64736f6c634300081a0033000000000000000000000000f11a61f808526b45ba797777ab7b1db5cc65de0f0000000000000000000000008aaa2caeca30ab50d48eb0ea71b83c49a2f49791000000000000000000000000e45ee4046bd755330d555dfe4ada7839a3eeb926", 19 | "nonce": "0x4", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x144d71", 30 | "logs": [], 31 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 32 | "type": "0x2", 33 | "transactionHash": "0xf5c3f126ea29d92560403ca5786befce51a9faf6c630fe2a58a90b4fd5340fec", 34 | "transactionIndex": "0x2", 35 | "blockHash": "0x4078b6a8202e7fc66e5a3daafa32a49212f345d0fc72d7c1c0bfeaf847bd6f01", 36 | "blockNumber": "0xe4e7bd5", 37 | "gasUsed": "0x11c618", 38 | "effectiveGasPrice": "0xb8f790", 39 | "from": "0xec5df17559e6e4172b82fcd8df84d425748f6dd2", 40 | "to": null, 41 | "contractAddress": "0xe95e012038d78c3582adfba4691beba3e62a4c65", 42 | "gasUsedForL1": "0x26df5", 43 | "l1BlockNumber": "0x138569d" 44 | } 45 | ], 46 | "libraries": [], 47 | "pending": [], 48 | "returns": {}, 49 | "timestamp": 1722945806, 50 | "chain": 42161, 51 | "commit": "ea47789" 52 | } -------------------------------------------------------------------------------- /broadcast/LiquidationSetupWithVaultCreated.sol/42161/run-1722942413.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 8 | "function": "borrow(uint256,address)", 9 | "arguments": [ 10 | "500000", 11 | "0x37B5559c63821820EaAC5FF770e5C421d6A2676B" 12 | ], 13 | "transaction": { 14 | "from": "0x37b5559c63821820eaac5ff770e5c421d6a2676b", 15 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 16 | "gas": "0x60a31", 17 | "value": "0x0", 18 | "input": "0x4b3fd148000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b", 19 | "nonce": "0x4", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0xb2a5f", 30 | "logs": [ 31 | { 32 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 33 | "topics": [ 34 | "0x6e9738e5aa38fe1517adbb480351ec386ece82947737b18badbcad1e911133ec", 35 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 36 | "0x37b5559c63821820eaac5ff770e5c421d6a26700000000000000000000000000", 37 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 38 | ], 39 | "data": "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b4b3fd14800000000000000000000000000000000000000000000000000000000", 40 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 41 | "blockNumber": "0xe4e4719", 42 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 43 | "transactionIndex": "0x4", 44 | "logIndex": "0x6", 45 | "removed": false 46 | }, 47 | { 48 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 49 | "topics": [ 50 | "0xcbc04eca7e9da35cb1393a6135a199ca52e450d5e9251cbd99f7847d33a36750", 51 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 52 | ], 53 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 54 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 55 | "blockNumber": "0xe4e4719", 56 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 57 | "transactionIndex": "0x4", 58 | "logIndex": "0x7", 59 | "removed": false 60 | }, 61 | { 62 | "address": "0xe486a6141116e47a8b6a85c2bd191225af941b6a", 63 | "topics": [ 64 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 65 | "0x0000000000000000000000000000000000000000000000000000000000000000", 66 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 67 | ], 68 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 69 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 70 | "blockNumber": "0xe4e4719", 71 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 72 | "transactionIndex": "0x4", 73 | "logIndex": "0x8", 74 | "removed": false 75 | }, 76 | { 77 | "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", 78 | "topics": [ 79 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 80 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 81 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 82 | ], 83 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 84 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 85 | "blockNumber": "0xe4e4719", 86 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 87 | "transactionIndex": "0x4", 88 | "logIndex": "0x9", 89 | "removed": false 90 | }, 91 | { 92 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 93 | "topics": [ 94 | "0x889a4d4628b31342e420737e2aeb45387087570710d26239aa8a5f13d3e829d4", 95 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b", 96 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 97 | ], 98 | "data": "0x", 99 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 100 | "blockNumber": "0xe4e4719", 101 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 102 | "transactionIndex": "0x4", 103 | "logIndex": "0xa", 104 | "removed": false 105 | }, 106 | { 107 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 108 | "topics": [ 109 | "0x80b61abbfc5f73cfe5cf93cec97a69ed20643dc6c6f1833b05a1560aa164e24c" 110 | ], 111 | "data": "0x00000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000033b2e3c9fd0803ce800000000000000000000000000000000000000000000000000000029ea18b4ac2bce960000000000000000000000000000000000000000000000000000000066b203cd", 112 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 113 | "blockNumber": "0xe4e4719", 114 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 115 | "transactionIndex": "0x4", 116 | "logIndex": "0xb", 117 | "removed": false 118 | }, 119 | { 120 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 121 | "topics": [ 122 | "0xaea973cfb51ea8ca328767d72f105b5b9d2360c65f5ac4110a2c4470434471c9", 123 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 124 | ], 125 | "data": "0x", 126 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 127 | "blockNumber": "0xe4e4719", 128 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 129 | "transactionIndex": "0x4", 130 | "logIndex": "0xc", 131 | "removed": false 132 | } 133 | ], 134 | "logsBloom": "0x0000000000000000000000000000000084000008000000000000000000022000000000000000000000000000000000000000000100000000000000000000000000000001000000000000001800000000000002000000000000400000000000000000000002000000000000000000080008000000000000800000001000000000000000000000000000000000100000000000000000000000084000000000000000000000000000000000004000001100000000000002002200000800000080000000a002000004000000000010000100000000000000000000001000000020000000200000000000800000400000200000000000000000000020000002020000", 135 | "type": "0x2", 136 | "transactionHash": "0x73080f956c454648ea885d9ab0999c87f868a5a6bb352d78228a405b1584b667", 137 | "transactionIndex": "0x4", 138 | "blockHash": "0x552cb7362ae83f99d5a67b81fae4b9013a61da6bd0ddaafb9885c1f8532921a0", 139 | "blockNumber": "0xe4e4719", 140 | "gasUsed": "0x44611", 141 | "effectiveGasPrice": "0xb628d0", 142 | "from": "0x37b5559c63821820eaac5ff770e5c421d6a2676b", 143 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 144 | "contractAddress": null, 145 | "gasUsedForL1": "0x1fff", 146 | "l1BlockNumber": "0x1385583" 147 | } 148 | ], 149 | "libraries": [], 150 | "pending": [], 151 | "returns": {}, 152 | "timestamp": 1722942413, 153 | "chain": 42161, 154 | "commit": "ea47789" 155 | } -------------------------------------------------------------------------------- /broadcast/LiquidationSetupWithVaultCreated.sol/42161/run-1722945742.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 8 | "function": "deposit(uint256,address)", 9 | "arguments": [ 10 | "1000000", 11 | "0xd20C2892e9cf9248c2561581F9f037b80d79a69d" 12 | ], 13 | "transaction": { 14 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 15 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 16 | "gas": "0x3c87c", 17 | "value": "0x0", 18 | "input": "0x6e553f6500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000d20c2892e9cf9248c2561581f9f037b80d79a69d", 19 | "nonce": "0x6e", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x354cea", 30 | "logs": [ 31 | { 32 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 33 | "topics": [ 34 | "0x6e9738e5aa38fe1517adbb480351ec386ece82947737b18badbcad1e911133ec", 35 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 36 | "0xe32bfe0922d38007b47e08c8b89b1ada8e4d0300000000000000000000000000", 37 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 38 | ], 39 | "data": "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb6e553f6500000000000000000000000000000000000000000000000000000000", 40 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 41 | "blockNumber": "0xe4e7abf", 42 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 43 | "transactionIndex": "0x15", 44 | "logIndex": "0x3c", 45 | "removed": false 46 | }, 47 | { 48 | "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", 49 | "topics": [ 50 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 51 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 52 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 53 | ], 54 | "data": "0x00000000000000000000000000000000000000000000000000000000000f4240", 55 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 56 | "blockNumber": "0xe4e7abf", 57 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 58 | "transactionIndex": "0x15", 59 | "logIndex": "0x3d", 60 | "removed": false 61 | }, 62 | { 63 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 64 | "topics": [ 65 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 66 | "0x0000000000000000000000000000000000000000000000000000000000000000", 67 | "0x000000000000000000000000d20c2892e9cf9248c2561581f9f037b80d79a69d" 68 | ], 69 | "data": "0x00000000000000000000000000000000000000000000000000000000000f423d", 70 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 71 | "blockNumber": "0xe4e7abf", 72 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 73 | "transactionIndex": "0x15", 74 | "logIndex": "0x3e", 75 | "removed": false 76 | }, 77 | { 78 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 79 | "topics": [ 80 | "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", 81 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 82 | "0x000000000000000000000000d20c2892e9cf9248c2561581f9f037b80d79a69d" 83 | ], 84 | "data": "0x00000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000f423d", 85 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 86 | "blockNumber": "0xe4e7abf", 87 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 88 | "transactionIndex": "0x15", 89 | "logIndex": "0x3f", 90 | "removed": false 91 | }, 92 | { 93 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 94 | "topics": [ 95 | "0x80b61abbfc5f73cfe5cf93cec97a69ed20643dc6c6f1833b05a1560aa164e24c" 96 | ], 97 | "data": "0x00000000000000000000000000000000000000000000000000000000001e847d000000000000000000000000000000000000000000000000000000000007a1260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016e3600000000000000000000000000000000000000000033b305c5e5da8cdd9e0d84b00000000000000000000000000000000000000000000000014f518b6b67530160000000000000000000000000000000000000000000000000000000066b210c6", 98 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 99 | "blockNumber": "0xe4e7abf", 100 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 101 | "transactionIndex": "0x15", 102 | "logIndex": "0x40", 103 | "removed": false 104 | }, 105 | { 106 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 107 | "topics": [ 108 | "0xaea973cfb51ea8ca328767d72f105b5b9d2360c65f5ac4110a2c4470434471c9", 109 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 110 | ], 111 | "data": "0x", 112 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 113 | "blockNumber": "0xe4e7abf", 114 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 115 | "transactionIndex": "0x15", 116 | "logIndex": "0x41", 117 | "removed": false 118 | } 119 | ], 120 | "logsBloom": "0x00000000000000000000000000000000000000080000000000000000000220802000000400000000000000000000000000000001000000000000008000000000000000400000000000000008000000000000000000000000004000000000000000000000020000000000000000000800280000000004000000000010000000000000040000000000000000001000000000000000000400000000000000000000000000000000000000000000000011000000000000020002000008000000800000002002000004000000000010000000000000000008000000001000000020020000200000000000000000000000200000000000000000000000000002020000", 121 | "type": "0x2", 122 | "transactionHash": "0xf47093c9a994180db717091db372d629a9de71e04ab204c6c557002ef63d2bee", 123 | "transactionIndex": "0x15", 124 | "blockHash": "0xac72d7855cd6f71aa84663d90b247eba4233e91758acd0d1bae6df2ca55117fe", 125 | "blockNumber": "0xe4e7abf", 126 | "gasUsed": "0x29ce1", 127 | "effectiveGasPrice": "0xa5d138", 128 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 129 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 130 | "contractAddress": null, 131 | "gasUsedForL1": "0x37a3", 132 | "l1BlockNumber": "0x1385697" 133 | } 134 | ], 135 | "libraries": [], 136 | "pending": [], 137 | "returns": {}, 138 | "timestamp": 1722945742, 139 | "chain": 42161, 140 | "commit": "ea47789" 141 | } -------------------------------------------------------------------------------- /broadcast/LiquidationSetupWithVaultCreated.sol/42161/run-1722945872.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 8 | "function": "deposit(uint256,address)", 9 | "arguments": [ 10 | "1000000", 11 | "0xe95E012038D78C3582aDFBa4691BeBA3E62A4c65" 12 | ], 13 | "transaction": { 14 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 15 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 16 | "gas": "0x3bd43", 17 | "value": "0x0", 18 | "input": "0x6e553f6500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65", 19 | "nonce": "0x6f", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | }, 25 | { 26 | "hash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 27 | "transactionType": "CALL", 28 | "contractName": null, 29 | "contractAddress": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 30 | "function": "deposit(uint256,address)", 31 | "arguments": [ 32 | "1000000000000000000", 33 | "0xe95E012038D78C3582aDFBa4691BeBA3E62A4c65" 34 | ], 35 | "transaction": { 36 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 37 | "to": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 38 | "gas": "0x35487", 39 | "value": "0x0", 40 | "input": "0x6e553f650000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65", 41 | "nonce": "0x70", 42 | "chainId": "0xa4b1" 43 | }, 44 | "additionalContracts": [], 45 | "isFixedGasLimit": false 46 | } 47 | ], 48 | "receipts": [ 49 | { 50 | "status": "0x1", 51 | "cumulativeGasUsed": "0x16e34f", 52 | "logs": [ 53 | { 54 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 55 | "topics": [ 56 | "0x6e9738e5aa38fe1517adbb480351ec386ece82947737b18badbcad1e911133ec", 57 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 58 | "0xe32bfe0922d38007b47e08c8b89b1ada8e4d0300000000000000000000000000", 59 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 60 | ], 61 | "data": "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb6e553f6500000000000000000000000000000000000000000000000000000000", 62 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 63 | "blockNumber": "0xe4e7cb9", 64 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 65 | "transactionIndex": "0x9", 66 | "logIndex": "0x14", 67 | "removed": false 68 | }, 69 | { 70 | "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", 71 | "topics": [ 72 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 73 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 74 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 75 | ], 76 | "data": "0x00000000000000000000000000000000000000000000000000000000000f4240", 77 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 78 | "blockNumber": "0xe4e7cb9", 79 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 80 | "transactionIndex": "0x9", 81 | "logIndex": "0x15", 82 | "removed": false 83 | }, 84 | { 85 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 86 | "topics": [ 87 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 88 | "0x0000000000000000000000000000000000000000000000000000000000000000", 89 | "0x000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65" 90 | ], 91 | "data": "0x00000000000000000000000000000000000000000000000000000000000f423d", 92 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 93 | "blockNumber": "0xe4e7cb9", 94 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 95 | "transactionIndex": "0x9", 96 | "logIndex": "0x16", 97 | "removed": false 98 | }, 99 | { 100 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 101 | "topics": [ 102 | "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", 103 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 104 | "0x000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65" 105 | ], 106 | "data": "0x00000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000f423d", 107 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 108 | "blockNumber": "0xe4e7cb9", 109 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 110 | "transactionIndex": "0x9", 111 | "logIndex": "0x17", 112 | "removed": false 113 | }, 114 | { 115 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 116 | "topics": [ 117 | "0x80b61abbfc5f73cfe5cf93cec97a69ed20643dc6c6f1833b05a1560aa164e24c" 118 | ], 119 | "data": "0x00000000000000000000000000000000000000000000000000000000002dc6ba000000000000000000000000000000000000000000000000000000000007a126000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002625a00000000000000000000000000000000000000000033b306702db45e56690a48b0000000000000000000000000000000000000000000000000df8bc0eb73ade400000000000000000000000000000000000000000000000000000000066b21148", 120 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 121 | "blockNumber": "0xe4e7cb9", 122 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 123 | "transactionIndex": "0x9", 124 | "logIndex": "0x18", 125 | "removed": false 126 | }, 127 | { 128 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 129 | "topics": [ 130 | "0xaea973cfb51ea8ca328767d72f105b5b9d2360c65f5ac4110a2c4470434471c9", 131 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 132 | ], 133 | "data": "0x", 134 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 135 | "blockNumber": "0xe4e7cb9", 136 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 137 | "transactionIndex": "0x9", 138 | "logIndex": "0x19", 139 | "removed": false 140 | } 141 | ], 142 | "logsBloom": "0x00000000000000000000000000000000000000080000000000000000000220800000000400010000000000000000000000000001000000000000000000000000000000400000000000000008000000000000000000000000004000000000000000000000020000000000000000000800280000000004000000000010000000000000080000000000000000001000000000000000000400000000000000000000000000000000000000000000000011000000000000020002040008000000800000002002000004000000000010000000000000000008000000001000000020020000200000000000000000000000200000000000000000000000000002020000", 143 | "type": "0x2", 144 | "transactionHash": "0xe391b76887b29af5478aaa5b7e32aebee91fb224b2c1e8ced48ea84f27189442", 145 | "transactionIndex": "0x9", 146 | "blockHash": "0x33a804ffd1ec89659b03e893334506116282e7a3c1bb7b5b3729a7e5673f4fca", 147 | "blockNumber": "0xe4e7cb9", 148 | "gasUsed": "0x2927c", 149 | "effectiveGasPrice": "0xb9ce68", 150 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 151 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 152 | "contractAddress": null, 153 | "gasUsedForL1": "0x31a7", 154 | "l1BlockNumber": "0x13856a2" 155 | }, 156 | { 157 | "status": "0x1", 158 | "cumulativeGasUsed": "0x24575", 159 | "logs": [ 160 | { 161 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 162 | "topics": [ 163 | "0x6e9738e5aa38fe1517adbb480351ec386ece82947737b18badbcad1e911133ec", 164 | "0x000000000000000000000000f67f9b1042a7f419c2c0259c983fb1f75f981fd4", 165 | "0xe32bfe0922d38007b47e08c8b89b1ada8e4d0300000000000000000000000000", 166 | "0x000000000000000000000000f67f9b1042a7f419c2c0259c983fb1f75f981fd4" 167 | ], 168 | "data": "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb6e553f6500000000000000000000000000000000000000000000000000000000", 169 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 170 | "blockNumber": "0xe4e7cbc", 171 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 172 | "transactionIndex": "0x1", 173 | "logIndex": "0x0", 174 | "removed": false 175 | }, 176 | { 177 | "address": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", 178 | "topics": [ 179 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 180 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 181 | "0x000000000000000000000000f67f9b1042a7f419c2c0259c983fb1f75f981fd4" 182 | ], 183 | "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", 184 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 185 | "blockNumber": "0xe4e7cbc", 186 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 187 | "transactionIndex": "0x1", 188 | "logIndex": "0x1", 189 | "removed": false 190 | }, 191 | { 192 | "address": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 193 | "topics": [ 194 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 195 | "0x0000000000000000000000000000000000000000000000000000000000000000", 196 | "0x000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65" 197 | ], 198 | "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", 199 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 200 | "blockNumber": "0xe4e7cbc", 201 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 202 | "transactionIndex": "0x1", 203 | "logIndex": "0x2", 204 | "removed": false 205 | }, 206 | { 207 | "address": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 208 | "topics": [ 209 | "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", 210 | "0x000000000000000000000000e32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 211 | "0x000000000000000000000000e95e012038d78c3582adfba4691beba3e62a4c65" 212 | ], 213 | "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000de0b6b3a7640000", 214 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 215 | "blockNumber": "0xe4e7cbc", 216 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 217 | "transactionIndex": "0x1", 218 | "logIndex": "0x3", 219 | "removed": false 220 | }, 221 | { 222 | "address": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 223 | "topics": [ 224 | "0x80b61abbfc5f73cfe5cf93cec97a69ed20643dc6c6f1833b05a1560aa164e24c" 225 | ], 226 | "data": "0x00000000000000000000000000000000000000000000000029a2241af62c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029a2241af62c00000000000000000000000000000000000000000000033b2e3c9fd0803ce800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066b21149", 227 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 228 | "blockNumber": "0xe4e7cbc", 229 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 230 | "transactionIndex": "0x1", 231 | "logIndex": "0x4", 232 | "removed": false 233 | }, 234 | { 235 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 236 | "topics": [ 237 | "0xaea973cfb51ea8ca328767d72f105b5b9d2360c65f5ac4110a2c4470434471c9", 238 | "0x000000000000000000000000f67f9b1042a7f419c2c0259c983fb1f75f981fd4" 239 | ], 240 | "data": "0x", 241 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 242 | "blockNumber": "0xe4e7cbc", 243 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 244 | "transactionIndex": "0x1", 245 | "logIndex": "0x5", 246 | "removed": false 247 | } 248 | ], 249 | "logsBloom": "0x00000000000000000008000000000000000000040000000800000000000020800000000400010000000000000000000000000000000000000000000000000000000000400000000001000008000000400000000000000000004000000000000000000000020000000000000000000800280000000004000000000010000000000000080000000000000000001000000000000008000400000000000000000000000000000000000000000000000001000000000000020000040008000000800000000002000004000000000010000000200000000008000000001000000020020000000020000004000000000000000000000000000000000000000000020000", 250 | "type": "0x2", 251 | "transactionHash": "0xab52d02fce6fbc0f74e325ec2cd6468a57364dee04a38f146d3c3497544610a9", 252 | "transactionIndex": "0x1", 253 | "blockHash": "0xb1a8fcafea4c404f5912835b31b13b9c6547059af1d1eb1b488623f733be8b65", 254 | "blockNumber": "0xe4e7cbc", 255 | "gasUsed": "0x24575", 256 | "effectiveGasPrice": "0xbbf918", 257 | "from": "0xe32bfe0922d38007b47e08c8b89b1ada8e4d03fb", 258 | "to": "0xf67f9b1042a7f419c2c0259c983fb1f75f981fd4", 259 | "contractAddress": null, 260 | "gasUsedForL1": "0x3114", 261 | "l1BlockNumber": "0x13856a2" 262 | } 263 | ], 264 | "libraries": [], 265 | "pending": [], 266 | "returns": {}, 267 | "timestamp": 1722945872, 268 | "chain": 42161, 269 | "commit": "ea47789" 270 | } -------------------------------------------------------------------------------- /broadcast/LiquidationSetupWithVaultCreated.sol/42161/run-latest.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 8 | "function": "borrow(uint256,address)", 9 | "arguments": [ 10 | "500000", 11 | "0x37B5559c63821820EaAC5FF770e5C421d6A2676B" 12 | ], 13 | "transaction": { 14 | "from": "0x37b5559c63821820eaac5ff770e5c421d6a2676b", 15 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 16 | "gas": "0x55743", 17 | "value": "0x0", 18 | "input": "0x4b3fd148000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b", 19 | "nonce": "0x3d", 20 | "chainId": "0xa4b1" 21 | }, 22 | "additionalContracts": [], 23 | "isFixedGasLimit": false 24 | } 25 | ], 26 | "receipts": [ 27 | { 28 | "status": "0x1", 29 | "cumulativeGasUsed": "0x9f6c0", 30 | "logs": [ 31 | { 32 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 33 | "topics": [ 34 | "0x6e9738e5aa38fe1517adbb480351ec386ece82947737b18badbcad1e911133ec", 35 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 36 | "0x37b5559c63821820eaac5ff770e5c421d6a26700000000000000000000000000", 37 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 38 | ], 39 | "data": "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b4b3fd14800000000000000000000000000000000000000000000000000000000", 40 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 41 | "blockNumber": "0xeb9d3fd", 42 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 43 | "transactionIndex": "0x2", 44 | "logIndex": "0xe", 45 | "removed": false 46 | }, 47 | { 48 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 49 | "topics": [ 50 | "0xcbc04eca7e9da35cb1393a6135a199ca52e450d5e9251cbd99f7847d33a36750", 51 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 52 | ], 53 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 54 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 55 | "blockNumber": "0xeb9d3fd", 56 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 57 | "transactionIndex": "0x2", 58 | "logIndex": "0xf", 59 | "removed": false 60 | }, 61 | { 62 | "address": "0xe486a6141116e47a8b6a85c2bd191225af941b6a", 63 | "topics": [ 64 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 65 | "0x0000000000000000000000000000000000000000000000000000000000000000", 66 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 67 | ], 68 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 69 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 70 | "blockNumber": "0xeb9d3fd", 71 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 72 | "transactionIndex": "0x2", 73 | "logIndex": "0x10", 74 | "removed": false 75 | }, 76 | { 77 | "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", 78 | "topics": [ 79 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 80 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff", 81 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b" 82 | ], 83 | "data": "0x000000000000000000000000000000000000000000000000000000000007a120", 84 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 85 | "blockNumber": "0xeb9d3fd", 86 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 87 | "transactionIndex": "0x2", 88 | "logIndex": "0x11", 89 | "removed": false 90 | }, 91 | { 92 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 93 | "topics": [ 94 | "0x889a4d4628b31342e420737e2aeb45387087570710d26239aa8a5f13d3e829d4", 95 | "0x00000000000000000000000037b5559c63821820eaac5ff770e5c421d6a2676b", 96 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 97 | ], 98 | "data": "0x", 99 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 100 | "blockNumber": "0xeb9d3fd", 101 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 102 | "transactionIndex": "0x2", 103 | "logIndex": "0x12", 104 | "removed": false 105 | }, 106 | { 107 | "address": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 108 | "topics": [ 109 | "0x80b61abbfc5f73cfe5cf93cec97a69ed20643dc6c6f1833b05a1560aa164e24c" 110 | ], 111 | "data": "0x0000000000000000000000000000000000000000000000000000000001f7a38e00000000000000000000000000000000000000000000000000000000001e853500000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000001d86bba0000000000000000000000000000000000000000033b7a799d3d966b2e435314000000000000000000000000000000000000000000000000051648cb3350e5940000000000000000000000000000000000000000000000000000000066cd0d18", 112 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 113 | "blockNumber": "0xeb9d3fd", 114 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 115 | "transactionIndex": "0x2", 116 | "logIndex": "0x13", 117 | "removed": false 118 | }, 119 | { 120 | "address": "0xe45ee4046bd755330d555dfe4ada7839a3eeb926", 121 | "topics": [ 122 | "0xaea973cfb51ea8ca328767d72f105b5b9d2360c65f5ac4110a2c4470434471c9", 123 | "0x000000000000000000000000577e289f663a4e29c231135c09d6a0713ce7aaff" 124 | ], 125 | "data": "0x", 126 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 127 | "blockNumber": "0xeb9d3fd", 128 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 129 | "transactionIndex": "0x2", 130 | "logIndex": "0x14", 131 | "removed": false 132 | } 133 | ], 134 | "logsBloom": "0x0000000000000000000000000000000084000008000000000000000000022000000000000000000000000000000000000000000100000000000000000000000000000001000000000000001800000000000002000000000000400000000000000000000002000000000000000000080008000000000000800000001000000000000000000000000000000000100000000000000000000000084000000000000000000000000000000000004000001100000000000002002200000800000080000000a002000004000000000010000100000000000000000000001000000020000000200000000000800000400000200000000000000000000020000002020000", 135 | "type": "0x2", 136 | "transactionHash": "0x421790c31dda8588e3e3299fce067d4c08d032fefb5facf5b7e9128fff1f0e88", 137 | "transactionIndex": "0x2", 138 | "blockHash": "0x31761f338f274798485822df0d69365643685513b573feb2ca22fe9c9e7a3e9e", 139 | "blockNumber": "0xeb9d3fd", 140 | "gasUsed": "0x3cd55", 141 | "effectiveGasPrice": "0x989680", 142 | "from": "0x37b5559c63821820eaac5ff770e5c421d6a2676b", 143 | "to": "0x577e289f663a4e29c231135c09d6a0713ce7aaff", 144 | "contractAddress": null, 145 | "gasUsedForL1": "0x1543", 146 | "l1BlockNumber": "0x13a9336" 147 | } 148 | ], 149 | "libraries": [], 150 | "pending": [], 151 | "returns": {}, 152 | "timestamp": 1724714271, 153 | "chain": 42161, 154 | "commit": "a2339cb" 155 | } -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | # Comments are provided throughout this file to help you get started. 2 | # If you need more help, visit the Docker Compose reference guide at 3 | # https://docs.docker.com/go/compose-spec-reference/ 4 | 5 | # Here the instructions define your application as a service called "server". 6 | # This service is built from the Dockerfile in the current directory. 7 | # You can add other services your application may depend on here, such as a 8 | # database or a cache. For examples, see the Awesome Compose repository: 9 | # https://github.com/docker/awesome-compose 10 | services: 11 | server: 12 | build: 13 | context: . 14 | ports: 15 | - 8080:8080 16 | env_file: 17 | - .env 18 | 19 | # The commented out section below is an example of how to define a PostgreSQL 20 | # database that your application can use. `depends_on` tells Docker Compose to 21 | # start the database before your application. The `db-data` volume persists the 22 | # database data between container restarts. The `db-password` secret is used 23 | # to set the database password. You must create `db/password.txt` and add 24 | # a password of your choosing to it before running `docker compose up`. 25 | # depends_on: 26 | # db: 27 | # condition: service_healthy 28 | # db: 29 | # image: postgres 30 | # restart: always 31 | # user: postgres 32 | # secrets: 33 | # - db-password 34 | # volumes: 35 | # - db-data:/var/lib/postgresql/data 36 | # environment: 37 | # - POSTGRES_DB=example 38 | # - POSTGRES_PASSWORD_FILE=/run/secrets/db-password 39 | # expose: 40 | # - 5432 41 | # healthcheck: 42 | # test: [ "CMD", "pg_isready" ] 43 | # interval: 10s 44 | # timeout: 5s 45 | # retries: 5 46 | # volumes: 47 | # db-data: 48 | # secrets: 49 | # db-password: 50 | # file: db/password.txt 51 | 52 | -------------------------------------------------------------------------------- /contracts/DeployLiquidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.24; 4 | 5 | import {Script} from "forge-std/Script.sol"; 6 | import {Test} from "forge-std/Test.sol"; 7 | 8 | import {Liquidator} from "./Liquidator.sol"; 9 | 10 | import "forge-std/console2.sol"; 11 | 12 | contract DeployLiquidator is Script { 13 | function run() public { 14 | uint256 deployerPrivateKey = vm.envUint("LIQUIDATOR_PRIVATE_KEY"); 15 | 16 | address swapperAddress = 0x2Bba09866b6F1025258542478C39720A09B728bF; 17 | address swapVerifierAddress = 0xae26485ACDDeFd486Fe9ad7C2b34169d360737c7; 18 | address evcAddress = 0x0C9a3dd6b8F28529d72d7f9cE918D493519EE383; 19 | address pyth = 0x4305FB66699C3B2702D4d05CF36551390A4c69C6; 20 | 21 | address deployer = vm.addr(deployerPrivateKey); 22 | vm.startBroadcast(deployerPrivateKey); 23 | 24 | uint256 beforeGas = gasleft(); 25 | console2.log("Gas before: ", beforeGas); 26 | console2.log("Gas price: ", tx.gasprice); 27 | 28 | Liquidator liquidator = new Liquidator(deployer, swapperAddress, swapVerifierAddress, evcAddress, pyth); 29 | uint256 afterGas = gasleft(); 30 | console2.log("Gas after: ", afterGas); 31 | 32 | console2.log("Total gas cost: ", (beforeGas - afterGas) * tx.gasprice); 33 | 34 | console2.log("Liquidator deployed at: ", address(liquidator)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/IPyth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | 5 | /// @title Consume prices from the Pyth Network (https://pyth.network/). 6 | /// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely. 7 | /// @author Pyth Data Association 8 | interface IPyth { 9 | /// @notice Update price feeds with given update messages. 10 | /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling 11 | /// `getUpdateFee` with the length of the `updateData` array. 12 | /// Prices will be updated if they are more recent than the current stored prices. 13 | /// The call will succeed even if the update is not the most recent. 14 | /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid. 15 | /// @param updateData Array of price update data. 16 | function updatePriceFeeds(bytes[] calldata updateData) external payable; 17 | 18 | 19 | /// @notice Returns the required fee to update an array of price updates. 20 | /// @param updateData Array of price update data. 21 | /// @return feeAmount The required fee in Wei. 22 | function getUpdateFee( 23 | bytes[] calldata updateData 24 | ) external view returns (uint feeAmount); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/ISwapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity >=0.8.0; 4 | 5 | /// @title ISwapper 6 | /// @custom:security-contact security@euler.xyz 7 | /// @author Euler Labs (https://www.eulerlabs.com/) 8 | /// @notice Interface of helper contracts, which handle swapping of assets for Euler Vault Kit 9 | interface ISwapper { 10 | /// @title SwapParams 11 | /// @notice This struct holds all the parameters needed to carry out a swap 12 | struct SwapParams { 13 | // An id of the swap handler to use 14 | bytes32 handler; 15 | // Swap mode to execute 16 | // 0 - exact input swap 17 | // 1 - exect output swap 18 | // 2 - exact output swap and repay, targeting a debt amount of an account 19 | uint256 mode; 20 | // An EVC compatible account address, used e.g. as receiver of repay in swap and repay mode 21 | address account; 22 | // Sold asset 23 | address tokenIn; 24 | // Bought asset 25 | address tokenOut; 26 | // Vault to which the unused input in exact output swap will be deposited back 27 | address vaultIn; 28 | // An EVC compatible account address, to which the unused input in exact output swap will be deposited back 29 | address accountIn; 30 | // In swapping modes (0 and 1) - address of the intended recipient of the bought tokens 31 | // In swap and repay mode (2) - address of the liability vault of the account, where to repay debt 32 | // Note that if the swap uses off-chain encoded payload, the receiver might be ignored. The user 33 | // should verify the assets are in fact in the receiver address after the swap 34 | address receiver; 35 | // In exact input mode (0) - ignored 36 | // In exact output mode (1) - amount of `tokenOut` to buy 37 | // In swap and repay mode (2) - amount of debt the account should have after swap and repay. 38 | // To repay all debt without leaving any dust, set this to zero. 39 | uint256 amountOut; 40 | // Auxiliary payload for swap providers. For GenericHandler it's an abi encoded tuple: target contract address 41 | // and call data 42 | bytes data; 43 | } 44 | 45 | /// @notice Execute a swap (and possibly repay or deposit) according to the SwapParams configuration 46 | /// @param params Configuration of the swap 47 | function swap(SwapParams calldata params) external; 48 | 49 | /// @notice Use the contract's token balance to repay debt of the account in a lending vault 50 | /// @param token The asset that is borrowed 51 | /// @param vault The lending vault where the debt is tracked 52 | /// @param repayAmount Amount of debt to repay 53 | /// @param account Receiver of the repay 54 | /// @dev If contract's balance is lower than requested repay amount, repay only the balance 55 | function repay(address token, address vault, uint256 repayAmount, address account) external; 56 | 57 | /// @notice Use the contract's token balance to repay debt of the account in a lending vault 58 | /// and deposit any remaining balance for the account in that same vault 59 | /// @param token The asset that is borrowed 60 | /// @param vault The lending vault where the debt is tracked 61 | /// @param repayAmount Amount of debt to repay 62 | /// @param account Receiver of the repay 63 | /// @dev If contract's balance is lower than requested repay amount, repay only the balance 64 | function repayAndDeposit(address token, address vault, uint256 repayAmount, address account) external; 65 | 66 | /// @notice Use all of the contract's token balance to execute a deposit for an account 67 | /// @param token Asset to deposit 68 | /// @param vault Vault to deposit the token to 69 | /// @param amountMin A minimum amount of tokens to deposit. If unavailable, the operation is a no-op 70 | /// @param account Receiver of the repay 71 | /// @dev Use amountMin to ignore dust 72 | function deposit(address token, address vault, uint256 amountMin, address account) external; 73 | 74 | /// @notice Transfer all tokens held by the contract 75 | /// @param token Token to transfer 76 | /// @param amountMin Minimum amount of tokens to transfer. If unavailable, the operation is a no-op 77 | /// @param to Address to send the tokens to 78 | function sweep(address token, uint256 amountMin, address to) external; 79 | 80 | /// @notice Call multiple functions of the contract 81 | /// @param calls Array of encoded payloads 82 | /// @dev Calls itself with regular external calls 83 | function multicall(bytes[] memory calls) external; 84 | } 85 | -------------------------------------------------------------------------------- /contracts/IVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.19; 4 | 5 | /// @title IVault 6 | /// @custom:security-contact security@euler.xyz 7 | /// @author Euler Labs (https://www.eulerlabs.com/) 8 | /// @notice This interface defines the methods for the Vault for the purpose of integration with the Ethereum Vault 9 | /// Connector. 10 | interface IVault { 11 | /// @notice Disables a controller (this vault) for the authenticated account. 12 | /// @dev A controller is a vault that has been chosen for an account to have special control over account’s 13 | /// balances in the enabled collaterals vaults. User calls this function in order for the vault to disable itself 14 | /// for the account if the conditions are met (i.e. user has repaid debt in full). If the conditions are not met, 15 | /// the function reverts. 16 | function disableController() external; 17 | 18 | /// @notice Checks the status of an account. 19 | /// @dev This function must only deliberately revert if the account status is invalid. If this function reverts due 20 | /// to any other reason, it may render the account unusable with possibly no way to recover funds. 21 | /// @param account The address of the account to be checked. 22 | /// @param collaterals The array of enabled collateral addresses to be considered for the account status check. 23 | /// @return magicValue Must return the bytes4 magic value 0xb168c58f (which is a selector of this function) when 24 | /// account status is valid, or revert otherwise. 25 | function checkAccountStatus(address account, address[] calldata collaterals) external returns (bytes4 magicValue); 26 | 27 | /// @notice Checks the status of the vault. 28 | /// @dev This function must only deliberately revert if the vault status is invalid. If this function reverts due to 29 | /// any other reason, it may render some accounts unusable with possibly no way to recover funds. 30 | /// @return magicValue Must return the bytes4 magic value 0x4b3d1223 (which is a selector of this function) when 31 | /// account status is valid, or revert otherwise. 32 | function checkVaultStatus() external returns (bytes4 magicValue); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/Liquidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | import {ISwapper} from "./ISwapper.sol"; 5 | import {SwapVerifier} from "./SwapVerifier.sol"; 6 | import {IEVC} from "./IEVC.sol"; 7 | 8 | import {IERC4626, IERC20} from "./IEVault.sol"; 9 | import {IEVault, IRiskManager, IBorrowing, ILiquidation} from "./IEVault.sol"; 10 | 11 | import {IPyth} from "./IPyth.sol"; 12 | 13 | contract Liquidator { 14 | address public immutable owner; 15 | address public immutable swapperAddress; 16 | address public immutable swapVerifierAddress; 17 | address public immutable evcAddress; 18 | 19 | address public immutable PYTH; 20 | 21 | ISwapper swapper; 22 | IEVC evc; 23 | 24 | error Unauthorized(); 25 | error LessThanExpectedCollateralReceived(); 26 | 27 | constructor(address _owner, address _swapperAddress, address _swapVerifierAddress, address _evcAddress, address _pythAddress) { 28 | owner = _owner; 29 | swapperAddress = _swapperAddress; 30 | swapVerifierAddress = _swapVerifierAddress; 31 | evcAddress = _evcAddress; 32 | PYTH = _pythAddress; 33 | 34 | swapper = ISwapper(_swapperAddress); 35 | evc = IEVC(_evcAddress); 36 | } 37 | 38 | modifier onlyOwner() { 39 | require(msg.sender == owner, "Unauthorized"); 40 | _; 41 | } 42 | 43 | struct LiquidationParams { 44 | address violatorAddress; 45 | address vault; 46 | address borrowedAsset; 47 | address collateralVault; 48 | address collateralAsset; 49 | uint256 repayAmount; 50 | uint256 seizedCollateralAmount; 51 | address receiver; 52 | } 53 | 54 | event Liquidation( 55 | address indexed violatorAddress, 56 | address indexed vault, 57 | address repaidBorrowAsset, 58 | address seizedCollateralAsset, 59 | uint256 amountRepaid, 60 | uint256 amountCollaterallSeized 61 | ); 62 | 63 | function liquidateSingleCollateral(LiquidationParams calldata params, bytes[] calldata swapperData) external returns (bool success) { 64 | bytes[] memory multicallItems = new bytes[](swapperData.length + 2); 65 | 66 | for (uint256 i = 0; i < swapperData.length; i++){ 67 | multicallItems[i] = swapperData[i]; 68 | } 69 | 70 | // Use swapper contract to repay borrowed asset 71 | multicallItems[swapperData.length] = 72 | // abi.encodeCall(ISwapper.repay, (params.borrowedAsset, params.vault, params.repayAmount, address(this))); 73 | abi.encodeCall(ISwapper.repay, (params.borrowedAsset, params.vault, type(uint256).max, address(this))); 74 | 75 | // Sweep any dust left in the swapper contract 76 | multicallItems[swapperData.length + 1] = abi.encodeCall(ISwapper.sweep, (params.borrowedAsset, 0, params.receiver)); 77 | 78 | IEVC.BatchItem[] memory batchItems = new IEVC.BatchItem[](7); 79 | 80 | // Step 1: enable controller 81 | batchItems[0] = IEVC.BatchItem({ 82 | onBehalfOfAccount: address(0), 83 | targetContract: address(evc), 84 | value: 0, 85 | data: abi.encodeCall(IEVC.enableController, (address(this), params.vault)) 86 | }); 87 | 88 | // Step 2: enable collateral 89 | batchItems[1] = IEVC.BatchItem({ 90 | onBehalfOfAccount: address(0), 91 | targetContract: address(evc), 92 | value: 0, 93 | data: abi.encodeCall(IEVC.enableCollateral, (address(this), params.collateralVault)) 94 | }); 95 | 96 | (uint256 maxRepay, uint256 maxYield) = ILiquidation(params.vault).checkLiquidation(address(this), params.violatorAddress, params.collateralVault); 97 | 98 | // Step 3: Liquidate account in violation 99 | batchItems[2] = IEVC.BatchItem({ 100 | onBehalfOfAccount: address(this), 101 | targetContract: params.vault, 102 | value: 0, 103 | data: abi.encodeCall( 104 | ILiquidation.liquidate, 105 | (params.violatorAddress, params.collateralVault, maxRepay, 0) // TODO: adjust minimum collateral 106 | ) 107 | }); 108 | 109 | // Step 4: Withdraw collateral from vault to swapper 110 | batchItems[3] = IEVC.BatchItem({ 111 | onBehalfOfAccount: address(this), 112 | targetContract: params.collateralVault, 113 | value: 0, 114 | data: abi.encodeCall(IERC4626.redeem, (maxYield, swapperAddress, address(this))) 115 | }); 116 | 117 | // Step 5: Swap collateral for borrowed asset, repay, and sweep overswapped borrow asset 118 | batchItems[4] = IEVC.BatchItem({ 119 | onBehalfOfAccount: address(this), 120 | targetContract: swapperAddress, 121 | value: 0, 122 | data: abi.encodeCall(ISwapper.multicall, multicallItems) 123 | }); 124 | 125 | batchItems[5] = IEVC.BatchItem({ 126 | onBehalfOfAccount: address(this), 127 | targetContract: params.vault, 128 | value: 0, 129 | data: abi.encodeCall(IRiskManager.disableController, ()) 130 | }); 131 | 132 | batchItems[6] = IEVC.BatchItem({ 133 | onBehalfOfAccount: address(0), 134 | targetContract: address(evc), 135 | value: 0, 136 | data: abi.encodeCall(IEVC.disableCollateral, (address(this), params.collateralVault)) 137 | }); 138 | 139 | 140 | // Submit batch to EVC 141 | evc.batch(batchItems); 142 | 143 | emit Liquidation( 144 | params.violatorAddress, 145 | params.vault, 146 | params.borrowedAsset, 147 | params.collateralAsset, 148 | params.repayAmount, 149 | params.seizedCollateralAmount 150 | ); 151 | 152 | if (IERC20(params.collateralVault).balanceOf(address(this)) > 0) { 153 | IERC20(params.collateralVault).transfer(params.receiver, IERC20(params.collateralVault).balanceOf(address(this))); 154 | } 155 | 156 | return true; 157 | } 158 | 159 | function liquidateSingleCollateralWithPythOracle(LiquidationParams calldata params, bytes[] calldata swapperData, bytes[] calldata pythUpdateData) external payable returns (bool success) { 160 | bytes[] memory multicallItems = new bytes[](swapperData.length + 2); 161 | 162 | for (uint256 i = 0; i < swapperData.length; i++){ 163 | multicallItems[i] = swapperData[i]; 164 | } 165 | 166 | // Use swapper contract to repay borrowed asset 167 | multicallItems[swapperData.length] = 168 | // abi.encodeCall(ISwapper.repay, (params.borrowedAsset, params.vault, params.repayAmount, address(this))); 169 | abi.encodeCall(ISwapper.repay, (params.borrowedAsset, params.vault, type(uint256).max, address(this))); 170 | 171 | // Sweep any dust left in the swapper contract 172 | multicallItems[swapperData.length + 1] = abi.encodeCall(ISwapper.sweep, (params.borrowedAsset, 0, params.receiver)); 173 | 174 | IEVC.BatchItem[] memory batchItems = new IEVC.BatchItem[](7); 175 | 176 | // Update Pyth oracles 177 | IPyth(PYTH).updatePriceFeeds{value: msg.value}(pythUpdateData); 178 | 179 | // Step 1: enable controller 180 | batchItems[0] = IEVC.BatchItem({ 181 | onBehalfOfAccount: address(0), 182 | targetContract: address(evc), 183 | value: 0, 184 | data: abi.encodeCall(IEVC.enableController, (address(this), params.vault)) 185 | }); 186 | 187 | (uint256 maxRepay, uint256 maxYield) = ILiquidation(params.vault).checkLiquidation(address(this), params.violatorAddress, params.collateralVault); 188 | 189 | // Step 2: enable collateral 190 | batchItems[1] = IEVC.BatchItem({ 191 | onBehalfOfAccount: address(0), 192 | targetContract: address(evc), 193 | value: 0, 194 | data: abi.encodeCall(IEVC.enableCollateral, (address(this), params.collateralVault)) 195 | }); 196 | 197 | // Step 3: Liquidate account in violation 198 | batchItems[2] = IEVC.BatchItem({ 199 | onBehalfOfAccount: address(this), 200 | targetContract: params.vault, 201 | value: 0, 202 | data: abi.encodeCall( 203 | ILiquidation.liquidate, 204 | (params.violatorAddress, params.collateralVault, maxRepay, 0) // TODO: adjust minimum collateral 205 | ) 206 | }); 207 | 208 | // Step 4: Withdraw collateral from vault to swapper 209 | batchItems[3] = IEVC.BatchItem({ 210 | onBehalfOfAccount: address(this), 211 | targetContract: params.collateralVault, 212 | value: 0, 213 | data: abi.encodeCall(IERC4626.redeem, (maxYield, swapperAddress, address(this))) 214 | }); 215 | 216 | // Step 5: Swap collateral for borrowed asset, repay, and sweep overswapped borrow asset 217 | batchItems[4] = IEVC.BatchItem({ 218 | onBehalfOfAccount: address(this), 219 | targetContract: swapperAddress, 220 | value: 0, 221 | data: abi.encodeCall(ISwapper.multicall, multicallItems) 222 | }); 223 | 224 | batchItems[5] = IEVC.BatchItem({ 225 | onBehalfOfAccount: address(this), 226 | targetContract: params.vault, 227 | value: 0, 228 | data: abi.encodeCall(IRiskManager.disableController, ()) 229 | }); 230 | 231 | batchItems[6] = IEVC.BatchItem({ 232 | onBehalfOfAccount: address(0), 233 | targetContract: address(evc), 234 | value: 0, 235 | data: abi.encodeCall(IEVC.disableCollateral, (address(this), params.collateralVault)) 236 | }); 237 | 238 | 239 | // Submit batch to EVC 240 | evc.batch(batchItems); 241 | 242 | emit Liquidation( 243 | params.violatorAddress, 244 | params.vault, 245 | params.borrowedAsset, 246 | params.collateralAsset, 247 | params.repayAmount, 248 | params.seizedCollateralAmount 249 | ); 250 | 251 | if (IERC20(params.collateralVault).balanceOf(address(this)) > 0) { 252 | IERC20(params.collateralVault).transfer(params.receiver, IERC20(params.collateralVault).balanceOf(address(this))); 253 | } 254 | 255 | return true; 256 | } 257 | 258 | 259 | // 2nd liquidation option: seize liquidated position without swapping/repaying, can only be done with existing collateral position 260 | // TODO: implement this as an operator so debt can be seized directly by whitelisted liquidators 261 | function liquidateFromExistingCollateralPosition(LiquidationParams calldata params) 262 | external 263 | returns (bool success) 264 | { 265 | IEVC.BatchItem[] memory batchItems = new IEVC.BatchItem[](3); 266 | 267 | batchItems[0] = IEVC.BatchItem({ 268 | onBehalfOfAccount: address(0), 269 | targetContract: evcAddress, 270 | value: 0, 271 | data: abi.encodeCall(IEVC.enableController, (address(this), params.vault)) 272 | }); 273 | 274 | batchItems[1] = IEVC.BatchItem({ 275 | onBehalfOfAccount: address(0), 276 | targetContract: evcAddress, 277 | value: 0, 278 | data: abi.encodeCall(IEVC.enableCollateral, (address(this), params.collateralVault)) 279 | }); 280 | 281 | batchItems[2] = IEVC.BatchItem({ 282 | onBehalfOfAccount: address(this), 283 | targetContract: params.vault, 284 | value: 0, 285 | data: abi.encodeCall( 286 | ILiquidation.liquidate, 287 | (params.violatorAddress, params.collateralVault, params.repayAmount, params.seizedCollateralAmount) 288 | ) 289 | }); 290 | 291 | // batchItems[3] = IEVC.BatchItem({ 292 | // onBehalfOfAccount: address(this), 293 | // targetContract: params.vault, 294 | // value: 0, 295 | // data: abi.encodeCall( 296 | // IBorrowing.pullDebt(amount, from) 297 | // (params.expectedRemainingCollateral, params.receiver, address(this)) 298 | // ) 299 | // }); 300 | 301 | evc.batch(batchItems); 302 | 303 | emit Liquidation( 304 | params.violatorAddress, 305 | params.vault, 306 | params.borrowedAsset, 307 | params.collateralAsset, 308 | params.repayAmount, 309 | params.seizedCollateralAmount 310 | ); 311 | 312 | return true; 313 | } 314 | 315 | function simulatePythUpdateAndGetAccountStatus(bytes[] calldata pythUpdateData, uint256 pythUpdateFee, address vaultAddress, address accountAddress) external payable returns (uint256 collateralValue, uint256 liabilityValue) { 316 | IEVC.BatchItem[] memory batchItems = new IEVC.BatchItem[](2); 317 | 318 | batchItems[0] = IEVC.BatchItem({ 319 | onBehalfOfAccount: address(this), 320 | targetContract: PYTH, 321 | value: pythUpdateFee, 322 | data: abi.encodeCall(IPyth.updatePriceFeeds, pythUpdateData) 323 | }); 324 | 325 | batchItems[1] = IEVC.BatchItem({ 326 | onBehalfOfAccount: address(this), 327 | targetContract: vaultAddress, 328 | value: 0, 329 | data: abi.encodeCall(IRiskManager.accountLiquidity, (accountAddress, true)) 330 | }); 331 | 332 | (IEVC.BatchItemResult[] memory batchItemsResult,,) = evc.batchSimulation{value: pythUpdateFee}(batchItems); 333 | 334 | (collateralValue, liabilityValue) = abi.decode(batchItemsResult[1].result, (uint256, uint256)); 335 | 336 | return (collateralValue, liabilityValue); 337 | } 338 | 339 | function simulatePythUpdateAndCheckLiquidation(bytes[] calldata pythUpdateData, uint256 pythUpdateFee, address vaultAddress, address liquidatorAddress, address borrowerAddress, address collateralAddress) external payable returns (uint256 maxRepay, uint256 seizedCollateral) { 340 | IEVC.BatchItem[] memory batchItems = new IEVC.BatchItem[](2); 341 | 342 | batchItems[0] = IEVC.BatchItem({ 343 | onBehalfOfAccount: address(this), 344 | targetContract: PYTH, 345 | value: pythUpdateFee, 346 | data: abi.encodeCall(IPyth.updatePriceFeeds, pythUpdateData) 347 | }); 348 | 349 | batchItems[1] = IEVC.BatchItem({ 350 | onBehalfOfAccount: address(this), 351 | targetContract: vaultAddress, 352 | value: 0, 353 | data: abi.encodeCall(ILiquidation.checkLiquidation, (liquidatorAddress, borrowerAddress, collateralAddress)) 354 | }); 355 | 356 | (IEVC.BatchItemResult[] memory batchItemsResult,,) = evc.batchSimulation{value: pythUpdateFee}(batchItems); 357 | 358 | (maxRepay, seizedCollateral) = abi.decode(batchItemsResult[1].result, (uint256, uint256)); 359 | 360 | return (maxRepay, seizedCollateral); 361 | } 362 | } -------------------------------------------------------------------------------- /contracts/MockPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import {IERC4626} from "./IEVault.sol"; 6 | 7 | contract MockPriceOracle { 8 | error PriceOracle_InvalidConfiguration(); 9 | 10 | uint256 constant SPREAD_SCALE = 100; 11 | uint256 spread; 12 | mapping(address vault => address asset) resolvedVaults; 13 | mapping(address base => mapping(address quote => uint256)) price; 14 | 15 | function name() external pure returns (string memory) { 16 | return "MockPriceOracle"; 17 | } 18 | 19 | function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256) { 20 | (,,, uint256 midOut) = resolveOracle(inAmount, base, quote); 21 | return midOut; 22 | } 23 | 24 | function getQuotes(uint256 inAmount, address base, address quote) 25 | external 26 | view 27 | returns (uint256 bidOut, uint256 askOut) 28 | { 29 | (,,, uint256 midOut) = resolveOracle(inAmount, base, quote); 30 | 31 | if (spread > 0) { 32 | bidOut = midOut * (100 - spread / 2) / SPREAD_SCALE; 33 | askOut = midOut * (100 + spread / 2) / SPREAD_SCALE; 34 | } else { 35 | bidOut = askOut = midOut; 36 | } 37 | } 38 | 39 | ///// Mock functions 40 | 41 | function setSpread(uint256 newSpread) external { 42 | spread = newSpread; 43 | } 44 | 45 | function setResolvedVault(address vault, bool set) external { 46 | address asset = set ? IERC4626(vault).asset() : address(0); 47 | resolvedVaults[vault] = asset; 48 | } 49 | 50 | function setPrice(address base, address quote, uint256 newPrice) external { 51 | price[base][quote] = newPrice; 52 | } 53 | 54 | function resolveOracle(uint256 inAmount, address base, address quote) 55 | public 56 | view 57 | returns (uint256, /* resolvedAmount */ address, /* base */ address, /* quote */ uint256 /* outAmount */ ) 58 | { 59 | if (base == quote) return (inAmount, base, quote, inAmount); 60 | 61 | uint256 p = price[base][quote]; 62 | if (p != 0) { 63 | return (inAmount, base, quote, inAmount * p / 1e18); 64 | } 65 | 66 | address baseAsset = resolvedVaults[base]; 67 | if (baseAsset != address(0)) { 68 | inAmount = IERC4626(base).convertToAssets(inAmount); 69 | return resolveOracle(inAmount, baseAsset, quote); 70 | } 71 | 72 | revert PriceOracle_InvalidConfiguration(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /contracts/SwapVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import {IEVault, IERC20} from "./IEVault.sol"; 6 | 7 | /// @title SwapVerifier 8 | /// @custom:security-contact security@euler.xyz 9 | /// @author Euler Labs (https://www.eulerlabs.com/) 10 | /// @notice Simple contract used to verify post swap conditions 11 | /// @dev This contract is the only trusted code in the EVK swap periphery 12 | contract SwapVerifier { 13 | error SwapVerifier_skimMin(); 14 | error SwapVerifier_debtMax(); 15 | error SwapVerifier_pastDeadline(); 16 | 17 | /// @notice Verify results of a regular swap, when bought tokens are sent to the vault and skim for the buyer 18 | /// @param vault The EVault to query 19 | /// @param receiver Account to skim to 20 | /// @param amountMin Minimum amount of assets that should be available for skim 21 | /// @param deadline Timestamp after which the swap transaction is outdated 22 | /// @dev Swapper contract will send bought assets to the vault in certain situations. 23 | /// @dev Calling this function is then necessary to perform slippage check and claim the output for the buyer 24 | function verifyAmountMinAndSkim(address vault, address receiver, uint256 amountMin, uint256 deadline) external { 25 | if (deadline < block.timestamp) revert SwapVerifier_pastDeadline(); 26 | if (amountMin == 0) return; 27 | 28 | uint256 cash = IEVault(vault).cash(); 29 | uint256 balance = IERC20(IEVault(vault).asset()).balanceOf(vault); 30 | 31 | if (balance <= cash || balance - cash < amountMin) revert SwapVerifier_skimMin(); 32 | 33 | IEVault(vault).skim(type(uint256).max, receiver); 34 | } 35 | 36 | /// @notice Verify results of a swap and repay operation, when debt is repaid down to a requested target 37 | /// @param vault The EVault to query 38 | /// @param account User account to query 39 | /// @param amountMax Max amount of debt that can be held by the account 40 | /// @param deadline Timestamp after which the swap transaction is outdated 41 | /// @dev Swapper contract will repay debt up to a requested target amount in certain situations. 42 | /// @dev Calling the function is then equivalent to a slippage check. 43 | function verifyDebtMax(address vault, address account, uint256 amountMax, uint256 deadline) external view { 44 | if (deadline < block.timestamp) revert SwapVerifier_pastDeadline(); 45 | if (amountMax == type(uint256).max) return; 46 | 47 | uint256 debt = IEVault(vault).debtOf(account); 48 | 49 | if (debt > amountMax) revert SwapVerifier_debtMax(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "contracts" 3 | out = "out" 4 | libs = ["lib"] 5 | 6 | remappings = [ 7 | "forge-std/=lib/forge-std/src/" 8 | ] 9 | 10 | # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options 11 | -------------------------------------------------------------------------------- /pylintrc: -------------------------------------------------------------------------------- 1 | # This Pylint rcfile contains a best-effort configuration to uphold the 2 | # best-practices and style described in the Google Python style guide: 3 | # https://google.github.io/styleguide/pyguide.html 4 | # 5 | # Its canonical open-source location is: 6 | # https://google.github.io/styleguide/pylintrc 7 | 8 | [MAIN] 9 | 10 | # Files or directories to be skipped. They should be base names, not paths. 11 | ignore=third_party 12 | 13 | # Files or directories matching the regex patterns are skipped. The regex 14 | # matches against base names, not paths. 15 | ignore-patterns= 16 | 17 | # Pickle collected data for later comparisons. 18 | persistent=no 19 | 20 | # List of plugins (as comma separated values of python modules names) to load, 21 | # usually to register additional checkers. 22 | load-plugins= 23 | 24 | # Use multiple processes to speed up Pylint. 25 | jobs=4 26 | 27 | # Allow loading of arbitrary C extensions. Extensions are imported into the 28 | # active Python interpreter and may run arbitrary code. 29 | unsafe-load-any-extension=no 30 | 31 | 32 | [MESSAGES CONTROL] 33 | 34 | # Only show warnings with the listed confidence levels. Leave empty to show 35 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 36 | confidence= 37 | 38 | # Enable the message, report, category or checker with the given id(s). You can 39 | # either give multiple identifier separated by comma (,) or put this option 40 | # multiple time (only on the command line, not in the configuration file where 41 | # it should appear only once). See also the "--disable" option for examples. 42 | #enable= 43 | 44 | # Disable the message, report, category or checker with the given id(s). You 45 | # can either give multiple identifiers separated by comma (,) or put this 46 | # option multiple times (only on the command line, not in the configuration 47 | # file where it should appear only once).You can also use "--disable=all" to 48 | # disable everything first and then reenable specific checks. For example, if 49 | # you want to run only the similarities checker, you can use "--disable=all 50 | # --enable=similarities". If you want to run only the classes checker, but have 51 | # no Warning level messages displayed, use"--disable=all --enable=classes 52 | # --disable=W" 53 | disable=R, 54 | abstract-method, 55 | apply-builtin, 56 | arguments-differ, 57 | attribute-defined-outside-init, 58 | backtick, 59 | bad-option-value, 60 | basestring-builtin, 61 | buffer-builtin, 62 | c-extension-no-member, 63 | consider-using-enumerate, 64 | cmp-builtin, 65 | cmp-method, 66 | coerce-builtin, 67 | coerce-method, 68 | delslice-method, 69 | div-method, 70 | eq-without-hash, 71 | execfile-builtin, 72 | file-builtin, 73 | filter-builtin-not-iterating, 74 | fixme, 75 | getslice-method, 76 | global-statement, 77 | hex-method, 78 | idiv-method, 79 | implicit-str-concat, 80 | import-error, 81 | import-self, 82 | import-star-module-level, 83 | input-builtin, 84 | intern-builtin, 85 | invalid-str-codec, 86 | locally-disabled, 87 | long-builtin, 88 | long-suffix, 89 | map-builtin-not-iterating, 90 | misplaced-comparison-constant, 91 | missing-function-docstring, 92 | metaclass-assignment, 93 | next-method-called, 94 | next-method-defined, 95 | no-absolute-import, 96 | no-init, # added 97 | no-member, 98 | no-name-in-module, 99 | no-self-use, 100 | nonzero-method, 101 | oct-method, 102 | old-division, 103 | old-ne-operator, 104 | old-octal-literal, 105 | old-raise-syntax, 106 | parameter-unpacking, 107 | print-statement, 108 | raising-string, 109 | range-builtin-not-iterating, 110 | raw_input-builtin, 111 | rdiv-method, 112 | reduce-builtin, 113 | relative-import, 114 | reload-builtin, 115 | round-builtin, 116 | setslice-method, 117 | signature-differs, 118 | standarderror-builtin, 119 | suppressed-message, 120 | sys-max-int, 121 | trailing-newlines, 122 | unichr-builtin, 123 | unicode-builtin, 124 | unnecessary-pass, 125 | unpacking-in-except, 126 | useless-else-on-loop, 127 | useless-suppression, 128 | using-cmp-argument, 129 | wrong-import-order, 130 | xrange-builtin, 131 | zip-builtin-not-iterating, 132 | 133 | 134 | [REPORTS] 135 | 136 | # Set the output format. Available formats are text, parseable, colorized, msvs 137 | # (visual studio) and html. You can also give a reporter class, eg 138 | # mypackage.mymodule.MyReporterClass. 139 | output-format=text 140 | 141 | # Tells whether to display a full report or only the messages 142 | reports=no 143 | 144 | # Python expression which should return a note less than 10 (10 is the highest 145 | # note). You have access to the variables errors warning, statement which 146 | # respectively contain the number of errors / warnings messages and the total 147 | # number of statements analyzed. This is used by the global evaluation report 148 | # (RP0004). 149 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 150 | 151 | # Template used to display messages. This is a python new-style format string 152 | # used to format the message information. See doc for all details 153 | #msg-template= 154 | 155 | 156 | [BASIC] 157 | 158 | # Good variable names which should always be accepted, separated by a comma 159 | good-names=main,_ 160 | 161 | # Bad variable names which should always be refused, separated by a comma 162 | bad-names= 163 | 164 | # Colon-delimited sets of names that determine each other's naming style when 165 | # the name regexes allow several styles. 166 | name-group= 167 | 168 | # Include a hint for the correct naming format with invalid-name 169 | include-naming-hint=no 170 | 171 | # List of decorators that produce properties, such as abc.abstractproperty. Add 172 | # to this list to register other decorators that produce valid properties. 173 | property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl 174 | 175 | # Regular expression matching correct function names 176 | function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*)|(?P_?[a-z][a-z0-9_]*))$ 177 | 178 | # Regular expression matching correct variable names 179 | variable-rgx=^[a-z][a-z0-9_]*$ 180 | 181 | # Regular expression matching correct constant names 182 | const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ 183 | 184 | # Regular expression matching correct attribute names 185 | attr-rgx=^_{0,2}[a-z][a-z0-9_]*$ 186 | 187 | # Regular expression matching correct argument names 188 | argument-rgx=^[a-z][a-z0-9_]*$ 189 | 190 | # Regular expression matching correct class attribute names 191 | class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ 192 | 193 | # Regular expression matching correct inline iteration names 194 | inlinevar-rgx=^[a-z][a-z0-9_]*$ 195 | 196 | # Regular expression matching correct class names 197 | class-rgx=^_?[A-Z][a-zA-Z0-9]*$ 198 | 199 | # Regular expression matching correct module names 200 | module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$ 201 | 202 | # Regular expression matching correct method names 203 | method-rgx=(?x)^(?:(?P_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P_{0,2}[a-z][a-z0-9_]*))$ 204 | 205 | # Regular expression which should only match function or class names that do 206 | # not require a docstring. 207 | no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$ 208 | 209 | # Minimum line length for functions/classes that require docstrings, shorter 210 | # ones are exempt. 211 | docstring-min-length=12 212 | 213 | 214 | [TYPECHECK] 215 | 216 | # List of decorators that produce context managers, such as 217 | # contextlib.contextmanager. Add to this list to register other decorators that 218 | # produce valid context managers. 219 | contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager 220 | 221 | # List of module names for which member attributes should not be checked 222 | # (useful for modules/projects where namespaces are manipulated during runtime 223 | # and thus existing member attributes cannot be deduced by static analysis. It 224 | # supports qualified module names, as well as Unix pattern matching. 225 | ignored-modules= 226 | 227 | # List of class names for which member attributes should not be checked (useful 228 | # for classes with dynamically set attributes). This supports the use of 229 | # qualified names. 230 | ignored-classes=optparse.Values,thread._local,_thread._local 231 | 232 | # List of members which are set dynamically and missed by pylint inference 233 | # system, and so shouldn't trigger E1101 when accessed. Python regular 234 | # expressions are accepted. 235 | generated-members= 236 | 237 | 238 | [FORMAT] 239 | 240 | # Maximum number of characters on a single line. 241 | max-line-length=100 242 | 243 | 244 | # Regexp for a line that is allowed to be longer than the limit. 245 | ignore-long-lines=(?x)( 246 | ^\s*(\#\ )??$| 247 | ^\s*(from\s+\S+\s+)?import\s+.+$) 248 | 249 | # Allow the body of an if to be on the same line as the test if there is no 250 | # else. 251 | single-line-if-stmt=yes 252 | 253 | # Maximum number of lines in a module 254 | max-module-lines=99999 255 | 256 | # String used as indentation unit. The internal Google style guide mandates 2 257 | # spaces. Google's externaly-published style guide says 4, consistent with 258 | # PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google 259 | # projects (like TensorFlow). 260 | indent-string=' ' 261 | 262 | # Number of spaces of indent required inside a hanging or continued line. 263 | indent-after-paren=4 264 | 265 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 266 | expected-line-ending-format= 267 | 268 | 269 | [MISCELLANEOUS] 270 | 271 | # List of note tags to take in consideration, separated by a comma. 272 | notes=TODO 273 | 274 | 275 | [STRING] 276 | 277 | # This flag controls whether inconsistent-quotes generates a warning when the 278 | # character used as a quote delimiter is used inconsistently within a module. 279 | check-quote-consistency=yes 280 | 281 | 282 | [VARIABLES] 283 | 284 | # Tells whether we should check for unused import in __init__ files. 285 | init-import=no 286 | 287 | # A regular expression matching the name of dummy variables (i.e. expectedly 288 | # not used). 289 | dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_) 290 | 291 | # List of additional names supposed to be defined in builtins. Remember that 292 | # you should avoid to define new builtins when possible. 293 | additional-builtins= 294 | 295 | # List of strings which can identify a callback function by name. A callback 296 | # name must start or end with one of those strings. 297 | callbacks=cb_,_cb 298 | 299 | # List of qualified module names which can have objects that can redefine 300 | # builtins. 301 | redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools 302 | 303 | 304 | [LOGGING] 305 | 306 | # Logging modules to check that the string format arguments are in logging 307 | # function parameter format 308 | logging-modules=logging,absl.logging,tensorflow.io.logging 309 | 310 | 311 | [SIMILARITIES] 312 | 313 | # Minimum lines number of a similarity. 314 | min-similarity-lines=4 315 | 316 | # Ignore comments when computing similarities. 317 | ignore-comments=yes 318 | 319 | # Ignore docstrings when computing similarities. 320 | ignore-docstrings=yes 321 | 322 | # Ignore imports when computing similarities. 323 | ignore-imports=no 324 | 325 | 326 | [SPELLING] 327 | 328 | # Spelling dictionary name. Available dictionaries: none. To make it working 329 | # install python-enchant package. 330 | spelling-dict= 331 | 332 | # List of comma separated words that should not be checked. 333 | spelling-ignore-words= 334 | 335 | # A path to a file that contains private dictionary; one word per line. 336 | spelling-private-dict-file= 337 | 338 | # Tells whether to store unknown words to indicated private dictionary in 339 | # --spelling-private-dict-file option instead of raising a message. 340 | spelling-store-unknown-words=no 341 | 342 | 343 | [IMPORTS] 344 | 345 | # Deprecated modules which should not be used, separated by a comma 346 | deprecated-modules=regsub, 347 | TERMIOS, 348 | Bastion, 349 | rexec, 350 | sets 351 | 352 | # Create a graph of every (i.e. internal and external) dependencies in the 353 | # given file (report RP0402 must not be disabled) 354 | import-graph= 355 | 356 | # Create a graph of external dependencies in the given file (report RP0402 must 357 | # not be disabled) 358 | ext-import-graph= 359 | 360 | # Create a graph of internal dependencies in the given file (report RP0402 must 361 | # not be disabled) 362 | int-import-graph= 363 | 364 | # Force import order to recognize a module as part of the standard 365 | # compatibility libraries. 366 | known-standard-library= 367 | 368 | # Force import order to recognize a module as part of a third party library. 369 | known-third-party=enchant, absl 370 | 371 | # Analyse import fallback blocks. This can be used to support both Python 2 and 372 | # 3 compatible code, which means that the block might have code that exists 373 | # only in one or another interpreter, leading to false positives when analysed. 374 | analyse-fallback-blocks=no 375 | 376 | 377 | [CLASSES] 378 | 379 | # List of method names used to declare (i.e. assign) instance attributes. 380 | defining-attr-methods=__init__, 381 | __new__, 382 | setUp 383 | 384 | # List of member names, which should be excluded from the protected access 385 | # warning. 386 | exclude-protected=_asdict, 387 | _fields, 388 | _replace, 389 | _source, 390 | _make 391 | 392 | # List of valid names for the first argument in a class method. 393 | valid-classmethod-first-arg=cls, 394 | class_ 395 | 396 | # List of valid names for the first argument in a metaclass class method. 397 | valid-metaclass-classmethod-first-arg=mcs 398 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | forge-std/=lib/forge-std/src/ -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiodns==3.2.0 2 | aiohttp==3.10.2 3 | aiosignal==1.3.1 4 | astroid==3.2.3 5 | attrs==23.2.0 6 | bitarray==2.9.2 7 | blinker==1.8.2 8 | Brotli==1.1.0 9 | certifi==2024.7.4 10 | cffi==1.17.0 11 | charset-normalizer==3.3.2 12 | ckzg==1.0.2 13 | click==8.1.7 14 | cytoolz==0.12.3 15 | dill==0.3.8 16 | eth-account==0.11.2 17 | eth-hash==0.7.0 18 | eth-keyfile==0.8.1 19 | eth-keys==0.5.1 20 | eth-rlp==1.0.1 21 | eth-typing==4.2.3 22 | eth-utils==4.1.1 23 | eth_abi==5.1.0 24 | Flask==3.0.3 25 | Flask-Cors==5.0.0 26 | frozenlist==1.4.1 27 | gunicorn==23.0.0 28 | hexbytes==0.3.1 29 | idna==3.7 30 | isort==5.13.2 31 | itsdangerous==2.2.0 32 | Jinja2==3.1.4 33 | jsonschema==4.22.0 34 | jsonschema-specifications==2023.12.1 35 | lru-dict==1.2.0 36 | MarkupSafe==2.1.5 37 | mccabe==0.7.0 38 | multidict==6.0.5 39 | numpy==2.0.0 40 | packaging==23.2 41 | parsimonious==0.10.0 42 | platformdirs==4.2.2 43 | protobuf==5.27.0 44 | py-solc-x==2.0.3 45 | pycares==4.4.0 46 | pycparser==2.22 47 | pycryptodome==3.20.0 48 | pylint==3.2.5 49 | python-dotenv==1.0.1 50 | pyunormalize==15.1.0 51 | PyYAML==6.0.1 52 | referencing==0.35.1 53 | regex==2024.5.15 54 | requests==2.32.3 55 | rlp==4.0.1 56 | rpds-py==0.18.1 57 | solc-select==1.0.4 58 | tomlkit==0.13.0 59 | toolz==0.12.1 60 | typing_extensions==4.12.1 61 | urllib3==2.2.2 62 | web3==6.19.0 63 | websockets==12.0 64 | Werkzeug==3.0.3 65 | yarl==1.9.4 66 | -------------------------------------------------------------------------------- /state/Berachain_state.json: -------------------------------------------------------------------------------- 1 | {"accounts": {}, "vaults": {}, "queue": [], "last_saved_block": 1186305} -------------------------------------------------------------------------------- /state/Swell_state.json: -------------------------------------------------------------------------------- 1 | {"accounts": {"0x75CFe4Ef963232AE8313ac33E21FC3924133861A": {"address": "0x75CFe4Ef963232AE8313ac33E21FC3924133861A", "controller_address": "0x522D58AEFB7b4f54Fc1bD31b5063E55c7984bADD", "time_of_next_update": 1737829901.195362, "current_health_score": 1.9269352929628358}, "0xB42DB6eE1f7e92dbd8ad5fe6e64025E41868C2A7": {"address": "0xB42DB6eE1f7e92dbd8ad5fe6e64025E41868C2A7", "controller_address": "0x4a5C95a0e3FCA4148F91cEb637fBA0E1080BE40e", "time_of_next_update": 1737833955.6042516, "current_health_score": 13.876318871703932}, "0xdbd5c529e84f2A1955171578E1DB86eFf56a2885": {"address": "0xdbd5c529e84f2A1955171578E1DB86eFf56a2885", "controller_address": "0x4a5C95a0e3FCA4148F91cEb637fBA0E1080BE40e", "time_of_next_update": 1737823244.1946702, "current_health_score": 866240.465801157}}, "vaults": {"0x522D58AEFB7b4f54Fc1bD31b5063E55c7984bADD": "0x522D58AEFB7b4f54Fc1bD31b5063E55c7984bADD", "0x4a5C95a0e3FCA4148F91cEb637fBA0E1080BE40e": "0x4a5C95a0e3FCA4148F91cEb637fBA0E1080BE40e"}, "queue": [[1737823244.1946702, "0xdbd5c529e84f2A1955171578E1DB86eFf56a2885"], [1737833955.6042516, "0xB42DB6eE1f7e92dbd8ad5fe6e64025E41868C2A7"], [1737829901.195362, "0x75CFe4Ef963232AE8313ac33E21FC3924133861A"]], "last_saved_block": 2526530} -------------------------------------------------------------------------------- /test/LiquidationSetupWithVaultCreated.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.24; 4 | 5 | import {Test, console} from "forge-std/Test.sol"; 6 | import {Script} from "forge-std/Script.sol"; 7 | 8 | import {IEVault} from "../contracts/IEVault.sol"; 9 | import {IEVC} from "../contracts/IEVC.sol"; 10 | import {IERC20} from "../contracts/IEVault.sol"; 11 | 12 | import {MockPriceOracle} from "../contracts/MockPriceOracle.sol"; 13 | 14 | contract LiquidationSetup is Test, Script { 15 | address constant USDC_VAULT = 0x577e289F663A4E29c231135c09d6a0713ce7AAff; 16 | address constant USDC = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831; 17 | 18 | address constant DAI_VAULT = 0xF67F9B1042A7f419c2C0259C983FB1f75f981fD4; 19 | address constant DAI = 0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1; 20 | 21 | address constant EVC_ADDRESS = 0xE45Ee4046bD755330D555dFe4aDA7839a3eEb926; 22 | address constant LIQUIDATOR_CONTRACT_ADDRESS = 0xA8A46596a7B17542d2cf6993FC61Ea0CBb4474c1; 23 | 24 | address constant profitReceiver = 0x140556939f9Cfa711078DeFBb01B3e51A53Bc464; 25 | 26 | address depositor; 27 | uint256 depositorPrivateKey; 28 | address borrower; 29 | uint256 borrowerPrivateKey; 30 | address liquidator; 31 | uint256 liquidatorPrivateKey; 32 | 33 | IEVault usdc_vault; 34 | IEVault dai_vault; 35 | 36 | IERC20 usdc; 37 | IERC20 dai; 38 | 39 | IEVC evc; 40 | 41 | function run() public { 42 | evc = IEVC(EVC_ADDRESS); 43 | 44 | usdc_vault = IEVault(USDC_VAULT); 45 | usdc = IERC20(USDC); 46 | 47 | dai_vault = IEVault(DAI_VAULT); 48 | dai = IERC20(DAI); 49 | 50 | depositorPrivateKey = vm.envUint("DEPOSITOR_PRIVATE_KEY"); 51 | depositor = vm.addr(depositorPrivateKey); 52 | 53 | borrowerPrivateKey = vm.envUint("BORROWER_PRIVATE_KEY"); 54 | borrower = vm.addr(borrowerPrivateKey); 55 | 56 | liquidatorPrivateKey = vm.envUint("LIQUIDATOR_PRIVATE_KEY"); 57 | liquidator = vm.addr(liquidatorPrivateKey); 58 | 59 | console.log("Current state:"); 60 | logState(); 61 | 62 | // depositorDepositInVaults(); 63 | // console.log("After depositing in vaults:"); 64 | // logState(); 65 | 66 | // borrowerDepositAndEnableCollateralAndController(); 67 | // console.log("After borrower deposit in vaults:"); 68 | // logState(); 69 | 70 | // borrowerBorrowUSDC(); 71 | // console.log("After borrower borrow:"); 72 | // logState(); 73 | 74 | // depositorDepositAndTransferToLiquidatorContract(); 75 | // console.log("After depositor deposit in liquidator contract:"); 76 | // logState(); 77 | } 78 | 79 | function depositorDepositInVaults() internal { 80 | vm.startBroadcast(depositorPrivateKey); 81 | 82 | usdc.approve(address(usdc_vault), type(uint256).max); 83 | dai.approve(address(dai_vault), type(uint256).max); 84 | 85 | usdc_vault.deposit(1e6, depositor); 86 | dai_vault.deposit(1e18, depositor); 87 | 88 | vm.stopBroadcast(); 89 | } 90 | 91 | function borrowerDepositAndEnableCollateralAndController() internal { 92 | vm.startBroadcast(borrowerPrivateKey); 93 | 94 | dai.approve(address(dai_vault), type(uint256).max); 95 | dai_vault.deposit(1e18, borrower); 96 | 97 | evc.enableCollateral(borrower, address(dai_vault)); 98 | evc.enableController(borrower, address(usdc_vault)); 99 | 100 | vm.stopBroadcast(); 101 | } 102 | 103 | function borrowerBorrowUSDC() internal { 104 | vm.startBroadcast(borrowerPrivateKey); 105 | 106 | usdc_vault.borrow(5e5, borrower); 107 | 108 | vm.stopBroadcast(); 109 | } 110 | 111 | function depositorDepositAndTransferToLiquidatorContract() internal { 112 | vm.startBroadcast(depositorPrivateKey); 113 | usdc_vault.deposit(1e6, LIQUIDATOR_CONTRACT_ADDRESS); 114 | dai_vault.deposit(1e18, LIQUIDATOR_CONTRACT_ADDRESS); 115 | vm.stopBroadcast(); 116 | } 117 | 118 | function logState() internal view { 119 | console.log("Account States:"); 120 | console.log("Depositor: ", depositor); 121 | console.log("USDC Vault balance: ", usdc_vault.balanceOf(depositor)); 122 | console.log("USDC balance: ", usdc.balanceOf(depositor)); 123 | console.log("DAI Vault balance: ", dai_vault.balanceOf(depositor)); 124 | console.log("DAI balance: ", dai.balanceOf(depositor)); 125 | console.log("--------------------"); 126 | console.log("Borrower: ", borrower); 127 | console.log("USDC Vault balance: ", usdc_vault.balanceOf(borrower)); 128 | console.log("USDC borrow: ", usdc_vault.debtOf(borrower)); 129 | console.log("USDC balance: ", usdc.balanceOf(borrower)); 130 | console.log("DAI Vault balance: ", dai_vault.balanceOf(borrower)); 131 | console.log("DAI borrow: ", dai_vault.debtOf(borrower)); 132 | console.log("DAI balance: ", dai.balanceOf(borrower)); 133 | console.log("--------------------"); 134 | console.log("Liquidator: ", liquidator); 135 | console.log("USDC Vault balance: ", usdc_vault.balanceOf(liquidator)); 136 | console.log("USDC balance: ", usdc.balanceOf(liquidator)); 137 | console.log("DAI Vault balance: ", dai_vault.balanceOf(liquidator)); 138 | console.log("DAI balance: ", dai.balanceOf(liquidator)); 139 | console.log("--------------------"); 140 | console.log("Profit Receiver: ", profitReceiver); 141 | console.log("USDC Vault balance: ", usdc_vault.balanceOf(profitReceiver)); 142 | console.log("USDC balance: ", usdc.balanceOf(profitReceiver)); 143 | console.log("DAI Vault balance: ", dai_vault.balanceOf(profitReceiver)); 144 | console.log("DAI balance: ", dai.balanceOf(profitReceiver)); 145 | console.log("--------------------"); 146 | console.log("Liquidator Contract: ", LIQUIDATOR_CONTRACT_ADDRESS); 147 | console.log("USDC Vault balance: ", usdc_vault.balanceOf(LIQUIDATOR_CONTRACT_ADDRESS)); 148 | console.log("USDC borrow: ", usdc_vault.debtOf(LIQUIDATOR_CONTRACT_ADDRESS)); 149 | console.log("USDC balance: ", usdc.balanceOf(LIQUIDATOR_CONTRACT_ADDRESS)); 150 | console.log("DAI Vault balance: ", dai_vault.balanceOf(LIQUIDATOR_CONTRACT_ADDRESS)); 151 | console.log("DAI borrow: ", dai_vault.debtOf(LIQUIDATOR_CONTRACT_ADDRESS)); 152 | console.log("DAI balance: ", dai.balanceOf(LIQUIDATOR_CONTRACT_ADDRESS)); 153 | console.log("----------------------------------------"); 154 | console.log(" "); 155 | console.log("Vault States:"); 156 | console.log("USDC Vault:"); 157 | console.log("Total Supply: ", usdc_vault.totalSupply()); 158 | console.log("Total Assets: ", usdc_vault.totalAssets()); 159 | console.log("Total Borrow: ", usdc_vault.totalBorrows()); 160 | console.log("--------------------"); 161 | console.log("DAI Vault:"); 162 | console.log("Total Supply: ", dai_vault.totalSupply()); 163 | console.log("Total Assets: ", dai_vault.totalAssets()); 164 | console.log("Total Borrow: ", dai_vault.totalBorrows()); 165 | console.log("----------------------------------------"); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /test/TestLiquidator.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | 3 | pragma solidity ^0.8.24; 4 | 5 | import {Test, console} from "forge-std/Test.sol"; 6 | import {Liquidator} from "../contracts/Liquidator.sol"; 7 | 8 | 9 | contract LiquidatorTest is Test { 10 | address constant LIQUIDATOR_CONTRACT_ADDRESS = 0x8d244058D946801bf39df29F1F67C7A4b3201521; 11 | address constant VAULT = 0xce45EF0414dE3516cAF1BCf937bF7F2Cf67873De; 12 | address constant ACCOUNT = 0xA5f0f68dCc5bE108126d79ded881ef2993841c2f; 13 | 14 | 15 | Liquidator liquidator; 16 | 17 | function setUp() public { 18 | 19 | liquidator = Liquidator(payable(LIQUIDATOR_CONTRACT_ADDRESS)); 20 | } 21 | 22 | function testLiquidatorWithPythUpdate() public { 23 | bytes[] memory pythUpdateData = new bytes[](1); 24 | pythUpdateData[0] = hex"504e41550100000003b801000000040d00430b259b8339a0ce13437f029b730172832c61413ffb0423a1d775b6a3ed7cc959e91999253cd6ddeee89762692fc8514a8b694dd94a3321013820c7e3d012670002083c46ff3abf42f65b641554b7a61e5f882c27dd321f47239c6fe779be3ba68c31c67e255425fe0f77fb8b55fa81b46956b14ba493f6f39339335196757dadc40103cdc59afee22cd50f9889a8c6d614e4ce971dfff1865e5ea697417f6c2071df3a39f9ab58e7996cc10f95dd68c9b0eff64f264cd2e621ef0ce9d879aa6c46e24001044ffad84e81d8fd8fa70706ad8217c88c18ef9219a5b171f193bf23a577b395460e506456048c70fad2d12b2718141eb91efe0efcb0ef02932a9576ef7375507a010603b2781fbc65a9476e656cc95af4a3046e82f97c3ffe80d998bbed068c0c0a3d43bac0d6cbcfb44a5aaec842536c69b2cae69b9d6400edf497558e0bf838e7ad0008f58f6f4382b3e299d275d2864b7ab2fe282281d3d4587b3a2229fabf05997549681ca791ea1289a5fd8783868960c269d3a6346b39775d1ada91cadf130c939b000aabae762ea9f7974936a314d291643538454bb29077a940f95a4d0bb650a7dcb76c3fd96385591131013103cc0cb1b8646a31ec8a1ae46db0e96d9bcac696a121000c19237de2f6422cad69ee0292d7c0f435e42607fbcf581db28f2f7c2a57439dd30178ef9af907643dc5f23496dec77eadad3c1903b2da6f008ad1589eacf388f0010de7ebf559918d7bbd82ec20469cfb6e74b89013ba8f3bd549dc5c08e5f1b68d334cd4544da7dd5fc716aefdf53c494de9aa1eb3cd350f931406bc2f237fc8c11c010ec4111361969a29ce40a78a2261454fe8565e1ba3341009d4c186e13f9d749809657cceb6dcf802818c397f3e6a4e1530556ff9b3448d62720d9b9eb2cdc7f3be010febce9984e3d65aff66b8119bc56715a2a077def83f80b1fbd8289113feb89e3873c7839951ecb3512a92864222f0a720f6c2b0d6ec7c721d8efed70342a6fbaa00109e3bda4c1b85188ae93f73e47d17900ece6a2a4112bafe780b150cdaea72e5bc79caded35061933d20e9021f4c5e85875352d8df2403359476531089aebd6f060112fc281d4e21f3ebb87afd6d287df00c003e203864d61310f7eefec85641ae69f030d3c531185ec4f298719803cd77f21ba514384e0d90da866f603c8883dc45c90066eaa75400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000004d69e860141555756000000000009e223b7000027103d7fb8d6236feea98baed2249f8fdef4c6f9e54b03005500ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c00000000068997fd000000000007c17ffffffff80000000066eaa7540000000066eaa754000000000689a9d8000000000005d6e20adf469931287004c1a28479fdc444ba2c753fd68852e371410edd9d43c71dbae11408cdf5bb62c0b241ef91dff02756a32140d8911f79c3e5381816c62342a9521b993d60213ed22ffa6e6c51d48089e8599d63d61822c6022b9985b08c6ab16d3e9d516ae4763f50d171273f73e4b82f843036f8edc0959de902cb4040d3a443a392e05b209fa587c949052bab36f97645427f48d2007f01626e1568e46f022e475ccb534b57ae5ad2e2088538fef5c5a46045be547c6d2a28b1a32f2eeea61de902d151f0fb11ee0055006ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d0000000005f44b850000000000021abffffffff80000000066eaa7540000000066eaa7540000000005f4550a0000000000020e150a626ade5a18d656ebfa72b93469413d7df85d2c6ac0b7f1b0b1bb433ca37a943baf94e3cb44cab57e406883444fef27da7caa392bdbdcc8f8ab9b59c0ea8159957eab38bcd0989c9476aefaeee7ec1caceeeb96b97e9aee5d0f5cbf218577094aca5c18d110f636c028beba38ddf8c1f81fb6b90148bdaac5f1be3cefbfbeb2f436f426bef95eedffc8e3ca55e9b46f5744f1856250e8d4f1ae13b8f4259fe1741f7b04f34b6915613be866411873e091287dc7b3547c6d2a28b1a32f2eeea61de902d151f0fb11ee005500e393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e732600000000064b1420000000000007f0cafffffff80000000066eaa7540000000066eaa75400000000064b1a3f000000000007ce760a1f1a8f3094cdc0357e16e9209615823efeae4141923f98878c0264198f28da4e4a5a24886b746c0293e2d2f6f806e47781526271de6de2b15215daaa9b7e9fc2be6896d1efcb5fa0d685c400c6d276403ea9cc126dc6240cb3de7c34d1a400daa2b2584333ef6a33a1085272c18dc7bd1d83877e5ee7a4ff3e9b7a3ca8d0ac7436e0d4ef07b615285ecfc5c7ab36f97645427f48d2007f01626e1568e46f022e475ccb534b57ae5ad2e2088538fef5c5a46045be547c6d2a28b1a32f2eeea61de902d151f0fb11ee"; 25 | uint256 updateFee = 3; 26 | (uint256 collateral, uint256 liability) = liquidator.simulatePythUpdateAndGetAccountStatus{value: updateFee}(pythUpdateData, updateFee, VAULT, ACCOUNT); 27 | 28 | console.log(collateral, liability); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/get_ids.py: -------------------------------------------------------------------------------- 1 | from app.liquidation.utils import load_config, create_contract_instance 2 | from app.liquidation.liquidation_bot import Vault 3 | test_vault = Vault("0xce45EF0414dE3516cAF1BCf937bF7F2Cf67873De") 4 | config = load_config() 5 | 6 | def get_feed_ids(vault): 7 | oracle_address = vault.oracle_address 8 | oracle = create_contract_instance(oracle_address, config.ORACLE_ABI_PATH) 9 | 10 | unit_of_account = vault.unit_of_account 11 | 12 | collateral_vault_list = vault.get_ltv_list() 13 | asset_list = [Vault(collateral_vault).underlying_asset_address for collateral_vault in collateral_vault_list] 14 | 15 | feed_ids = [] 16 | asset_list.append(vault.underlying_asset_address) 17 | 18 | for asset in asset_list: 19 | print("Collateral:", asset) 20 | configured_oracle_address = oracle.functions.getConfiguredOracle(asset, unit_of_account).call() 21 | configured_oracle = create_contract_instance(configured_oracle_address, config.ORACLE_ABI_PATH) 22 | 23 | try: 24 | configured_oracle_name = configured_oracle.functions.name().call() 25 | except Exception as ex: 26 | continue 27 | if configured_oracle_name == "PythOracle": 28 | feed_ids.append(configured_oracle.functions.feedId().call().hex()) 29 | 30 | return feed_ids 31 | 32 | print(get_feed_ids(test_vault)) -------------------------------------------------------------------------------- /test/oracle_test.py: -------------------------------------------------------------------------------- 1 | from app.liquidation.utils import get_eth_usd_quote 2 | 3 | print(get_eth_usd_quote()) -------------------------------------------------------------------------------- /test/pyth_test.py: -------------------------------------------------------------------------------- 1 | from app.liquidation.utils import make_api_request, load_config, create_contract_instance 2 | from web3 import Web3 3 | 4 | pyth_url = "https://hermes.pyth.network/v2/" 5 | 6 | headers = {} 7 | 8 | price_update_input_url = pyth_url + "updates/price/latest?" 9 | 10 | # feeds = ["ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c", 11 | # "6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d", 12 | # "e393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e7326"] 13 | 14 | feeds = ['ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c', '6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d', 'e393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e7326', 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a'] 15 | 16 | 17 | print(feeds) 18 | 19 | for feed in feeds: 20 | price_update_input_url += "ids[]=" + feed + "&" 21 | 22 | price_update_input_url = price_update_input_url[:-1] 23 | 24 | return_data = make_api_request(price_update_input_url, {}, {}) 25 | 26 | update_data = "0x" + return_data["binary"]["data"][0] 27 | 28 | config = load_config() 29 | 30 | pyth = create_contract_instance(config.PYTH, config.PYTH_ABI_PATH) 31 | 32 | update_fee = pyth.functions.getUpdateFee([update_data]).call() 33 | 34 | print(update_fee) 35 | 36 | liquidator = create_contract_instance(config.LIQUIDATOR_CONTRACT, config.LIQUIDATOR_ABI_PATH) 37 | 38 | print(liquidator.functions.PYTH().call()) 39 | print(liquidator.functions.evcAddress().call()) 40 | 41 | vault_address = Web3.to_checksum_address("0xce45EF0414dE3516cAF1BCf937bF7F2Cf67873De") 42 | account_address = Web3.to_checksum_address("0xA5f0f68dCc5bE108126d79ded881ef2993841c2f") 43 | 44 | vault = create_contract_instance(vault_address, config.EVAULT_ABI_PATH) 45 | 46 | print("update data: ", update_data) 47 | 48 | result = liquidator.functions.simulate_pyth_update_and_get_account_status( 49 | [update_data], update_fee, vault_address, account_address 50 | ).call( 51 | {"value": update_fee} 52 | ) 53 | 54 | print(result) -------------------------------------------------------------------------------- /test/swap_api_test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from typing import TypedDict 3 | from eth_utils import to_checksum_address 4 | 5 | class SwapResponse(TypedDict): 6 | swapperAddress: str 7 | swapperData: str 8 | multicallItems: list 9 | 10 | def get_swap_quote( 11 | chain_id: int, 12 | token_in: str, 13 | token_out: str, 14 | amount: int, # exact in - amount to sell, exact out - amount to buy, exact out repay - estimated amount to buy (from current debt) 15 | min_amount_out: int, 16 | receiver: str, # vault to swap or repay to 17 | vault_in: str, 18 | origin: str, 19 | account_in: str, 20 | account_out: str, 21 | swapper_mode: str, 22 | slippage: float, #in percent 1 = 1% 23 | deadline: int, 24 | is_repay: bool, 25 | current_debt: int, # needed in exact input or output and with `isRepay` set 26 | target_debt: int # ignored if not in target debt mode 27 | ) -> SwapResponse: 28 | # Normalize addresses 29 | token_in = to_checksum_address(token_in) 30 | token_out = to_checksum_address(token_out) 31 | receiver = to_checksum_address(receiver) 32 | vault_in = to_checksum_address(vault_in) 33 | origin = to_checksum_address(origin) 34 | account_in = to_checksum_address(account_in) 35 | account_out = to_checksum_address(account_out) 36 | 37 | params = { 38 | "chainId": str(chain_id), 39 | "tokenIn": token_in, 40 | "tokenOut": token_out, 41 | "amount": str(amount), 42 | "receiver": receiver, 43 | "vaultIn": vault_in, 44 | "origin": origin, 45 | "accountIn": account_in, 46 | "accountOut": account_out, 47 | "swapperMode": swapper_mode, # TARGET_DEBT mode 48 | "slippage": str(slippage), 49 | "deadline": str(deadline), # 30 min 50 | "isRepay": str(is_repay), 51 | "currentDebt": str(current_debt), # 2000 USDC debt 52 | "targetDebt": str(target_debt) # Fully repay the debt 53 | } 54 | 55 | response = requests.get("http://localhost:3002/swap", params=params) 56 | 57 | if not response.ok: 58 | raise Exception(f"Request failed: {response.status_code} {response.text}") 59 | 60 | data = response.json() 61 | 62 | if not data["success"]: 63 | raise Exception(f"Swap failed: {data['message']}") 64 | 65 | amount_out = int(data["data"]["amountOut"]) 66 | if amount_out < min_amount_out: 67 | raise ValueError( 68 | f"Quote too low: got {amount_out}, wanted minimum {min_amount_out}" 69 | ) 70 | 71 | return data["data"] 72 | 73 | # Example usage 74 | if __name__ == "__main__": 75 | IN_VAULT = "0x631D8E808f2c4177a8147Eaa39a4F57C47634dE8" 76 | LIQUIDATOR_EOA = "0x8cbB534874bab83e44a7325973D2F04493359dF8" 77 | BORROW_VAULT = "0xa992d3777282c44ee980e9b0ca9bd0c0e4f737af" 78 | 79 | try: 80 | swap_response = get_swap_quote( 81 | chain_id=1, 82 | token_in="0x8c9532a60E0E7C6BbD2B2c1303F63aCE1c3E9811", 83 | token_out="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 84 | amount=int(.03518*10**18), 85 | # amount=int(.04061*10**18), 86 | min_amount_out=0, 87 | receiver=BORROW_VAULT, 88 | vault_in=IN_VAULT, 89 | origin=LIQUIDATOR_EOA, 90 | account_in=LIQUIDATOR_EOA, 91 | account_out=LIQUIDATOR_EOA, 92 | swapper_mode="0", 93 | slippage=1.0, 94 | deadline=600, 95 | is_repay=False, 96 | # current_debt=int(.04061*10**18), 97 | current_debt=0, 98 | target_debt=0 99 | ) 100 | swap = swap_response['swap'] 101 | print("\nSwap Response:") 102 | print("-------------") 103 | print(f"Amount In: {swap_response['amountIn']}") 104 | print(f"Max Amount In: {swap_response['amountInMax']}") 105 | print(f"Amount Out: {swap_response['amountOut']}") 106 | print(f"Min Amount Out: {swap_response['amountOutMin']}") 107 | print(f"\nAccounts:") 108 | print(f" Account In: {swap_response['accountIn']}") 109 | print(f" Account Out: {swap_response['accountOut']}") 110 | print(f" Vault In: {swap_response['vaultIn']}") 111 | print(f" Receiver: {swap_response['receiver']}") 112 | print(f"\nTokens:") 113 | print(f" Token In: {swap_response['tokenIn']['symbol']} ({swap_response['tokenIn']['addressInfo']})") 114 | print(f" Name: {swap_response['tokenIn']['name']}") 115 | print(f" Decimals: {swap_response['tokenIn']['decimals']}") 116 | print(f" Token Out: {swap_response['tokenOut']['symbol']} ({swap_response['tokenOut']['addressInfo']})") 117 | print(f" Name: {swap_response['tokenOut']['name']}") 118 | print(f" Decimals: {swap_response['tokenOut']['decimals']}") 119 | print(f"\nSlippage: {swap_response['slippage']}%") 120 | print(f"\nRoute:") 121 | for step in swap_response['route']: 122 | print(f" - {step['providerName']}") 123 | 124 | print("\nMulticall Items:") 125 | print("---------------") 126 | for i, item in enumerate(swap['multicallItems'], 1): 127 | print(f"\nStep {i}:") 128 | print(f" Function: {item['functionName']}") 129 | print(f" Arguments: {item['args']}") 130 | print(f" Call data: {item['data']}") 131 | 132 | swap_data = [] 133 | for _, item in enumerate(swap['multicallItems']): 134 | swap_data.append(item['data']) 135 | 136 | print(swap_data) 137 | 138 | except ValueError as e: 139 | print(f"Quote check failed: {e}") 140 | except Exception as e: 141 | print(f"Request failed: {e}") --------------------------------------------------------------------------------