├── .gitignore ├── README.md ├── contracts ├── FlashloanLiquidator.json ├── IERC20.json ├── INonfungiblePositionManager.json ├── IUniswapV3Factory.json ├── IUniswapV3Pool.json ├── V3Vault.json └── WETH.json ├── index.js ├── lib └── common.js ├── license.txt ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Liquidator-js 2 | 3 | An open-source implementation of a simple liquidation bot for Revert Lend. This bot is designed to perform liquidations and also to serve as an example implementation for developers interested in building similar tools. 4 | 5 | ## Overview 6 | 7 | This bot monitors active positions on the Revert Lend protocol and executes liquidations when certain conditions are met. It uses a combination of WebSocket connections and periodic checks to stay updated on the state of the positions and the market. 8 | 9 | Key features: 10 | 11 | - **WebSocket Monitoring**: Listens to real-time events from the Uniswap contracts to update positions as their underlying value changes. 12 | - **Periodic Position Checks**: Regularly checks all positions at set intervals. 13 | - **Flashloan Liquidations**: Executes liquidations using flashloans, requiring no upfront capital in the asset being liquidated. 14 | - **Non-Flashloan Liquidations**: Optionally supports liquidations without flashloans if the liquidator holds the necessary USDC and has approved the V3Vault contract. 15 | 16 | Revert Lend contract is currently deployed on Arbitrum only: 17 | 18 | - [Revert Lend Contract on Arbiscan](https://arbiscan.io/address/0x74e6afef5705beb126c6d3bf46f8fad8f3e07825) 19 | 20 | ## Getting Started 21 | 22 | ### Prerequisites 23 | 24 | - Node.js (v14 or higher) 25 | - npm (v6 or higher) 26 | - An Ethereum-compatible wallet with sufficient ETH on Arbitrum 27 | - Access to Arbitrum RPC endpoints (both HTTP and WebSocket) 28 | 29 | ### Installation 30 | 31 | 1. **Clone the Repository** 32 | 33 | ```bash 34 | git clone https://github.com/revert-finance/liquidator-js.git 35 | cd liquidator-js 36 | ``` 37 | 38 | 2. **Install Dependencies** 39 | ```bash 40 | npm install 41 | ``` 42 | 43 | 3. **Create a `.env` File** 44 | 45 | Before running the script, create a `.env` file in the root directory with the following configurations: 46 | 47 | ```dotenv 48 | PRIVATE_KEY_LIQUIDATOR=your_private_key_here 49 | RPC_URL_ARBITRUM=your_arbitrum_rpc_url_here 50 | WS_RPC_URL_ARBITRUM=your_arbitrum_websocket_url_here 51 | NETWORK=arbitrum 52 | ``` 53 | 54 | 4. **Optional: Non-Flashloan Liquidations** 55 | 56 | To enable non-flashloan liquidations: 57 | 58 | - Deposit the required amount of USDC into your liquidator account. 59 | - Approve the V3Vault contract to spend your USDC. 60 | 61 | ```javascript 62 | // Example approval script (ensure to customize token addresses and amounts) 63 | const USDC_CONTRACT = new ethers.Contract(USDC_ADDRESS, IERC20_ABI, signer); 64 | await USDC_CONTRACT.approve(V3_VAULT_ADDRESS, ethers.constants.MaxUint256); 65 | ``` 66 | 67 | ## Running the Bot 68 | 69 | Start the bot by running: 70 | 71 | ```bash 72 | node index.js 73 | ``` 74 | 75 | ## How It Works 76 | 77 | ### Monitoring Positions 78 | 79 | The bot maintains an internal cache of active positions by: 80 | 81 | - Loading all active positions on startup. 82 | - Listening to events (`Add`, `Remove`, `Borrow`, `Repay`, `WithdrawCollateral`, `IncreaseLiquidity`) to update positions in real-time. 83 | 84 | ### Checking Positions 85 | 86 | Positions are checked for liquidation opportunities in two ways: 87 | 88 | 1. **Event-Driven Checks**: When swap events on monitored uniswap pools are detected via WebSocket, the bot checks the affected positions immediately. 89 | 2. **Periodic Checks**: Every 15 minutes, the bot performs a full scan of all positions to ensure no opportunities are missed with the swap events strategy. 90 | 91 | ### Liquidation Process 92 | 93 | When a position is eligible for liquidation: 94 | 95 | - The bot estimates the liquidation value and prepares the necessary swap data using the Uniswap Universal Router. 96 | - **Flashloan Liquidations**: The bot uses a flashloan to perform the liquidation without needing upfront USDC. 97 | - **Non-Flashloan Liquidations**: If enabled, the bot can perform liquidations using its own USDC balance. 98 | 99 | 100 | ## Configuration Options 101 | 102 | A few options can be configured in the `index.js` file: 103 | 104 | - `positionLogInterval`: Interval for logging low collateral factors (default is every 1 minute). 105 | - `enableNonFlashloanLiquidation`: Set to `true` to enable non-flashloan liquidations (default is `false`). 106 | - `CHECK_INTERVAL`: Interval for periodic position checks (default is every 15 minutes). 107 | 108 | ## Important Notes 109 | 110 | - **Gas Fees**: Ensure your liquidator account has enough ETH on Arbitrum to cover gas fees. 111 | - **Security**: Keep your private keys secure. Do not share or commit them to version control. 112 | - **Dependencies**: The bot relies on several external services (e.g., RPC providers). Ensure your connections are reliable. 113 | 114 | ## Additional Resources 115 | 116 | - **Revert Lend Documentation**: [Docs](https://docs.revert.finance/revert/revert-lend) 117 | 118 | 119 | ## Contributing 120 | 121 | Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes. 122 | 123 | ## License 124 | 125 | This project is licensed under the MIT License. 126 | 127 | --- 128 | 129 | *Disclaimer: Use this bot responsibly and at your own risk. The maintainers are not responsible for any financial losses incurred.* 130 | -------------------------------------------------------------------------------- /contracts/FlashloanLiquidator.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "type": "constructor", 5 | "inputs": [ 6 | { 7 | "name": "_nonfungiblePositionManager", 8 | "type": "address", 9 | "internalType": "contract INonfungiblePositionManager" 10 | }, 11 | { 12 | "name": "_zeroxRouter", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "_universalRouter", 18 | "type": "address", 19 | "internalType": "address" 20 | } 21 | ], 22 | "stateMutability": "nonpayable" 23 | }, 24 | { 25 | "type": "function", 26 | "name": "factory", 27 | "inputs": [], 28 | "outputs": [ 29 | { 30 | "name": "", 31 | "type": "address", 32 | "internalType": "address" 33 | } 34 | ], 35 | "stateMutability": "view" 36 | }, 37 | { 38 | "type": "function", 39 | "name": "liquidate", 40 | "inputs": [ 41 | { 42 | "name": "params", 43 | "type": "tuple", 44 | "internalType": "struct FlashloanLiquidator.LiquidateParams", 45 | "components": [ 46 | { 47 | "name": "tokenId", 48 | "type": "uint256", 49 | "internalType": "uint256" 50 | }, 51 | { 52 | "name": "vault", 53 | "type": "address", 54 | "internalType": "contract IVault" 55 | }, 56 | { 57 | "name": "flashLoanPool", 58 | "type": "address", 59 | "internalType": "contract IUniswapV3Pool" 60 | }, 61 | { 62 | "name": "amount0In", 63 | "type": "uint256", 64 | "internalType": "uint256" 65 | }, 66 | { 67 | "name": "swapData0", 68 | "type": "bytes", 69 | "internalType": "bytes" 70 | }, 71 | { 72 | "name": "amount1In", 73 | "type": "uint256", 74 | "internalType": "uint256" 75 | }, 76 | { 77 | "name": "swapData1", 78 | "type": "bytes", 79 | "internalType": "bytes" 80 | }, 81 | { 82 | "name": "minReward", 83 | "type": "uint256", 84 | "internalType": "uint256" 85 | }, 86 | { 87 | "name": "deadline", 88 | "type": "uint256", 89 | "internalType": "uint256" 90 | } 91 | ] 92 | } 93 | ], 94 | "outputs": [], 95 | "stateMutability": "nonpayable" 96 | }, 97 | { 98 | "type": "function", 99 | "name": "nonfungiblePositionManager", 100 | "inputs": [], 101 | "outputs": [ 102 | { 103 | "name": "", 104 | "type": "address", 105 | "internalType": "contract INonfungiblePositionManager" 106 | } 107 | ], 108 | "stateMutability": "view" 109 | }, 110 | { 111 | "type": "function", 112 | "name": "uniswapV3FlashCallback", 113 | "inputs": [ 114 | { 115 | "name": "fee0", 116 | "type": "uint256", 117 | "internalType": "uint256" 118 | }, 119 | { 120 | "name": "fee1", 121 | "type": "uint256", 122 | "internalType": "uint256" 123 | }, 124 | { 125 | "name": "callbackData", 126 | "type": "bytes", 127 | "internalType": "bytes" 128 | } 129 | ], 130 | "outputs": [], 131 | "stateMutability": "nonpayable" 132 | }, 133 | { 134 | "type": "function", 135 | "name": "uniswapV3SwapCallback", 136 | "inputs": [ 137 | { 138 | "name": "amount0Delta", 139 | "type": "int256", 140 | "internalType": "int256" 141 | }, 142 | { 143 | "name": "amount1Delta", 144 | "type": "int256", 145 | "internalType": "int256" 146 | }, 147 | { 148 | "name": "data", 149 | "type": "bytes", 150 | "internalType": "bytes" 151 | } 152 | ], 153 | "outputs": [], 154 | "stateMutability": "nonpayable" 155 | }, 156 | { 157 | "type": "function", 158 | "name": "universalRouter", 159 | "inputs": [], 160 | "outputs": [ 161 | { 162 | "name": "", 163 | "type": "address", 164 | "internalType": "address" 165 | } 166 | ], 167 | "stateMutability": "view" 168 | }, 169 | { 170 | "type": "function", 171 | "name": "weth", 172 | "inputs": [], 173 | "outputs": [ 174 | { 175 | "name": "", 176 | "type": "address", 177 | "internalType": "contract IWETH9" 178 | } 179 | ], 180 | "stateMutability": "view" 181 | }, 182 | { 183 | "type": "function", 184 | "name": "zeroxRouter", 185 | "inputs": [], 186 | "outputs": [ 187 | { 188 | "name": "", 189 | "type": "address", 190 | "internalType": "address" 191 | } 192 | ], 193 | "stateMutability": "view" 194 | }, 195 | { 196 | "type": "event", 197 | "name": "Swap", 198 | "inputs": [ 199 | { 200 | "name": "tokenIn", 201 | "type": "address", 202 | "indexed": true, 203 | "internalType": "address" 204 | }, 205 | { 206 | "name": "tokenOut", 207 | "type": "address", 208 | "indexed": true, 209 | "internalType": "address" 210 | }, 211 | { 212 | "name": "amountIn", 213 | "type": "uint256", 214 | "indexed": false, 215 | "internalType": "uint256" 216 | }, 217 | { 218 | "name": "amountOut", 219 | "type": "uint256", 220 | "indexed": false, 221 | "internalType": "uint256" 222 | } 223 | ], 224 | "anonymous": false 225 | }, 226 | { 227 | "type": "error", 228 | "name": "AmountError", 229 | "inputs": [] 230 | }, 231 | { 232 | "type": "error", 233 | "name": "ChainlinkPriceError", 234 | "inputs": [] 235 | }, 236 | { 237 | "type": "error", 238 | "name": "CollateralFactorExceedsMax", 239 | "inputs": [] 240 | }, 241 | { 242 | "type": "error", 243 | "name": "CollateralFail", 244 | "inputs": [] 245 | }, 246 | { 247 | "type": "error", 248 | "name": "CollateralValueLimit", 249 | "inputs": [] 250 | }, 251 | { 252 | "type": "error", 253 | "name": "CollectError", 254 | "inputs": [] 255 | }, 256 | { 257 | "type": "error", 258 | "name": "DailyDebtIncreaseLimit", 259 | "inputs": [] 260 | }, 261 | { 262 | "type": "error", 263 | "name": "DailyLendIncreaseLimit", 264 | "inputs": [] 265 | }, 266 | { 267 | "type": "error", 268 | "name": "DebtChanged", 269 | "inputs": [] 270 | }, 271 | { 272 | "type": "error", 273 | "name": "EtherSendFailed", 274 | "inputs": [] 275 | }, 276 | { 277 | "type": "error", 278 | "name": "ExceedsMaxReward", 279 | "inputs": [] 280 | }, 281 | { 282 | "type": "error", 283 | "name": "GlobalDebtLimit", 284 | "inputs": [] 285 | }, 286 | { 287 | "type": "error", 288 | "name": "GlobalLendLimit", 289 | "inputs": [] 290 | }, 291 | { 292 | "type": "error", 293 | "name": "InsufficientLiquidity", 294 | "inputs": [] 295 | }, 296 | { 297 | "type": "error", 298 | "name": "InterestNotUpdated", 299 | "inputs": [] 300 | }, 301 | { 302 | "type": "error", 303 | "name": "InvalidConfig", 304 | "inputs": [] 305 | }, 306 | { 307 | "type": "error", 308 | "name": "InvalidPool", 309 | "inputs": [] 310 | }, 311 | { 312 | "type": "error", 313 | "name": "InvalidToken", 314 | "inputs": [] 315 | }, 316 | { 317 | "type": "error", 318 | "name": "MinLoanSize", 319 | "inputs": [] 320 | }, 321 | { 322 | "type": "error", 323 | "name": "MissingSwapData", 324 | "inputs": [] 325 | }, 326 | { 327 | "type": "error", 328 | "name": "NeedsRepay", 329 | "inputs": [] 330 | }, 331 | { 332 | "type": "error", 333 | "name": "NoEtherToken", 334 | "inputs": [] 335 | }, 336 | { 337 | "type": "error", 338 | "name": "NoLiquidity", 339 | "inputs": [] 340 | }, 341 | { 342 | "type": "error", 343 | "name": "NoSharesRepayed", 344 | "inputs": [] 345 | }, 346 | { 347 | "type": "error", 348 | "name": "NotConfigured", 349 | "inputs": [] 350 | }, 351 | { 352 | "type": "error", 353 | "name": "NotEnoughReward", 354 | "inputs": [] 355 | }, 356 | { 357 | "type": "error", 358 | "name": "NotLiquidatable", 359 | "inputs": [] 360 | }, 361 | { 362 | "type": "error", 363 | "name": "NotReady", 364 | "inputs": [] 365 | }, 366 | { 367 | "type": "error", 368 | "name": "NotSupportedFeeTier", 369 | "inputs": [] 370 | }, 371 | { 372 | "type": "error", 373 | "name": "NotSupportedWhatToDo", 374 | "inputs": [] 375 | }, 376 | { 377 | "type": "error", 378 | "name": "NotWETH", 379 | "inputs": [] 380 | }, 381 | { 382 | "type": "error", 383 | "name": "PriceDifferenceExceeded", 384 | "inputs": [] 385 | }, 386 | { 387 | "type": "error", 388 | "name": "Reentrancy", 389 | "inputs": [] 390 | }, 391 | { 392 | "type": "error", 393 | "name": "SameRange", 394 | "inputs": [] 395 | }, 396 | { 397 | "type": "error", 398 | "name": "SameToken", 399 | "inputs": [] 400 | }, 401 | { 402 | "type": "error", 403 | "name": "SelfSend", 404 | "inputs": [] 405 | }, 406 | { 407 | "type": "error", 408 | "name": "SequencerDown", 409 | "inputs": [] 410 | }, 411 | { 412 | "type": "error", 413 | "name": "SequencerGracePeriodNotOver", 414 | "inputs": [] 415 | }, 416 | { 417 | "type": "error", 418 | "name": "SlippageError", 419 | "inputs": [] 420 | }, 421 | { 422 | "type": "error", 423 | "name": "SwapAmountTooLarge", 424 | "inputs": [] 425 | }, 426 | { 427 | "type": "error", 428 | "name": "SwapFailed", 429 | "inputs": [] 430 | }, 431 | { 432 | "type": "error", 433 | "name": "TWAPCheckFailed", 434 | "inputs": [] 435 | }, 436 | { 437 | "type": "error", 438 | "name": "TooMuchEtherSent", 439 | "inputs": [] 440 | }, 441 | { 442 | "type": "error", 443 | "name": "TransferError", 444 | "inputs": [] 445 | }, 446 | { 447 | "type": "error", 448 | "name": "TransformFailed", 449 | "inputs": [] 450 | }, 451 | { 452 | "type": "error", 453 | "name": "TransformNotAllowed", 454 | "inputs": [] 455 | }, 456 | { 457 | "type": "error", 458 | "name": "Unauthorized", 459 | "inputs": [] 460 | }, 461 | { 462 | "type": "error", 463 | "name": "WrongContract", 464 | "inputs": [] 465 | } 466 | ], 467 | "bytecode": { 468 | "object": "0x610120604081815234620001725760608262001e048038038091620000258285620001d7565b833981010312620001725781516001600160a01b03808216939190848203620001725760209062000065856200005d84870162000211565b950162000211565b9585516312a9293f60e21b81528381600481855afa908115620001cc57908492916000916200018a575b50926004931660805286519283809263c45a015560e01b82525afa9182156200017f576000926200013c575b505060a05260c05260e05261010091825251611bdd918262000227833960805182610dc0015260a0518281816101e201526107be015260c05182818161080301526108d8015260e051828181608e015281816113a30152611492015251818181610e0301528181611662015281816117a6015281816117db01526118750152f35b90809250813d831162000177575b620001568183620001d7565b8101031262000172576200016a9062000211565b3880620000bb565b600080fd5b503d6200014a565b85513d6000823e3d90fd5b83819492503d8311620001c4575b620001a48183620001d7565b810103126200017257600492620001bc859362000211565b90936200008f565b503d62000198565b87513d6000823e3d90fd5b601f909101601f19168101906001600160401b03821190821017620001fb57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620001725756fe608080604052600436101561001357600080fd5b600090813560e01c90816335a9e4df14610def575080633fc8cef314610daa578063b39cad6e14610832578063b44a2722146107ed578063c45a0155146107a8578063e9cbafb0146102a3578063fa461e33146100c05763faba44631461007957600080fd5b346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b80fd5b50346100bd5760603660031901126100bd576004356024356044356001600160401b03811161029f576100f7903690600401610e32565b92909184821393848015610296575b1561029257836060918101031261028e5761012083611066565b604061012e60208601611066565b94013562ffffff811680910361028a57604080516001600160a01b03938416968416928792909184918b9161016281610ebd565b828152826020820152015283881161027f575b50806040858082519561018787610ebd565b1695868652169384602082015201528183101561027b57604051916020830193845260408301526060820152606081526101c081610ed8565b519020604051602081019160ff60f81b83526bffffffffffffffffffffffff197f000000000000000000000000000000000000000000000000000000000000000060601b16602183015260358201527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460558201526055815261024281610ed8565b51902016330361026a5761025f93156102625750905b33906119ca565b80f35b905090610258565b6040516282b42960e81b8152600490fd5b8880fd5b879350915038610175565b8680fd5b8480fd5b8580fd5b50858213610106565b8380fd5b50346100bd5760603660031901126100bd576001600160401b036044358181116107a4576102d5903690600401610e32565b8101919060208184031261029f5780359082821161028e5701906101208284031261029f576040519261030784610e8e565b823584526020808401359085015260408301356001600160a01b038116810361029257604085015261033b60608401611066565b60608501526080830135828111610292578161035891850161107a565b608085015260a0830135908282116102925761037591840161107a565b60a084015260c08201356001600160a01b038116810361028e5760c084015260e08281013590840152610100918201359183019182526060830151604084015160208501516103d29290916001600160a01b03908116911661111f565b60018060a01b0360408401511683519060406080860151015193604060a087015101519051946040519360c085018581108782111761078e57604052845260208401526040830152306060830152604051928360208101109060208501111761078e5782866104ac9360206040960186528183526080810192835260a081019687528551968795869485936325908dc360e21b8552602060048601528051602486015260208101516044860152898101516064860152606060018060a01b039101511660848501525160c060a485015260e4840190610ffa565b905160c483015203925af1801561063a5761075f575b50606081015160408201516104e3916001600160a01b0391821691166111f5565b6104f060808201516112af565b50506104ff60a08201516112af565b505060608101516020820151610539916001600160a01b0316906105319061052b6024356004356110fc565b906110fc565b9033906119ca565b60808101515160608201516001600160a01b03918216911681036106d2575b5060a08101515160608201516001600160a01b0391821691168103610645575b5060608101516040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa90811561063a578391610603575b5060e082015181106105f157806105ca578280f35b606082015160c0909201516105eb926001600160a01b0391821691166119ca565b38808280f35b60405163193a582f60e31b8152600490fd5b90506020813d602011610632575b8161061e60209383610ef3565b8101031261062d5751386105b5565b600080fd5b3d9150610611565b6040513d85823e3d90fd5b6020602491604051928380926370a0823160e01b82523060048301525afa90811561063a5783916106a0575b5080156105785760a08201515160c083015161069a92916001600160a01b0391821691166119ca565b38610578565b90506020813d6020116106ca575b816106bb60209383610ef3565b8101031261062d575138610671565b3d91506106ae565b6020602491604051928380926370a0823160e01b82523060048301525afa90811561063a57839161072d575b5080156105585760808201515160c083015161072792916001600160a01b0391821691166119ca565b38610558565b90506020813d602011610757575b8161074860209383610ef3565b8101031261062d5751386106fe565b3d915061073b565b604090813d8311610787575b6107758183610ef3565b8101031261078357386104c2565b5080fd5b503d61076b565b634e487b7160e01b600052604160045260246000fd5b8280fd5b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346100bd57600319602036820112610783576001600160401b03600435116107835761012090600435360301126100bd57602460a06001600160a01b0361087d6004358401610e5f565b16604051928380926341a4eb5f60e11b82526004356004013560048301525afa908115610bf7578291610d75575b508015610d635760405163133f757160e31b815260048035810135908201529082906101809081846024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561063a5783928491610ca2575b506004945060206001600160a01b0361092d8735602401610e5f565b16604051968780926338d52e0f60e01b82525afa948515610c97578495610c57575b506004919060206001600160a01b0361096b8535604401610e5f565b1660405194858092630dfe168160e01b82525afa928315610c4c578593610c10575b5061099c602460043501610e5f565b936109ef6109b4608460043501600435600401610f53565b604051936109c185610e73565b6001600160a01b0390811685528a166020850152600435606401356040850152606084018990523691610fa0565b6080820152610a46610a0b60c460043501600435600401610f53565b60405194610a1886610e73565b6001600160a01b0390811686528a16602086015260043560a401356040860152606085018990523691610fa0565b608083015260405194610a5886610e8e565b60043560040135865283602087015260018060a01b0316604086015260018060a01b0387166060860152608085015260a08401523360c084015260e4600435013560e08401526101046004350135610100840152610b5a6040518094602080830152805160408301526020810151606083015260018060a01b03604082015116608083015260018060a01b0360608201511660a0830152610100610b26610b10608084015161012060c087015261016086019061101f565b60a0840151858203603f190160e087015261101f565b60c08301516001600160a01b03168483015260e083015161012085015291015161014083015203601f198101855284610ef3565b6001600160a01b03610b70600435604401610e5f565b16916001600160a01b0380821690871603610c095781955b6001600160a01b03918216911614610c02575b813b1561029f5783610bdc95604051968795869485936312439b2f60e21b855230600486015260248501526044840152608060648401526084830190610ffa565b03925af18015610bf757610bee575080f35b61025f90610eaa565b6040513d84823e3d90fd5b5082610b9b565b8495610b88565b9092506020813d602011610c44575b81610c2c60209383610ef3565b8101031261028e57610c3d90610f14565b913861098d565b3d9150610c1f565b6040513d87823e3d90fd5b919094506020823d602011610c8f575b81610c7460209383610ef3565b8101031261029f57610c87600492610f14565b94909161094f565b3d9150610c67565b6040513d86823e3d90fd5b809293508591503d8311610d5c575b610cbb8183610ef3565b810103126107835782516bffffffffffffffffffffffff81160361078357610ce560208401610f14565b50610cf260408401610f14565b90610cff60608501610f14565b91608085015162ffffff81160361029f57610d5461016086610d2560a060049901610f28565b50610d3260c08201610f28565b50610d3f60e08201610f36565b50610d4d6101408201610f36565b5001610f36565b509138610911565b503d610cb1565b604051636ef5bcdd60e11b8152600490fd5b905060a0813d60a011610da2575b81610d9060a09383610ef3565b810103126107835760600151386108ab565b3d9150610d83565b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9050346107835781600319360112610783577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9181601f8401121561062d578235916001600160401b03831161062d576020838186019501011161062d57565b356001600160a01b038116810361062d5790565b60a081019081106001600160401b0382111761078e57604052565b61012081019081106001600160401b0382111761078e57604052565b6001600160401b03811161078e57604052565b606081019081106001600160401b0382111761078e57604052565b608081019081106001600160401b0382111761078e57604052565b90601f801991011681019081106001600160401b0382111761078e57604052565b51906001600160a01b038216820361062d57565b51908160020b820361062d57565b51906fffffffffffffffffffffffffffffffff8216820361062d57565b903590601e198136030182121561062d57018035906001600160401b03821161062d5760200191813603831361062d57565b6001600160401b03811161078e57601f01601f191660200190565b929192610fac82610f85565b91610fba6040519384610ef3565b82948184528183011161062d578281602093846000960137010152565b60005b838110610fea5750506000910152565b8181015183820152602001610fda565b9060209161101381518092818552858086019101610fd7565b601f01601f1916010190565b9060a0608061106393600180841b03808251168552602082015116602085015260408101516040850152606081015160608501520151918160808201520190610ffa565b90565b35906001600160a01b038216820361062d57565b919060a08382031261062d576040519061109382610e73565b819361109e81611066565b83526110ac60208201611066565b602084015260408101356040840152606081013560608401526080810135906001600160401b03821161062d570181601f8201121561062d576080918160206110f793359101610fa0565b910152565b9190820180921161110957565b634e487b7160e01b600052601160045260246000fd5b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301529093906020908590604490829086165afa9384156111e9576000946111b3575b506111736111ac916111b1956110fc565b60405163095ea7b360e01b60208201526001600160a01b039094166024850152604484015282606481015b03601f198101845283610ef3565b611a03565b565b93506020843d6020116111e1575b816111ce60209383610ef3565b8101031261062d57925192611173611162565b3d91506111c1565b6040513d6000823e3d90fd5b60405163095ea7b360e01b60208201526001600160a01b039092166024830152600060448084019190915282526111b191906111ac82610ed8565b81601f8201121561062d57805161124681610f85565b926112546040519485610ef3565b8184526020828401011161062d576110639160208085019101610fd7565b3d1561129d573d9061128382610f85565b916112916040519384610ef3565b82523d6000602084013e565b606090565b9190820391821161110957565b60009160009160009060408101511515806119bc575b806119a6575b6112d3575050565b80516040516370a0823160e01b8152306004820152929550909350602090829060249082906001600160a01b03165afa9081156111e957600091611974575b506020838101516040516370a0823160e01b81523060048201529190829060249082906001600160a01b03165afa9081156111e957600091611942575b5060808401518051810160408282031261062d5760208201516001600160a01b038116929083900361062d576040810151916001600160401b03831161062d576113a0926020809201920101611230565b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681036116605750805181019060208183031261028a576020810151916001600160401b03831161165c57604083830182031261165c57604051928360408101106001600160401b0360408601111761078e57889260408501604052611434602083830101610f14565b855260408282010151926001600160401b03841161028e57849361146093602080930193010101611230565b602084019081528751845160408a01516114889290916001600160a01b03908116911661111f565b51602081519101827f00000000000000000000000000000000000000000000000000000000000000005af16114bb611272565b501561164a57845190516114db916001600160a01b0391821691166111f5565b83516040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa90811561163f57869161160c575b50611521906024936112a2565b6020858101516040516370a0823160e01b815230600482015292979294859182906001600160a01b03165afa90811561160057906115cc575b61156492506112a2565b91606081015183106115ba5760018060a01b0381511690602060018060a01b0391015116907ffa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe23560408051878152866020820152a3565b604051630d4205a160e11b8152600490fd5b506020823d6020116115f8575b816115e660209383610ef3565b8101031261062d57611564915161155a565b3d91506115d9565b604051903d90823e3d90fd5b90506020813d602011611637575b8161162760209383610ef3565b8101031261062d57516024611514565b3d915061161a565b6040513d88823e3d90fd5b60405163081ceff360e41b8152600490fd5b8780fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03160361193057805181019060208183031261062d5760208101516001600160401b03811161062d57606081830184031261062d57604051916116ca83610ebd565b602082820101516001600160401b03811161062d576116f3906020808701918585010101611230565b835260408282010151936001600160401b03851161062d5760208101603f868585010101121561062d57602085848401010151946001600160401b03861161078e578560051b906040519661174b6020840189610ef3565b87526020870160208401604084848989010101011161062d576040828787010101905b6040848489890101010182106118f757505050505060208301938452016060015160408083019182528751908801519192916117d4917f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03166119ca565b51915190517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b1561062d57604051630d64d59360e21b8152606060048201529290918391611830906064840190610ffa565b600319838203016024840152815180825260208201916020808360051b8301019401926000915b8383106118c4575050505060448301939093526000925081900381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156111e9576118b0575b506114db565b6118bb919550610eaa565b600093386118aa565b919396955091936020806118e4600193601f198682030187528a51610ffa565b9801930193019092879596949293611857565b8151906001600160401b03821161062d57602080916119238960408096898e878e019401010101611230565b815201920191905061176e565b604051630d348b9b60e41b8152600490fd5b90506020813d60201161196c575b8161195d60209383610ef3565b8101031261062d57513861134f565b3d9150611950565b90506020813d60201161199e575b8161198f60209383610ef3565b8101031261062d575138611312565b3d9150611982565b5060208101516001600160a01b031615156112cb565b5060808101515115156112c5565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526111b1916111ac826064810161119e565b60018060a01b03169060405160408101908082106001600160401b0383111761078e57611a74916040526020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af1611a6e611272565b91611b0a565b805191821591848315611ae6575b505050905015611a8f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312610783578201519081151582036100bd575080388084611a82565b91929015611b6c5750815115611b1e575090565b3b15611b275790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015611b7f5750805190602001fd5b60405162461bcd60e51b815260206004820152908190611ba3906024830190610ffa565b0390fdfea26469706673582212207a9023f0639847d419ff7dca88c0979c4c30383240150654fab5e2da56ab985764736f6c63430008180033", 469 | "sourceMap": "338:4325:68:-:0;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;1420:35:69;;;;;;;;;;;;;;;;;;-1:-1:-1;1420:35:69;;;-1:-1:-1;338:4325:68;;1420:35:69;338:4325:68;;1406:50:69;;338:4325:68;;;;;;;;;1476:37:69;;;;;;;;;-1:-1:-1;1476:37:69;;;-1:-1:-1;1466:47:69;;;;1523:56;;338:4325:68;1589:26:69;1625:34;;;;338:4325:68;;;;;;;1406:50:69;338:4325:68;;;;;1466:47:69;338:4325:68;;;;;;;;;;1523:56:69;338:4325:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1476:37:69;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325:68;;;;;;;:::i;:::-;1476:37:69;;;;338:4325:68;-1:-1:-1;338:4325:68;;1476:37:69;;;;;;338:4325:68;;;-1:-1:-1;338:4325:68;;;;;1420:35:69;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325:68;;;;1420:35:69;338:4325:68;;;;;:::i;:::-;1420:35:69;;;;;;;;;;338:4325:68;;;-1:-1:-1;338:4325:68;;;;;;;;;;-1:-1:-1;;338:4325:68;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;:::o", 470 | "linkReferences": {} 471 | }, 472 | "deployedBytecode": { 473 | "object": "0x608080604052600436101561001357600080fd5b600090813560e01c90816335a9e4df14610def575080633fc8cef314610daa578063b39cad6e14610832578063b44a2722146107ed578063c45a0155146107a8578063e9cbafb0146102a3578063fa461e33146100c05763faba44631461007957600080fd5b346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b80fd5b50346100bd5760603660031901126100bd576004356024356044356001600160401b03811161029f576100f7903690600401610e32565b92909184821393848015610296575b1561029257836060918101031261028e5761012083611066565b604061012e60208601611066565b94013562ffffff811680910361028a57604080516001600160a01b03938416968416928792909184918b9161016281610ebd565b828152826020820152015283881161027f575b50806040858082519561018787610ebd565b1695868652169384602082015201528183101561027b57604051916020830193845260408301526060820152606081526101c081610ed8565b519020604051602081019160ff60f81b83526bffffffffffffffffffffffff197f000000000000000000000000000000000000000000000000000000000000000060601b16602183015260358201527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460558201526055815261024281610ed8565b51902016330361026a5761025f93156102625750905b33906119ca565b80f35b905090610258565b6040516282b42960e81b8152600490fd5b8880fd5b879350915038610175565b8680fd5b8480fd5b8580fd5b50858213610106565b8380fd5b50346100bd5760603660031901126100bd576001600160401b036044358181116107a4576102d5903690600401610e32565b8101919060208184031261029f5780359082821161028e5701906101208284031261029f576040519261030784610e8e565b823584526020808401359085015260408301356001600160a01b038116810361029257604085015261033b60608401611066565b60608501526080830135828111610292578161035891850161107a565b608085015260a0830135908282116102925761037591840161107a565b60a084015260c08201356001600160a01b038116810361028e5760c084015260e08281013590840152610100918201359183019182526060830151604084015160208501516103d29290916001600160a01b03908116911661111f565b60018060a01b0360408401511683519060406080860151015193604060a087015101519051946040519360c085018581108782111761078e57604052845260208401526040830152306060830152604051928360208101109060208501111761078e5782866104ac9360206040960186528183526080810192835260a081019687528551968795869485936325908dc360e21b8552602060048601528051602486015260208101516044860152898101516064860152606060018060a01b039101511660848501525160c060a485015260e4840190610ffa565b905160c483015203925af1801561063a5761075f575b50606081015160408201516104e3916001600160a01b0391821691166111f5565b6104f060808201516112af565b50506104ff60a08201516112af565b505060608101516020820151610539916001600160a01b0316906105319061052b6024356004356110fc565b906110fc565b9033906119ca565b60808101515160608201516001600160a01b03918216911681036106d2575b5060a08101515160608201516001600160a01b0391821691168103610645575b5060608101516040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa90811561063a578391610603575b5060e082015181106105f157806105ca578280f35b606082015160c0909201516105eb926001600160a01b0391821691166119ca565b38808280f35b60405163193a582f60e31b8152600490fd5b90506020813d602011610632575b8161061e60209383610ef3565b8101031261062d5751386105b5565b600080fd5b3d9150610611565b6040513d85823e3d90fd5b6020602491604051928380926370a0823160e01b82523060048301525afa90811561063a5783916106a0575b5080156105785760a08201515160c083015161069a92916001600160a01b0391821691166119ca565b38610578565b90506020813d6020116106ca575b816106bb60209383610ef3565b8101031261062d575138610671565b3d91506106ae565b6020602491604051928380926370a0823160e01b82523060048301525afa90811561063a57839161072d575b5080156105585760808201515160c083015161072792916001600160a01b0391821691166119ca565b38610558565b90506020813d602011610757575b8161074860209383610ef3565b8101031261062d5751386106fe565b3d915061073b565b604090813d8311610787575b6107758183610ef3565b8101031261078357386104c2565b5080fd5b503d61076b565b634e487b7160e01b600052604160045260246000fd5b8280fd5b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346100bd57600319602036820112610783576001600160401b03600435116107835761012090600435360301126100bd57602460a06001600160a01b0361087d6004358401610e5f565b16604051928380926341a4eb5f60e11b82526004356004013560048301525afa908115610bf7578291610d75575b508015610d635760405163133f757160e31b815260048035810135908201529082906101809081846024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa801561063a5783928491610ca2575b506004945060206001600160a01b0361092d8735602401610e5f565b16604051968780926338d52e0f60e01b82525afa948515610c97578495610c57575b506004919060206001600160a01b0361096b8535604401610e5f565b1660405194858092630dfe168160e01b82525afa928315610c4c578593610c10575b5061099c602460043501610e5f565b936109ef6109b4608460043501600435600401610f53565b604051936109c185610e73565b6001600160a01b0390811685528a166020850152600435606401356040850152606084018990523691610fa0565b6080820152610a46610a0b60c460043501600435600401610f53565b60405194610a1886610e73565b6001600160a01b0390811686528a16602086015260043560a401356040860152606085018990523691610fa0565b608083015260405194610a5886610e8e565b60043560040135865283602087015260018060a01b0316604086015260018060a01b0387166060860152608085015260a08401523360c084015260e4600435013560e08401526101046004350135610100840152610b5a6040518094602080830152805160408301526020810151606083015260018060a01b03604082015116608083015260018060a01b0360608201511660a0830152610100610b26610b10608084015161012060c087015261016086019061101f565b60a0840151858203603f190160e087015261101f565b60c08301516001600160a01b03168483015260e083015161012085015291015161014083015203601f198101855284610ef3565b6001600160a01b03610b70600435604401610e5f565b16916001600160a01b0380821690871603610c095781955b6001600160a01b03918216911614610c02575b813b1561029f5783610bdc95604051968795869485936312439b2f60e21b855230600486015260248501526044840152608060648401526084830190610ffa565b03925af18015610bf757610bee575080f35b61025f90610eaa565b6040513d84823e3d90fd5b5082610b9b565b8495610b88565b9092506020813d602011610c44575b81610c2c60209383610ef3565b8101031261028e57610c3d90610f14565b913861098d565b3d9150610c1f565b6040513d87823e3d90fd5b919094506020823d602011610c8f575b81610c7460209383610ef3565b8101031261029f57610c87600492610f14565b94909161094f565b3d9150610c67565b6040513d86823e3d90fd5b809293508591503d8311610d5c575b610cbb8183610ef3565b810103126107835782516bffffffffffffffffffffffff81160361078357610ce560208401610f14565b50610cf260408401610f14565b90610cff60608501610f14565b91608085015162ffffff81160361029f57610d5461016086610d2560a060049901610f28565b50610d3260c08201610f28565b50610d3f60e08201610f36565b50610d4d6101408201610f36565b5001610f36565b509138610911565b503d610cb1565b604051636ef5bcdd60e11b8152600490fd5b905060a0813d60a011610da2575b81610d9060a09383610ef3565b810103126107835760600151386108ab565b3d9150610d83565b50346100bd57806003193601126100bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9050346107835781600319360112610783577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9181601f8401121561062d578235916001600160401b03831161062d576020838186019501011161062d57565b356001600160a01b038116810361062d5790565b60a081019081106001600160401b0382111761078e57604052565b61012081019081106001600160401b0382111761078e57604052565b6001600160401b03811161078e57604052565b606081019081106001600160401b0382111761078e57604052565b608081019081106001600160401b0382111761078e57604052565b90601f801991011681019081106001600160401b0382111761078e57604052565b51906001600160a01b038216820361062d57565b51908160020b820361062d57565b51906fffffffffffffffffffffffffffffffff8216820361062d57565b903590601e198136030182121561062d57018035906001600160401b03821161062d5760200191813603831361062d57565b6001600160401b03811161078e57601f01601f191660200190565b929192610fac82610f85565b91610fba6040519384610ef3565b82948184528183011161062d578281602093846000960137010152565b60005b838110610fea5750506000910152565b8181015183820152602001610fda565b9060209161101381518092818552858086019101610fd7565b601f01601f1916010190565b9060a0608061106393600180841b03808251168552602082015116602085015260408101516040850152606081015160608501520151918160808201520190610ffa565b90565b35906001600160a01b038216820361062d57565b919060a08382031261062d576040519061109382610e73565b819361109e81611066565b83526110ac60208201611066565b602084015260408101356040840152606081013560608401526080810135906001600160401b03821161062d570181601f8201121561062d576080918160206110f793359101610fa0565b910152565b9190820180921161110957565b634e487b7160e01b600052601160045260246000fd5b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301529093906020908590604490829086165afa9384156111e9576000946111b3575b506111736111ac916111b1956110fc565b60405163095ea7b360e01b60208201526001600160a01b039094166024850152604484015282606481015b03601f198101845283610ef3565b611a03565b565b93506020843d6020116111e1575b816111ce60209383610ef3565b8101031261062d57925192611173611162565b3d91506111c1565b6040513d6000823e3d90fd5b60405163095ea7b360e01b60208201526001600160a01b039092166024830152600060448084019190915282526111b191906111ac82610ed8565b81601f8201121561062d57805161124681610f85565b926112546040519485610ef3565b8184526020828401011161062d576110639160208085019101610fd7565b3d1561129d573d9061128382610f85565b916112916040519384610ef3565b82523d6000602084013e565b606090565b9190820391821161110957565b60009160009160009060408101511515806119bc575b806119a6575b6112d3575050565b80516040516370a0823160e01b8152306004820152929550909350602090829060249082906001600160a01b03165afa9081156111e957600091611974575b506020838101516040516370a0823160e01b81523060048201529190829060249082906001600160a01b03165afa9081156111e957600091611942575b5060808401518051810160408282031261062d5760208201516001600160a01b038116929083900361062d576040810151916001600160401b03831161062d576113a0926020809201920101611230565b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681036116605750805181019060208183031261028a576020810151916001600160401b03831161165c57604083830182031261165c57604051928360408101106001600160401b0360408601111761078e57889260408501604052611434602083830101610f14565b855260408282010151926001600160401b03841161028e57849361146093602080930193010101611230565b602084019081528751845160408a01516114889290916001600160a01b03908116911661111f565b51602081519101827f00000000000000000000000000000000000000000000000000000000000000005af16114bb611272565b501561164a57845190516114db916001600160a01b0391821691166111f5565b83516040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa90811561163f57869161160c575b50611521906024936112a2565b6020858101516040516370a0823160e01b815230600482015292979294859182906001600160a01b03165afa90811561160057906115cc575b61156492506112a2565b91606081015183106115ba5760018060a01b0381511690602060018060a01b0391015116907ffa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe23560408051878152866020820152a3565b604051630d4205a160e11b8152600490fd5b506020823d6020116115f8575b816115e660209383610ef3565b8101031261062d57611564915161155a565b3d91506115d9565b604051903d90823e3d90fd5b90506020813d602011611637575b8161162760209383610ef3565b8101031261062d57516024611514565b3d915061161a565b6040513d88823e3d90fd5b60405163081ceff360e41b8152600490fd5b8780fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03160361193057805181019060208183031261062d5760208101516001600160401b03811161062d57606081830184031261062d57604051916116ca83610ebd565b602082820101516001600160401b03811161062d576116f3906020808701918585010101611230565b835260408282010151936001600160401b03851161062d5760208101603f868585010101121561062d57602085848401010151946001600160401b03861161078e578560051b906040519661174b6020840189610ef3565b87526020870160208401604084848989010101011161062d576040828787010101905b6040848489890101010182106118f757505050505060208301938452016060015160408083019182528751908801519192916117d4917f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03166119ca565b51915190517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b1561062d57604051630d64d59360e21b8152606060048201529290918391611830906064840190610ffa565b600319838203016024840152815180825260208201916020808360051b8301019401926000915b8383106118c4575050505060448301939093526000925081900381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156111e9576118b0575b506114db565b6118bb919550610eaa565b600093386118aa565b919396955091936020806118e4600193601f198682030187528a51610ffa565b9801930193019092879596949293611857565b8151906001600160401b03821161062d57602080916119238960408096898e878e019401010101611230565b815201920191905061176e565b604051630d348b9b60e41b8152600490fd5b90506020813d60201161196c575b8161195d60209383610ef3565b8101031261062d57513861134f565b3d9150611950565b90506020813d60201161199e575b8161198f60209383610ef3565b8101031261062d575138611312565b3d9150611982565b5060208101516001600160a01b031615156112cb565b5060808101515115156112c5565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448201929092526111b1916111ac826064810161119e565b60018060a01b03169060405160408101908082106001600160401b0383111761078e57611a74916040526020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af1611a6e611272565b91611b0a565b805191821591848315611ae6575b505050905015611a8f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312610783578201519081151582036100bd575080388084611a82565b91929015611b6c5750815115611b1e575090565b3b15611b275790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015611b7f5750805190602001fd5b60405162461bcd60e51b815260206004820152908190611ba3906024830190610ffa565b0390fdfea26469706673582212207a9023f0639847d419ff7dca88c0979c4c30383240150654fab5e2da56ab985764736f6c63430008180033", 474 | "sourceMap": "338:4325:68:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;973:36:69;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;-1:-1:-1;;338:4325:68;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;:::i;:::-;6039:16:69;;;;;;:36;;;;;;338:4325:68;;;;6244:44:69;338:4325:68;6244:44:69;;;338:4325:68;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;931:15:52;;;927:56;;338:4325:68;;;;;;;;;;;;:::i;:::-;;;;;;;1000:51:52;;338:4325:68;1000:51:52;;338:4325:68;1000:51:52;338:4325:68;1421:23:52;;;338:4325:68;;;;;1702:43:52;338:4325:68;1702:43:52;;338:4325:68;;;;;;;;;;;;1702:43:52;;;;;:::i;:::-;338:4325:68;1692:54:52;;338:4325:68;;;1572:249:52;;241:66;;;;;;338:4325:68;241:66:52;6784:7:69;338:4325:68;241:66:52;;;;;;;;;338:4325:68;241:66:52;;;;338:4325:68;241:66:52;1572:249;;;;;:::i;:::-;338:4325:68;1537:306:52;;338:4325:68;6347:10:69;6302:55;6298:107;;6512:64;;;;;;;;6347:10;6512:64;;:::i;:::-;338:4325:68;;6512:64:69;;;;;;6298:107;338:4325:68;;-1:-1:-1;;;6380:14:69;;338:4325:68;;6380:14:69;338:4325:68;;;;927:56:52;948:35;;-1:-1:-1;948:35:52;-1:-1:-1;927:56:52;;;338:4325:68;;;;;;;;;;;;6039:36:69;6059:16;;;;6039:36;;338:4325:68;;;;;;;;;;;-1:-1:-1;;338:4325:68;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;:::i;:::-;3088:45;;;;338:4325;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3209:20;;338:4325;;-1:-1:-1;;;;;338:4325:68;;;;;3209:20;:::i;:::-;338:4325;;;;;;;;;;;;;;;;;3328:10;:19;338:4325;;;;;;3349:10;:19;338:4325;;;;;;;;;;;;;;;;;;;;;;;;3274:142;;338:4325;;3274:142;;338:4325;3378:4;338:4325;3274:142;;338:4325;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3274:142;;338:4325;;;;3274:142;;338:4325;;;;;;;;;;;;;;;3240:186;;338:4325;;3240:186;;338:4325;;;;;;;;3274:142;;338:4325;;;;;3274:142;;;338:4325;;;;;;;;;;;3274:142;;338:4325;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;3240:186;;;;;;;;;;338:4325;-1:-1:-1;338:4325:68;;;;;;;;3436:57;;-1:-1:-1;;;;;338:4325:68;;;;;3436:57;:::i;:::-;3524:23;338:4325;;;3536:10;3524:23;:::i;:::-;338:4325;;3557:23;338:4325;;;3569:10;3557:23;:::i;:::-;-1:-1:-1;;338:4325:68;;;;;;;;3721:36;;-1:-1:-1;;;;;338:4325:68;;3721:36;;3745:11;338:4325;;;;3745:11;:::i;:::-;3721:36;;:::i;:::-;3709:10;;3721:36;;:::i;:::-;338:4325;;;3851:10;338:4325;;;;;-1:-1:-1;;;;;338:4325:68;;;;;3851:32;;3847:248;;338:4325;-1:-1:-1;338:4325:68;;;4108:10;338:4325;;;;;-1:-1:-1;;;;;338:4325:68;;;;;4108:32;;4104:248;;338:4325;-1:-1:-1;338:4325:68;;;;;;-1:-1:-1;;;4385:35:68;;3378:4;338:4325;4385:35;;338:4325;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;4385:35;;;;;;;;;;;338:4325;;;;;;4438:24;;4434:87;;4538:12;4534:111;;338:4325;;;4534:111;338:4325;;;;;;;;;4622:7;;-1:-1:-1;;;;;338:4325:68;;;;;4622:7;:::i;:::-;4534:111;;338:4325;;;4434:87;338:4325;;-1:-1:-1;;;4489:17:68;;338:4325;;4489:17;4385:35;;;338:4325;4385:35;;338:4325;4385:35;;;;;;338:4325;4385:35;;;:::i;:::-;;;338:4325;;;;;4385:35;;;338:4325;;;;4385:35;;;-1:-1:-1;4385:35:68;;;338:4325;;;;;;;;;4104:248;338:4325;;;;;;;;;;;;4166:43;;3378:4;338:4325;4166:43;;338:4325;4166:43;;;;;;;;;;;4104:248;4227:12;;4223:119;4104:248;4223:119;338:4325;;;4282:10;338:4325;;;;;4319:7;;338:4325;-1:-1:-1;;;;;338:4325:68;;;;;4319:7;:::i;:::-;4223:119;4104:248;;4166:43;;;338:4325;4166:43;;338:4325;4166:43;;;;;;338:4325;4166:43;;;:::i;:::-;;;338:4325;;;;;4166:43;;;;;;-1:-1:-1;4166:43:68;;3847:248;338:4325;;;;;;;;;;;;3909:43;;3378:4;338:4325;3909:43;;338:4325;3909:43;;;;;;;;;;;3847:248;3970:12;;3966:119;3847:248;3966:119;338:4325;;;4025:10;338:4325;;;;;4062:7;;338:4325;-1:-1:-1;;;;;338:4325:68;;;;;4062:7;:::i;:::-;3966:119;3847:248;;3909:43;;;338:4325;3909:43;;338:4325;3909:43;;;;;;338:4325;3909:43;;;:::i;:::-;;;338:4325;;;;;3909:43;;;;;;-1:-1:-1;3909:43:68;;3240:186;338:4325;3240:186;;;;;;;;;;;;:::i;:::-;;;338:4325;;;;3240:186;;;338:4325;;;;3240:186;;;;;338:4325;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;778:32:69;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;;;861:71:69;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;-1:-1:-1;;338:4325:68;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;1776:12;:37;-1:-1:-1;;;;;1776:12:68;338:4325;;1776:12;;;:::i;:::-;338:4325;;;;;;;;;;1776:37;;338:4325;;;;;;1776:37;;338:4325;1776:37;;;;;;;338:4325;1776:37;;;338:4325;1827:20;;;1823:75;;338:4325;;-1:-1:-1;;;1954:52:68;;338:4325;;;;;;1954:52;;;338:4325;;;;1954:52;;;338:4325;1776:12;338:4325;1954:26;-1:-1:-1;;;;;338:4325:68;1954:52;;;;;;338:4325;;;1954:52;;;338:4325;-1:-1:-1;338:4325:68;;-1:-1:-1;338:4325:68;-1:-1:-1;;;;;2032:12:68;338:4325;;1776:12;;2032;:::i;:::-;338:4325;;;;;;;;;;2032:20;;;;;;;;;;;;;338:4325;-1:-1:-1;338:4325:68;;;;-1:-1:-1;;;;;2079:20:68;338:4325;;2079:20;;;:::i;:::-;338:4325;;;;;;;;;;2079:29;;;;;;;;;;;;;338:4325;;2271:12;1776;338:4325;;1776:12;2271;:::i;:::-;338:4325;;2401:16;;338:4325;;2401:16;338:4325;;;;2401:16;:::i;:::-;338:4325;;;;;;:::i;:::-;-1:-1:-1;;;;;338:4325:68;;;;;;;;2332:86;;338:4325;;;2380:16;;338:4325;;2332:86;;338:4325;2380:16;2332:86;;338:4325;;;;;;:::i;:::-;2401:16;2332:86;;338:4325;;2505:16;;338:4325;;2505:16;338:4325;;;;2505:16;:::i;:::-;338:4325;;;;;;:::i;:::-;-1:-1:-1;;;;;338:4325:68;;;;;;;;2436:86;;338:4325;;;2484:16;;338:4325;;2436:86;;338:4325;2380:16;2436:86;;338:4325;;;;;;:::i;:::-;2401:16;2436:86;;338:4325;;;;;;;:::i;:::-;;;;;;;;2171:460;338:4325;2171:460;;338:4325;;;;;;;;2171:460;;338:4325;;;;;;;;2380:16;2171:460;;338:4325;2401:16;2171:460;;338:4325;1776:37;2171:460;;338:4325;2540:10;2505:16;2171:460;;338:4325;2568:16;338:4325;;2568:16;338:4325;;2171:460;;338:4325;2602:15;338:4325;;2602:15;338:4325;2602:15;2171:460;;338:4325;2147:494;338:4325;;2147:494;;338:4325;2147:494;;;338:4325;;;;;;;;2171:460;;338:4325;2380:16;338:4325;;;;;;;;;2171:460;;338:4325;;2401:16;338:4325;;;;;;;;2380:16;2171:460;;338:4325;;1776:37;338:4325;;;2602:15;338:4325;;2401:16;2171:460;;338:4325;;2505:16;338:4325;;;;;;;;:::i;:::-;1776:37;2171:460;;338:4325;;;;-1:-1:-1;;338:4325:68;;;;;;:::i;:::-;2505:16;2171:460;;338:4325;-1:-1:-1;;;;;338:4325:68;;;;;;2171:460;;338:4325;;;;;2171:460;;338:4325;;;;;2147:494;-1:-1:-1;;2147:494:68;;;;;;:::i;:::-;-1:-1:-1;;;;;2651:20:68;338:4325;;2079:20;;2651;:::i;:::-;338:4325;;-1:-1:-1;;;;;338:4325:68;;;;;;2079:38;338:4325;;2693:30;;;-1:-1:-1;;;;;338:4325:68;;;;;2079:38;338:4325;;2725:31;2651:112;;;;;338:4325;;;;;;;;;;;;;;;2651:112;;2686:4;338:4325;2651:112;;338:4325;1776:12;338:4325;;;2079:20;338:4325;;;2401:16;2380;338:4325;;;2401:16;338:4325;;;;:::i;:::-;2651:112;;;;;;;;;;338:4325;;;2651:112;;;;:::i;:::-;338:4325;;;;;;;;;2725:31;;;;;2693:30;;;;;2079:29;;;;338:4325;2079:29;;338:4325;2079:29;;;;;;338:4325;2079:29;;;:::i;:::-;;;338:4325;;;;;;;:::i;:::-;2079:29;;;;;;;-1:-1:-1;2079:29:68;;;338:4325;;;;;;;;;2032:20;;;;;338:4325;2032:20;;338:4325;2032:20;;;;;;338:4325;2032:20;;;:::i;:::-;;;338:4325;;;;;;;;:::i;:::-;2032:20;;;;;;;;-1:-1:-1;2032:20:68;;;338:4325;;;;;;;;;1954:52;;;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;1776:37;338:4325;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::i;:::-;;1954:52;;;;;;;;;1823:75;338:4325;;-1:-1:-1;;;1870:17:68;;338:4325;;1870:17;1776:37;;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325;;;;;;;1776:37;;;;;;-1:-1:-1;1776:37:68;;338:4325;;;;;;;;;;;;;;;743:28:69;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;;1057:40:69;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;1776:37;338:4325;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;-1:-1:-1;;;;;338:4325:68;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;;;2147:494;;338:4325;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;338:4325:68;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;338:4325:68;;;;;;-1:-1:-1;;338:4325:68;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;338:4325:68;;;;;;:::o;:::-;;;;;;;;-1:-1:-1;;338:4325:68;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;338:4325:68;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;-1:-1:-1;;;;;338:4325:68;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;2582:280:15;338:4325:68;;-1:-1:-1;;;2701:39:15;;2725:4;2701:39;;;338:4325:68;-1:-1:-1;;;;;338:4325:68;;;;;;;;;2582:280:15;2701:39;;338:4325:68;;;;;;;;2701:39:15;;;;;;;-1:-1:-1;2701:39:15;;;2582:280;2833:20;;2777:77;2833:20;2777:77;2833:20;;:::i;:::-;338:4325:68;;-1:-1:-1;;;2701:39:15;2777:77;;;-1:-1:-1;;;;;338:4325:68;;;;2777:77:15;;338:4325:68;;;;;;;;;2777:77:15;;2147:494:68;;2777:77:15;;;;;;:::i;:::-;;:::i;:::-;2582:280::o;2701:39::-;;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325:68;;;;;;;2833:20:15;2701:39;;;;;-1:-1:-1;2701:39:15;;;338:4325:68;;;-1:-1:-1;338:4325:68;;;;;1818:573:15;338:4325:68;;-1:-1:-1;;;2321:62:15;;;;-1:-1:-1;;;;;338:4325:68;;;2321:62:15;;;338:4325:68;-1:-1:-1;338:4325:68;;;;;;;;2321:62:15;;;;338:4325:68;2321:62:15;338:4325:68;2321:62:15;:::i;338:4325:68:-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;338:4325:68;;;;:::o;:::-;;;:::o;:::-;;;;;;;;;;:::o;2325:2171:69:-;338:4325:68;2435:22:69;338:4325:68;2412:21:69;338:4325:68;2477:15:69;;;;338:4325:68;2477:20:69;;:51;;;2325:2171;2477:93;;;2325:2171;2473:2017;;2325:2171;;:::o;2473:2017::-;338:4325:68;;2477:15:69;338:4325:68;-1:-1:-1;;;2612:39:69;;2645:4;2612:39;;;338:4325:68;;;-1:-1:-1;338:4325:68;;-1:-1:-1;2612:39:69;;338:4325:68;;;;;;-1:-1:-1;;;;;338:4325:68;2612:39:69;;;;;;;338:4325:68;2612:39:69;;;2473:2017;-1:-1:-1;2612:39:69;2692:15;;;338:4325:68;2477:15:69;338:4325:68;-1:-1:-1;;;2692:40:69;;2645:4;2612:39;2692:40;;338:4325:68;;2612:39:69;338:4325:68;;;;;;-1:-1:-1;;;;;338:4325:68;2692:40:69;;;;;;;338:4325:68;2692:40:69;;;2473:2017;2847:15;;;;;338:4325:68;;2836:45:69;;2477:15;338:4325:68;;;;;;2612:39:69;2836:45;;338:4325:68;-1:-1:-1;;;;;338:4325:68;;;2836:45:69;338:4325:68;;;;;2477:15:69;338:4325:68;;;;-1:-1:-1;;;;;338:4325:68;;;;;2836:45:69;2612:39;2836:45;;;338:4325:68;;;;:::i;:::-;;2910:11:69;-1:-1:-1;;;;;338:4325:68;2900:21:69;;338:4325:68;;;;;2971:41:69;;338:4325:68;2612:39:69;338:4325:68;;;;;;2612:39:69;2971:41;;338:4325:68;;-1:-1:-1;;;;;338:4325:68;;;;2477:15:69;338:4325:68;;;;;;;;2477:15:69;338:4325:68;;;2477:15:69;338:4325:68;;;-1:-1:-1;;;;;2477:15:69;338:4325:68;;;;;;;;2477:15:69;338:4325:68;;2477:15:69;338:4325:68;;2612:39:69;338:4325:68;;;;;:::i;:::-;;;2477:15:69;338:4325:68;;;;;;-1:-1:-1;;;;;338:4325:68;;;;2971:41:69;;338:4325:68;2971:41:69;2612:39;2971:41;;;338:4325:68;;;;;:::i;:::-;2612:39:69;338:4325:68;;;;;;;;;2477:15:69;;;338:4325:68;3141:15:69;;338:4325:68;;-1:-1:-1;;;;;338:4325:68;;;;;3141:15:69;:::i;:::-;3242:9;2612:39;3225:27;;;;2910:11;;3225:27;;;;:::i;:::-;;3274:8;3270:74;;338:4325:68;;;;3395:62:69;;-1:-1:-1;;;;;338:4325:68;;;;;3395:62:69;:::i;:::-;338:4325:68;;2477:15:69;338:4325:68;-1:-1:-1;;;4034:39:69;;2645:4;2612:39;4034;;338:4325:68;;2612:39:69;;338:4325:68;;;;;;-1:-1:-1;;;;;338:4325:68;4034:39:69;;;;;;;;;;;2896:1090;4016:57;;;338:4325:68;4016:57:69;;:::i;:::-;2612:39;2692:15;;;338:4325:68;2477:15:69;338:4325:68;-1:-1:-1;;;4104:40:69;;2645:4;2612:39;4104:40;;338:4325:68;;;;;;;;;-1:-1:-1;;;;;338:4325:68;4104:40:69;;;;;;;;;;2896:1090;4104:59;;;;:::i;:::-;4239:19;;;;338:4325:68;4222:36:69;;4218:97;;338:4325:68;;;;;;;;;2612:39:69;338:4325:68;;;;;2692:15:69;;338:4325:68;;;4393:86:69;2477:15;338:4325:68;;;;;;2612:39:69;338:4325:68;;;4393:86:69;2325:2171::o;4218:97::-;2477:15;338:4325:68;-1:-1:-1;;;4285:15:69;;2612:39;;4285:15;4104:40;;2612:39;4104:40;;2612:39;4104:40;;;;;;2612:39;4104:40;;;:::i;:::-;;;338:4325:68;;;;4104:59:69;338:4325:68;;4104:40:69;;;;;-1:-1:-1;4104:40:69;;;2477:15;338:4325:68;;;;;;;;;4034:39:69;;;2612;4034;;2612;4034;;;;;;2612;4034;;;:::i;:::-;;;338:4325:68;;;;;;4034:39:69;;;;;-1:-1:-1;4034:39:69;;;2477:15;338:4325:68;;;;;;;;3270:74:69;2477:15;338:4325:68;-1:-1:-1;;;3313:12:69;;2612:39;;3313:12;338:4325:68;;;;2896:1090:69;3492:15;-1:-1:-1;;;;;338:4325:68;3482:25:69;338:4325:68;;;;3561:45:69;;338:4325:68;2612:39:69;338:4325:68;;;;;;2612:39:69;3561:45;;338:4325:68;-1:-1:-1;;;;;338:4325:68;;;;;;;;;;;;;2477:15:69;338:4325:68;;;;;:::i;:::-;2612:39:69;338:4325:68;;;;;-1:-1:-1;;;;;338:4325:68;;;;;3561:45:69;2612:39;3561:45;;;338:4325:68;;;;;;;:::i;:::-;;;2477:15:69;338:4325:68;;;;;;-1:-1:-1;;;;;338:4325:68;;;;2612:39:69;3561:45;;338:4325:68;;;;;;;;;;;2612:39:69;338:4325:68;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;;;;2477:15:69;338:4325:68;;;2612:39:69;338:4325:68;;;;:::i;:::-;;;2612:39:69;338:4325:68;;2612:39:69;3561:45;;2477:15;338:4325:68;;;;;;;;;;;2477:15:69;338:4325:68;;;;;;;;2477:15:69;338:4325:68;;;;;;;;;;;;-1:-1:-1;;;;;2612:39:69;338:4325:68;;;;;;;;;2477:15:69;338:4325:68;;;;;;;;2477:15:69;;;338:4325:68;;;;3792:15:69;;3492;;-1:-1:-1;;;;;338:4325:68;3792:15:69;:::i;:::-;3868:13;3883:11;;338:4325:68;;3492:15:69;-1:-1:-1;;;;;338:4325:68;3826:84:69;;;;2477:15;338:4325:68;-1:-1:-1;;;3826:84:69;;338:4325:68;2612:39:69;3826:84;;338:4325:68;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2612:39:69;338:4325:68;;;2612:39:69;338:4325:68;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;338:4325:68;;;;;;;;;-1:-1:-1;3826:84:69;;;338:4325:68;;3492:15:69;-1:-1:-1;;;;;338:4325:68;3826:84:69;;;;;;;;338:4325:68;3478:508:69;2896:1090;;3826:84;;;;;;:::i;:::-;338:4325:68;3826:84:69;;;;338:4325:68;2147:494;;;;;;;2612:39:69;2147:494:68;338:4325;;2147:494;;;338:4325;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;2612:39:69;3561:45;;338:4325:68;3561:45:69;2477:15;3561:45;;;;;;;338:4325:68;;;;;;:::i;:::-;;;;;;;;;;;3478:508:69;2477:15;338:4325:68;-1:-1:-1;;;3956:15:69;;2612:39;;3956:15;2692:40;;;2612:39;2692:40;;2612:39;2692:40;;;;;;2612:39;2692:40;;;:::i;:::-;;;338:4325:68;;;;;2692:40:69;;;;;;-1:-1:-1;2692:40:69;;2612:39;;;;;;;;;;;;;;;;;:::i;:::-;;;338:4325:68;;;;;2612:39:69;;;;;;-1:-1:-1;2612:39:69;;2477:93;-1:-1:-1;2540:15:69;;;338:4325:68;-1:-1:-1;;;;;338:4325:68;2532:38:69;;2477:93;;:51;2501:15;;;;;338:4325:68;2501:27:69;;2477:51;;941:175:15;338:4325:68;;-1:-1:-1;;;1050:58:15;;;;-1:-1:-1;;;;;338:4325:68;;;1050:58:15;;;338:4325:68;;;;;;;;1050:58:15;;;338:4325:68;;;;1050:58:15;338:4325:68;5196:642:15;338:4325:68;;;;;;;;;;;;;;;;-1:-1:-1;;;;;338:4325:68;;;;;5535:69:20;338:4325:68;;;;;;;;;;;;;-1:-1:-1;5487:31:20;;;;;;;;;;;;;;:::i;:::-;5535:69;;:::i;:::-;338:4325:68;;5728:22:15;;;:56;;;;;;5196:642;338:4325:68;;;;;;;;5196:642:15;:::o;338:4325:68:-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;338:4325:68;;;;;5728:56:15;5754:30;;;;;;;338:4325:68;;;;5754:30:15;;338:4325:68;;;;;;;;;5728:56:15;;;;;;;7671:628:20;;;;7875:418;;;338:4325:68;;;7906:22:20;7902:286;;8201:17;;:::o;7902:286::-;1702:19;:23;338:4325:68;;8201:17:20;:::o;338:4325:68:-;;;-1:-1:-1;;;338:4325:68;;;;;;;;;;;;;;;;;;;;7875:418:20;338:4325:68;;;;-1:-1:-1;8980:21:20;:17;;9152:142;;;;;;;8976:379;338:4325:68;;-1:-1:-1;;;9324:20:20;;338:4325:68;9324:20:20;;;338:4325:68;;;;;;;;;;;:::i;:::-;9324:20:20;;", 475 | "linkReferences": {}, 476 | "immutableReferences": { 477 | "38658": [ 478 | { 479 | "start": 3520, 480 | "length": 32 481 | } 482 | ], 483 | "38660": [ 484 | { 485 | "start": 482, 486 | "length": 32 487 | }, 488 | { 489 | "start": 1982, 490 | "length": 32 491 | } 492 | ], 493 | "38664": [ 494 | { 495 | "start": 2051, 496 | "length": 32 497 | }, 498 | { 499 | "start": 2264, 500 | "length": 32 501 | } 502 | ], 503 | "38667": [ 504 | { 505 | "start": 142, 506 | "length": 32 507 | }, 508 | { 509 | "start": 5027, 510 | "length": 32 511 | }, 512 | { 513 | "start": 5266, 514 | "length": 32 515 | } 516 | ], 517 | "38670": [ 518 | { 519 | "start": 3587, 520 | "length": 32 521 | }, 522 | { 523 | "start": 5730, 524 | "length": 32 525 | }, 526 | { 527 | "start": 6054, 528 | "length": 32 529 | }, 530 | { 531 | "start": 6107, 532 | "length": 32 533 | }, 534 | { 535 | "start": 6261, 536 | "length": 32 537 | } 538 | ] 539 | } 540 | }, 541 | "methodIdentifiers": { 542 | "factory()": "c45a0155", 543 | "liquidate((uint256,address,address,uint256,bytes,uint256,bytes,uint256,uint256))": "b39cad6e", 544 | "nonfungiblePositionManager()": "b44a2722", 545 | "uniswapV3FlashCallback(uint256,uint256,bytes)": "e9cbafb0", 546 | "uniswapV3SwapCallback(int256,int256,bytes)": "fa461e33", 547 | "universalRouter()": "35a9e4df", 548 | "weth()": "3fc8cef3", 549 | "zeroxRouter()": "faba4463" 550 | }, 551 | "rawMetadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract INonfungiblePositionManager\",\"name\":\"_nonfungiblePositionManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroxRouter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_universalRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AmountError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainlinkPriceError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CollateralFactorExceedsMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CollateralFail\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CollateralValueLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CollectError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DailyDebtIncreaseLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DailyLendIncreaseLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DebtChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EtherSendFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExceedsMaxReward\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GlobalDebtLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GlobalLendLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InterestNotUpdated\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPool\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MinLoanSize\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MissingSwapData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NeedsRepay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoEtherToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoSharesRepayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotConfigured\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughReward\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotLiquidatable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotReady\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSupportedFeeTier\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSupportedWhatToDo\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotWETH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PriceDifferenceExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrancy\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SameRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SameToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SelfSend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SequencerDown\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SequencerGracePeriodNotOver\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SlippageError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SwapAmountTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SwapFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TWAPCheckFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooMuchEtherSent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransformFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransformNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongContract\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenIn\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenOut\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"contract IVault\",\"name\":\"vault\",\"type\":\"address\"},{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"flashLoanPool\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0In\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"swapData0\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount1In\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"swapData1\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"minReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct FlashloanLiquidator.LiquidateParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"liquidate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonfungiblePositionManager\",\"outputs\":[{\"internalType\":\"contract INonfungiblePositionManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fee0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fee1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"uniswapV3FlashCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"amount0Delta\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1Delta\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"uniswapV3SwapCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"universalRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contract IWETH9\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zeroxRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"uniswapV3SwapCallback(int256,int256,bytes)\":{\"details\":\"In the implementation you must pay the pool tokens owed for the swap. The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\",\"params\":{\"amount0Delta\":\"The amount of token0 that was sent (negative) or must be received (positive) by the pool by the end of the swap. If positive, the callback must send that amount of token0 to the pool.\",\"amount1Delta\":\"The amount of token1 that was sent (negative) or must be received (positive) by the pool by the end of the swap. If positive, the callback must send that amount of token1 to the pool.\",\"data\":\"Any data passed through by the caller via the IUniswapV3PoolActions#swap call\"}}},\"title\":\"Helper contract which allows atomic liquidation and needed swaps by using UniV3 Flashloan\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"liquidate((uint256,address,address,uint256,bytes,uint256,bytes,uint256,uint256))\":{\"notice\":\"Liquidates a loan, using a Uniswap Flashloan\"},\"nonfungiblePositionManager()\":{\"notice\":\"Uniswap v3 position manager\"},\"uniswapV3SwapCallback(int256,int256,bytes)\":{\"notice\":\"Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\"},\"universalRouter()\":{\"notice\":\"Uniswap Universal Router\"},\"weth()\":{\"notice\":\"Wrapped native token address\"},\"zeroxRouter()\":{\"notice\":\"0x Exchange Proxy\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/utils/FlashloanLiquidator.sol\":\"FlashloanLiquidator\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/=lib/openzeppelin-contracts/\",\":@uniswap/v3-core/=lib/v3-core/\",\":@uniswap/v3-periphery/=lib/v3-periphery/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts/contracts/\",\":permit2/=lib/permit2/src/\",\":solmate/=lib/permit2/lib/solmate/\",\":v3-core/=lib/v3-core/contracts/\",\":v3-periphery/=lib/v3-periphery/contracts/\"],\"viaIR\":true},\"sources\":{\"lib/IUniversalRouter.sol\":{\"keccak256\":\"0x691be9a0799db6471dc3bcc2ab3a09561abee9aaf9bb101f4218a4ebc91b6c24\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://9774a25af801bd0b705cd822cad21853e44be23240ddfea06b7c2e1908e875fa\",\"dweb:/ipfs/QmUziX5YqD6ydKdAVoiDHHW6S94fBFmQTZNhLSgw3mTsbs\"]},\"lib/IWETH9.sol\":{\"keccak256\":\"0x4e71fe456302668ba3537e382ae094e352fc972e5ef5c42810c5ecb8ea7d62a4\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://10890c34cc2a0592abec494be675ed9b06610d29cdcc784d08de16017b8a9cb7\",\"dweb:/ipfs/QmdQ3G3RJx2SaJZCrkVzP9bBtifS9W8cAzx1HDkeGiKo1U\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol\":{\"keccak256\":\"0x5a173dcd1c1f0074e4df6a9cdab3257e17f2e64f7b8f30ca9e17a8c5ea250e1c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7883819ce2b72264a756063ae578661f62b23f4104b08e9565ac075e619f6ce3\",\"dweb:/ipfs/QmcSZdFiEQkWRmZQhnCdfH9ychooV81pBjr7hfaiYiNZT2\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5\",\"dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5a376d3dda2cb70536c0a45c208b29b34ac560c4cb4f513a42079f96ba47d2dd\",\"dweb:/ipfs/QmZQg6gn1sUpM8wHzwNvSnihumUCAhxD119MpXeKp8B9s8\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"keccak256\":\"0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://28879d01fd22c07b44f006612775f8577defbe459cb01685c5e25cd518c91a71\",\"dweb:/ipfs/QmVgfkwv2Fxw6hhTcDUZhE7NkoSKjab3ipM7UaRbt6uXb5\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol\":{\"keccak256\":\"0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9d213d3befca47da33f6db0310826bcdb148299805c10d77175ecfe1d06a9a68\",\"dweb:/ipfs/QmRgCn6SP1hbBkExUADFuDo8xkT4UU47yjNF5FhCeRbQmS\"]},\"lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol\":{\"keccak256\":\"0x5bce51e11f7d194b79ea59fe00c9e8de9fa2c5530124960f29a24d4c740a3266\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7e66dfde185df46104c11bc89d08fa0760737aa59a2b8546a656473d810a8ea4\",\"dweb:/ipfs/QmXvyqtXPaPss2PD7eqPoSao5Szm2n6UMoiG8TZZDjmChR\"]},\"lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol\":{\"keccak256\":\"0xd1556954440b31c97a142c6ba07d5cade45f96fafd52091d33a14ebe365aecbf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26fef835622b46a5ba08b3ef6b46a22e94b5f285d0f0fb66b703bd30217d2c34\",\"dweb:/ipfs/QmZ548qdwfL1qF7aXz3xh1GCdTiST81kGGuKRqVUfYmPZR\"]},\"lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol\":{\"keccak256\":\"0x75b829ff2f26c14355d1cba20e16fe7b29ca58eb5fef665ede48bc0f9c6c74b9\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a0a107160525724f9e1bbbab031defc2f298296dd9e331f16a6f7130cec32146\",\"dweb:/ipfs/QmemujxSd7gX8A9M8UwmNbz4Ms3U9FG9QfudUgxwvTmPWf\"]},\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931\",\"dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm\"]},\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://be161e54f24e5c6fae81a12db1a8ae87bc5ae1b0ddc805d82a1440a68455088f\",\"dweb:/ipfs/QmP7C3CHdY9urF4dEMb9wmsp1wMxHF6nhA2yQE5SKiPAdy\"]},\"lib/v3-core/contracts/interfaces/IUniswapV3Pool.sol\":{\"keccak256\":\"0x4e64844c56061cd90e0a80de73534a9166704c43eed579eb83f90bc2780ce968\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://cba4fab5cebdddf644b901994a7f0f52b98885d4c56012f4dc51d52c2bf9de0e\",\"dweb:/ipfs/QmVyyrRmqXrAiapewWunRVgiPVFJHpH2hKiE1py1svMSNV\"]},\"lib/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol\":{\"keccak256\":\"0x151ba1777392771025f0fca946c95fbc16ec4b5eff05e1f236115b99bd574de2\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://738a50c25d9d26ca3fabb1865bf6a0cdd8d7a2eec9dbfbd1fc000c81fb8e2b5e\",\"dweb:/ipfs/QmQjgCiLhrq5eLJgQcVHV24MRHyf6YdVzrGH8Ms7LnSSRA\"]},\"lib/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol\":{\"keccak256\":\"0x3f485fb1a44e8fbeadefb5da07d66edab3cfe809f0ac4074b1e54e3eb3c4cf69\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://095ce0626b41318c772b3ebf19d548282607f6a8f3d6c41c13edfbd5370c8652\",\"dweb:/ipfs/QmVDZfJJ89UUCE1hMyzqpkZAtQ8jUsBgZNE5AMRG7RzRFS\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol\":{\"keccak256\":\"0x9453dd0e7442188667d01d9b65de3f1e14e9511ff3e303179a15f6fc267f7634\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://982f4328f956c3e60e67501e759eb292ac487f76460c774c50e9ae4fcc92aae5\",\"dweb:/ipfs/QmRnzEDsaqtd9PJEVcgQi7p5aV5pMSvRUoGZJAdwFUJxgZ\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol\":{\"keccak256\":\"0xe603ac5b17ecdee73ba2b27efdf386c257a19c14206e87eee77e2017b742d9e5\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://8febc9bdb399a4d94bb89f5377732652e2400e4a8dee808201ade6848f9004e7\",\"dweb:/ipfs/QmaKDqYYFU4d2W2iN77aDHptfbFmYZRrMYXHeGpJmM8C1c\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolErrors.sol\":{\"keccak256\":\"0xf80abf13fb1fafc127ba4e792f240dd8ea7c8c893978cdfd8439c27fae9a037b\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://b04fc72a656bbf3631e9c2e67b9870a2d9d235185e833fe050e9606e6816a9aa\",\"dweb:/ipfs/QmUcz4bkEkJ9pwzFu1C3n97hBQ3st9U6qTAqCdyFwddKco\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol\":{\"keccak256\":\"0x8071514d0fe5d17d6fbd31c191cdfb703031c24e0ece3621d88ab10e871375cd\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://d0b571930cc7488b1d546a7e9cea7c52d8b3c4e207da657ed0e0db7343b8cd03\",\"dweb:/ipfs/QmaGK6vVwB95QSTR1XMYvrh7ivYAYZxi3fD7v6VMA4jZ39\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol\":{\"keccak256\":\"0xf6e5d2cd1139c4c276bdbc8e1d2b256e456c866a91f1b868da265c6d2685c3f7\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://b99c8c9ae8e27ee6559e5866bea82cbc9ffc8247f8d15b7422a4deb287d4d047\",\"dweb:/ipfs/QmfL8gaqt3ffAnm6nVj5ksuNpLygXuL3xq5VBqrkwC2JJ3\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol\":{\"keccak256\":\"0x759b78a2918af9e99e246dc3af084f654e48ef32bb4e4cb8a966aa3dcaece235\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://64144fb96e1c7fdba87305acadb98a198d26a3d46c097cb3a666e567f6f29735\",\"dweb:/ipfs/QmUnWVwN9FKB9uV5Pr8YfLpWZnYM2DENnRMaadZ492JS9u\"]},\"lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol\":{\"keccak256\":\"0x44fa2ce1182f6c2f6bead3d1737804bf7e112252ae86e0f2e92f9b8249603f43\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://54154e8665b98d65f5dc91b256551852cb47882180b501b260657122d207c0ea\",\"dweb:/ipfs/QmcfemK1A2PXYrWB5SBFGERpMCderbFRb8BtTzQDj1sUBp\"]},\"lib/v3-core/contracts/libraries/TickMath.sol\":{\"keccak256\":\"0x5c57de03a91cc2ec8939865dbbcb0197bb6c353b711075eefd8e0fca5e102129\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://1e994c24fd891ef8a3f5dbf5eba42b34feaf05e0376a29f91322faa18054449c\",\"dweb:/ipfs/QmNdUJGUQxd1dPkMbnA5f5UNqakxRkQE5r7bTZJAuHeapS\"]},\"lib/v3-periphery/contracts/interfaces/IERC721Permit.sol\":{\"keccak256\":\"0x9e3c2a4ee65ddf95b2dfcb0815784eea3a295707e6f8b83e4c4f0f8fe2e3a1d4\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://bfd939085b3618101b955f87c7fabf38338ba1aad480295acb8102ebc5d72471\",\"dweb:/ipfs/QmauQD8bGDHTztmTDfaKXjzM7Wacrq2XU7VcTbwn1WrDBL\"]},\"lib/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol\":{\"keccak256\":\"0x3357b065654abb7f4a9ebd184a260bc39efde2afa4e99dca2e72ffc28e9c2984\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://f7682dab014724be8e0a5a401b047788ff9c70b77fa5bd567ea6adc333cb3b56\",\"dweb:/ipfs/QmatH1Gc6z3AkP4dHjAEBKfCBbgBfD4vCceF4TuZU2bCyW\"]},\"lib/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol\":{\"keccak256\":\"0x7affcfeb5127c0925a71d6a65345e117c33537523aeca7bc98085ead8452519d\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://e16b291294210e71cb0f20cd0afe62ae2dc6878d627f5ccc19c4dc9cd80aec3f\",\"dweb:/ipfs/QmQGitSyBr26nour81BZmpmDMyJpvZRqHQZvnCD1Acb127\"]},\"lib/v3-periphery/contracts/interfaces/IPeripheryPayments.sol\":{\"keccak256\":\"0xb547e10f1e69bed03621a62b73a503e260643066c6b4054867a4d1fef47eb274\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://f9a90f58f5fd5fb42f7811f4094113b532f307b14a73764c91f977590747f407\",\"dweb:/ipfs/QmSeNH2mfiDMKf3Q6V2sqtNxx1s72JNuA1VVxRM9HoMqYp\"]},\"lib/v3-periphery/contracts/interfaces/IPoolInitializer.sol\":{\"keccak256\":\"0x9d7695e8d94c22cc5fcced602017aabb988de89981ea7bee29ea629d5328a862\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://61b50933026ee1017db2a6273af8cedc3238c95dca58880db0918dbdbb2f064f\",\"dweb:/ipfs/QmUebR26pqG25d18aBELKz8aFFKkmHa8PxntzXTA7o9Ldu\"]},\"lib/v3-periphery/contracts/libraries/PoolAddress.sol\":{\"keccak256\":\"0x4703d506f590554af23e6e01e0412c88f9eff7410205d9af639b3559cc4f9a05\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://cb0eac1c44d1bebb3d20c5068d737781a138526172af762b0a77b60987ec4145\",\"dweb:/ipfs/QmT5xmY46qJAXvuhDuWHxgiWf56ccGdNbUAeeQWuP3W4zk\"]},\"src/interfaces/IVault.sol\":{\"keccak256\":\"0x5528dd33982194427e7cfaab96d1e8b5ca7029111a486ba480b105599228f5a2\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://9b736d96ce763f8ebb183366f86c0e81849586977a904b6a6d1ffd977117fd80\",\"dweb:/ipfs/QmNdckQwYm9v8q8Ffb6zsW4b2YFSHRkhkRXgSmnHLvtHGh\"]},\"src/utils/Constants.sol\":{\"keccak256\":\"0xba47fb0107342763f81343be1870cddb125ce71aad80a578b66350017f1a6737\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://3bcb51a5b6b7baa1e2015b145e0e1d4719e0b43d682118c9b0b6447fee79870a\",\"dweb:/ipfs/QmRLFFNdNGp6g6b53XQQ9GW6Ysrqu1Txr5cscW44putCaU\"]},\"src/utils/FlashloanLiquidator.sol\":{\"keccak256\":\"0x8e1ce351ea57fbd987e24be160887f89df5f3f44170646a3d32d35ba61061613\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://f5c939d1a12478e1968048ee6b8232c4541491e55380272ece016a749d0aa054\",\"dweb:/ipfs/QmZgCZLndfvKMQUbf3JwxsHVYC2Q5aF6TfNpNXdjqFKk5q\"]},\"src/utils/Swapper.sol\":{\"keccak256\":\"0x961aa3526b288b59451eadc75b2b051323d1689a3b141d058ec06017c65be98e\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://8004f4f0db0f93d48e6a7c166c1a7c314f64b0e16d4b61f93ad5dfe07e16f2d2\",\"dweb:/ipfs/QmSus6pZoPYZBud3rZ2KxMJNGZgXi8kCcjeQaWmMptn4UV\"]}},\"version\":1}", 552 | "metadata": { 553 | "compiler": { 554 | "version": "0.8.24+commit.e11b9ed9" 555 | }, 556 | "language": "Solidity", 557 | "output": { 558 | "abi": [ 559 | { 560 | "inputs": [ 561 | { 562 | "internalType": "contract INonfungiblePositionManager", 563 | "name": "_nonfungiblePositionManager", 564 | "type": "address" 565 | }, 566 | { 567 | "internalType": "address", 568 | "name": "_zeroxRouter", 569 | "type": "address" 570 | }, 571 | { 572 | "internalType": "address", 573 | "name": "_universalRouter", 574 | "type": "address" 575 | } 576 | ], 577 | "stateMutability": "nonpayable", 578 | "type": "constructor" 579 | }, 580 | { 581 | "inputs": [], 582 | "type": "error", 583 | "name": "AmountError" 584 | }, 585 | { 586 | "inputs": [], 587 | "type": "error", 588 | "name": "ChainlinkPriceError" 589 | }, 590 | { 591 | "inputs": [], 592 | "type": "error", 593 | "name": "CollateralFactorExceedsMax" 594 | }, 595 | { 596 | "inputs": [], 597 | "type": "error", 598 | "name": "CollateralFail" 599 | }, 600 | { 601 | "inputs": [], 602 | "type": "error", 603 | "name": "CollateralValueLimit" 604 | }, 605 | { 606 | "inputs": [], 607 | "type": "error", 608 | "name": "CollectError" 609 | }, 610 | { 611 | "inputs": [], 612 | "type": "error", 613 | "name": "DailyDebtIncreaseLimit" 614 | }, 615 | { 616 | "inputs": [], 617 | "type": "error", 618 | "name": "DailyLendIncreaseLimit" 619 | }, 620 | { 621 | "inputs": [], 622 | "type": "error", 623 | "name": "DebtChanged" 624 | }, 625 | { 626 | "inputs": [], 627 | "type": "error", 628 | "name": "EtherSendFailed" 629 | }, 630 | { 631 | "inputs": [], 632 | "type": "error", 633 | "name": "ExceedsMaxReward" 634 | }, 635 | { 636 | "inputs": [], 637 | "type": "error", 638 | "name": "GlobalDebtLimit" 639 | }, 640 | { 641 | "inputs": [], 642 | "type": "error", 643 | "name": "GlobalLendLimit" 644 | }, 645 | { 646 | "inputs": [], 647 | "type": "error", 648 | "name": "InsufficientLiquidity" 649 | }, 650 | { 651 | "inputs": [], 652 | "type": "error", 653 | "name": "InterestNotUpdated" 654 | }, 655 | { 656 | "inputs": [], 657 | "type": "error", 658 | "name": "InvalidConfig" 659 | }, 660 | { 661 | "inputs": [], 662 | "type": "error", 663 | "name": "InvalidPool" 664 | }, 665 | { 666 | "inputs": [], 667 | "type": "error", 668 | "name": "InvalidToken" 669 | }, 670 | { 671 | "inputs": [], 672 | "type": "error", 673 | "name": "MinLoanSize" 674 | }, 675 | { 676 | "inputs": [], 677 | "type": "error", 678 | "name": "MissingSwapData" 679 | }, 680 | { 681 | "inputs": [], 682 | "type": "error", 683 | "name": "NeedsRepay" 684 | }, 685 | { 686 | "inputs": [], 687 | "type": "error", 688 | "name": "NoEtherToken" 689 | }, 690 | { 691 | "inputs": [], 692 | "type": "error", 693 | "name": "NoLiquidity" 694 | }, 695 | { 696 | "inputs": [], 697 | "type": "error", 698 | "name": "NoSharesRepayed" 699 | }, 700 | { 701 | "inputs": [], 702 | "type": "error", 703 | "name": "NotConfigured" 704 | }, 705 | { 706 | "inputs": [], 707 | "type": "error", 708 | "name": "NotEnoughReward" 709 | }, 710 | { 711 | "inputs": [], 712 | "type": "error", 713 | "name": "NotLiquidatable" 714 | }, 715 | { 716 | "inputs": [], 717 | "type": "error", 718 | "name": "NotReady" 719 | }, 720 | { 721 | "inputs": [], 722 | "type": "error", 723 | "name": "NotSupportedFeeTier" 724 | }, 725 | { 726 | "inputs": [], 727 | "type": "error", 728 | "name": "NotSupportedWhatToDo" 729 | }, 730 | { 731 | "inputs": [], 732 | "type": "error", 733 | "name": "NotWETH" 734 | }, 735 | { 736 | "inputs": [], 737 | "type": "error", 738 | "name": "PriceDifferenceExceeded" 739 | }, 740 | { 741 | "inputs": [], 742 | "type": "error", 743 | "name": "Reentrancy" 744 | }, 745 | { 746 | "inputs": [], 747 | "type": "error", 748 | "name": "SameRange" 749 | }, 750 | { 751 | "inputs": [], 752 | "type": "error", 753 | "name": "SameToken" 754 | }, 755 | { 756 | "inputs": [], 757 | "type": "error", 758 | "name": "SelfSend" 759 | }, 760 | { 761 | "inputs": [], 762 | "type": "error", 763 | "name": "SequencerDown" 764 | }, 765 | { 766 | "inputs": [], 767 | "type": "error", 768 | "name": "SequencerGracePeriodNotOver" 769 | }, 770 | { 771 | "inputs": [], 772 | "type": "error", 773 | "name": "SlippageError" 774 | }, 775 | { 776 | "inputs": [], 777 | "type": "error", 778 | "name": "SwapAmountTooLarge" 779 | }, 780 | { 781 | "inputs": [], 782 | "type": "error", 783 | "name": "SwapFailed" 784 | }, 785 | { 786 | "inputs": [], 787 | "type": "error", 788 | "name": "TWAPCheckFailed" 789 | }, 790 | { 791 | "inputs": [], 792 | "type": "error", 793 | "name": "TooMuchEtherSent" 794 | }, 795 | { 796 | "inputs": [], 797 | "type": "error", 798 | "name": "TransferError" 799 | }, 800 | { 801 | "inputs": [], 802 | "type": "error", 803 | "name": "TransformFailed" 804 | }, 805 | { 806 | "inputs": [], 807 | "type": "error", 808 | "name": "TransformNotAllowed" 809 | }, 810 | { 811 | "inputs": [], 812 | "type": "error", 813 | "name": "Unauthorized" 814 | }, 815 | { 816 | "inputs": [], 817 | "type": "error", 818 | "name": "WrongContract" 819 | }, 820 | { 821 | "inputs": [ 822 | { 823 | "internalType": "address", 824 | "name": "tokenIn", 825 | "type": "address", 826 | "indexed": true 827 | }, 828 | { 829 | "internalType": "address", 830 | "name": "tokenOut", 831 | "type": "address", 832 | "indexed": true 833 | }, 834 | { 835 | "internalType": "uint256", 836 | "name": "amountIn", 837 | "type": "uint256", 838 | "indexed": false 839 | }, 840 | { 841 | "internalType": "uint256", 842 | "name": "amountOut", 843 | "type": "uint256", 844 | "indexed": false 845 | } 846 | ], 847 | "type": "event", 848 | "name": "Swap", 849 | "anonymous": false 850 | }, 851 | { 852 | "inputs": [], 853 | "stateMutability": "view", 854 | "type": "function", 855 | "name": "factory", 856 | "outputs": [ 857 | { 858 | "internalType": "address", 859 | "name": "", 860 | "type": "address" 861 | } 862 | ] 863 | }, 864 | { 865 | "inputs": [ 866 | { 867 | "internalType": "struct FlashloanLiquidator.LiquidateParams", 868 | "name": "params", 869 | "type": "tuple", 870 | "components": [ 871 | { 872 | "internalType": "uint256", 873 | "name": "tokenId", 874 | "type": "uint256" 875 | }, 876 | { 877 | "internalType": "contract IVault", 878 | "name": "vault", 879 | "type": "address" 880 | }, 881 | { 882 | "internalType": "contract IUniswapV3Pool", 883 | "name": "flashLoanPool", 884 | "type": "address" 885 | }, 886 | { 887 | "internalType": "uint256", 888 | "name": "amount0In", 889 | "type": "uint256" 890 | }, 891 | { 892 | "internalType": "bytes", 893 | "name": "swapData0", 894 | "type": "bytes" 895 | }, 896 | { 897 | "internalType": "uint256", 898 | "name": "amount1In", 899 | "type": "uint256" 900 | }, 901 | { 902 | "internalType": "bytes", 903 | "name": "swapData1", 904 | "type": "bytes" 905 | }, 906 | { 907 | "internalType": "uint256", 908 | "name": "minReward", 909 | "type": "uint256" 910 | }, 911 | { 912 | "internalType": "uint256", 913 | "name": "deadline", 914 | "type": "uint256" 915 | } 916 | ] 917 | } 918 | ], 919 | "stateMutability": "nonpayable", 920 | "type": "function", 921 | "name": "liquidate" 922 | }, 923 | { 924 | "inputs": [], 925 | "stateMutability": "view", 926 | "type": "function", 927 | "name": "nonfungiblePositionManager", 928 | "outputs": [ 929 | { 930 | "internalType": "contract INonfungiblePositionManager", 931 | "name": "", 932 | "type": "address" 933 | } 934 | ] 935 | }, 936 | { 937 | "inputs": [ 938 | { 939 | "internalType": "uint256", 940 | "name": "fee0", 941 | "type": "uint256" 942 | }, 943 | { 944 | "internalType": "uint256", 945 | "name": "fee1", 946 | "type": "uint256" 947 | }, 948 | { 949 | "internalType": "bytes", 950 | "name": "callbackData", 951 | "type": "bytes" 952 | } 953 | ], 954 | "stateMutability": "nonpayable", 955 | "type": "function", 956 | "name": "uniswapV3FlashCallback" 957 | }, 958 | { 959 | "inputs": [ 960 | { 961 | "internalType": "int256", 962 | "name": "amount0Delta", 963 | "type": "int256" 964 | }, 965 | { 966 | "internalType": "int256", 967 | "name": "amount1Delta", 968 | "type": "int256" 969 | }, 970 | { 971 | "internalType": "bytes", 972 | "name": "data", 973 | "type": "bytes" 974 | } 975 | ], 976 | "stateMutability": "nonpayable", 977 | "type": "function", 978 | "name": "uniswapV3SwapCallback" 979 | }, 980 | { 981 | "inputs": [], 982 | "stateMutability": "view", 983 | "type": "function", 984 | "name": "universalRouter", 985 | "outputs": [ 986 | { 987 | "internalType": "address", 988 | "name": "", 989 | "type": "address" 990 | } 991 | ] 992 | }, 993 | { 994 | "inputs": [], 995 | "stateMutability": "view", 996 | "type": "function", 997 | "name": "weth", 998 | "outputs": [ 999 | { 1000 | "internalType": "contract IWETH9", 1001 | "name": "", 1002 | "type": "address" 1003 | } 1004 | ] 1005 | }, 1006 | { 1007 | "inputs": [], 1008 | "stateMutability": "view", 1009 | "type": "function", 1010 | "name": "zeroxRouter", 1011 | "outputs": [ 1012 | { 1013 | "internalType": "address", 1014 | "name": "", 1015 | "type": "address" 1016 | } 1017 | ] 1018 | } 1019 | ], 1020 | "devdoc": { 1021 | "kind": "dev", 1022 | "methods": { 1023 | "uniswapV3SwapCallback(int256,int256,bytes)": { 1024 | "details": "In the implementation you must pay the pool tokens owed for the swap. The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. amount0Delta and amount1Delta can both be 0 if no tokens were swapped.", 1025 | "params": { 1026 | "amount0Delta": "The amount of token0 that was sent (negative) or must be received (positive) by the pool by the end of the swap. If positive, the callback must send that amount of token0 to the pool.", 1027 | "amount1Delta": "The amount of token1 that was sent (negative) or must be received (positive) by the pool by the end of the swap. If positive, the callback must send that amount of token1 to the pool.", 1028 | "data": "Any data passed through by the caller via the IUniswapV3PoolActions#swap call" 1029 | } 1030 | } 1031 | }, 1032 | "version": 1 1033 | }, 1034 | "userdoc": { 1035 | "kind": "user", 1036 | "methods": { 1037 | "liquidate((uint256,address,address,uint256,bytes,uint256,bytes,uint256,uint256))": { 1038 | "notice": "Liquidates a loan, using a Uniswap Flashloan" 1039 | }, 1040 | "nonfungiblePositionManager()": { 1041 | "notice": "Uniswap v3 position manager" 1042 | }, 1043 | "uniswapV3SwapCallback(int256,int256,bytes)": { 1044 | "notice": "Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap." 1045 | }, 1046 | "universalRouter()": { 1047 | "notice": "Uniswap Universal Router" 1048 | }, 1049 | "weth()": { 1050 | "notice": "Wrapped native token address" 1051 | }, 1052 | "zeroxRouter()": { 1053 | "notice": "0x Exchange Proxy" 1054 | } 1055 | }, 1056 | "version": 1 1057 | } 1058 | }, 1059 | "settings": { 1060 | "remappings": [ 1061 | "@openzeppelin/=lib/openzeppelin-contracts/", 1062 | "@uniswap/v3-core/=lib/v3-core/", 1063 | "@uniswap/v3-periphery/=lib/v3-periphery/", 1064 | "ds-test/=lib/forge-std/lib/ds-test/src/", 1065 | "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", 1066 | "forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/", 1067 | "forge-std/=lib/forge-std/src/", 1068 | "openzeppelin-contracts/=lib/openzeppelin-contracts/", 1069 | "openzeppelin/=lib/openzeppelin-contracts/contracts/", 1070 | "permit2/=lib/permit2/src/", 1071 | "solmate/=lib/permit2/lib/solmate/", 1072 | "v3-core/=lib/v3-core/contracts/", 1073 | "v3-periphery/=lib/v3-periphery/contracts/" 1074 | ], 1075 | "optimizer": { 1076 | "enabled": true, 1077 | "runs": 200 1078 | }, 1079 | "metadata": { 1080 | "bytecodeHash": "ipfs" 1081 | }, 1082 | "compilationTarget": { 1083 | "src/utils/FlashloanLiquidator.sol": "FlashloanLiquidator" 1084 | }, 1085 | "evmVersion": "paris", 1086 | "libraries": {}, 1087 | "viaIR": true 1088 | }, 1089 | "sources": { 1090 | "lib/IUniversalRouter.sol": { 1091 | "keccak256": "0x691be9a0799db6471dc3bcc2ab3a09561abee9aaf9bb101f4218a4ebc91b6c24", 1092 | "urls": [ 1093 | "bzz-raw://9774a25af801bd0b705cd822cad21853e44be23240ddfea06b7c2e1908e875fa", 1094 | "dweb:/ipfs/QmUziX5YqD6ydKdAVoiDHHW6S94fBFmQTZNhLSgw3mTsbs" 1095 | ], 1096 | "license": "GPL-3.0-or-later" 1097 | }, 1098 | "lib/IWETH9.sol": { 1099 | "keccak256": "0x4e71fe456302668ba3537e382ae094e352fc972e5ef5c42810c5ecb8ea7d62a4", 1100 | "urls": [ 1101 | "bzz-raw://10890c34cc2a0592abec494be675ed9b06610d29cdcc784d08de16017b8a9cb7", 1102 | "dweb:/ipfs/QmdQ3G3RJx2SaJZCrkVzP9bBtifS9W8cAzx1HDkeGiKo1U" 1103 | ], 1104 | "license": "GPL-2.0-or-later" 1105 | }, 1106 | "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol": { 1107 | "keccak256": "0x5a173dcd1c1f0074e4df6a9cdab3257e17f2e64f7b8f30ca9e17a8c5ea250e1c", 1108 | "urls": [ 1109 | "bzz-raw://7883819ce2b72264a756063ae578661f62b23f4104b08e9565ac075e619f6ce3", 1110 | "dweb:/ipfs/QmcSZdFiEQkWRmZQhnCdfH9ychooV81pBjr7hfaiYiNZT2" 1111 | ], 1112 | "license": "MIT" 1113 | }, 1114 | "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { 1115 | "keccak256": "0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305", 1116 | "urls": [ 1117 | "bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5", 1118 | "dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53" 1119 | ], 1120 | "license": "MIT" 1121 | }, 1122 | "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol": { 1123 | "keccak256": "0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca", 1124 | "urls": [ 1125 | "bzz-raw://5a376d3dda2cb70536c0a45c208b29b34ac560c4cb4f513a42079f96ba47d2dd", 1126 | "dweb:/ipfs/QmZQg6gn1sUpM8wHzwNvSnihumUCAhxD119MpXeKp8B9s8" 1127 | ], 1128 | "license": "MIT" 1129 | }, 1130 | "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": { 1131 | "keccak256": "0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69", 1132 | "urls": [ 1133 | "bzz-raw://28879d01fd22c07b44f006612775f8577defbe459cb01685c5e25cd518c91a71", 1134 | "dweb:/ipfs/QmVgfkwv2Fxw6hhTcDUZhE7NkoSKjab3ipM7UaRbt6uXb5" 1135 | ], 1136 | "license": "MIT" 1137 | }, 1138 | "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": { 1139 | "keccak256": "0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1", 1140 | "urls": [ 1141 | "bzz-raw://9d213d3befca47da33f6db0310826bcdb148299805c10d77175ecfe1d06a9a68", 1142 | "dweb:/ipfs/QmRgCn6SP1hbBkExUADFuDo8xkT4UU47yjNF5FhCeRbQmS" 1143 | ], 1144 | "license": "MIT" 1145 | }, 1146 | "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol": { 1147 | "keccak256": "0x5bce51e11f7d194b79ea59fe00c9e8de9fa2c5530124960f29a24d4c740a3266", 1148 | "urls": [ 1149 | "bzz-raw://7e66dfde185df46104c11bc89d08fa0760737aa59a2b8546a656473d810a8ea4", 1150 | "dweb:/ipfs/QmXvyqtXPaPss2PD7eqPoSao5Szm2n6UMoiG8TZZDjmChR" 1151 | ], 1152 | "license": "MIT" 1153 | }, 1154 | "lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol": { 1155 | "keccak256": "0xd1556954440b31c97a142c6ba07d5cade45f96fafd52091d33a14ebe365aecbf", 1156 | "urls": [ 1157 | "bzz-raw://26fef835622b46a5ba08b3ef6b46a22e94b5f285d0f0fb66b703bd30217d2c34", 1158 | "dweb:/ipfs/QmZ548qdwfL1qF7aXz3xh1GCdTiST81kGGuKRqVUfYmPZR" 1159 | ], 1160 | "license": "MIT" 1161 | }, 1162 | "lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol": { 1163 | "keccak256": "0x75b829ff2f26c14355d1cba20e16fe7b29ca58eb5fef665ede48bc0f9c6c74b9", 1164 | "urls": [ 1165 | "bzz-raw://a0a107160525724f9e1bbbab031defc2f298296dd9e331f16a6f7130cec32146", 1166 | "dweb:/ipfs/QmemujxSd7gX8A9M8UwmNbz4Ms3U9FG9QfudUgxwvTmPWf" 1167 | ], 1168 | "license": "MIT" 1169 | }, 1170 | "lib/openzeppelin-contracts/contracts/utils/Address.sol": { 1171 | "keccak256": "0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa", 1172 | "urls": [ 1173 | "bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931", 1174 | "dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm" 1175 | ], 1176 | "license": "MIT" 1177 | }, 1178 | "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": { 1179 | "keccak256": "0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1", 1180 | "urls": [ 1181 | "bzz-raw://be161e54f24e5c6fae81a12db1a8ae87bc5ae1b0ddc805d82a1440a68455088f", 1182 | "dweb:/ipfs/QmP7C3CHdY9urF4dEMb9wmsp1wMxHF6nhA2yQE5SKiPAdy" 1183 | ], 1184 | "license": "MIT" 1185 | }, 1186 | "lib/v3-core/contracts/interfaces/IUniswapV3Pool.sol": { 1187 | "keccak256": "0x4e64844c56061cd90e0a80de73534a9166704c43eed579eb83f90bc2780ce968", 1188 | "urls": [ 1189 | "bzz-raw://cba4fab5cebdddf644b901994a7f0f52b98885d4c56012f4dc51d52c2bf9de0e", 1190 | "dweb:/ipfs/QmVyyrRmqXrAiapewWunRVgiPVFJHpH2hKiE1py1svMSNV" 1191 | ], 1192 | "license": "GPL-2.0-or-later" 1193 | }, 1194 | "lib/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol": { 1195 | "keccak256": "0x151ba1777392771025f0fca946c95fbc16ec4b5eff05e1f236115b99bd574de2", 1196 | "urls": [ 1197 | "bzz-raw://738a50c25d9d26ca3fabb1865bf6a0cdd8d7a2eec9dbfbd1fc000c81fb8e2b5e", 1198 | "dweb:/ipfs/QmQjgCiLhrq5eLJgQcVHV24MRHyf6YdVzrGH8Ms7LnSSRA" 1199 | ], 1200 | "license": "GPL-2.0-or-later" 1201 | }, 1202 | "lib/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol": { 1203 | "keccak256": "0x3f485fb1a44e8fbeadefb5da07d66edab3cfe809f0ac4074b1e54e3eb3c4cf69", 1204 | "urls": [ 1205 | "bzz-raw://095ce0626b41318c772b3ebf19d548282607f6a8f3d6c41c13edfbd5370c8652", 1206 | "dweb:/ipfs/QmVDZfJJ89UUCE1hMyzqpkZAtQ8jUsBgZNE5AMRG7RzRFS" 1207 | ], 1208 | "license": "GPL-2.0-or-later" 1209 | }, 1210 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol": { 1211 | "keccak256": "0x9453dd0e7442188667d01d9b65de3f1e14e9511ff3e303179a15f6fc267f7634", 1212 | "urls": [ 1213 | "bzz-raw://982f4328f956c3e60e67501e759eb292ac487f76460c774c50e9ae4fcc92aae5", 1214 | "dweb:/ipfs/QmRnzEDsaqtd9PJEVcgQi7p5aV5pMSvRUoGZJAdwFUJxgZ" 1215 | ], 1216 | "license": "GPL-2.0-or-later" 1217 | }, 1218 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol": { 1219 | "keccak256": "0xe603ac5b17ecdee73ba2b27efdf386c257a19c14206e87eee77e2017b742d9e5", 1220 | "urls": [ 1221 | "bzz-raw://8febc9bdb399a4d94bb89f5377732652e2400e4a8dee808201ade6848f9004e7", 1222 | "dweb:/ipfs/QmaKDqYYFU4d2W2iN77aDHptfbFmYZRrMYXHeGpJmM8C1c" 1223 | ], 1224 | "license": "GPL-2.0-or-later" 1225 | }, 1226 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolErrors.sol": { 1227 | "keccak256": "0xf80abf13fb1fafc127ba4e792f240dd8ea7c8c893978cdfd8439c27fae9a037b", 1228 | "urls": [ 1229 | "bzz-raw://b04fc72a656bbf3631e9c2e67b9870a2d9d235185e833fe050e9606e6816a9aa", 1230 | "dweb:/ipfs/QmUcz4bkEkJ9pwzFu1C3n97hBQ3st9U6qTAqCdyFwddKco" 1231 | ], 1232 | "license": "GPL-2.0-or-later" 1233 | }, 1234 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol": { 1235 | "keccak256": "0x8071514d0fe5d17d6fbd31c191cdfb703031c24e0ece3621d88ab10e871375cd", 1236 | "urls": [ 1237 | "bzz-raw://d0b571930cc7488b1d546a7e9cea7c52d8b3c4e207da657ed0e0db7343b8cd03", 1238 | "dweb:/ipfs/QmaGK6vVwB95QSTR1XMYvrh7ivYAYZxi3fD7v6VMA4jZ39" 1239 | ], 1240 | "license": "GPL-2.0-or-later" 1241 | }, 1242 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol": { 1243 | "keccak256": "0xf6e5d2cd1139c4c276bdbc8e1d2b256e456c866a91f1b868da265c6d2685c3f7", 1244 | "urls": [ 1245 | "bzz-raw://b99c8c9ae8e27ee6559e5866bea82cbc9ffc8247f8d15b7422a4deb287d4d047", 1246 | "dweb:/ipfs/QmfL8gaqt3ffAnm6nVj5ksuNpLygXuL3xq5VBqrkwC2JJ3" 1247 | ], 1248 | "license": "GPL-2.0-or-later" 1249 | }, 1250 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol": { 1251 | "keccak256": "0x759b78a2918af9e99e246dc3af084f654e48ef32bb4e4cb8a966aa3dcaece235", 1252 | "urls": [ 1253 | "bzz-raw://64144fb96e1c7fdba87305acadb98a198d26a3d46c097cb3a666e567f6f29735", 1254 | "dweb:/ipfs/QmUnWVwN9FKB9uV5Pr8YfLpWZnYM2DENnRMaadZ492JS9u" 1255 | ], 1256 | "license": "GPL-2.0-or-later" 1257 | }, 1258 | "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol": { 1259 | "keccak256": "0x44fa2ce1182f6c2f6bead3d1737804bf7e112252ae86e0f2e92f9b8249603f43", 1260 | "urls": [ 1261 | "bzz-raw://54154e8665b98d65f5dc91b256551852cb47882180b501b260657122d207c0ea", 1262 | "dweb:/ipfs/QmcfemK1A2PXYrWB5SBFGERpMCderbFRb8BtTzQDj1sUBp" 1263 | ], 1264 | "license": "GPL-2.0-or-later" 1265 | }, 1266 | "lib/v3-core/contracts/libraries/TickMath.sol": { 1267 | "keccak256": "0x5c57de03a91cc2ec8939865dbbcb0197bb6c353b711075eefd8e0fca5e102129", 1268 | "urls": [ 1269 | "bzz-raw://1e994c24fd891ef8a3f5dbf5eba42b34feaf05e0376a29f91322faa18054449c", 1270 | "dweb:/ipfs/QmNdUJGUQxd1dPkMbnA5f5UNqakxRkQE5r7bTZJAuHeapS" 1271 | ], 1272 | "license": "GPL-2.0-or-later" 1273 | }, 1274 | "lib/v3-periphery/contracts/interfaces/IERC721Permit.sol": { 1275 | "keccak256": "0x9e3c2a4ee65ddf95b2dfcb0815784eea3a295707e6f8b83e4c4f0f8fe2e3a1d4", 1276 | "urls": [ 1277 | "bzz-raw://bfd939085b3618101b955f87c7fabf38338ba1aad480295acb8102ebc5d72471", 1278 | "dweb:/ipfs/QmauQD8bGDHTztmTDfaKXjzM7Wacrq2XU7VcTbwn1WrDBL" 1279 | ], 1280 | "license": "GPL-2.0-or-later" 1281 | }, 1282 | "lib/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol": { 1283 | "keccak256": "0x3357b065654abb7f4a9ebd184a260bc39efde2afa4e99dca2e72ffc28e9c2984", 1284 | "urls": [ 1285 | "bzz-raw://f7682dab014724be8e0a5a401b047788ff9c70b77fa5bd567ea6adc333cb3b56", 1286 | "dweb:/ipfs/QmatH1Gc6z3AkP4dHjAEBKfCBbgBfD4vCceF4TuZU2bCyW" 1287 | ], 1288 | "license": "GPL-2.0-or-later" 1289 | }, 1290 | "lib/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol": { 1291 | "keccak256": "0x7affcfeb5127c0925a71d6a65345e117c33537523aeca7bc98085ead8452519d", 1292 | "urls": [ 1293 | "bzz-raw://e16b291294210e71cb0f20cd0afe62ae2dc6878d627f5ccc19c4dc9cd80aec3f", 1294 | "dweb:/ipfs/QmQGitSyBr26nour81BZmpmDMyJpvZRqHQZvnCD1Acb127" 1295 | ], 1296 | "license": "GPL-2.0-or-later" 1297 | }, 1298 | "lib/v3-periphery/contracts/interfaces/IPeripheryPayments.sol": { 1299 | "keccak256": "0xb547e10f1e69bed03621a62b73a503e260643066c6b4054867a4d1fef47eb274", 1300 | "urls": [ 1301 | "bzz-raw://f9a90f58f5fd5fb42f7811f4094113b532f307b14a73764c91f977590747f407", 1302 | "dweb:/ipfs/QmSeNH2mfiDMKf3Q6V2sqtNxx1s72JNuA1VVxRM9HoMqYp" 1303 | ], 1304 | "license": "GPL-2.0-or-later" 1305 | }, 1306 | "lib/v3-periphery/contracts/interfaces/IPoolInitializer.sol": { 1307 | "keccak256": "0x9d7695e8d94c22cc5fcced602017aabb988de89981ea7bee29ea629d5328a862", 1308 | "urls": [ 1309 | "bzz-raw://61b50933026ee1017db2a6273af8cedc3238c95dca58880db0918dbdbb2f064f", 1310 | "dweb:/ipfs/QmUebR26pqG25d18aBELKz8aFFKkmHa8PxntzXTA7o9Ldu" 1311 | ], 1312 | "license": "GPL-2.0-or-later" 1313 | }, 1314 | "lib/v3-periphery/contracts/libraries/PoolAddress.sol": { 1315 | "keccak256": "0x4703d506f590554af23e6e01e0412c88f9eff7410205d9af639b3559cc4f9a05", 1316 | "urls": [ 1317 | "bzz-raw://cb0eac1c44d1bebb3d20c5068d737781a138526172af762b0a77b60987ec4145", 1318 | "dweb:/ipfs/QmT5xmY46qJAXvuhDuWHxgiWf56ccGdNbUAeeQWuP3W4zk" 1319 | ], 1320 | "license": "GPL-2.0-or-later" 1321 | }, 1322 | "src/interfaces/IVault.sol": { 1323 | "keccak256": "0x5528dd33982194427e7cfaab96d1e8b5ca7029111a486ba480b105599228f5a2", 1324 | "urls": [ 1325 | "bzz-raw://9b736d96ce763f8ebb183366f86c0e81849586977a904b6a6d1ffd977117fd80", 1326 | "dweb:/ipfs/QmNdckQwYm9v8q8Ffb6zsW4b2YFSHRkhkRXgSmnHLvtHGh" 1327 | ], 1328 | "license": "BUSL-1.1" 1329 | }, 1330 | "src/utils/Constants.sol": { 1331 | "keccak256": "0xba47fb0107342763f81343be1870cddb125ce71aad80a578b66350017f1a6737", 1332 | "urls": [ 1333 | "bzz-raw://3bcb51a5b6b7baa1e2015b145e0e1d4719e0b43d682118c9b0b6447fee79870a", 1334 | "dweb:/ipfs/QmRLFFNdNGp6g6b53XQQ9GW6Ysrqu1Txr5cscW44putCaU" 1335 | ], 1336 | "license": "BUSL-1.1" 1337 | }, 1338 | "src/utils/FlashloanLiquidator.sol": { 1339 | "keccak256": "0x8e1ce351ea57fbd987e24be160887f89df5f3f44170646a3d32d35ba61061613", 1340 | "urls": [ 1341 | "bzz-raw://f5c939d1a12478e1968048ee6b8232c4541491e55380272ece016a749d0aa054", 1342 | "dweb:/ipfs/QmZgCZLndfvKMQUbf3JwxsHVYC2Q5aF6TfNpNXdjqFKk5q" 1343 | ], 1344 | "license": "BUSL-1.1" 1345 | }, 1346 | "src/utils/Swapper.sol": { 1347 | "keccak256": "0x961aa3526b288b59451eadc75b2b051323d1689a3b141d058ec06017c65be98e", 1348 | "urls": [ 1349 | "bzz-raw://8004f4f0db0f93d48e6a7c166c1a7c314f64b0e16d4b61f93ad5dfe07e16f2d2", 1350 | "dweb:/ipfs/QmSus6pZoPYZBud3rZ2KxMJNGZgXi8kCcjeQaWmMptn4UV" 1351 | ], 1352 | "license": "BUSL-1.1" 1353 | } 1354 | }, 1355 | "version": 1 1356 | }, 1357 | "id": 68 1358 | } -------------------------------------------------------------------------------- /contracts/IERC20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] -------------------------------------------------------------------------------- /contracts/INonfungiblePositionManager.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "INonfungiblePositionManager", 4 | "sourceName": "contracts/external/uniswap/v3-periphery/interfaces/INonfungiblePositionManager.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": true, 11 | "internalType": "address", 12 | "name": "owner", 13 | "type": "address" 14 | }, 15 | { 16 | "indexed": true, 17 | "internalType": "address", 18 | "name": "approved", 19 | "type": "address" 20 | }, 21 | { 22 | "indexed": true, 23 | "internalType": "uint256", 24 | "name": "tokenId", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "Approval", 29 | "type": "event" 30 | }, 31 | { 32 | "anonymous": false, 33 | "inputs": [ 34 | { 35 | "indexed": true, 36 | "internalType": "address", 37 | "name": "owner", 38 | "type": "address" 39 | }, 40 | { 41 | "indexed": true, 42 | "internalType": "address", 43 | "name": "operator", 44 | "type": "address" 45 | }, 46 | { 47 | "indexed": false, 48 | "internalType": "bool", 49 | "name": "approved", 50 | "type": "bool" 51 | } 52 | ], 53 | "name": "ApprovalForAll", 54 | "type": "event" 55 | }, 56 | { 57 | "anonymous": false, 58 | "inputs": [ 59 | { 60 | "indexed": true, 61 | "internalType": "uint256", 62 | "name": "tokenId", 63 | "type": "uint256" 64 | }, 65 | { 66 | "indexed": false, 67 | "internalType": "address", 68 | "name": "recipient", 69 | "type": "address" 70 | }, 71 | { 72 | "indexed": false, 73 | "internalType": "uint256", 74 | "name": "amount0", 75 | "type": "uint256" 76 | }, 77 | { 78 | "indexed": false, 79 | "internalType": "uint256", 80 | "name": "amount1", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "Collect", 85 | "type": "event" 86 | }, 87 | { 88 | "anonymous": false, 89 | "inputs": [ 90 | { 91 | "indexed": true, 92 | "internalType": "uint256", 93 | "name": "tokenId", 94 | "type": "uint256" 95 | }, 96 | { 97 | "indexed": false, 98 | "internalType": "uint128", 99 | "name": "liquidity", 100 | "type": "uint128" 101 | }, 102 | { 103 | "indexed": false, 104 | "internalType": "uint256", 105 | "name": "amount0", 106 | "type": "uint256" 107 | }, 108 | { 109 | "indexed": false, 110 | "internalType": "uint256", 111 | "name": "amount1", 112 | "type": "uint256" 113 | } 114 | ], 115 | "name": "DecreaseLiquidity", 116 | "type": "event" 117 | }, 118 | { 119 | "anonymous": false, 120 | "inputs": [ 121 | { 122 | "indexed": true, 123 | "internalType": "uint256", 124 | "name": "tokenId", 125 | "type": "uint256" 126 | }, 127 | { 128 | "indexed": false, 129 | "internalType": "uint128", 130 | "name": "liquidity", 131 | "type": "uint128" 132 | }, 133 | { 134 | "indexed": false, 135 | "internalType": "uint256", 136 | "name": "amount0", 137 | "type": "uint256" 138 | }, 139 | { 140 | "indexed": false, 141 | "internalType": "uint256", 142 | "name": "amount1", 143 | "type": "uint256" 144 | } 145 | ], 146 | "name": "IncreaseLiquidity", 147 | "type": "event" 148 | }, 149 | { 150 | "anonymous": false, 151 | "inputs": [ 152 | { 153 | "indexed": true, 154 | "internalType": "address", 155 | "name": "from", 156 | "type": "address" 157 | }, 158 | { 159 | "indexed": true, 160 | "internalType": "address", 161 | "name": "to", 162 | "type": "address" 163 | }, 164 | { 165 | "indexed": true, 166 | "internalType": "uint256", 167 | "name": "tokenId", 168 | "type": "uint256" 169 | } 170 | ], 171 | "name": "Transfer", 172 | "type": "event" 173 | }, 174 | { 175 | "inputs": [], 176 | "name": "DOMAIN_SEPARATOR", 177 | "outputs": [ 178 | { 179 | "internalType": "bytes32", 180 | "name": "", 181 | "type": "bytes32" 182 | } 183 | ], 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [], 189 | "name": "PERMIT_TYPEHASH", 190 | "outputs": [ 191 | { 192 | "internalType": "bytes32", 193 | "name": "", 194 | "type": "bytes32" 195 | } 196 | ], 197 | "stateMutability": "pure", 198 | "type": "function" 199 | }, 200 | { 201 | "inputs": [], 202 | "name": "WETH9", 203 | "outputs": [ 204 | { 205 | "internalType": "address", 206 | "name": "", 207 | "type": "address" 208 | } 209 | ], 210 | "stateMutability": "view", 211 | "type": "function" 212 | }, 213 | { 214 | "inputs": [ 215 | { 216 | "internalType": "address", 217 | "name": "to", 218 | "type": "address" 219 | }, 220 | { 221 | "internalType": "uint256", 222 | "name": "tokenId", 223 | "type": "uint256" 224 | } 225 | ], 226 | "name": "approve", 227 | "outputs": [], 228 | "stateMutability": "nonpayable", 229 | "type": "function" 230 | }, 231 | { 232 | "inputs": [ 233 | { 234 | "internalType": "address", 235 | "name": "owner", 236 | "type": "address" 237 | } 238 | ], 239 | "name": "balanceOf", 240 | "outputs": [ 241 | { 242 | "internalType": "uint256", 243 | "name": "balance", 244 | "type": "uint256" 245 | } 246 | ], 247 | "stateMutability": "view", 248 | "type": "function" 249 | }, 250 | { 251 | "inputs": [ 252 | { 253 | "internalType": "uint256", 254 | "name": "tokenId", 255 | "type": "uint256" 256 | } 257 | ], 258 | "name": "burn", 259 | "outputs": [], 260 | "stateMutability": "payable", 261 | "type": "function" 262 | }, 263 | { 264 | "inputs": [ 265 | { 266 | "components": [ 267 | { 268 | "internalType": "uint256", 269 | "name": "tokenId", 270 | "type": "uint256" 271 | }, 272 | { 273 | "internalType": "address", 274 | "name": "recipient", 275 | "type": "address" 276 | }, 277 | { 278 | "internalType": "uint128", 279 | "name": "amount0Max", 280 | "type": "uint128" 281 | }, 282 | { 283 | "internalType": "uint128", 284 | "name": "amount1Max", 285 | "type": "uint128" 286 | } 287 | ], 288 | "internalType": "struct INonfungiblePositionManager.CollectParams", 289 | "name": "params", 290 | "type": "tuple" 291 | } 292 | ], 293 | "name": "collect", 294 | "outputs": [ 295 | { 296 | "internalType": "uint256", 297 | "name": "amount0", 298 | "type": "uint256" 299 | }, 300 | { 301 | "internalType": "uint256", 302 | "name": "amount1", 303 | "type": "uint256" 304 | } 305 | ], 306 | "stateMutability": "payable", 307 | "type": "function" 308 | }, 309 | { 310 | "inputs": [ 311 | { 312 | "internalType": "address", 313 | "name": "token0", 314 | "type": "address" 315 | }, 316 | { 317 | "internalType": "address", 318 | "name": "token1", 319 | "type": "address" 320 | }, 321 | { 322 | "internalType": "uint24", 323 | "name": "fee", 324 | "type": "uint24" 325 | }, 326 | { 327 | "internalType": "uint160", 328 | "name": "sqrtPriceX96", 329 | "type": "uint160" 330 | } 331 | ], 332 | "name": "createAndInitializePoolIfNecessary", 333 | "outputs": [ 334 | { 335 | "internalType": "address", 336 | "name": "pool", 337 | "type": "address" 338 | } 339 | ], 340 | "stateMutability": "payable", 341 | "type": "function" 342 | }, 343 | { 344 | "inputs": [ 345 | { 346 | "components": [ 347 | { 348 | "internalType": "uint256", 349 | "name": "tokenId", 350 | "type": "uint256" 351 | }, 352 | { 353 | "internalType": "uint128", 354 | "name": "liquidity", 355 | "type": "uint128" 356 | }, 357 | { 358 | "internalType": "uint256", 359 | "name": "amount0Min", 360 | "type": "uint256" 361 | }, 362 | { 363 | "internalType": "uint256", 364 | "name": "amount1Min", 365 | "type": "uint256" 366 | }, 367 | { 368 | "internalType": "uint256", 369 | "name": "deadline", 370 | "type": "uint256" 371 | } 372 | ], 373 | "internalType": "struct INonfungiblePositionManager.DecreaseLiquidityParams", 374 | "name": "params", 375 | "type": "tuple" 376 | } 377 | ], 378 | "name": "decreaseLiquidity", 379 | "outputs": [ 380 | { 381 | "internalType": "uint256", 382 | "name": "amount0", 383 | "type": "uint256" 384 | }, 385 | { 386 | "internalType": "uint256", 387 | "name": "amount1", 388 | "type": "uint256" 389 | } 390 | ], 391 | "stateMutability": "payable", 392 | "type": "function" 393 | }, 394 | { 395 | "inputs": [], 396 | "name": "factory", 397 | "outputs": [ 398 | { 399 | "internalType": "address", 400 | "name": "", 401 | "type": "address" 402 | } 403 | ], 404 | "stateMutability": "view", 405 | "type": "function" 406 | }, 407 | { 408 | "inputs": [ 409 | { 410 | "internalType": "uint256", 411 | "name": "tokenId", 412 | "type": "uint256" 413 | } 414 | ], 415 | "name": "getApproved", 416 | "outputs": [ 417 | { 418 | "internalType": "address", 419 | "name": "operator", 420 | "type": "address" 421 | } 422 | ], 423 | "stateMutability": "view", 424 | "type": "function" 425 | }, 426 | { 427 | "inputs": [ 428 | { 429 | "components": [ 430 | { 431 | "internalType": "uint256", 432 | "name": "tokenId", 433 | "type": "uint256" 434 | }, 435 | { 436 | "internalType": "uint256", 437 | "name": "amount0Desired", 438 | "type": "uint256" 439 | }, 440 | { 441 | "internalType": "uint256", 442 | "name": "amount1Desired", 443 | "type": "uint256" 444 | }, 445 | { 446 | "internalType": "uint256", 447 | "name": "amount0Min", 448 | "type": "uint256" 449 | }, 450 | { 451 | "internalType": "uint256", 452 | "name": "amount1Min", 453 | "type": "uint256" 454 | }, 455 | { 456 | "internalType": "uint256", 457 | "name": "deadline", 458 | "type": "uint256" 459 | } 460 | ], 461 | "internalType": "struct INonfungiblePositionManager.IncreaseLiquidityParams", 462 | "name": "params", 463 | "type": "tuple" 464 | } 465 | ], 466 | "name": "increaseLiquidity", 467 | "outputs": [ 468 | { 469 | "internalType": "uint128", 470 | "name": "liquidity", 471 | "type": "uint128" 472 | }, 473 | { 474 | "internalType": "uint256", 475 | "name": "amount0", 476 | "type": "uint256" 477 | }, 478 | { 479 | "internalType": "uint256", 480 | "name": "amount1", 481 | "type": "uint256" 482 | } 483 | ], 484 | "stateMutability": "payable", 485 | "type": "function" 486 | }, 487 | { 488 | "inputs": [ 489 | { 490 | "internalType": "address", 491 | "name": "owner", 492 | "type": "address" 493 | }, 494 | { 495 | "internalType": "address", 496 | "name": "operator", 497 | "type": "address" 498 | } 499 | ], 500 | "name": "isApprovedForAll", 501 | "outputs": [ 502 | { 503 | "internalType": "bool", 504 | "name": "", 505 | "type": "bool" 506 | } 507 | ], 508 | "stateMutability": "view", 509 | "type": "function" 510 | }, 511 | { 512 | "inputs": [ 513 | { 514 | "components": [ 515 | { 516 | "internalType": "address", 517 | "name": "token0", 518 | "type": "address" 519 | }, 520 | { 521 | "internalType": "address", 522 | "name": "token1", 523 | "type": "address" 524 | }, 525 | { 526 | "internalType": "uint24", 527 | "name": "fee", 528 | "type": "uint24" 529 | }, 530 | { 531 | "internalType": "int24", 532 | "name": "tickLower", 533 | "type": "int24" 534 | }, 535 | { 536 | "internalType": "int24", 537 | "name": "tickUpper", 538 | "type": "int24" 539 | }, 540 | { 541 | "internalType": "uint256", 542 | "name": "amount0Desired", 543 | "type": "uint256" 544 | }, 545 | { 546 | "internalType": "uint256", 547 | "name": "amount1Desired", 548 | "type": "uint256" 549 | }, 550 | { 551 | "internalType": "uint256", 552 | "name": "amount0Min", 553 | "type": "uint256" 554 | }, 555 | { 556 | "internalType": "uint256", 557 | "name": "amount1Min", 558 | "type": "uint256" 559 | }, 560 | { 561 | "internalType": "address", 562 | "name": "recipient", 563 | "type": "address" 564 | }, 565 | { 566 | "internalType": "uint256", 567 | "name": "deadline", 568 | "type": "uint256" 569 | } 570 | ], 571 | "internalType": "struct INonfungiblePositionManager.MintParams", 572 | "name": "params", 573 | "type": "tuple" 574 | } 575 | ], 576 | "name": "mint", 577 | "outputs": [ 578 | { 579 | "internalType": "uint256", 580 | "name": "tokenId", 581 | "type": "uint256" 582 | }, 583 | { 584 | "internalType": "uint128", 585 | "name": "liquidity", 586 | "type": "uint128" 587 | }, 588 | { 589 | "internalType": "uint256", 590 | "name": "amount0", 591 | "type": "uint256" 592 | }, 593 | { 594 | "internalType": "uint256", 595 | "name": "amount1", 596 | "type": "uint256" 597 | } 598 | ], 599 | "stateMutability": "payable", 600 | "type": "function" 601 | }, 602 | { 603 | "inputs": [], 604 | "name": "name", 605 | "outputs": [ 606 | { 607 | "internalType": "string", 608 | "name": "", 609 | "type": "string" 610 | } 611 | ], 612 | "stateMutability": "view", 613 | "type": "function" 614 | }, 615 | { 616 | "inputs": [ 617 | { 618 | "internalType": "uint256", 619 | "name": "tokenId", 620 | "type": "uint256" 621 | } 622 | ], 623 | "name": "ownerOf", 624 | "outputs": [ 625 | { 626 | "internalType": "address", 627 | "name": "owner", 628 | "type": "address" 629 | } 630 | ], 631 | "stateMutability": "view", 632 | "type": "function" 633 | }, 634 | { 635 | "inputs": [ 636 | { 637 | "internalType": "address", 638 | "name": "spender", 639 | "type": "address" 640 | }, 641 | { 642 | "internalType": "uint256", 643 | "name": "tokenId", 644 | "type": "uint256" 645 | }, 646 | { 647 | "internalType": "uint256", 648 | "name": "deadline", 649 | "type": "uint256" 650 | }, 651 | { 652 | "internalType": "uint8", 653 | "name": "v", 654 | "type": "uint8" 655 | }, 656 | { 657 | "internalType": "bytes32", 658 | "name": "r", 659 | "type": "bytes32" 660 | }, 661 | { 662 | "internalType": "bytes32", 663 | "name": "s", 664 | "type": "bytes32" 665 | } 666 | ], 667 | "name": "permit", 668 | "outputs": [], 669 | "stateMutability": "payable", 670 | "type": "function" 671 | }, 672 | { 673 | "inputs": [ 674 | { 675 | "internalType": "uint256", 676 | "name": "tokenId", 677 | "type": "uint256" 678 | } 679 | ], 680 | "name": "positions", 681 | "outputs": [ 682 | { 683 | "internalType": "uint96", 684 | "name": "nonce", 685 | "type": "uint96" 686 | }, 687 | { 688 | "internalType": "address", 689 | "name": "operator", 690 | "type": "address" 691 | }, 692 | { 693 | "internalType": "address", 694 | "name": "token0", 695 | "type": "address" 696 | }, 697 | { 698 | "internalType": "address", 699 | "name": "token1", 700 | "type": "address" 701 | }, 702 | { 703 | "internalType": "uint24", 704 | "name": "fee", 705 | "type": "uint24" 706 | }, 707 | { 708 | "internalType": "int24", 709 | "name": "tickLower", 710 | "type": "int24" 711 | }, 712 | { 713 | "internalType": "int24", 714 | "name": "tickUpper", 715 | "type": "int24" 716 | }, 717 | { 718 | "internalType": "uint128", 719 | "name": "liquidity", 720 | "type": "uint128" 721 | }, 722 | { 723 | "internalType": "uint256", 724 | "name": "feeGrowthInside0LastX128", 725 | "type": "uint256" 726 | }, 727 | { 728 | "internalType": "uint256", 729 | "name": "feeGrowthInside1LastX128", 730 | "type": "uint256" 731 | }, 732 | { 733 | "internalType": "uint128", 734 | "name": "tokensOwed0", 735 | "type": "uint128" 736 | }, 737 | { 738 | "internalType": "uint128", 739 | "name": "tokensOwed1", 740 | "type": "uint128" 741 | } 742 | ], 743 | "stateMutability": "view", 744 | "type": "function" 745 | }, 746 | { 747 | "inputs": [], 748 | "name": "refundETH", 749 | "outputs": [], 750 | "stateMutability": "payable", 751 | "type": "function" 752 | }, 753 | { 754 | "inputs": [ 755 | { 756 | "internalType": "address", 757 | "name": "from", 758 | "type": "address" 759 | }, 760 | { 761 | "internalType": "address", 762 | "name": "to", 763 | "type": "address" 764 | }, 765 | { 766 | "internalType": "uint256", 767 | "name": "tokenId", 768 | "type": "uint256" 769 | } 770 | ], 771 | "name": "safeTransferFrom", 772 | "outputs": [], 773 | "stateMutability": "nonpayable", 774 | "type": "function" 775 | }, 776 | { 777 | "inputs": [ 778 | { 779 | "internalType": "address", 780 | "name": "from", 781 | "type": "address" 782 | }, 783 | { 784 | "internalType": "address", 785 | "name": "to", 786 | "type": "address" 787 | }, 788 | { 789 | "internalType": "uint256", 790 | "name": "tokenId", 791 | "type": "uint256" 792 | }, 793 | { 794 | "internalType": "bytes", 795 | "name": "data", 796 | "type": "bytes" 797 | } 798 | ], 799 | "name": "safeTransferFrom", 800 | "outputs": [], 801 | "stateMutability": "nonpayable", 802 | "type": "function" 803 | }, 804 | { 805 | "inputs": [ 806 | { 807 | "internalType": "address", 808 | "name": "operator", 809 | "type": "address" 810 | }, 811 | { 812 | "internalType": "bool", 813 | "name": "_approved", 814 | "type": "bool" 815 | } 816 | ], 817 | "name": "setApprovalForAll", 818 | "outputs": [], 819 | "stateMutability": "nonpayable", 820 | "type": "function" 821 | }, 822 | { 823 | "inputs": [ 824 | { 825 | "internalType": "bytes4", 826 | "name": "interfaceId", 827 | "type": "bytes4" 828 | } 829 | ], 830 | "name": "supportsInterface", 831 | "outputs": [ 832 | { 833 | "internalType": "bool", 834 | "name": "", 835 | "type": "bool" 836 | } 837 | ], 838 | "stateMutability": "view", 839 | "type": "function" 840 | }, 841 | { 842 | "inputs": [ 843 | { 844 | "internalType": "address", 845 | "name": "token", 846 | "type": "address" 847 | }, 848 | { 849 | "internalType": "uint256", 850 | "name": "amountMinimum", 851 | "type": "uint256" 852 | }, 853 | { 854 | "internalType": "address", 855 | "name": "recipient", 856 | "type": "address" 857 | } 858 | ], 859 | "name": "sweepToken", 860 | "outputs": [], 861 | "stateMutability": "payable", 862 | "type": "function" 863 | }, 864 | { 865 | "inputs": [], 866 | "name": "symbol", 867 | "outputs": [ 868 | { 869 | "internalType": "string", 870 | "name": "", 871 | "type": "string" 872 | } 873 | ], 874 | "stateMutability": "view", 875 | "type": "function" 876 | }, 877 | { 878 | "inputs": [ 879 | { 880 | "internalType": "uint256", 881 | "name": "index", 882 | "type": "uint256" 883 | } 884 | ], 885 | "name": "tokenByIndex", 886 | "outputs": [ 887 | { 888 | "internalType": "uint256", 889 | "name": "", 890 | "type": "uint256" 891 | } 892 | ], 893 | "stateMutability": "view", 894 | "type": "function" 895 | }, 896 | { 897 | "inputs": [ 898 | { 899 | "internalType": "address", 900 | "name": "owner", 901 | "type": "address" 902 | }, 903 | { 904 | "internalType": "uint256", 905 | "name": "index", 906 | "type": "uint256" 907 | } 908 | ], 909 | "name": "tokenOfOwnerByIndex", 910 | "outputs": [ 911 | { 912 | "internalType": "uint256", 913 | "name": "tokenId", 914 | "type": "uint256" 915 | } 916 | ], 917 | "stateMutability": "view", 918 | "type": "function" 919 | }, 920 | { 921 | "inputs": [ 922 | { 923 | "internalType": "uint256", 924 | "name": "tokenId", 925 | "type": "uint256" 926 | } 927 | ], 928 | "name": "tokenURI", 929 | "outputs": [ 930 | { 931 | "internalType": "string", 932 | "name": "", 933 | "type": "string" 934 | } 935 | ], 936 | "stateMutability": "view", 937 | "type": "function" 938 | }, 939 | { 940 | "inputs": [], 941 | "name": "totalSupply", 942 | "outputs": [ 943 | { 944 | "internalType": "uint256", 945 | "name": "", 946 | "type": "uint256" 947 | } 948 | ], 949 | "stateMutability": "view", 950 | "type": "function" 951 | }, 952 | { 953 | "inputs": [ 954 | { 955 | "internalType": "address", 956 | "name": "from", 957 | "type": "address" 958 | }, 959 | { 960 | "internalType": "address", 961 | "name": "to", 962 | "type": "address" 963 | }, 964 | { 965 | "internalType": "uint256", 966 | "name": "tokenId", 967 | "type": "uint256" 968 | } 969 | ], 970 | "name": "transferFrom", 971 | "outputs": [], 972 | "stateMutability": "nonpayable", 973 | "type": "function" 974 | }, 975 | { 976 | "inputs": [ 977 | { 978 | "internalType": "uint256", 979 | "name": "amountMinimum", 980 | "type": "uint256" 981 | }, 982 | { 983 | "internalType": "address", 984 | "name": "recipient", 985 | "type": "address" 986 | } 987 | ], 988 | "name": "unwrapWETH9", 989 | "outputs": [], 990 | "stateMutability": "payable", 991 | "type": "function" 992 | } 993 | ], 994 | "bytecode": "0x", 995 | "deployedBytecode": "0x", 996 | "linkReferences": {}, 997 | "deployedLinkReferences": {} 998 | } 999 | -------------------------------------------------------------------------------- /contracts/IUniswapV3Factory.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "IUniswapV3Factory", 4 | "sourceName": "contracts/external/uniswap/v3-core/interfaces/IUniswapV3Factory.sol", 5 | "abi": [ 6 | { 7 | "anonymous": false, 8 | "inputs": [ 9 | { 10 | "indexed": true, 11 | "internalType": "uint24", 12 | "name": "fee", 13 | "type": "uint24" 14 | }, 15 | { 16 | "indexed": true, 17 | "internalType": "int24", 18 | "name": "tickSpacing", 19 | "type": "int24" 20 | } 21 | ], 22 | "name": "FeeAmountEnabled", 23 | "type": "event" 24 | }, 25 | { 26 | "anonymous": false, 27 | "inputs": [ 28 | { 29 | "indexed": true, 30 | "internalType": "address", 31 | "name": "oldOwner", 32 | "type": "address" 33 | }, 34 | { 35 | "indexed": true, 36 | "internalType": "address", 37 | "name": "newOwner", 38 | "type": "address" 39 | } 40 | ], 41 | "name": "OwnerChanged", 42 | "type": "event" 43 | }, 44 | { 45 | "anonymous": false, 46 | "inputs": [ 47 | { 48 | "indexed": true, 49 | "internalType": "address", 50 | "name": "token0", 51 | "type": "address" 52 | }, 53 | { 54 | "indexed": true, 55 | "internalType": "address", 56 | "name": "token1", 57 | "type": "address" 58 | }, 59 | { 60 | "indexed": true, 61 | "internalType": "uint24", 62 | "name": "fee", 63 | "type": "uint24" 64 | }, 65 | { 66 | "indexed": false, 67 | "internalType": "int24", 68 | "name": "tickSpacing", 69 | "type": "int24" 70 | }, 71 | { 72 | "indexed": false, 73 | "internalType": "address", 74 | "name": "pool", 75 | "type": "address" 76 | } 77 | ], 78 | "name": "PoolCreated", 79 | "type": "event" 80 | }, 81 | { 82 | "inputs": [ 83 | { 84 | "internalType": "address", 85 | "name": "tokenA", 86 | "type": "address" 87 | }, 88 | { 89 | "internalType": "address", 90 | "name": "tokenB", 91 | "type": "address" 92 | }, 93 | { 94 | "internalType": "uint24", 95 | "name": "fee", 96 | "type": "uint24" 97 | } 98 | ], 99 | "name": "createPool", 100 | "outputs": [ 101 | { 102 | "internalType": "address", 103 | "name": "pool", 104 | "type": "address" 105 | } 106 | ], 107 | "stateMutability": "nonpayable", 108 | "type": "function" 109 | }, 110 | { 111 | "inputs": [ 112 | { 113 | "internalType": "uint24", 114 | "name": "fee", 115 | "type": "uint24" 116 | }, 117 | { 118 | "internalType": "int24", 119 | "name": "tickSpacing", 120 | "type": "int24" 121 | } 122 | ], 123 | "name": "enableFeeAmount", 124 | "outputs": [], 125 | "stateMutability": "nonpayable", 126 | "type": "function" 127 | }, 128 | { 129 | "inputs": [ 130 | { 131 | "internalType": "uint24", 132 | "name": "fee", 133 | "type": "uint24" 134 | } 135 | ], 136 | "name": "feeAmountTickSpacing", 137 | "outputs": [ 138 | { 139 | "internalType": "int24", 140 | "name": "", 141 | "type": "int24" 142 | } 143 | ], 144 | "stateMutability": "view", 145 | "type": "function" 146 | }, 147 | { 148 | "inputs": [ 149 | { 150 | "internalType": "address", 151 | "name": "tokenA", 152 | "type": "address" 153 | }, 154 | { 155 | "internalType": "address", 156 | "name": "tokenB", 157 | "type": "address" 158 | }, 159 | { 160 | "internalType": "uint24", 161 | "name": "fee", 162 | "type": "uint24" 163 | } 164 | ], 165 | "name": "getPool", 166 | "outputs": [ 167 | { 168 | "internalType": "address", 169 | "name": "pool", 170 | "type": "address" 171 | } 172 | ], 173 | "stateMutability": "view", 174 | "type": "function" 175 | }, 176 | { 177 | "inputs": [], 178 | "name": "owner", 179 | "outputs": [ 180 | { 181 | "internalType": "address", 182 | "name": "", 183 | "type": "address" 184 | } 185 | ], 186 | "stateMutability": "view", 187 | "type": "function" 188 | }, 189 | { 190 | "inputs": [ 191 | { 192 | "internalType": "address", 193 | "name": "_owner", 194 | "type": "address" 195 | } 196 | ], 197 | "name": "setOwner", 198 | "outputs": [], 199 | "stateMutability": "nonpayable", 200 | "type": "function" 201 | } 202 | ], 203 | "bytecode": "0x", 204 | "deployedBytecode": "0x", 205 | "linkReferences": {}, 206 | "deployedLinkReferences": {} 207 | } 208 | -------------------------------------------------------------------------------- /contracts/IUniswapV3Pool.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "owner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "int24", 14 | "name": "tickLower", 15 | "type": "int24" 16 | }, 17 | { 18 | "indexed": true, 19 | "internalType": "int24", 20 | "name": "tickUpper", 21 | "type": "int24" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "uint128", 26 | "name": "amount", 27 | "type": "uint128" 28 | }, 29 | { 30 | "indexed": false, 31 | "internalType": "uint256", 32 | "name": "amount0", 33 | "type": "uint256" 34 | }, 35 | { 36 | "indexed": false, 37 | "internalType": "uint256", 38 | "name": "amount1", 39 | "type": "uint256" 40 | } 41 | ], 42 | "name": "Burn", 43 | "type": "event" 44 | }, 45 | { 46 | "anonymous": false, 47 | "inputs": [ 48 | { 49 | "indexed": true, 50 | "internalType": "address", 51 | "name": "owner", 52 | "type": "address" 53 | }, 54 | { 55 | "indexed": false, 56 | "internalType": "address", 57 | "name": "recipient", 58 | "type": "address" 59 | }, 60 | { 61 | "indexed": true, 62 | "internalType": "int24", 63 | "name": "tickLower", 64 | "type": "int24" 65 | }, 66 | { 67 | "indexed": true, 68 | "internalType": "int24", 69 | "name": "tickUpper", 70 | "type": "int24" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "uint128", 75 | "name": "amount0", 76 | "type": "uint128" 77 | }, 78 | { 79 | "indexed": false, 80 | "internalType": "uint128", 81 | "name": "amount1", 82 | "type": "uint128" 83 | } 84 | ], 85 | "name": "Collect", 86 | "type": "event" 87 | }, 88 | { 89 | "anonymous": false, 90 | "inputs": [ 91 | { 92 | "indexed": true, 93 | "internalType": "address", 94 | "name": "sender", 95 | "type": "address" 96 | }, 97 | { 98 | "indexed": true, 99 | "internalType": "address", 100 | "name": "recipient", 101 | "type": "address" 102 | }, 103 | { 104 | "indexed": false, 105 | "internalType": "uint128", 106 | "name": "amount0", 107 | "type": "uint128" 108 | }, 109 | { 110 | "indexed": false, 111 | "internalType": "uint128", 112 | "name": "amount1", 113 | "type": "uint128" 114 | } 115 | ], 116 | "name": "CollectProtocol", 117 | "type": "event" 118 | }, 119 | { 120 | "anonymous": false, 121 | "inputs": [ 122 | { 123 | "indexed": true, 124 | "internalType": "address", 125 | "name": "sender", 126 | "type": "address" 127 | }, 128 | { 129 | "indexed": true, 130 | "internalType": "address", 131 | "name": "recipient", 132 | "type": "address" 133 | }, 134 | { 135 | "indexed": false, 136 | "internalType": "uint256", 137 | "name": "amount0", 138 | "type": "uint256" 139 | }, 140 | { 141 | "indexed": false, 142 | "internalType": "uint256", 143 | "name": "amount1", 144 | "type": "uint256" 145 | }, 146 | { 147 | "indexed": false, 148 | "internalType": "uint256", 149 | "name": "paid0", 150 | "type": "uint256" 151 | }, 152 | { 153 | "indexed": false, 154 | "internalType": "uint256", 155 | "name": "paid1", 156 | "type": "uint256" 157 | } 158 | ], 159 | "name": "Flash", 160 | "type": "event" 161 | }, 162 | { 163 | "anonymous": false, 164 | "inputs": [ 165 | { 166 | "indexed": false, 167 | "internalType": "uint16", 168 | "name": "observationCardinalityNextOld", 169 | "type": "uint16" 170 | }, 171 | { 172 | "indexed": false, 173 | "internalType": "uint16", 174 | "name": "observationCardinalityNextNew", 175 | "type": "uint16" 176 | } 177 | ], 178 | "name": "IncreaseObservationCardinalityNext", 179 | "type": "event" 180 | }, 181 | { 182 | "anonymous": false, 183 | "inputs": [ 184 | { 185 | "indexed": false, 186 | "internalType": "uint160", 187 | "name": "sqrtPriceX96", 188 | "type": "uint160" 189 | }, 190 | { 191 | "indexed": false, 192 | "internalType": "int24", 193 | "name": "tick", 194 | "type": "int24" 195 | } 196 | ], 197 | "name": "Initialize", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": false, 205 | "internalType": "address", 206 | "name": "sender", 207 | "type": "address" 208 | }, 209 | { 210 | "indexed": true, 211 | "internalType": "address", 212 | "name": "owner", 213 | "type": "address" 214 | }, 215 | { 216 | "indexed": true, 217 | "internalType": "int24", 218 | "name": "tickLower", 219 | "type": "int24" 220 | }, 221 | { 222 | "indexed": true, 223 | "internalType": "int24", 224 | "name": "tickUpper", 225 | "type": "int24" 226 | }, 227 | { 228 | "indexed": false, 229 | "internalType": "uint128", 230 | "name": "amount", 231 | "type": "uint128" 232 | }, 233 | { 234 | "indexed": false, 235 | "internalType": "uint256", 236 | "name": "amount0", 237 | "type": "uint256" 238 | }, 239 | { 240 | "indexed": false, 241 | "internalType": "uint256", 242 | "name": "amount1", 243 | "type": "uint256" 244 | } 245 | ], 246 | "name": "Mint", 247 | "type": "event" 248 | }, 249 | { 250 | "anonymous": false, 251 | "inputs": [ 252 | { 253 | "indexed": false, 254 | "internalType": "uint8", 255 | "name": "feeProtocol0Old", 256 | "type": "uint8" 257 | }, 258 | { 259 | "indexed": false, 260 | "internalType": "uint8", 261 | "name": "feeProtocol1Old", 262 | "type": "uint8" 263 | }, 264 | { 265 | "indexed": false, 266 | "internalType": "uint8", 267 | "name": "feeProtocol0New", 268 | "type": "uint8" 269 | }, 270 | { 271 | "indexed": false, 272 | "internalType": "uint8", 273 | "name": "feeProtocol1New", 274 | "type": "uint8" 275 | } 276 | ], 277 | "name": "SetFeeProtocol", 278 | "type": "event" 279 | }, 280 | { 281 | "anonymous": false, 282 | "inputs": [ 283 | { 284 | "indexed": true, 285 | "internalType": "address", 286 | "name": "sender", 287 | "type": "address" 288 | }, 289 | { 290 | "indexed": true, 291 | "internalType": "address", 292 | "name": "recipient", 293 | "type": "address" 294 | }, 295 | { 296 | "indexed": false, 297 | "internalType": "int256", 298 | "name": "amount0", 299 | "type": "int256" 300 | }, 301 | { 302 | "indexed": false, 303 | "internalType": "int256", 304 | "name": "amount1", 305 | "type": "int256" 306 | }, 307 | { 308 | "indexed": false, 309 | "internalType": "uint160", 310 | "name": "sqrtPriceX96", 311 | "type": "uint160" 312 | }, 313 | { 314 | "indexed": false, 315 | "internalType": "uint128", 316 | "name": "liquidity", 317 | "type": "uint128" 318 | }, 319 | { 320 | "indexed": false, 321 | "internalType": "int24", 322 | "name": "tick", 323 | "type": "int24" 324 | } 325 | ], 326 | "name": "Swap", 327 | "type": "event" 328 | }, 329 | { 330 | "inputs": [ 331 | { 332 | "internalType": "int24", 333 | "name": "tickLower", 334 | "type": "int24" 335 | }, 336 | { 337 | "internalType": "int24", 338 | "name": "tickUpper", 339 | "type": "int24" 340 | }, 341 | { 342 | "internalType": "uint128", 343 | "name": "amount", 344 | "type": "uint128" 345 | } 346 | ], 347 | "name": "burn", 348 | "outputs": [ 349 | { 350 | "internalType": "uint256", 351 | "name": "amount0", 352 | "type": "uint256" 353 | }, 354 | { 355 | "internalType": "uint256", 356 | "name": "amount1", 357 | "type": "uint256" 358 | } 359 | ], 360 | "stateMutability": "nonpayable", 361 | "type": "function" 362 | }, 363 | { 364 | "inputs": [ 365 | { 366 | "internalType": "address", 367 | "name": "recipient", 368 | "type": "address" 369 | }, 370 | { 371 | "internalType": "int24", 372 | "name": "tickLower", 373 | "type": "int24" 374 | }, 375 | { 376 | "internalType": "int24", 377 | "name": "tickUpper", 378 | "type": "int24" 379 | }, 380 | { 381 | "internalType": "uint128", 382 | "name": "amount0Requested", 383 | "type": "uint128" 384 | }, 385 | { 386 | "internalType": "uint128", 387 | "name": "amount1Requested", 388 | "type": "uint128" 389 | } 390 | ], 391 | "name": "collect", 392 | "outputs": [ 393 | { 394 | "internalType": "uint128", 395 | "name": "amount0", 396 | "type": "uint128" 397 | }, 398 | { 399 | "internalType": "uint128", 400 | "name": "amount1", 401 | "type": "uint128" 402 | } 403 | ], 404 | "stateMutability": "nonpayable", 405 | "type": "function" 406 | }, 407 | { 408 | "inputs": [ 409 | { 410 | "internalType": "address", 411 | "name": "recipient", 412 | "type": "address" 413 | }, 414 | { 415 | "internalType": "uint128", 416 | "name": "amount0Requested", 417 | "type": "uint128" 418 | }, 419 | { 420 | "internalType": "uint128", 421 | "name": "amount1Requested", 422 | "type": "uint128" 423 | } 424 | ], 425 | "name": "collectProtocol", 426 | "outputs": [ 427 | { 428 | "internalType": "uint128", 429 | "name": "amount0", 430 | "type": "uint128" 431 | }, 432 | { 433 | "internalType": "uint128", 434 | "name": "amount1", 435 | "type": "uint128" 436 | } 437 | ], 438 | "stateMutability": "nonpayable", 439 | "type": "function" 440 | }, 441 | { 442 | "inputs": [], 443 | "name": "factory", 444 | "outputs": [ 445 | { 446 | "internalType": "address", 447 | "name": "", 448 | "type": "address" 449 | } 450 | ], 451 | "stateMutability": "view", 452 | "type": "function" 453 | }, 454 | { 455 | "inputs": [], 456 | "name": "fee", 457 | "outputs": [ 458 | { 459 | "internalType": "uint24", 460 | "name": "", 461 | "type": "uint24" 462 | } 463 | ], 464 | "stateMutability": "view", 465 | "type": "function" 466 | }, 467 | { 468 | "inputs": [], 469 | "name": "feeGrowthGlobal0X128", 470 | "outputs": [ 471 | { 472 | "internalType": "uint256", 473 | "name": "", 474 | "type": "uint256" 475 | } 476 | ], 477 | "stateMutability": "view", 478 | "type": "function" 479 | }, 480 | { 481 | "inputs": [], 482 | "name": "feeGrowthGlobal1X128", 483 | "outputs": [ 484 | { 485 | "internalType": "uint256", 486 | "name": "", 487 | "type": "uint256" 488 | } 489 | ], 490 | "stateMutability": "view", 491 | "type": "function" 492 | }, 493 | { 494 | "inputs": [ 495 | { 496 | "internalType": "address", 497 | "name": "recipient", 498 | "type": "address" 499 | }, 500 | { 501 | "internalType": "uint256", 502 | "name": "amount0", 503 | "type": "uint256" 504 | }, 505 | { 506 | "internalType": "uint256", 507 | "name": "amount1", 508 | "type": "uint256" 509 | }, 510 | { 511 | "internalType": "bytes", 512 | "name": "data", 513 | "type": "bytes" 514 | } 515 | ], 516 | "name": "flash", 517 | "outputs": [], 518 | "stateMutability": "nonpayable", 519 | "type": "function" 520 | }, 521 | { 522 | "inputs": [ 523 | { 524 | "internalType": "uint16", 525 | "name": "observationCardinalityNext", 526 | "type": "uint16" 527 | } 528 | ], 529 | "name": "increaseObservationCardinalityNext", 530 | "outputs": [], 531 | "stateMutability": "nonpayable", 532 | "type": "function" 533 | }, 534 | { 535 | "inputs": [ 536 | { 537 | "internalType": "uint160", 538 | "name": "sqrtPriceX96", 539 | "type": "uint160" 540 | } 541 | ], 542 | "name": "initialize", 543 | "outputs": [], 544 | "stateMutability": "nonpayable", 545 | "type": "function" 546 | }, 547 | { 548 | "inputs": [], 549 | "name": "liquidity", 550 | "outputs": [ 551 | { 552 | "internalType": "uint128", 553 | "name": "", 554 | "type": "uint128" 555 | } 556 | ], 557 | "stateMutability": "view", 558 | "type": "function" 559 | }, 560 | { 561 | "inputs": [], 562 | "name": "maxLiquidityPerTick", 563 | "outputs": [ 564 | { 565 | "internalType": "uint128", 566 | "name": "", 567 | "type": "uint128" 568 | } 569 | ], 570 | "stateMutability": "view", 571 | "type": "function" 572 | }, 573 | { 574 | "inputs": [ 575 | { 576 | "internalType": "address", 577 | "name": "recipient", 578 | "type": "address" 579 | }, 580 | { 581 | "internalType": "int24", 582 | "name": "tickLower", 583 | "type": "int24" 584 | }, 585 | { 586 | "internalType": "int24", 587 | "name": "tickUpper", 588 | "type": "int24" 589 | }, 590 | { 591 | "internalType": "uint128", 592 | "name": "amount", 593 | "type": "uint128" 594 | }, 595 | { 596 | "internalType": "bytes", 597 | "name": "data", 598 | "type": "bytes" 599 | } 600 | ], 601 | "name": "mint", 602 | "outputs": [ 603 | { 604 | "internalType": "uint256", 605 | "name": "amount0", 606 | "type": "uint256" 607 | }, 608 | { 609 | "internalType": "uint256", 610 | "name": "amount1", 611 | "type": "uint256" 612 | } 613 | ], 614 | "stateMutability": "nonpayable", 615 | "type": "function" 616 | }, 617 | { 618 | "inputs": [ 619 | { 620 | "internalType": "uint256", 621 | "name": "index", 622 | "type": "uint256" 623 | } 624 | ], 625 | "name": "observations", 626 | "outputs": [ 627 | { 628 | "internalType": "uint32", 629 | "name": "blockTimestamp", 630 | "type": "uint32" 631 | }, 632 | { 633 | "internalType": "int56", 634 | "name": "tickCumulative", 635 | "type": "int56" 636 | }, 637 | { 638 | "internalType": "uint160", 639 | "name": "secondsPerLiquidityCumulativeX128", 640 | "type": "uint160" 641 | }, 642 | { 643 | "internalType": "bool", 644 | "name": "initialized", 645 | "type": "bool" 646 | } 647 | ], 648 | "stateMutability": "view", 649 | "type": "function" 650 | }, 651 | { 652 | "inputs": [ 653 | { 654 | "internalType": "uint32[]", 655 | "name": "secondsAgos", 656 | "type": "uint32[]" 657 | } 658 | ], 659 | "name": "observe", 660 | "outputs": [ 661 | { 662 | "internalType": "int56[]", 663 | "name": "tickCumulatives", 664 | "type": "int56[]" 665 | }, 666 | { 667 | "internalType": "uint160[]", 668 | "name": "secondsPerLiquidityCumulativeX128s", 669 | "type": "uint160[]" 670 | } 671 | ], 672 | "stateMutability": "view", 673 | "type": "function" 674 | }, 675 | { 676 | "inputs": [ 677 | { 678 | "internalType": "bytes32", 679 | "name": "key", 680 | "type": "bytes32" 681 | } 682 | ], 683 | "name": "positions", 684 | "outputs": [ 685 | { 686 | "internalType": "uint128", 687 | "name": "_liquidity", 688 | "type": "uint128" 689 | }, 690 | { 691 | "internalType": "uint256", 692 | "name": "feeGrowthInside0LastX128", 693 | "type": "uint256" 694 | }, 695 | { 696 | "internalType": "uint256", 697 | "name": "feeGrowthInside1LastX128", 698 | "type": "uint256" 699 | }, 700 | { 701 | "internalType": "uint128", 702 | "name": "tokensOwed0", 703 | "type": "uint128" 704 | }, 705 | { 706 | "internalType": "uint128", 707 | "name": "tokensOwed1", 708 | "type": "uint128" 709 | } 710 | ], 711 | "stateMutability": "view", 712 | "type": "function" 713 | }, 714 | { 715 | "inputs": [], 716 | "name": "protocolFees", 717 | "outputs": [ 718 | { 719 | "internalType": "uint128", 720 | "name": "token0", 721 | "type": "uint128" 722 | }, 723 | { 724 | "internalType": "uint128", 725 | "name": "token1", 726 | "type": "uint128" 727 | } 728 | ], 729 | "stateMutability": "view", 730 | "type": "function" 731 | }, 732 | { 733 | "inputs": [ 734 | { 735 | "internalType": "uint8", 736 | "name": "feeProtocol0", 737 | "type": "uint8" 738 | }, 739 | { 740 | "internalType": "uint8", 741 | "name": "feeProtocol1", 742 | "type": "uint8" 743 | } 744 | ], 745 | "name": "setFeeProtocol", 746 | "outputs": [], 747 | "stateMutability": "nonpayable", 748 | "type": "function" 749 | }, 750 | { 751 | "inputs": [], 752 | "name": "slot0", 753 | "outputs": [ 754 | { 755 | "internalType": "uint160", 756 | "name": "sqrtPriceX96", 757 | "type": "uint160" 758 | }, 759 | { 760 | "internalType": "int24", 761 | "name": "tick", 762 | "type": "int24" 763 | }, 764 | { 765 | "internalType": "uint16", 766 | "name": "observationIndex", 767 | "type": "uint16" 768 | }, 769 | { 770 | "internalType": "uint16", 771 | "name": "observationCardinality", 772 | "type": "uint16" 773 | }, 774 | { 775 | "internalType": "uint16", 776 | "name": "observationCardinalityNext", 777 | "type": "uint16" 778 | }, 779 | { 780 | "internalType": "uint8", 781 | "name": "feeProtocol", 782 | "type": "uint8" 783 | }, 784 | { 785 | "internalType": "bool", 786 | "name": "unlocked", 787 | "type": "bool" 788 | } 789 | ], 790 | "stateMutability": "view", 791 | "type": "function" 792 | }, 793 | { 794 | "inputs": [ 795 | { 796 | "internalType": "int24", 797 | "name": "tickLower", 798 | "type": "int24" 799 | }, 800 | { 801 | "internalType": "int24", 802 | "name": "tickUpper", 803 | "type": "int24" 804 | } 805 | ], 806 | "name": "snapshotCumulativesInside", 807 | "outputs": [ 808 | { 809 | "internalType": "int56", 810 | "name": "tickCumulativeInside", 811 | "type": "int56" 812 | }, 813 | { 814 | "internalType": "uint160", 815 | "name": "secondsPerLiquidityInsideX128", 816 | "type": "uint160" 817 | }, 818 | { 819 | "internalType": "uint32", 820 | "name": "secondsInside", 821 | "type": "uint32" 822 | } 823 | ], 824 | "stateMutability": "view", 825 | "type": "function" 826 | }, 827 | { 828 | "inputs": [ 829 | { 830 | "internalType": "address", 831 | "name": "recipient", 832 | "type": "address" 833 | }, 834 | { 835 | "internalType": "bool", 836 | "name": "zeroForOne", 837 | "type": "bool" 838 | }, 839 | { 840 | "internalType": "int256", 841 | "name": "amountSpecified", 842 | "type": "int256" 843 | }, 844 | { 845 | "internalType": "uint160", 846 | "name": "sqrtPriceLimitX96", 847 | "type": "uint160" 848 | }, 849 | { 850 | "internalType": "bytes", 851 | "name": "data", 852 | "type": "bytes" 853 | } 854 | ], 855 | "name": "swap", 856 | "outputs": [ 857 | { 858 | "internalType": "int256", 859 | "name": "amount0", 860 | "type": "int256" 861 | }, 862 | { 863 | "internalType": "int256", 864 | "name": "amount1", 865 | "type": "int256" 866 | } 867 | ], 868 | "stateMutability": "nonpayable", 869 | "type": "function" 870 | }, 871 | { 872 | "inputs": [ 873 | { 874 | "internalType": "int16", 875 | "name": "wordPosition", 876 | "type": "int16" 877 | } 878 | ], 879 | "name": "tickBitmap", 880 | "outputs": [ 881 | { 882 | "internalType": "uint256", 883 | "name": "", 884 | "type": "uint256" 885 | } 886 | ], 887 | "stateMutability": "view", 888 | "type": "function" 889 | }, 890 | { 891 | "inputs": [], 892 | "name": "tickSpacing", 893 | "outputs": [ 894 | { 895 | "internalType": "int24", 896 | "name": "", 897 | "type": "int24" 898 | } 899 | ], 900 | "stateMutability": "view", 901 | "type": "function" 902 | }, 903 | { 904 | "inputs": [ 905 | { 906 | "internalType": "int24", 907 | "name": "tick", 908 | "type": "int24" 909 | } 910 | ], 911 | "name": "ticks", 912 | "outputs": [ 913 | { 914 | "internalType": "uint128", 915 | "name": "liquidityGross", 916 | "type": "uint128" 917 | }, 918 | { 919 | "internalType": "int128", 920 | "name": "liquidityNet", 921 | "type": "int128" 922 | }, 923 | { 924 | "internalType": "uint256", 925 | "name": "feeGrowthOutside0X128", 926 | "type": "uint256" 927 | }, 928 | { 929 | "internalType": "uint256", 930 | "name": "feeGrowthOutside1X128", 931 | "type": "uint256" 932 | }, 933 | { 934 | "internalType": "int56", 935 | "name": "tickCumulativeOutside", 936 | "type": "int56" 937 | }, 938 | { 939 | "internalType": "uint160", 940 | "name": "secondsPerLiquidityOutsideX128", 941 | "type": "uint160" 942 | }, 943 | { 944 | "internalType": "uint32", 945 | "name": "secondsOutside", 946 | "type": "uint32" 947 | }, 948 | { 949 | "internalType": "bool", 950 | "name": "initialized", 951 | "type": "bool" 952 | } 953 | ], 954 | "stateMutability": "view", 955 | "type": "function" 956 | }, 957 | { 958 | "inputs": [], 959 | "name": "token0", 960 | "outputs": [ 961 | { 962 | "internalType": "address", 963 | "name": "", 964 | "type": "address" 965 | } 966 | ], 967 | "stateMutability": "view", 968 | "type": "function" 969 | }, 970 | { 971 | "inputs": [], 972 | "name": "token1", 973 | "outputs": [ 974 | { 975 | "internalType": "address", 976 | "name": "", 977 | "type": "address" 978 | } 979 | ], 980 | "stateMutability": "view", 981 | "type": "function" 982 | } 983 | ] -------------------------------------------------------------------------------- /contracts/WETH.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "guy", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "wad", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "src", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "dst", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "wad", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": false, 82 | "inputs": [ 83 | { 84 | "name": "wad", 85 | "type": "uint256" 86 | } 87 | ], 88 | "name": "withdraw", 89 | "outputs": [], 90 | "payable": false, 91 | "stateMutability": "nonpayable", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [], 97 | "name": "decimals", 98 | "outputs": [ 99 | { 100 | "name": "", 101 | "type": "uint8" 102 | } 103 | ], 104 | "payable": false, 105 | "stateMutability": "view", 106 | "type": "function" 107 | }, 108 | { 109 | "constant": true, 110 | "inputs": [ 111 | { 112 | "name": "", 113 | "type": "address" 114 | } 115 | ], 116 | "name": "balanceOf", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "uint256" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": true, 129 | "inputs": [], 130 | "name": "symbol", 131 | "outputs": [ 132 | { 133 | "name": "", 134 | "type": "string" 135 | } 136 | ], 137 | "payable": false, 138 | "stateMutability": "view", 139 | "type": "function" 140 | }, 141 | { 142 | "constant": false, 143 | "inputs": [ 144 | { 145 | "name": "dst", 146 | "type": "address" 147 | }, 148 | { 149 | "name": "wad", 150 | "type": "uint256" 151 | } 152 | ], 153 | "name": "transfer", 154 | "outputs": [ 155 | { 156 | "name": "", 157 | "type": "bool" 158 | } 159 | ], 160 | "payable": false, 161 | "stateMutability": "nonpayable", 162 | "type": "function" 163 | }, 164 | { 165 | "constant": false, 166 | "inputs": [], 167 | "name": "deposit", 168 | "outputs": [], 169 | "payable": true, 170 | "stateMutability": "payable", 171 | "type": "function" 172 | }, 173 | { 174 | "constant": true, 175 | "inputs": [ 176 | { 177 | "name": "", 178 | "type": "address" 179 | }, 180 | { 181 | "name": "", 182 | "type": "address" 183 | } 184 | ], 185 | "name": "allowance", 186 | "outputs": [ 187 | { 188 | "name": "", 189 | "type": "uint256" 190 | } 191 | ], 192 | "payable": false, 193 | "stateMutability": "view", 194 | "type": "function" 195 | }, 196 | { 197 | "payable": true, 198 | "stateMutability": "payable", 199 | "type": "fallback" 200 | }, 201 | { 202 | "anonymous": false, 203 | "inputs": [ 204 | { 205 | "indexed": true, 206 | "name": "src", 207 | "type": "address" 208 | }, 209 | { 210 | "indexed": true, 211 | "name": "guy", 212 | "type": "address" 213 | }, 214 | { 215 | "indexed": false, 216 | "name": "wad", 217 | "type": "uint256" 218 | } 219 | ], 220 | "name": "Approval", 221 | "type": "event" 222 | }, 223 | { 224 | "anonymous": false, 225 | "inputs": [ 226 | { 227 | "indexed": true, 228 | "name": "src", 229 | "type": "address" 230 | }, 231 | { 232 | "indexed": true, 233 | "name": "dst", 234 | "type": "address" 235 | }, 236 | { 237 | "indexed": false, 238 | "name": "wad", 239 | "type": "uint256" 240 | } 241 | ], 242 | "name": "Transfer", 243 | "type": "event" 244 | }, 245 | { 246 | "anonymous": false, 247 | "inputs": [ 248 | { 249 | "indexed": true, 250 | "name": "dst", 251 | "type": "address" 252 | }, 253 | { 254 | "indexed": false, 255 | "name": "wad", 256 | "type": "uint256" 257 | } 258 | ], 259 | "name": "Deposit", 260 | "type": "event" 261 | }, 262 | { 263 | "anonymous": false, 264 | "inputs": [ 265 | { 266 | "indexed": true, 267 | "name": "src", 268 | "type": "address" 269 | }, 270 | { 271 | "indexed": false, 272 | "name": "wad", 273 | "type": "uint256" 274 | } 275 | ], 276 | "name": "Withdrawal", 277 | "type": "event" 278 | } 279 | ] -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const { ethers, BigNumber } = require('ethers') 3 | const { logWithTimestamp} = require('./lib/common') 4 | const { quoteUniversalRouter, registerErrorHandler, npmContract, provider, signer, setupWebsocket, 5 | getPool, getAllLogs, getPoolPrice, getAmounts, getTokenAssetPriceX96, 6 | getTickSpacing, getFlashloanPoolOptions, getV3VaultAddress, getFlashLoanLiquidatorAddress, 7 | executeTx, getTokenDecimals, getTokenSymbol, getPoolToToken, 8 | getRevertUrlForDiscord, getExplorerUrlForDiscord, Q32, Q96 } = require('./lib/common') 9 | 10 | const v3VaultContract = new ethers.Contract(getV3VaultAddress(), require("./contracts/V3Vault.json").abi, provider) 11 | const floashLoanLiquidatorContract = new ethers.Contract(getFlashLoanLiquidatorAddress(), require("./contracts/FlashloanLiquidator.json").abi, provider) 12 | 13 | const positionLogInterval = 1 * 6000 // log positions each 1 min 14 | const enableNonFlashloanLiquidation = false 15 | 16 | const positions = {} 17 | const cachedTokenDecimals = {} 18 | const cachedCollateralFactorX32 = {} 19 | 20 | let cachedExchangeRateX96 21 | let asset, assetDecimals, assetSymbol 22 | let lastWSLifeCheck = new Date().getTime() 23 | 24 | let isCheckingAllPositions = false; 25 | 26 | async function updateDebtExchangeRate() { 27 | const info = await v3VaultContract.vaultInfo() 28 | cachedExchangeRateX96 = info.debtExchangeRateX96 29 | } 30 | 31 | async function loadPositions() { 32 | let adds = await getAllLogs(v3VaultContract.filters.Add()) 33 | let removes = await getAllLogs(v3VaultContract.filters.Remove()) 34 | let loadedPositions = 0 35 | // from newest to oldest - process each event once - remove deactivated positions 36 | while (adds.length > 0) { 37 | const event = adds[adds.length - 1] 38 | const tokenId = v3VaultContract.interface.parseLog(event).args.tokenId 39 | const isActive = removes.filter(e => tokenId.eq(v3VaultContract.interface.parseLog(e).args.tokenId) && (e.blockNumber > event.blockNumber || (e.blockNumber == event.blockNumber && e.logIndex > event.logIndex))).length === 0 40 | if (isActive) { 41 | await updatePosition(tokenId) 42 | loadedPositions++ 43 | } 44 | adds = adds.filter(e => !v3VaultContract.interface.parseLog(e).args.tokenId.eq(tokenId)) 45 | } 46 | logWithTimestamp(`Loaded ${loadedPositions} active positions`) 47 | } 48 | 49 | 50 | // loads all needed data for position 51 | async function updatePosition(tokenId) { 52 | // if processing - retry later 53 | if (positions[tokenId] && (positions[tokenId].isChecking || positions[tokenId].isExecuting || positions[tokenId].isUpdating)) { 54 | setTimeout(async() => await updatePosition(tokenId), 10000) 55 | return 56 | } 57 | 58 | if (!positions[tokenId]) { 59 | positions[tokenId] = { isUpdating: true } 60 | } else { 61 | positions[tokenId].isUpdating = true 62 | } 63 | 64 | try { 65 | const debtShares = await v3VaultContract.loans(tokenId) 66 | if (debtShares.gt(0)) { 67 | // add or update 68 | const { liquidity, tickLower, tickUpper, fee, token0, token1 } = await npmContract.positions(tokenId); 69 | const tickSpacing = getTickSpacing(fee) 70 | const poolAddress = await getPool(token0, token1, fee) 71 | 72 | const owner = await v3VaultContract.ownerOf(tokenId) 73 | 74 | // get current fees - for estimation 75 | const fees = await npmContract.connect(v3VaultContract.address).callStatic.collect([tokenId, ethers.constants.AddressZero, BigNumber.from(2).pow(128).sub(1), BigNumber.from(2).pow(128).sub(1)]) 76 | 77 | if (cachedTokenDecimals[token0] === undefined) { 78 | cachedTokenDecimals[token0] = await getTokenDecimals(token0) 79 | } 80 | if (cachedTokenDecimals[token1] === undefined) { 81 | cachedTokenDecimals[token1] = await getTokenDecimals(token1) 82 | } 83 | const decimals0 = cachedTokenDecimals[token0] 84 | const decimals1 = cachedTokenDecimals[token1] 85 | 86 | if (!cachedCollateralFactorX32[token0]) { 87 | const tokenConfig = await v3VaultContract.tokenConfigs(token0) 88 | cachedCollateralFactorX32[token0] = tokenConfig.collateralFactorX32 89 | } 90 | if (!cachedCollateralFactorX32[token1]) { 91 | const tokenConfig = await v3VaultContract.tokenConfigs(token1) 92 | cachedCollateralFactorX32[token1] = tokenConfig.collateralFactorX32 93 | } 94 | 95 | const collateralFactorX32 = cachedCollateralFactorX32[token0] < cachedCollateralFactorX32[token1] ? cachedCollateralFactorX32[token0] : cachedCollateralFactorX32[token1] 96 | 97 | positions[tokenId] = { ...positions[tokenId], tokenId, liquidity, tickLower, tickUpper, tickSpacing, fee, token0: token0.toLowerCase(), token1: token1.toLowerCase(), decimals0, decimals1, poolAddress, debtShares, owner, collateralFactorX32, fees0: fees.amount0, fees1: fees.amount1 } 98 | 99 | } else { 100 | delete positions[tokenId] 101 | } 102 | } catch(err) { 103 | // retry on error after 1 min 104 | setTimeout(async() => await updatePosition(tokenId), 60000) 105 | logWithTimestamp("Error updating position " + tokenId.toString(), err) 106 | } 107 | 108 | if (positions[tokenId]) { 109 | positions[tokenId].isUpdating = false 110 | } 111 | } 112 | 113 | // checks position 114 | async function checkPosition(position) { 115 | 116 | if (!position || position.isChecking || position.isExecuting || position.isUpdating) { 117 | return 118 | } 119 | position.isChecking = true 120 | 121 | let info, amount0, amount1 122 | 123 | // check if liquidation needed - step I 124 | try { 125 | const poolPrice = await getPoolPrice(position.poolAddress) 126 | const amounts = position.liquidity.gt(0) ? getAmounts(poolPrice.sqrtPriceX96, position.tickLower, position.tickUpper, position.liquidity) : { amount0: BigNumber.from(0), amount1 : BigNumber.from(0) } 127 | amount0 = amounts.amount0.add(position.fees0) 128 | amount1 = amounts.amount1.add(position.fees1) 129 | 130 | const price0X96 = await getTokenAssetPriceX96(position.token0, asset) 131 | const price1X96 = await getTokenAssetPriceX96(position.token1, asset) 132 | 133 | const assetValue = price0X96.mul(amount0).div(Q96).add(price1X96.mul(amount1).div(Q96)) 134 | const collateralValue = assetValue.mul(position.collateralFactorX32).div(Q32) 135 | const debtValue = position.debtShares.mul(cachedExchangeRateX96).div(Q96) 136 | 137 | if (debtValue.gt(collateralValue)) { 138 | // only call this once per minute to update position (&fees) 139 | if (!position.lastLiquidationCheck || position.lastLiquidationCheck + 60000 < Date.now()) { 140 | info = await v3VaultContract.loanInfo(position.tokenId) 141 | position.lastLiquidationCheck = Date.now() 142 | } 143 | } 144 | 145 | if (debtValue.gt(0) && (!position.lastLog || position.lastLog + positionLogInterval < Date.now())) { 146 | const factor = collateralValue.mul(100).div(debtValue).toNumber() / 100 147 | if (factor < 1.1) { 148 | const msg = `Low collateral factor ${factor.toFixed(2)} for ${getRevertUrlForDiscord(position.tokenId)} with debt ${ethers.utils.formatUnits(debtValue, assetDecimals)} ${assetSymbol}` 149 | logWithTimestamp(msg) 150 | position.lastLog = Date.now() 151 | } 152 | } 153 | 154 | } catch (err) { 155 | logWithTimestamp("Error checking position " + position.tokenId.toString(), err) 156 | info = null 157 | } 158 | 159 | if (info && info.liquidationValue.gt(0)) { 160 | 161 | // run liquidation - step II 162 | try { 163 | // amount that will be available to the contract - remove a bit for withdrawal slippage 164 | const amount0Available = amount0.mul(995).div(1000).mul(info.liquidationValue).div(info.fullValue) 165 | const amount1Available = amount1.mul(995).div(1000).mul(info.liquidationValue).div(info.fullValue) 166 | 167 | const deadline = Math.floor(Date.now() / 1000 + 1800) 168 | 169 | // prepare swaps 170 | let amount0In = BigNumber.from(0) 171 | let swapData0 = "0x" 172 | let pools = [] 173 | if (position.token0 != asset && amount0Available.gt(0)) { 174 | amount0In = amount0Available 175 | const quote = await quoteUniversalRouter(position.token0, asset, position.decimals0, assetDecimals, amount0In, floashLoanLiquidatorContract.address, 100, deadline, 0, ethers.constants.AddressZero) 176 | swapData0 = quote.data 177 | pools.push(...quote.pools.map(p => p.toLowerCase())) 178 | } 179 | 180 | let amount1In = BigNumber.from(0) 181 | let swapData1 = "0x" 182 | if (position.token1 != asset && amount1Available.gt(0)) { 183 | amount1In = amount1Available 184 | const quote = await quoteUniversalRouter(position.token1, asset, position.decimals1, assetDecimals, amount1In, floashLoanLiquidatorContract.address, 100, deadline, 0, ethers.constants.AddressZero) 185 | swapData1 = quote.data 186 | pools.push(...quote.pools.map(p => p.toLowerCase())) 187 | } 188 | 189 | pools.push(position.poolAddress) 190 | 191 | const flashLoanPoolOptions = getFlashloanPoolOptions(asset) 192 | const flashLoanPool = flashLoanPoolOptions.filter(o => !pools.includes(o.toLowerCase()))[0] 193 | 194 | const reward = info.liquidationValue.sub(info.liquidationCost) 195 | 196 | const minReward = BigNumber.from(0) // 0% of reward must be recieved in assset after swaps and everything - rest in leftover token - no problem because flashloan liquidation 197 | 198 | let params = {tokenId : position.tokenId, debtShares: position.debtShares, vault: v3VaultContract.address, flashLoanPool, amount0In, swapData0, amount1In, swapData1, minReward, deadline } 199 | 200 | let useFlashloan = true 201 | let gasLimit 202 | try { 203 | gasLimit = await floashLoanLiquidatorContract.connect(signer).estimateGas.liquidate(params) 204 | } catch (err) { 205 | logWithTimestamp("Error trying flashloan liquidation for " + position.tokenId.toString(), err) 206 | 207 | if (enableNonFlashloanLiquidation) { 208 | // if there is any error with liquidation - fallback to non-flashloan liquidation 209 | useFlashloan = false 210 | params = { tokenId : position.tokenId, amount0Min: BigNumber.from(0), amount1Min: BigNumber.from(0), recipient: signer.address, permitData: "0x", deadline} 211 | gasLimit = await v3VaultContract.connect(signer).estimateGas.liquidate(params) 212 | } else { 213 | throw err 214 | } 215 | } 216 | 217 | const tx = useFlashloan ? 218 | await floashLoanLiquidatorContract.populateTransaction.liquidate(params, { gasLimit: gasLimit.mul(125).div(100) }) : 219 | await v3VaultContract.populateTransaction.liquidate(params, { gasLimit: gasLimit.mul(125).div(100) }) 220 | 221 | position.isExecuting = true 222 | const { hash, error } = await executeTx(tx, async (success) => { 223 | position.isExecuting = false 224 | }) 225 | 226 | if (hash) { 227 | const msg = `Executing liquidation ${useFlashloan ? "with" : "without" } flashloan for ${getRevertUrlForDiscord(position.tokenId)} with reward of ${ethers.utils.formatUnits(reward, assetDecimals)} ${assetSymbol} - ${getExplorerUrlForDiscord(hash)}` 228 | logWithTimestamp(msg) 229 | } else { 230 | throw error 231 | } 232 | } catch (err) { 233 | logWithTimestamp("Error liquidating position " + position.tokenId.toString(), err) 234 | } 235 | } else if (info) { 236 | // update values if not liquidatable - but estimation indicated it was 237 | position.isChecking = false 238 | await updatePosition(position.tokenId) 239 | } 240 | 241 | position.isChecking = false 242 | } 243 | 244 | async function checkAllPositions() { 245 | if (isCheckingAllPositions) { 246 | logWithTimestamp("Regular check of all positions is already in progress. Skipping this execution."); 247 | return; 248 | } 249 | 250 | isCheckingAllPositions = true; 251 | logWithTimestamp("Performing regular check of all positions"); 252 | 253 | try { 254 | for (const position of Object.values(positions)) { 255 | await checkPosition(position); 256 | } 257 | logWithTimestamp("Regular check of all positions completed successfully"); 258 | } catch (error) { 259 | logWithTimestamp("Error during regular position check:", error); 260 | } finally { 261 | isCheckingAllPositions = false; 262 | } 263 | } 264 | 265 | async function run() { 266 | 267 | registerErrorHandler() 268 | 269 | asset = (await v3VaultContract.asset()).toLowerCase() 270 | assetDecimals = await getTokenDecimals(asset) 271 | assetSymbol = await getTokenSymbol(asset) 272 | 273 | await updateDebtExchangeRate() 274 | 275 | // setup websockets for monitoring changes to positions 276 | setupWebsocket([ 277 | { 278 | filter: v3VaultContract.filters.Add(), 279 | handler: async (e) => { await updatePosition(v3VaultContract.interface.parseLog(e).args.tokenId) } 280 | }, 281 | { 282 | filter: v3VaultContract.filters.Remove(), 283 | handler: async (e) => { await updatePosition(v3VaultContract.interface.parseLog(e).args.tokenId) } 284 | }, 285 | { 286 | filter: v3VaultContract.filters.Borrow(), 287 | handler: async (e) => { await updatePosition(v3VaultContract.interface.parseLog(e).args.tokenId) } 288 | }, 289 | { 290 | filter: v3VaultContract.filters.Repay(), 291 | handler: async (e) => { await updatePosition(v3VaultContract.interface.parseLog(e).args.tokenId) } 292 | }, 293 | { 294 | filter: v3VaultContract.filters.WithdrawCollateral(), 295 | handler: async (e) => { await updatePosition(v3VaultContract.interface.parseLog(e).args.tokenId) } 296 | }, 297 | { 298 | filter: npmContract.filters.IncreaseLiquidity(), 299 | handler: async (e) => { 300 | const tokenId = npmContract.interface.parseLog(e).args.tokenId 301 | if (positions[tokenId]) { 302 | await updatePosition(tokenId) 303 | } 304 | } 305 | } 306 | ], async function(poolAddress) { 307 | 308 | 309 | const time = new Date() 310 | // every 5 minutes 311 | if (time.getTime() > lastWSLifeCheck + 300000) { 312 | logWithTimestamp("WS Live check", time.toISOString()) 313 | lastWSLifeCheck = time.getTime() 314 | } 315 | 316 | // if price reference pool price changed - check all positions with affected token 317 | const affectedToken = getPoolToToken(asset, poolAddress) 318 | if (affectedToken) { 319 | const toCheckPositions = Object.values(positions).filter(p => p.token0 === affectedToken || p.token1 === affectedToken) 320 | for (const position of toCheckPositions) { 321 | await checkPosition(position) 322 | } 323 | } 324 | }) 325 | 326 | await loadPositions() 327 | 328 | setInterval(async () => { await updateDebtExchangeRate() }, 60000) 329 | 330 | // Set up regular interval checks 331 | const CHECK_INTERVAL = 15 * 60 * 1000; // 15 minutes in milliseconds 332 | setInterval(async () => { 333 | await checkAllPositions(); 334 | }, CHECK_INTERVAL); 335 | 336 | process.on('SIGINT', () => { 337 | logWithTimestamp('Received SIGINT. Shutting down gracefully...'); 338 | // Close any open connections, stop any ongoing operations 339 | process.exit(0); 340 | }); 341 | } 342 | 343 | run() -------------------------------------------------------------------------------- /lib/common.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const ethers = require("ethers"); 3 | const univ3prices = require('@thanpolas/univ3prices') 4 | const Mutex = require('async-mutex').Mutex 5 | const mutex = new Mutex() 6 | const fs = require('fs') 7 | 8 | const { AlphaRouter, SwapType } = require('@uniswap/smart-order-router') 9 | const { Token, CurrencyAmount, TradeType, Percent, ChainId } = require('@uniswap/sdk-core') 10 | 11 | const mode = "LIQUIDATOR" 12 | const network = process.env.NETWORK 13 | const exchange = "uniswap-v3" 14 | 15 | const IERC20_ABI = require("../contracts/IERC20.json") 16 | const POOL_ABI = require("../contracts/IUniswapV3Pool.json") 17 | const FACTORY_RAW = require("../contracts/IUniswapV3Factory.json") 18 | const NPM_RAW = require("../contracts/INonfungiblePositionManager.json") 19 | 20 | const BigNumber = ethers.BigNumber 21 | 22 | const Q32 = BigNumber.from(2).pow(32) 23 | const Q64 = BigNumber.from(2).pow(64) 24 | const Q96 = BigNumber.from(2).pow(96) 25 | 26 | const genericPoolContract = new ethers.Contract(ethers.constants.AddressZero, POOL_ABI) 27 | 28 | // cache for price pools used to estimate token value in ETH 29 | const pricePoolCache = {} 30 | 31 | const observationCardinalityIncreases = {} 32 | 33 | // current prices are stored here 34 | const prices = {} 35 | 36 | const provider = new ethers.providers.JsonRpcProvider(process.env["RPC_URL_" + network.toUpperCase()]) 37 | const privateProvider = process.env["PRIVATE_RPC_URL_" + network.toUpperCase()] ? new ethers.providers.JsonRpcProvider(process.env["PRIVATE_RPC_URL_" + network.toUpperCase()]) : provider 38 | const signer = new ethers.Wallet(process.env["PRIVATE_KEY_" + mode], provider) 39 | const privateSigner = new ethers.Wallet(process.env["PRIVATE_KEY_" + mode], privateProvider) 40 | 41 | const npmContract = new ethers.Contract(getNPMAddress(), NPM_RAW.abi, provider) 42 | 43 | // current ws provider, is replaced on disconnect 44 | let wsProvider; 45 | 46 | // last nonce 47 | let lastNonce; 48 | const pendingTxs = {}; 49 | 50 | // gas price for tx execution 51 | async function getGasPriceData() { 52 | if (network == "mainnet" || network == "arbitrum") { 53 | // mainnet EIP-1559 handling 54 | const { maxFeePerGas, maxPriorityFeePerGas } = await provider.getFeeData() 55 | return { maxFeePerGas, maxPriorityFeePerGas } 56 | } else { 57 | return { gasPrice: await provider.getGasPrice() } 58 | } 59 | } 60 | 61 | // executes transaction and does checking until it is really executed 62 | // IMPORTANT this method must not be called in parallel because of nonce handling 63 | async function executeTx(tx, callback) { 64 | const release = await mutex.acquire() 65 | try { 66 | let nonce 67 | // first time load nonce 68 | if (!lastNonce) { 69 | nonce = await provider.getTransactionCount(signer.address) 70 | } else { 71 | nonce = lastNonce + 1 72 | } 73 | const gasPriceData = await getGasPriceData() 74 | tx = { ...tx, ...gasPriceData, nonce } 75 | 76 | // set pending tx - BEFORE sending because sending may fail (in this case will be resent) 77 | pendingTxs[nonce] = tx 78 | lastNonce = nonce 79 | setTimeout(async () => await checkTx(nonce, signer, 0, callback), 10000) 80 | 81 | const result = await privateSigner.sendTransaction(tx) 82 | 83 | return { hash: result.hash } 84 | } catch (err) { 85 | console.log(err) 86 | await callback(false) 87 | return { error: err } 88 | } finally { 89 | release(); 90 | } 91 | } 92 | 93 | // gets all logs for a given filter (works only on alchemy for now) 94 | // this method should help us avoid 95 | // creating subgraphs for each small contract 96 | async function getAllLogs(filter) { 97 | 98 | let finished = false 99 | let from = 0 100 | let to = "latest" 101 | 102 | const logs = [] 103 | 104 | while (!finished) { 105 | try { 106 | let events = await provider.getLogs({ 107 | fromBlock: from, 108 | toBlock: to, 109 | ...filter 110 | }) 111 | logs.push(...events) 112 | 113 | if (to == "latest") { 114 | finished = true 115 | } else { 116 | // continue from here 117 | from = to + 1 118 | to = "latest" 119 | } 120 | } catch (err) { 121 | const values = err.body.match("this block range should work: \\[(0x.*), (0x.*)\\]") 122 | if (values && values.length === 3) { 123 | const newTo = parseInt(values[2], 16) 124 | if (newTo == to) { 125 | throw new Error("Invalid block range reached.") 126 | } else { 127 | to = newTo 128 | } 129 | } else { 130 | throw err 131 | } 132 | } 133 | } 134 | return logs 135 | } 136 | 137 | function getDummyTx(nonce) { 138 | return { value: 0, nonce, to: ethers.utils.AddressZero } 139 | } 140 | 141 | async function checkTx(nonce, signer, intents, callback) { 142 | try { 143 | // confirmed tx count 144 | const currentNonce = await provider.getTransactionCount(signer.address) 145 | 146 | console.log("Checking nonce", nonce, "current", currentNonce, "intent", intents) 147 | 148 | if (currentNonce > nonce) { 149 | console.log("Tx with nonce", nonce, "complete") 150 | 151 | delete pendingTxs[nonce] 152 | 153 | // call callback with true if tx was executed 154 | await callback(intents <= 3) 155 | 156 | return 157 | } else if (currentNonce === nonce) { 158 | 159 | // replace it with current gas price - same nonce 160 | const gasPriceData = await getGasPriceData() 161 | 162 | console.log("Replacing tx with gas", gasPriceData) 163 | 164 | // after 3 intents - give up - try cheap dummy tx to free up nonce 165 | const txToSend = intents < 3 ? pendingTxs[nonce] : getDummyTx(nonce) 166 | const newTx = { ...txToSend, ...gasPriceData } 167 | 168 | intents++ 169 | 170 | const result = await signer.sendTransaction(newTx) 171 | 172 | console.log("Replacement TX for nonce " + nonce + " " + result.hash) 173 | } else { 174 | // keep timeout there are other tx before this one 175 | } 176 | } catch (err) { 177 | // if error happens same hash is checked later on 178 | console.log("error in checkTx", nonce, intents, err) 179 | } 180 | setTimeout(async () => await checkTx(nonce, signer, intents, callback), 10000) 181 | } 182 | 183 | async function findPricePoolForTokenCached(address) { 184 | 185 | if (pricePoolCache[address]) { 186 | return pricePoolCache[address] 187 | } 188 | 189 | const minimalBalanceETH = BigNumber.from(10).pow(18) 190 | let maxBalanceETH = BigNumber.from(0) 191 | let pricePoolAddress = null 192 | let isToken1WETH = null 193 | 194 | const nativeTokenAddress = getNativeTokenAddress() 195 | const nativeToken = new ethers.Contract(nativeTokenAddress, IERC20_ABI, provider) 196 | 197 | for (let fee of [100, 500, 3000, 10000]) { 198 | const candidatePricePoolAddress = await getPool(address, nativeTokenAddress, fee) 199 | if (candidatePricePoolAddress > 0) { 200 | const poolContract = new ethers.Contract(candidatePricePoolAddress, POOL_ABI, provider) 201 | 202 | const balanceETH = (await nativeToken.balanceOf(candidatePricePoolAddress)) 203 | if (balanceETH.gt(maxBalanceETH) && balanceETH.gte(minimalBalanceETH)) { 204 | pricePoolAddress = candidatePricePoolAddress 205 | maxBalanceETH = balanceETH 206 | if (isToken1WETH === null) { 207 | isToken1WETH = (await poolContract.token1()).toLowerCase() == nativeTokenAddress; 208 | } 209 | } 210 | 211 | } 212 | } 213 | 214 | pricePoolCache[address] = { address: pricePoolAddress, isToken1WETH } 215 | 216 | return pricePoolCache[address] 217 | } 218 | 219 | async function getTokenDecimals(token) { 220 | const tokenContract = new ethers.Contract(token, IERC20_ABI, provider) 221 | return await tokenContract.decimals() 222 | } 223 | 224 | async function getTokenSymbol(token) { 225 | const tokenContract = new ethers.Contract(token, IERC20_ABI, provider) 226 | return await tokenContract.symbol() 227 | } 228 | 229 | async function getPoolPrice(poolAddress, force) { 230 | let price = prices[poolAddress] 231 | if (!force && price) { 232 | return price 233 | } 234 | const poolContract = new ethers.Contract(poolAddress, POOL_ABI, provider) 235 | const slot0 = await poolContract.slot0() 236 | prices[poolAddress] = { tick: slot0.tick, sqrtPriceX96: slot0.sqrtPriceX96 } 237 | return prices[poolAddress] 238 | } 239 | 240 | async function getPool(token0, token1, fee) { 241 | const factoryContract = new ethers.Contract(getFactoryAddress(), FACTORY_RAW.abi, provider) 242 | const poolAddress = await factoryContract.getPool(token0, token1, fee) 243 | return poolAddress.toLowerCase() 244 | } 245 | 246 | function toEthersBigInt(ca) { 247 | return ethers.utils.parseUnits(ca.toFixed(), ca.currency.decimals) 248 | } 249 | 250 | async function quoteUniversalRouter(tokenIn, tokenOut, tokenInDecimals, tokenOutDecimals, amountIn, recipient, slippageX10000, deadline, feeX10000, feeRecipient) { 251 | 252 | const chainId = getChainId(network) 253 | 254 | const router = new AlphaRouter({ chainId: chainId, provider: provider }) 255 | 256 | const inputToken = new Token(chainId, tokenIn, tokenInDecimals, 'I', 'I') 257 | const outputToken = new Token(chainId, tokenOut, tokenOutDecimals, 'O', 'O') 258 | 259 | const inputAmount = CurrencyAmount.fromRawAmount(inputToken, amountIn.toString()) 260 | 261 | // collect all used pools 262 | const pools = [] 263 | 264 | // get quote from smart order router 265 | const route = await router.route( 266 | inputAmount, 267 | outputToken, 268 | TradeType.EXACT_INPUT, 269 | { 270 | type: SwapType.UNIVERSAL_ROUTER, 271 | recipient: recipient, 272 | slippageTolerance: new Percent(slippageX10000, 10000), 273 | deadline: deadline 274 | }, 275 | { 276 | protocols: ["V3"] 277 | } 278 | ) 279 | 280 | // subtract fee from output token amount - if present 281 | let commands = "0x" 282 | let inputs = [] 283 | 284 | const universalRouterAddress = getUniversalRouterAddress() 285 | 286 | for (const routePart of route.route) { 287 | const routeTypes = [] 288 | const routeData = [] 289 | for (const [i, token] of routePart.tokenPath.entries()) { 290 | if (i > 0) { 291 | routeTypes.push("uint24") 292 | routeData.push(routePart.route.pools[i - 1].fee) 293 | } 294 | routeTypes.push("address") 295 | routeData.push(token.address) 296 | } 297 | 298 | pools.push(...(routePart.poolAddresses || routePart.poolIdentifiers)) 299 | 300 | const packedRoute = ethers.utils.solidityPack(routeTypes, routeData) 301 | const amountIn = toEthersBigInt(routePart.amount) 302 | const amountOutMin = toEthersBigInt(routePart.quote).mul(10000 - slippageX10000).div(10000) 303 | 304 | // exact input command 305 | commands += "00" 306 | 307 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "uint256", "uint256", "bytes", "bool"], [universalRouterAddress, amountIn, amountOutMin, packedRoute, false])); 308 | } 309 | 310 | let amountFee = ethers.BigNumber.from(0) 311 | let amountOut = toEthersBigInt(route.quote) 312 | 313 | if (feeX10000 > 0) { 314 | // add fee transfer command for input token 315 | amountFee = amountOut.mul(feeX10000).div(10000) // estimate amount fee here - depends on the swap 316 | commands += "06" 317 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "address", "uint256"], [tokenOut, feeRecipient, feeX10000])) 318 | } 319 | 320 | 321 | // sweep commands for input and output tokens 322 | commands += "04" 323 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "address", "uint256"], [tokenIn, recipient, 0])) 324 | commands += "04" 325 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "address", "uint256"], [tokenOut, recipient, 0])) 326 | 327 | 328 | const data = getUniversalRouterSwapData(commands, inputs, deadline) 329 | 330 | return { 331 | amountIn: amountIn, 332 | amountFee: amountFee, 333 | amountOut: amountOut.sub(amountFee), 334 | amountOutMin: amountOut.mul(10000 - slippageX10000).div(10000), 335 | data: data, 336 | pools: pools 337 | } 338 | } 339 | 340 | function getUniversalRouterSwapDataSinglePool(tokenIn, tokenOut, fee, amountIn, amountOutMin, recipient, deadline) { 341 | let commands = "0x" 342 | let inputs = [] 343 | 344 | const packedRoute = ethers.utils.solidityPack(["address", "uint24", "address"], [tokenIn, fee, tokenOut]) 345 | 346 | // exact input command 347 | commands += "00" 348 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "uint256", "uint256", "bytes", "bool"], [recipient, amountIn, amountOutMin, packedRoute, false])); 349 | 350 | // sweep command for input token (if not all swapped) 351 | commands += "04" 352 | inputs.push(ethers.utils.defaultAbiCoder.encode(["address", "address", "uint256"], [tokenIn, recipient, 0])) 353 | 354 | const data = getUniversalRouterSwapData(commands, inputs, deadline) 355 | 356 | return { data } 357 | } 358 | 359 | function getUniversalRouterSwapData(commands, inputs, deadline) { 360 | const universalRouterAddress = getUniversalRouterAddress() 361 | const universalRouterData = ethers.utils.defaultAbiCoder.encode(["tuple(bytes,bytes[],uint256)"], [[commands, inputs, deadline]]) 362 | return ethers.utils.defaultAbiCoder.encode(["address", "bytes"], [universalRouterAddress, universalRouterData]) 363 | } 364 | 365 | function sqrt(bn) { 366 | x = BigNumber.from(bn) 367 | let z = x.add(1).div(2) 368 | let y = x 369 | while (z.sub(y).isNegative()) { 370 | y = z 371 | z = x.div(z).add(z).div(2) 372 | } 373 | return y 374 | } 375 | 376 | function getChainId() { 377 | return { 378 | "mainnet": ChainId.MAINNET, 379 | "polygon": ChainId.POLYGON, 380 | "optimism": ChainId.OPTIMISM, 381 | "arbitrum": ChainId.ARBITRUM_ONE, 382 | "bnb": ChainId.BNB, 383 | "evmos": 9001, 384 | "base": ChainId.BASE 385 | }[network]; 386 | } 387 | 388 | function getNativeTokenAddress() { 389 | return { 390 | "mainnet": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 391 | "polygon": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", 392 | "optimism": "0x4200000000000000000000000000000000000006", 393 | "arbitrum": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", 394 | "bnb": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", 395 | "evmos": "0xd4949664cd82660aae99bedc034a0dea8a0bd517", 396 | "base": "0x4200000000000000000000000000000000000006" 397 | }[network]; 398 | } 399 | function getNativeTokenSymbol() { 400 | return network === "evmos" ? "EVMOS" : (network === "polygon" ? "MATIC" : (network === "bnb" ? "BNB" : "ETH")) 401 | } 402 | function getFactoryAddress() { 403 | return { 404 | "mainnet": "0x1F98431c8aD98523631AE4a59f267346ea31F984", 405 | "polygon": "0x1F98431c8aD98523631AE4a59f267346ea31F984", 406 | "optimism": "0x1F98431c8aD98523631AE4a59f267346ea31F984", 407 | "arbitrum": "0x1F98431c8aD98523631AE4a59f267346ea31F984", 408 | "bnb": (exchange === "uniswap-v3" ? "0xdb1d10011ad0ff90774d0c6bb92e5c5c8b4461f7" : "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865"), 409 | "evmos": "0xf544365e7065966f190155f629ce0182fc68eaa2", 410 | "base": "0x33128a8fc17869897dce68ed026d694621f6fdfd" 411 | }[network]; 412 | } 413 | function getNPMAddress() { 414 | return { 415 | "mainnet": "0xc36442b4a4522e871399cd717abdd847ab11fe88", 416 | "polygon": "0xc36442b4a4522e871399cd717abdd847ab11fe88", 417 | "optimism": "0xc36442b4a4522e871399cd717abdd847ab11fe88", 418 | "arbitrum": "0xc36442b4a4522e871399cd717abdd847ab11fe88", 419 | "bnb": (exchange === "uniswap-v3" ? "0x7b8a01b39d58278b5de7e48c8449c9f4f5170613" : "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364"), 420 | "evmos": "0x5fe5daaa011673289847da4f76d63246ddb2965d", 421 | "base": "0x03a520b32c04bf3beef7beb72e919cf822ed34f1" 422 | }[network]; 423 | } 424 | function getUniversalRouterAddress() { 425 | return { 426 | "mainnet": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", 427 | "polygon": "0x643770E279d5D0733F21d6DC03A8efbABf3255B4", 428 | "optimism": "0xeC8B0F7Ffe3ae75d7FfAb09429e3675bb63503e4", 429 | "arbitrum": "0x5E325eDA8064b456f4781070C0738d849c824258", 430 | "bnb": "0xeC8B0F7Ffe3ae75d7FfAb09429e3675bb63503e4", 431 | "evmos": "", 432 | "base": "0xeC8B0F7Ffe3ae75d7FfAb09429e3675bb63503e4" 433 | }[network]; 434 | } 435 | function getV3VaultAddress() { 436 | return { 437 | "mainnet": "", 438 | "polygon": "", 439 | "optimism": "", 440 | "arbitrum": "0x74e6afef5705beb126c6d3bf46f8fad8f3e07825", 441 | "bnb": "", 442 | "evmos": "", 443 | "base": "" 444 | }[network]; 445 | } 446 | function getFlashLoanLiquidatorAddress() { 447 | return { 448 | "mainnet": "", 449 | "polygon": "", 450 | "optimism": "", 451 | "arbitrum": "0x5b94d444dfba48780524a1f0cd116f8a57bfefc2", 452 | "bnb": "", 453 | "evmos": "", 454 | "base": "" 455 | }[network]; 456 | } 457 | 458 | function getRevertUrlForDiscord(id) { 459 | const exchangeName = network === "evmos" ? "forge-position" : (exchange === "pancakeswap-v3" ? "pancake-position" : "uniswap-position") 460 | return `` 461 | } 462 | 463 | function getExplorerUrlForDiscord(hash) { 464 | const url = { 465 | "mainnet": "https://etherscan.io/tx/", 466 | "polygon": "https://polygonscan.com/tx/", 467 | "optimism": "https://optimistic.etherscan.io/tx/", 468 | "arbitrum": "https://arbiscan.io/tx/", 469 | "bnb": "https://bscscan.com/tx/", 470 | "evmos": "https://www.mintscan.io/evmos/tx/", 471 | "base": "https://basescan.org/tx/" 472 | }[network] 473 | 474 | return `[${hash}](<${url}${hash}>)` 475 | } 476 | 477 | function getFlashloanPoolOptions(asset) { 478 | return { 479 | "arbitrum": { 480 | "0xaf88d065e77c8cc2239327c5edb3a432268e5831": ["0xc6962004f452be9203591991d15f6b388e09e8d0", "0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6", "0xc473e2aee3441bf9240be85eb122abb059a3b57c"] 481 | } 482 | }[network][asset]; 483 | } 484 | 485 | // setups websocket for prices and adds reconnection handling 486 | function setupWebsocket(filters, poolChangeCallback) { 487 | 488 | console.log("WS Provider created") 489 | 490 | wsProvider = new ethers.providers.WebSocketProvider(process.env["WS_RPC_URL_" + network.toUpperCase()]) 491 | 492 | let pingTimeout = null 493 | let keepAliveInterval = null 494 | 495 | wsProvider._websocket.on('open', () => { 496 | 497 | console.log("WS Provider connected") 498 | 499 | keepAliveInterval = setInterval(() => { 500 | wsProvider._websocket.ping() 501 | pingTimeout = setTimeout(() => { 502 | try { 503 | wsProvider._websocket.terminate() 504 | } catch (err) { 505 | console.log(err) 506 | // failed terminating - so its still open - should be ok 507 | } 508 | }, 15000) 509 | }, 7500) 510 | 511 | // if pools (prices) need to be monitored 512 | if (poolChangeCallback) { 513 | const filter = genericPoolContract.filters.Swap(null, null) 514 | filter.address = null 515 | wsProvider.on(filter, async (...args) => { 516 | try { 517 | const event = args[args.length - 1] 518 | const a = genericPoolContract.interface.parseLog(event).args 519 | prices[event.address.toLowerCase()] = { tick: a.tick, sqrtPriceX96: a.sqrtPriceX96 } 520 | await poolChangeCallback(event.address.toLowerCase()) 521 | } catch (err) { 522 | console.log("Error processing swap event", err) 523 | } 524 | }) 525 | } 526 | 527 | // add custom filters 528 | for (const filter of filters) { 529 | wsProvider.on(filter.filter, async (...args) => { 530 | const event = args[args.length - 1] 531 | await filter.handler(event) 532 | }) 533 | } 534 | }) 535 | 536 | wsProvider._websocket.on('close', () => { 537 | 538 | console.log("WS Provider disconnected") 539 | 540 | clearInterval(keepAliveInterval) 541 | clearTimeout(pingTimeout) 542 | setupWebsocket(filters, poolChangeCallback) 543 | }) 544 | 545 | wsProvider._websocket.on('pong', () => { 546 | clearInterval(pingTimeout) 547 | }) 548 | } 549 | 550 | function getAmounts(sqrtPriceX96, lowerTick, upperTick, liquidity) { 551 | const lowerSqrtPriceX96 = BigNumber.from(univ3prices.tickMath.getSqrtRatioAtTick(lowerTick).toString()) 552 | const upperSqrtPriceX96 = BigNumber.from(univ3prices.tickMath.getSqrtRatioAtTick(upperTick).toString()) 553 | const amounts = univ3prices.getAmountsForLiquidityRange(sqrtPriceX96, lowerSqrtPriceX96, upperSqrtPriceX96, liquidity) 554 | return { amount0: BigNumber.from(amounts[0].toString()), amount1: BigNumber.from(amounts[1].toString()) } 555 | } 556 | 557 | async function getTokenAssetPriceX96(token, asset) { 558 | if (token === asset) { 559 | return BigNumber.from(2).pow(96) 560 | } 561 | 562 | const tokensToPools = getTokensToPools(asset) 563 | 564 | let priceToken = await getPoolPrice(tokensToPools[token].address) 565 | let priceTokenX96 = priceToken.sqrtPriceX96.mul(priceToken.sqrtPriceX96).div(Q96) 566 | if (tokensToPools[token].isToken0) { 567 | priceTokenX96 = Q96.mul(Q96).div(priceTokenX96) 568 | } 569 | 570 | return priceTokenX96 571 | } 572 | 573 | function getTokensToPools(asset) { 574 | return { 575 | "arbitrum": { 576 | "0xaf88d065e77c8cc2239327c5edb3a432268e5831": { 577 | "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1": { // DAI with USDC 578 | address: "0x7cf803e8d82a50504180f417b8bc7a493c0a0503", 579 | isToken0: true 580 | }, 581 | "0x82af49447d8a07e3bd95bd0d56f35241523fbab1": { // WETH with USDC 582 | address: "0xc6962004f452be9203591991d15f6b388e09e8d0", 583 | isToken0: false 584 | }, 585 | "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f": { // WBTC with USDC 586 | address: "0x0e4831319a50228b9e450861297ab92dee15b44f", 587 | isToken0: false 588 | }, 589 | "0x912ce59144191c1204e64559fe8253a0e49e6548": { // ARB with USDC 590 | address: "0xb0f6ca40411360c03d41c5ffc5f179b8403cdcf8", 591 | isToken0: false 592 | }, 593 | "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8": { // USDC.e with USDC 594 | address: "0x8e295789c9465487074a65b1ae9Ce0351172393f", 595 | isToken0: true 596 | }, 597 | "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9": { // USDT with USDC 598 | address: "0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6", 599 | isToken0: true 600 | }, 601 | "0x5979d7b546e38e414f7e9822514be443a4800529": { // wstETH with USDC.e (no USDC pool available) 602 | address: "0xc7341e85996eeb05897d3dec79448b6e4ccc09cf", 603 | isToken0: false 604 | } 605 | } 606 | } 607 | }[network][asset]; 608 | } 609 | 610 | function logWithTimestamp(...args) { 611 | const timestamp = new Date().toISOString(); 612 | console.log(`[${timestamp}]`, ...args); 613 | } 614 | 615 | function getPoolToToken(asset, pool) { 616 | const tokensToPools = getTokensToPools(asset) 617 | const lowerCasePool = pool.toLowerCase() 618 | return Object.keys(tokensToPools).filter(x => tokensToPools[x].address.toLowerCase() === lowerCasePool)[0] 619 | } 620 | 621 | module.exports = { 622 | provider, 623 | signer, 624 | npmContract, 625 | 626 | getNativeTokenAddress, 627 | getNPMAddress, 628 | getFactoryAddress, 629 | getV3VaultAddress, 630 | getFlashLoanLiquidatorAddress, 631 | getNativeTokenSymbol, 632 | getFlashloanPoolOptions, 633 | getTokenAssetPriceX96, 634 | getRevertUrlForDiscord, 635 | getExplorerUrlForDiscord, 636 | registerErrorHandler: function () { 637 | process.on('uncaughtException', (err) => handleGlobalError(err)) 638 | process.on('unhandledRejection', (err) => handleGlobalError(err)) 639 | 640 | function handleGlobalError(err) { 641 | console.log("Global error", err) 642 | } 643 | }, 644 | getAmounts, 645 | getPoolPrice, 646 | getPool, 647 | getPoolToToken, 648 | setupWebsocket, 649 | executeTx, 650 | getGasPriceData, 651 | getAllLogs, 652 | quoteUniversalRouter, 653 | getUniversalRouterSwapDataSinglePool, 654 | getTokenDecimals, 655 | getTokenSymbol, 656 | getTickSpacing: function (fee) { 657 | return fee == 100 ? 1 : (fee == 500 ? 10 : (fee == 3000 ? 60 : (fee == 2500 ? 50 : 200))) 658 | }, 659 | Q32, 660 | Q64, 661 | Q96, 662 | network, 663 | exchange, 664 | sqrt, 665 | POOL_ABI, 666 | logWithTimestamp 667 | } -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Revert Labs Inc 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. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "liquidator-js", 3 | "version": "1.0.0", 4 | "description": "implementation of liquidator bot for revert lend", 5 | "main": "index.js", 6 | "dependencies": { 7 | "@thanpolas/univ3prices": "^3.0.2", 8 | "@uniswap/smart-order-router": "3.47.0", 9 | "async-mutex": "^0.4.0", 10 | "axios": "^0.27.2", 11 | "dotenv": "^16.0.1", 12 | "ethers": "^5.5.4" 13 | } 14 | } 15 | --------------------------------------------------------------------------------