├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Flash.sol ├── README.md ├── TESTNET.md ├── abi ├── Controller.json ├── Liquidations.json └── UniswapV2Pair.json ├── build.rs └── src ├── bindings ├── controller.rs ├── liquidations.rs ├── mod.rs └── uniswapv2pair.rs ├── borrowers.rs ├── escalator.rs ├── keeper.rs ├── lib.rs ├── liquidations.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yield-liquidator" 3 | version = "0.1.0" 4 | authors = ["Georgios Konstantopoulos "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | anyhow = "1.0.32" 9 | ethers = "0.2.0" 10 | serde_json = "1.0.57" 11 | tokio = { version = "0.2.22", features = ["macros"] } 12 | 13 | # CLI 14 | gumdrop = "0.8.0" 15 | # Logging 16 | tracing = "0.1.18" 17 | tracing-subscriber = "0.2.10" 18 | serde = "1.0.114" 19 | thiserror = "1.0.20" 20 | 21 | [build-dependencies] 22 | ethers = { version = "0.2.0", features = ["abigen"] } 23 | -------------------------------------------------------------------------------- /Flash.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.10; 2 | 3 | interface LiquidationLike { 4 | function buy( 5 | address from, 6 | address to, 7 | address liquidated, 8 | uint256 daiAmount 9 | ) external returns (uint256); 10 | } 11 | 12 | interface PairLike { 13 | function token0() external returns (address); 14 | function token1() external returns (address); 15 | function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast); 16 | } 17 | 18 | interface ERC20Like { 19 | // ERC20 approve 20 | function approve(address spender, uint256 amount) external returns (bool); 21 | 22 | // ERC20 transfer 23 | function transfer(address recipient, uint256 amount) external returns (bool); 24 | 25 | // WETH withdraw 26 | function withdraw(uint256 amount) external; 27 | } 28 | 29 | contract Flash { 30 | address immutable rewards; 31 | 32 | LiquidationLike immutable liquidation; 33 | PairLike pair; 34 | ERC20Like dai; 35 | ERC20Like weth; 36 | 37 | constructor(address treasury, address _pair, address _liquidation) public { 38 | pair = PairLike(_pair); 39 | liquidation = LiquidationLike(_liquidation); 40 | rewards = msg.sender; 41 | dai = ERC20Like(pair.token0()); 42 | weth = ERC20Like(pair.token1()); 43 | 44 | // allow the treasury to pull funds 45 | dai.approve(treasury, type(uint).max); 46 | } 47 | 48 | // amount0 is always DAI for the DAI-WETH pair 49 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external { 50 | require(msg.sender == address(pair), "ONLY_PAIR"); 51 | require(amount1 == 0, "NON_ZERO_WETH_RECEIVED"); 52 | 53 | // get the person being liquidated 54 | (address user, uint minProfitETH) = abi.decode(data, (address, uint)); 55 | 56 | // send the received DAI to the auction and receive WETH (at a discount) 57 | uint wethReceived = liquidation.buy(address(this), address(this), user, amount0); 58 | 59 | // -> Calculate the amount of WETH required 60 | // 61 | // wethReserves * daiAmount * 1000 62 | // weth = ----------------------------------- 63 | // (daiReserves - daiAmount) * 997 64 | (uint112 daiReserves, uint112 wethReserves,) = pair.getReserves(); 65 | uint numerator = wethReserves * amount0 * 1000; 66 | uint denominator = (daiReserves - amount0) * 997; 67 | uint wethAmount = numerator / denominator + 1; 68 | 69 | require(wethReceived > wethAmount + minProfitETH, "NOT_ENOUGH_PROFIT"); 70 | 71 | // pay back the loan 72 | require(weth.transfer(address(pair), wethAmount), "WETH_PAYBACK_FAILED"); 73 | 74 | // reap the profit! 75 | uint profit = wethReceived - wethAmount; 76 | weth.withdraw(profit); 77 | (bool success,) = sender.call{value: profit}(new bytes(0)); 78 | require(success, "COULD NOT WITHDRAW"); 79 | } 80 | 81 | receive() external payable {} 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yield Protocol Liquidator 2 | 3 | Liquidates undercollateralized fyDAI-ETH positions using Uniswap V2 as a capital source. 4 | 5 | This liquidator altruistically calls the `Liquidations.liquidate` function for any 6 | position that is underwater, trigerring an auction for that position. It then tries 7 | to participate in the auction by flashloaning funds from Uniswap, if there's enough 8 | profit to be made. 9 | 10 | ## CLI 11 | 12 | ``` 13 | Usage: ./yield-liquidator [OPTIONS] 14 | 15 | Optional arguments: 16 | -h, --help 17 | -c, --config CONFIG path to json file with the contract addresses 18 | -u, --url URL the Ethereum node endpoint (HTTP or WS) (default: http://localhost:8545) 19 | -p, --private-key PRIVATE-KEY 20 | path to your private key 21 | -i, --interval INTERVAL polling interval (ms) (default: 1000) 22 | -f, --file FILE the file to be used for persistence (default: data.json) 23 | -m, --min-profit MIN-PROFIT 24 | the minimum profit per liquidation (default: 0) 25 | ``` 26 | 27 | Your contracts' `--config` file should be in the following format where `Uniswap` is the 28 | UniswapV2 WETH/DAI pair and `Flash` is the [Flashloan](./Flash.sol) contract. 29 | 30 | ``` 31 | { 32 | "Controller" : "0xd160C973a098608e2D7d6E43C64Eee48766800D1", 33 | "Liquidations" : "0xbC0200F0AAD7C1c0bBB1CC7885E1e796DFFac3e0", 34 | "Uniswap": "0xbC0200F0AAD7C1c0bBB1CC7885E1e796DFFac3e0", 35 | "Flash": "0xbC0200F0AAD7C1c0bBB1CC7885E1e796DFFac3e0" 36 | } 37 | ``` 38 | 39 | The `--private-key` _must not_ have a `0x` prefix. Set the `interval` to 15s for mainnet. 40 | 41 | ## Building and Running 42 | 43 | ``` 44 | # Build in release mode 45 | cargo build --release 46 | 47 | # Run it with 48 | ./target/release/yield-liquidator \ 49 | --config ./addrs.json \ 50 | --private-key ./private_key \ 51 | --url http://localhost:8545 \ 52 | --interval 7000 \ 53 | --file state.json \ 54 | ``` 55 | 56 | ## How it Works 57 | 58 | On each block: 59 | 1. Bumps the gas price of all of our pending transactions 60 | 2. Updates our dataset of borrowers debt health & liquidation auctions with the new block's data 61 | 3. Trigger the auction for any undercollateralized borrowers 62 | 4. Try participating in any auctions which are worth buying 63 | 64 | Take this liquidator for a spin by [running it in a test environment](TESTNET.md). 65 | -------------------------------------------------------------------------------- /TESTNET.md: -------------------------------------------------------------------------------- 1 | ## Testing 2 | 3 | In this guide, you will: 4 | 1. Deploy the yield contracts 5 | 2. Run the liquidator 6 | 3. Create a liquidation opportunity 7 | 4. See the liquidator trigger the liquidation 8 | 5. After some time, see the liquidator participate in the auction 9 | 10 | ### Deploy the contracts 11 | 12 | First we must clone the contracts and install the deps: 13 | 14 | ``` 15 | git clone https://github.com/yieldprotocol/eDai 16 | cd eDai 17 | git checkout liquidator-testing 18 | yarn 19 | ``` 20 | 21 | In one terminal, run ganache: `./scripts/ganache.sh` 22 | 23 | In another terminal, deploy the contracts: `npx truffle migrate --reset` 24 | 25 | This deploys MakerDAO, Yield, UniswapV2, [Multicall](https://github.com/makerdao/multicall) and the Flashloan contract. 26 | 27 | Run `npx truffle exec scripts/addresses.js`. This will create a JSON file called `addrs.json`, containing the addresses of all the deployed contracts. 28 | 29 | ### Run the liquidator 30 | 31 | In a new terminal, navigate back to the `yield-liquidator` directory. 32 | 33 | You first need to create your private key and fund it with some ETH. Here, we'll 34 | use a pre-funded key from ganache. 35 | 36 | ``` 37 | echo "0x8b6e036da61e5ac4874a770d7258583cd1b373798e740deaff4015fea80294b0" > private_key 38 | ``` 39 | 40 | Next, run the liquidator with the `addrs.json` file: 41 | 42 | ``` 43 | RUST_LOG=yield_liquidator=trace cargo run -- -c ../eDai/addrs.json -p ./private_key 44 | ``` 45 | 46 | You should see logs appear like below: 47 | 48 | ``` 49 | Oct 05 12:43:02.679 INFO yield_liquidator: Starting Yield Liquidator. 50 | Oct 05 12:43:02.683 INFO yield_liquidator: Profits will be sent to 0x66a1b7374960cc1be80adca1de1be24d56e0f3d0 51 | Oct 05 12:43:02.684 INFO yield_liquidator: Node: http://localhost:8545 52 | Oct 05 12:43:02.687 INFO yield_liquidator: Controller: 0x9a0b52cf69aab3ff9b4b04d3cbc6352413733400 53 | Oct 05 12:43:02.687 INFO yield_liquidator: Liquidations: 0xd45cf5045759c2a6a0213338a612d9ea1733c6c2 54 | Oct 05 12:43:02.687 INFO yield_liquidator: Uniswap: 0x341a003891e2ed8cf4910afdf23d3cd9dde39862 55 | Oct 05 12:43:02.687 INFO yield_liquidator: Multicall: Some(0x6107495d0f32d25ec6def1122ddfa21f42b50762) 56 | Oct 05 12:43:02.688 INFO yield_liquidator: FlashLiquidator 0x03f32fcf400d2829631846a1bbff5d6b46f7638c 57 | Oct 05 12:43:02.688 INFO yield_liquidator: Persistent data will be stored at: "data.json" 58 | Oct 05 12:43:03.487 DEBUG eloop{block=93}: yield_liquidator::liquidations: checking for undercollateralized positions... 59 | ``` 60 | 61 | ### Create a liquidation opportunity 62 | 63 | In a new terminal, navigate back to the `eDai` directory. 64 | 65 | Create a liquidation opportunity by running `npx truffle exec scripts/create_liquidation_opportunity.js`. This will borrow the max DAI possible at the current price, and then it will set the price to a lower value (via a backdoor method) so that the position is liquidatable. It will also fund Uniswap with some WETH/DAI at a favorable rate, so that an arbitrage is possible later on. You should see the following logs: 66 | 67 | ``` 68 | Oct 05 12:48:42.100 DEBUG eloop{block=109}: yield_liquidator::liquidations: new auction user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b vault=Auction { started: 1601891322, debt: 150000000000000000000, collateral: 1000000000000000000 } 69 | Oct 05 12:48:42.198 INFO eloop{block=109}: yield_liquidator::liquidations: found undercollateralized user. triggering liquidation user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b debt_dai=150000000000000000000 max_debt_dai=120000000000000000000 70 | Oct 05 12:48:42.559 TRACE eloop{block=109}: yield_liquidator::liquidations: Submitted liquidation tx_hash=0xff649dca811b8d81ae70e018e1824ad6a7853e2be274485802f1aa480477c878 user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b 71 | Oct 05 12:48:43.337 DEBUG eloop{block=109}:buying{user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b auction_start=1601891322 auction_end=1601894922 debt=150000000000000000000}: yield_liquidator::liquidations: Auction not yet profitable via Uniswap flash swaps. price=300000000000000000000000030000 72 | Oct 05 12:48:43.357 TRACE eloop{block=111}: yield_liquidator::liquidations: confirmed tx_hash=0xff649dca811b8d81ae70e018e1824ad6a7853e2be274485802f1aa480477c878 gas_used=139838 user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b status="success" tx_type=liquidation 73 | ``` 74 | 75 | The above logs show that the liquidator detects a new borrower, then notices that they are undercollateralized and triggers their liquidation. It then immediately tries to participate in the auction for that user, but skips that step since it cannot make enough profit. Then, at block 111, it notifies us that the transaction for trigerring the liquidation has been mined (if it were not mined, it would automatically bump its gas price, until it gets mined). 76 | 77 | ### Participate in the auction 78 | 79 | As shown in the previous logs, the current price does not yet allow for a profitable arbitrage 80 | using Uniswap. Yield auction prices drop over time. We will now advance time on Ganache to the end 81 | of the auction (notice how the argument is the same as the `auction_end` in the log above), and observe our liquidator participate and successfully reap the profit: 82 | 83 | ``` 84 | curl -H "Content-Type: application/json" -X POST --data '{"id":1337,"jsonrpc":"2.0","method":"evm_mine","params":[1601894922]}' http://localhost:8545 85 | ``` 86 | 87 | And on the liquidator: 88 | 89 | ``` 90 | Oct 05 12:53:41.110 TRACE eloop{block=112}:buying{user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b auction_start=1601891322 auction_end=1601894922 debt=150000000000000000000}: yield_liquidator::liquidations: Submitted buy order tx_hash=0x3abc538b3debb0cbbf8442dcc52f89de8e98e755a664e2ff42f3c636b8f5dcfe 91 | Oct 05 12:53:42.132 TRACE eloop{block=113}: yield_liquidator::liquidations: confirmed tx_hash=0x3abc538b3debb0cbbf8442dcc52f89de8e98e755a664e2ff42f3c636b8f5dcfe gas_used=393848 user=0x73bb8c9da5b0b3f5b05701e91f3925c3f247567b status="success" tx_type=auction 92 | ``` 93 | 94 | Success! We have liquidated and extracted a profit using funds from Uniswap. In order to guarantee a profit net of gas costs, consider passing a higher value to the `--min-profit` CLI argument. 95 | -------------------------------------------------------------------------------- /abi/Controller.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "vat_", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "pot_", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "treasury_", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "bytes32", 29 | "name": "collateral", 30 | "type": "bytes32" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "uint256", 35 | "name": "maturity", 36 | "type": "uint256" 37 | }, 38 | { 39 | "indexed": true, 40 | "internalType": "address", 41 | "name": "user", 42 | "type": "address" 43 | }, 44 | { 45 | "indexed": false, 46 | "internalType": "int256", 47 | "name": "amount", 48 | "type": "int256" 49 | } 50 | ], 51 | "name": "Borrowed", 52 | "type": "event" 53 | }, 54 | { 55 | "anonymous": false, 56 | "inputs": [ 57 | { 58 | "indexed": true, 59 | "internalType": "address", 60 | "name": "user", 61 | "type": "address" 62 | }, 63 | { 64 | "indexed": true, 65 | "internalType": "address", 66 | "name": "delegate", 67 | "type": "address" 68 | }, 69 | { 70 | "indexed": false, 71 | "internalType": "bool", 72 | "name": "enabled", 73 | "type": "bool" 74 | } 75 | ], 76 | "name": "Delegate", 77 | "type": "event" 78 | }, 79 | { 80 | "anonymous": false, 81 | "inputs": [ 82 | { 83 | "indexed": false, 84 | "internalType": "address", 85 | "name": "access", 86 | "type": "address" 87 | } 88 | ], 89 | "name": "GrantedAccess", 90 | "type": "event" 91 | }, 92 | { 93 | "anonymous": false, 94 | "inputs": [ 95 | { 96 | "indexed": true, 97 | "internalType": "address", 98 | "name": "previousOwner", 99 | "type": "address" 100 | }, 101 | { 102 | "indexed": true, 103 | "internalType": "address", 104 | "name": "newOwner", 105 | "type": "address" 106 | } 107 | ], 108 | "name": "OwnershipTransferred", 109 | "type": "event" 110 | }, 111 | { 112 | "anonymous": false, 113 | "inputs": [ 114 | { 115 | "indexed": true, 116 | "internalType": "bytes32", 117 | "name": "collateral", 118 | "type": "bytes32" 119 | }, 120 | { 121 | "indexed": true, 122 | "internalType": "address", 123 | "name": "user", 124 | "type": "address" 125 | }, 126 | { 127 | "indexed": false, 128 | "internalType": "int256", 129 | "name": "amount", 130 | "type": "int256" 131 | } 132 | ], 133 | "name": "Posted", 134 | "type": "event" 135 | }, 136 | { 137 | "inputs": [], 138 | "name": "CHAI", 139 | "outputs": [ 140 | { 141 | "internalType": "bytes32", 142 | "name": "", 143 | "type": "bytes32" 144 | } 145 | ], 146 | "stateMutability": "view", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "DUST", 152 | "outputs": [ 153 | { 154 | "internalType": "uint256", 155 | "name": "", 156 | "type": "uint256" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [], 164 | "name": "THREE_MONTHS", 165 | "outputs": [ 166 | { 167 | "internalType": "uint256", 168 | "name": "", 169 | "type": "uint256" 170 | } 171 | ], 172 | "stateMutability": "view", 173 | "type": "function" 174 | }, 175 | { 176 | "inputs": [], 177 | "name": "UNIT", 178 | "outputs": [ 179 | { 180 | "internalType": "uint256", 181 | "name": "", 182 | "type": "uint256" 183 | } 184 | ], 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "WETH", 191 | "outputs": [ 192 | { 193 | "internalType": "bytes32", 194 | "name": "", 195 | "type": "bytes32" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [ 203 | { 204 | "internalType": "bytes32", 205 | "name": "collateral", 206 | "type": "bytes32" 207 | }, 208 | { 209 | "internalType": "address", 210 | "name": "user", 211 | "type": "address" 212 | } 213 | ], 214 | "name": "aboveDustOrZero", 215 | "outputs": [ 216 | { 217 | "internalType": "bool", 218 | "name": "", 219 | "type": "bool" 220 | } 221 | ], 222 | "stateMutability": "view", 223 | "type": "function" 224 | }, 225 | { 226 | "inputs": [ 227 | { 228 | "internalType": "address", 229 | "name": "delegate", 230 | "type": "address" 231 | } 232 | ], 233 | "name": "addDelegate", 234 | "outputs": [], 235 | "stateMutability": "nonpayable", 236 | "type": "function" 237 | }, 238 | { 239 | "inputs": [ 240 | { 241 | "internalType": "address", 242 | "name": "yDaiContract", 243 | "type": "address" 244 | } 245 | ], 246 | "name": "addSeries", 247 | "outputs": [], 248 | "stateMutability": "nonpayable", 249 | "type": "function" 250 | }, 251 | { 252 | "inputs": [ 253 | { 254 | "internalType": "address", 255 | "name": "", 256 | "type": "address" 257 | } 258 | ], 259 | "name": "authorized", 260 | "outputs": [ 261 | { 262 | "internalType": "bool", 263 | "name": "", 264 | "type": "bool" 265 | } 266 | ], 267 | "stateMutability": "view", 268 | "type": "function" 269 | }, 270 | { 271 | "inputs": [ 272 | { 273 | "internalType": "bytes32", 274 | "name": "collateral", 275 | "type": "bytes32" 276 | }, 277 | { 278 | "internalType": "uint256", 279 | "name": "maturity", 280 | "type": "uint256" 281 | }, 282 | { 283 | "internalType": "address", 284 | "name": "from", 285 | "type": "address" 286 | }, 287 | { 288 | "internalType": "address", 289 | "name": "to", 290 | "type": "address" 291 | }, 292 | { 293 | "internalType": "uint256", 294 | "name": "yDaiAmount", 295 | "type": "uint256" 296 | } 297 | ], 298 | "name": "borrow", 299 | "outputs": [], 300 | "stateMutability": "nonpayable", 301 | "type": "function" 302 | }, 303 | { 304 | "inputs": [ 305 | { 306 | "internalType": "uint256", 307 | "name": "maturity", 308 | "type": "uint256" 309 | } 310 | ], 311 | "name": "containsSeries", 312 | "outputs": [ 313 | { 314 | "internalType": "bool", 315 | "name": "", 316 | "type": "bool" 317 | } 318 | ], 319 | "stateMutability": "view", 320 | "type": "function" 321 | }, 322 | { 323 | "inputs": [ 324 | { 325 | "internalType": "bytes32", 326 | "name": "collateral", 327 | "type": "bytes32" 328 | }, 329 | { 330 | "internalType": "uint256", 331 | "name": "maturity", 332 | "type": "uint256" 333 | }, 334 | { 335 | "internalType": "address", 336 | "name": "user", 337 | "type": "address" 338 | } 339 | ], 340 | "name": "debtDai", 341 | "outputs": [ 342 | { 343 | "internalType": "uint256", 344 | "name": "", 345 | "type": "uint256" 346 | } 347 | ], 348 | "stateMutability": "view", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [ 353 | { 354 | "internalType": "bytes32", 355 | "name": "", 356 | "type": "bytes32" 357 | }, 358 | { 359 | "internalType": "uint256", 360 | "name": "", 361 | "type": "uint256" 362 | }, 363 | { 364 | "internalType": "address", 365 | "name": "", 366 | "type": "address" 367 | } 368 | ], 369 | "name": "debtYDai", 370 | "outputs": [ 371 | { 372 | "internalType": "uint256", 373 | "name": "", 374 | "type": "uint256" 375 | } 376 | ], 377 | "stateMutability": "view", 378 | "type": "function" 379 | }, 380 | { 381 | "inputs": [ 382 | { 383 | "internalType": "address", 384 | "name": "", 385 | "type": "address" 386 | }, 387 | { 388 | "internalType": "address", 389 | "name": "", 390 | "type": "address" 391 | } 392 | ], 393 | "name": "delegated", 394 | "outputs": [ 395 | { 396 | "internalType": "bool", 397 | "name": "", 398 | "type": "bool" 399 | } 400 | ], 401 | "stateMutability": "view", 402 | "type": "function" 403 | }, 404 | { 405 | "inputs": [ 406 | { 407 | "internalType": "bytes32", 408 | "name": "collateral", 409 | "type": "bytes32" 410 | }, 411 | { 412 | "internalType": "address", 413 | "name": "user", 414 | "type": "address" 415 | } 416 | ], 417 | "name": "erase", 418 | "outputs": [ 419 | { 420 | "internalType": "uint256", 421 | "name": "", 422 | "type": "uint256" 423 | }, 424 | { 425 | "internalType": "uint256", 426 | "name": "", 427 | "type": "uint256" 428 | } 429 | ], 430 | "stateMutability": "nonpayable", 431 | "type": "function" 432 | }, 433 | { 434 | "inputs": [ 435 | { 436 | "internalType": "bytes32", 437 | "name": "collateral", 438 | "type": "bytes32" 439 | }, 440 | { 441 | "internalType": "uint256", 442 | "name": "maturity", 443 | "type": "uint256" 444 | }, 445 | { 446 | "internalType": "uint256", 447 | "name": "yDaiAmount", 448 | "type": "uint256" 449 | } 450 | ], 451 | "name": "inDai", 452 | "outputs": [ 453 | { 454 | "internalType": "uint256", 455 | "name": "", 456 | "type": "uint256" 457 | } 458 | ], 459 | "stateMutability": "view", 460 | "type": "function" 461 | }, 462 | { 463 | "inputs": [ 464 | { 465 | "internalType": "bytes32", 466 | "name": "collateral", 467 | "type": "bytes32" 468 | }, 469 | { 470 | "internalType": "uint256", 471 | "name": "maturity", 472 | "type": "uint256" 473 | }, 474 | { 475 | "internalType": "uint256", 476 | "name": "daiAmount", 477 | "type": "uint256" 478 | } 479 | ], 480 | "name": "inYDai", 481 | "outputs": [ 482 | { 483 | "internalType": "uint256", 484 | "name": "", 485 | "type": "uint256" 486 | } 487 | ], 488 | "stateMutability": "view", 489 | "type": "function" 490 | }, 491 | { 492 | "inputs": [ 493 | { 494 | "internalType": "bytes32", 495 | "name": "collateral", 496 | "type": "bytes32" 497 | }, 498 | { 499 | "internalType": "address", 500 | "name": "user", 501 | "type": "address" 502 | } 503 | ], 504 | "name": "isCollateralized", 505 | "outputs": [ 506 | { 507 | "internalType": "bool", 508 | "name": "", 509 | "type": "bool" 510 | } 511 | ], 512 | "stateMutability": "view", 513 | "type": "function" 514 | }, 515 | { 516 | "inputs": [], 517 | "name": "live", 518 | "outputs": [ 519 | { 520 | "internalType": "bool", 521 | "name": "", 522 | "type": "bool" 523 | } 524 | ], 525 | "stateMutability": "view", 526 | "type": "function" 527 | }, 528 | { 529 | "inputs": [ 530 | { 531 | "internalType": "bytes32", 532 | "name": "collateral", 533 | "type": "bytes32" 534 | }, 535 | { 536 | "internalType": "address", 537 | "name": "user", 538 | "type": "address" 539 | } 540 | ], 541 | "name": "locked", 542 | "outputs": [ 543 | { 544 | "internalType": "uint256", 545 | "name": "", 546 | "type": "uint256" 547 | } 548 | ], 549 | "stateMutability": "view", 550 | "type": "function" 551 | }, 552 | { 553 | "inputs": [ 554 | { 555 | "internalType": "address", 556 | "name": "user", 557 | "type": "address" 558 | } 559 | ], 560 | "name": "orchestrate", 561 | "outputs": [], 562 | "stateMutability": "nonpayable", 563 | "type": "function" 564 | }, 565 | { 566 | "inputs": [], 567 | "name": "owner", 568 | "outputs": [ 569 | { 570 | "internalType": "address", 571 | "name": "", 572 | "type": "address" 573 | } 574 | ], 575 | "stateMutability": "view", 576 | "type": "function" 577 | }, 578 | { 579 | "inputs": [ 580 | { 581 | "internalType": "bytes32", 582 | "name": "collateral", 583 | "type": "bytes32" 584 | }, 585 | { 586 | "internalType": "address", 587 | "name": "from", 588 | "type": "address" 589 | }, 590 | { 591 | "internalType": "address", 592 | "name": "to", 593 | "type": "address" 594 | }, 595 | { 596 | "internalType": "uint256", 597 | "name": "amount", 598 | "type": "uint256" 599 | } 600 | ], 601 | "name": "post", 602 | "outputs": [], 603 | "stateMutability": "nonpayable", 604 | "type": "function" 605 | }, 606 | { 607 | "inputs": [ 608 | { 609 | "internalType": "bytes32", 610 | "name": "", 611 | "type": "bytes32" 612 | }, 613 | { 614 | "internalType": "address", 615 | "name": "", 616 | "type": "address" 617 | } 618 | ], 619 | "name": "posted", 620 | "outputs": [ 621 | { 622 | "internalType": "uint256", 623 | "name": "", 624 | "type": "uint256" 625 | } 626 | ], 627 | "stateMutability": "view", 628 | "type": "function" 629 | }, 630 | { 631 | "inputs": [ 632 | { 633 | "internalType": "bytes32", 634 | "name": "collateral", 635 | "type": "bytes32" 636 | }, 637 | { 638 | "internalType": "address", 639 | "name": "user", 640 | "type": "address" 641 | } 642 | ], 643 | "name": "powerOf", 644 | "outputs": [ 645 | { 646 | "internalType": "uint256", 647 | "name": "", 648 | "type": "uint256" 649 | } 650 | ], 651 | "stateMutability": "view", 652 | "type": "function" 653 | }, 654 | { 655 | "inputs": [], 656 | "name": "renounceOwnership", 657 | "outputs": [], 658 | "stateMutability": "nonpayable", 659 | "type": "function" 660 | }, 661 | { 662 | "inputs": [ 663 | { 664 | "internalType": "bytes32", 665 | "name": "collateral", 666 | "type": "bytes32" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "maturity", 671 | "type": "uint256" 672 | }, 673 | { 674 | "internalType": "address", 675 | "name": "from", 676 | "type": "address" 677 | }, 678 | { 679 | "internalType": "address", 680 | "name": "to", 681 | "type": "address" 682 | }, 683 | { 684 | "internalType": "uint256", 685 | "name": "daiAmount", 686 | "type": "uint256" 687 | } 688 | ], 689 | "name": "repayDai", 690 | "outputs": [], 691 | "stateMutability": "nonpayable", 692 | "type": "function" 693 | }, 694 | { 695 | "inputs": [ 696 | { 697 | "internalType": "bytes32", 698 | "name": "collateral", 699 | "type": "bytes32" 700 | }, 701 | { 702 | "internalType": "uint256", 703 | "name": "maturity", 704 | "type": "uint256" 705 | }, 706 | { 707 | "internalType": "address", 708 | "name": "from", 709 | "type": "address" 710 | }, 711 | { 712 | "internalType": "address", 713 | "name": "to", 714 | "type": "address" 715 | }, 716 | { 717 | "internalType": "uint256", 718 | "name": "yDaiAmount", 719 | "type": "uint256" 720 | } 721 | ], 722 | "name": "repayYDai", 723 | "outputs": [], 724 | "stateMutability": "nonpayable", 725 | "type": "function" 726 | }, 727 | { 728 | "inputs": [ 729 | { 730 | "internalType": "address", 731 | "name": "delegate", 732 | "type": "address" 733 | } 734 | ], 735 | "name": "revokeDelegate", 736 | "outputs": [], 737 | "stateMutability": "nonpayable", 738 | "type": "function" 739 | }, 740 | { 741 | "inputs": [ 742 | { 743 | "internalType": "uint256", 744 | "name": "", 745 | "type": "uint256" 746 | } 747 | ], 748 | "name": "series", 749 | "outputs": [ 750 | { 751 | "internalType": "contract IYDai", 752 | "name": "", 753 | "type": "address" 754 | } 755 | ], 756 | "stateMutability": "view", 757 | "type": "function" 758 | }, 759 | { 760 | "inputs": [ 761 | { 762 | "internalType": "uint256", 763 | "name": "", 764 | "type": "uint256" 765 | } 766 | ], 767 | "name": "seriesIterator", 768 | "outputs": [ 769 | { 770 | "internalType": "uint256", 771 | "name": "", 772 | "type": "uint256" 773 | } 774 | ], 775 | "stateMutability": "view", 776 | "type": "function" 777 | }, 778 | { 779 | "inputs": [], 780 | "name": "shutdown", 781 | "outputs": [], 782 | "stateMutability": "nonpayable", 783 | "type": "function" 784 | }, 785 | { 786 | "inputs": [ 787 | { 788 | "internalType": "bytes32", 789 | "name": "collateral", 790 | "type": "bytes32" 791 | }, 792 | { 793 | "internalType": "address", 794 | "name": "user", 795 | "type": "address" 796 | } 797 | ], 798 | "name": "totalDebtDai", 799 | "outputs": [ 800 | { 801 | "internalType": "uint256", 802 | "name": "", 803 | "type": "uint256" 804 | } 805 | ], 806 | "stateMutability": "view", 807 | "type": "function" 808 | }, 809 | { 810 | "inputs": [], 811 | "name": "totalSeries", 812 | "outputs": [ 813 | { 814 | "internalType": "uint256", 815 | "name": "", 816 | "type": "uint256" 817 | } 818 | ], 819 | "stateMutability": "view", 820 | "type": "function" 821 | }, 822 | { 823 | "inputs": [ 824 | { 825 | "internalType": "address", 826 | "name": "newOwner", 827 | "type": "address" 828 | } 829 | ], 830 | "name": "transferOwnership", 831 | "outputs": [], 832 | "stateMutability": "nonpayable", 833 | "type": "function" 834 | }, 835 | { 836 | "inputs": [ 837 | { 838 | "internalType": "bytes32", 839 | "name": "collateral", 840 | "type": "bytes32" 841 | }, 842 | { 843 | "internalType": "address", 844 | "name": "from", 845 | "type": "address" 846 | }, 847 | { 848 | "internalType": "address", 849 | "name": "to", 850 | "type": "address" 851 | }, 852 | { 853 | "internalType": "uint256", 854 | "name": "amount", 855 | "type": "uint256" 856 | } 857 | ], 858 | "name": "withdraw", 859 | "outputs": [], 860 | "stateMutability": "nonpayable", 861 | "type": "function" 862 | } 863 | ] 864 | -------------------------------------------------------------------------------- /abi/Liquidations.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "dai_", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "treasury_", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "controller_", 17 | "type": "address" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "address", 29 | "name": "user", 30 | "type": "address" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "address", 35 | "name": "delegate", 36 | "type": "address" 37 | }, 38 | { 39 | "indexed": false, 40 | "internalType": "bool", 41 | "name": "enabled", 42 | "type": "bool" 43 | } 44 | ], 45 | "name": "Delegate", 46 | "type": "event" 47 | }, 48 | { 49 | "anonymous": false, 50 | "inputs": [ 51 | { 52 | "indexed": false, 53 | "internalType": "address", 54 | "name": "access", 55 | "type": "address" 56 | } 57 | ], 58 | "name": "GrantedAccess", 59 | "type": "event" 60 | }, 61 | { 62 | "anonymous": false, 63 | "inputs": [ 64 | { 65 | "indexed": true, 66 | "internalType": "address", 67 | "name": "user", 68 | "type": "address" 69 | }, 70 | { 71 | "indexed": false, 72 | "internalType": "uint256", 73 | "name": "started", 74 | "type": "uint256" 75 | }, 76 | { 77 | "indexed": false, 78 | "internalType": "uint256", 79 | "name": "collateral", 80 | "type": "uint256" 81 | }, 82 | { 83 | "indexed": false, 84 | "internalType": "uint256", 85 | "name": "debt", 86 | "type": "uint256" 87 | } 88 | ], 89 | "name": "Liquidation", 90 | "type": "event" 91 | }, 92 | { 93 | "anonymous": false, 94 | "inputs": [ 95 | { 96 | "indexed": true, 97 | "internalType": "address", 98 | "name": "previousOwner", 99 | "type": "address" 100 | }, 101 | { 102 | "indexed": true, 103 | "internalType": "address", 104 | "name": "newOwner", 105 | "type": "address" 106 | } 107 | ], 108 | "name": "OwnershipTransferred", 109 | "type": "event" 110 | }, 111 | { 112 | "inputs": [], 113 | "name": "AUCTION_TIME", 114 | "outputs": [ 115 | { 116 | "internalType": "uint256", 117 | "name": "", 118 | "type": "uint256" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [], 126 | "name": "DUST", 127 | "outputs": [ 128 | { 129 | "internalType": "uint256", 130 | "name": "", 131 | "type": "uint256" 132 | } 133 | ], 134 | "stateMutability": "view", 135 | "type": "function" 136 | }, 137 | { 138 | "inputs": [], 139 | "name": "UNIT", 140 | "outputs": [ 141 | { 142 | "internalType": "uint256", 143 | "name": "", 144 | "type": "uint256" 145 | } 146 | ], 147 | "stateMutability": "view", 148 | "type": "function" 149 | }, 150 | { 151 | "inputs": [], 152 | "name": "WETH", 153 | "outputs": [ 154 | { 155 | "internalType": "bytes32", 156 | "name": "", 157 | "type": "bytes32" 158 | } 159 | ], 160 | "stateMutability": "view", 161 | "type": "function" 162 | }, 163 | { 164 | "inputs": [ 165 | { 166 | "internalType": "address", 167 | "name": "user", 168 | "type": "address" 169 | } 170 | ], 171 | "name": "aboveDustOrZero", 172 | "outputs": [ 173 | { 174 | "internalType": "bool", 175 | "name": "", 176 | "type": "bool" 177 | } 178 | ], 179 | "stateMutability": "view", 180 | "type": "function" 181 | }, 182 | { 183 | "inputs": [ 184 | { 185 | "internalType": "address", 186 | "name": "delegate", 187 | "type": "address" 188 | } 189 | ], 190 | "name": "addDelegate", 191 | "outputs": [], 192 | "stateMutability": "nonpayable", 193 | "type": "function" 194 | }, 195 | { 196 | "inputs": [ 197 | { 198 | "internalType": "address", 199 | "name": "", 200 | "type": "address" 201 | } 202 | ], 203 | "name": "authorized", 204 | "outputs": [ 205 | { 206 | "internalType": "bool", 207 | "name": "", 208 | "type": "bool" 209 | } 210 | ], 211 | "stateMutability": "view", 212 | "type": "function" 213 | }, 214 | { 215 | "inputs": [ 216 | { 217 | "internalType": "address", 218 | "name": "from", 219 | "type": "address" 220 | }, 221 | { 222 | "internalType": "address", 223 | "name": "to", 224 | "type": "address" 225 | }, 226 | { 227 | "internalType": "address", 228 | "name": "liquidated", 229 | "type": "address" 230 | }, 231 | { 232 | "internalType": "uint256", 233 | "name": "daiAmount", 234 | "type": "uint256" 235 | } 236 | ], 237 | "name": "buy", 238 | "outputs": [ 239 | { 240 | "internalType": "uint256", 241 | "name": "", 242 | "type": "uint256" 243 | } 244 | ], 245 | "stateMutability": "nonpayable", 246 | "type": "function" 247 | }, 248 | { 249 | "inputs": [ 250 | { 251 | "internalType": "address", 252 | "name": "", 253 | "type": "address" 254 | }, 255 | { 256 | "internalType": "address", 257 | "name": "", 258 | "type": "address" 259 | } 260 | ], 261 | "name": "delegated", 262 | "outputs": [ 263 | { 264 | "internalType": "bool", 265 | "name": "", 266 | "type": "bool" 267 | } 268 | ], 269 | "stateMutability": "view", 270 | "type": "function" 271 | }, 272 | { 273 | "inputs": [ 274 | { 275 | "internalType": "address", 276 | "name": "user", 277 | "type": "address" 278 | } 279 | ], 280 | "name": "erase", 281 | "outputs": [ 282 | { 283 | "internalType": "uint128", 284 | "name": "", 285 | "type": "uint128" 286 | }, 287 | { 288 | "internalType": "uint128", 289 | "name": "", 290 | "type": "uint128" 291 | } 292 | ], 293 | "stateMutability": "nonpayable", 294 | "type": "function" 295 | }, 296 | { 297 | "inputs": [ 298 | { 299 | "internalType": "address", 300 | "name": "user", 301 | "type": "address" 302 | } 303 | ], 304 | "name": "liquidate", 305 | "outputs": [], 306 | "stateMutability": "nonpayable", 307 | "type": "function" 308 | }, 309 | { 310 | "inputs": [ 311 | { 312 | "internalType": "address", 313 | "name": "", 314 | "type": "address" 315 | } 316 | ], 317 | "name": "liquidations", 318 | "outputs": [ 319 | { 320 | "internalType": "uint256", 321 | "name": "", 322 | "type": "uint256" 323 | } 324 | ], 325 | "stateMutability": "view", 326 | "type": "function" 327 | }, 328 | { 329 | "inputs": [], 330 | "name": "live", 331 | "outputs": [ 332 | { 333 | "internalType": "bool", 334 | "name": "", 335 | "type": "bool" 336 | } 337 | ], 338 | "stateMutability": "view", 339 | "type": "function" 340 | }, 341 | { 342 | "inputs": [ 343 | { 344 | "internalType": "address", 345 | "name": "user", 346 | "type": "address" 347 | } 348 | ], 349 | "name": "orchestrate", 350 | "outputs": [], 351 | "stateMutability": "nonpayable", 352 | "type": "function" 353 | }, 354 | { 355 | "inputs": [], 356 | "name": "owner", 357 | "outputs": [ 358 | { 359 | "internalType": "address", 360 | "name": "", 361 | "type": "address" 362 | } 363 | ], 364 | "stateMutability": "view", 365 | "type": "function" 366 | }, 367 | { 368 | "inputs": [ 369 | { 370 | "internalType": "address", 371 | "name": "user", 372 | "type": "address" 373 | } 374 | ], 375 | "name": "price", 376 | "outputs": [ 377 | { 378 | "internalType": "uint256", 379 | "name": "", 380 | "type": "uint256" 381 | } 382 | ], 383 | "stateMutability": "view", 384 | "type": "function" 385 | }, 386 | { 387 | "inputs": [], 388 | "name": "renounceOwnership", 389 | "outputs": [], 390 | "stateMutability": "nonpayable", 391 | "type": "function" 392 | }, 393 | { 394 | "inputs": [ 395 | { 396 | "internalType": "address", 397 | "name": "delegate", 398 | "type": "address" 399 | } 400 | ], 401 | "name": "revokeDelegate", 402 | "outputs": [], 403 | "stateMutability": "nonpayable", 404 | "type": "function" 405 | }, 406 | { 407 | "inputs": [], 408 | "name": "shutdown", 409 | "outputs": [], 410 | "stateMutability": "nonpayable", 411 | "type": "function" 412 | }, 413 | { 414 | "inputs": [], 415 | "name": "totals", 416 | "outputs": [ 417 | { 418 | "internalType": "uint128", 419 | "name": "collateral", 420 | "type": "uint128" 421 | }, 422 | { 423 | "internalType": "uint128", 424 | "name": "debt", 425 | "type": "uint128" 426 | } 427 | ], 428 | "stateMutability": "view", 429 | "type": "function" 430 | }, 431 | { 432 | "inputs": [ 433 | { 434 | "internalType": "address", 435 | "name": "newOwner", 436 | "type": "address" 437 | } 438 | ], 439 | "name": "transferOwnership", 440 | "outputs": [], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "address", 448 | "name": "", 449 | "type": "address" 450 | } 451 | ], 452 | "name": "vaults", 453 | "outputs": [ 454 | { 455 | "internalType": "uint128", 456 | "name": "collateral", 457 | "type": "uint128" 458 | }, 459 | { 460 | "internalType": "uint128", 461 | "name": "debt", 462 | "type": "uint128" 463 | } 464 | ], 465 | "stateMutability": "view", 466 | "type": "function" 467 | }, 468 | { 469 | "inputs": [ 470 | { 471 | "internalType": "address", 472 | "name": "from", 473 | "type": "address" 474 | }, 475 | { 476 | "internalType": "address", 477 | "name": "to", 478 | "type": "address" 479 | }, 480 | { 481 | "internalType": "uint256", 482 | "name": "tokenAmount", 483 | "type": "uint256" 484 | } 485 | ], 486 | "name": "withdraw", 487 | "outputs": [], 488 | "stateMutability": "nonpayable", 489 | "type": "function" 490 | } 491 | ] 492 | -------------------------------------------------------------------------------- /abi/UniswapV2Pair.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "owner", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "spender", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": false, 24 | "internalType": "uint256", 25 | "name": "value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "Approval", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "sender", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": false, 43 | "internalType": "uint256", 44 | "name": "amount0", 45 | "type": "uint256" 46 | }, 47 | { 48 | "indexed": false, 49 | "internalType": "uint256", 50 | "name": "amount1", 51 | "type": "uint256" 52 | }, 53 | { 54 | "indexed": true, 55 | "internalType": "address", 56 | "name": "to", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "Burn", 61 | "type": "event" 62 | }, 63 | { 64 | "anonymous": false, 65 | "inputs": [ 66 | { 67 | "indexed": true, 68 | "internalType": "address", 69 | "name": "sender", 70 | "type": "address" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "uint256", 75 | "name": "amount0", 76 | "type": "uint256" 77 | }, 78 | { 79 | "indexed": false, 80 | "internalType": "uint256", 81 | "name": "amount1", 82 | "type": "uint256" 83 | } 84 | ], 85 | "name": "Mint", 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": false, 99 | "internalType": "uint256", 100 | "name": "amount0In", 101 | "type": "uint256" 102 | }, 103 | { 104 | "indexed": false, 105 | "internalType": "uint256", 106 | "name": "amount1In", 107 | "type": "uint256" 108 | }, 109 | { 110 | "indexed": false, 111 | "internalType": "uint256", 112 | "name": "amount0Out", 113 | "type": "uint256" 114 | }, 115 | { 116 | "indexed": false, 117 | "internalType": "uint256", 118 | "name": "amount1Out", 119 | "type": "uint256" 120 | }, 121 | { 122 | "indexed": true, 123 | "internalType": "address", 124 | "name": "to", 125 | "type": "address" 126 | } 127 | ], 128 | "name": "Swap", 129 | "type": "event" 130 | }, 131 | { 132 | "anonymous": false, 133 | "inputs": [ 134 | { 135 | "indexed": false, 136 | "internalType": "uint112", 137 | "name": "reserve0", 138 | "type": "uint112" 139 | }, 140 | { 141 | "indexed": false, 142 | "internalType": "uint112", 143 | "name": "reserve1", 144 | "type": "uint112" 145 | } 146 | ], 147 | "name": "Sync", 148 | "type": "event" 149 | }, 150 | { 151 | "anonymous": false, 152 | "inputs": [ 153 | { 154 | "indexed": true, 155 | "internalType": "address", 156 | "name": "from", 157 | "type": "address" 158 | }, 159 | { 160 | "indexed": true, 161 | "internalType": "address", 162 | "name": "to", 163 | "type": "address" 164 | }, 165 | { 166 | "indexed": false, 167 | "internalType": "uint256", 168 | "name": "value", 169 | "type": "uint256" 170 | } 171 | ], 172 | "name": "Transfer", 173 | "type": "event" 174 | }, 175 | { 176 | "inputs": [], 177 | "name": "DOMAIN_SEPARATOR", 178 | "outputs": [ 179 | { 180 | "internalType": "bytes32", 181 | "name": "", 182 | "type": "bytes32" 183 | } 184 | ], 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "MINIMUM_LIQUIDITY", 191 | "outputs": [ 192 | { 193 | "internalType": "uint256", 194 | "name": "", 195 | "type": "uint256" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [], 203 | "name": "PERMIT_TYPEHASH", 204 | "outputs": [ 205 | { 206 | "internalType": "bytes32", 207 | "name": "", 208 | "type": "bytes32" 209 | } 210 | ], 211 | "stateMutability": "view", 212 | "type": "function" 213 | }, 214 | { 215 | "inputs": [ 216 | { 217 | "internalType": "address", 218 | "name": "", 219 | "type": "address" 220 | }, 221 | { 222 | "internalType": "address", 223 | "name": "", 224 | "type": "address" 225 | } 226 | ], 227 | "name": "allowance", 228 | "outputs": [ 229 | { 230 | "internalType": "uint256", 231 | "name": "", 232 | "type": "uint256" 233 | } 234 | ], 235 | "stateMutability": "view", 236 | "type": "function" 237 | }, 238 | { 239 | "inputs": [ 240 | { 241 | "internalType": "address", 242 | "name": "spender", 243 | "type": "address" 244 | }, 245 | { 246 | "internalType": "uint256", 247 | "name": "value", 248 | "type": "uint256" 249 | } 250 | ], 251 | "name": "approve", 252 | "outputs": [ 253 | { 254 | "internalType": "bool", 255 | "name": "", 256 | "type": "bool" 257 | } 258 | ], 259 | "stateMutability": "nonpayable", 260 | "type": "function" 261 | }, 262 | { 263 | "inputs": [ 264 | { 265 | "internalType": "address", 266 | "name": "", 267 | "type": "address" 268 | } 269 | ], 270 | "name": "balanceOf", 271 | "outputs": [ 272 | { 273 | "internalType": "uint256", 274 | "name": "", 275 | "type": "uint256" 276 | } 277 | ], 278 | "stateMutability": "view", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [], 283 | "name": "decimals", 284 | "outputs": [ 285 | { 286 | "internalType": "uint8", 287 | "name": "", 288 | "type": "uint8" 289 | } 290 | ], 291 | "stateMutability": "view", 292 | "type": "function" 293 | }, 294 | { 295 | "inputs": [], 296 | "name": "factory", 297 | "outputs": [ 298 | { 299 | "internalType": "address", 300 | "name": "", 301 | "type": "address" 302 | } 303 | ], 304 | "stateMutability": "view", 305 | "type": "function" 306 | }, 307 | { 308 | "inputs": [], 309 | "name": "kLast", 310 | "outputs": [ 311 | { 312 | "internalType": "uint256", 313 | "name": "", 314 | "type": "uint256" 315 | } 316 | ], 317 | "stateMutability": "view", 318 | "type": "function" 319 | }, 320 | { 321 | "inputs": [], 322 | "name": "name", 323 | "outputs": [ 324 | { 325 | "internalType": "string", 326 | "name": "", 327 | "type": "string" 328 | } 329 | ], 330 | "stateMutability": "view", 331 | "type": "function" 332 | }, 333 | { 334 | "inputs": [ 335 | { 336 | "internalType": "address", 337 | "name": "", 338 | "type": "address" 339 | } 340 | ], 341 | "name": "nonces", 342 | "outputs": [ 343 | { 344 | "internalType": "uint256", 345 | "name": "", 346 | "type": "uint256" 347 | } 348 | ], 349 | "stateMutability": "view", 350 | "type": "function" 351 | }, 352 | { 353 | "inputs": [ 354 | { 355 | "internalType": "address", 356 | "name": "owner", 357 | "type": "address" 358 | }, 359 | { 360 | "internalType": "address", 361 | "name": "spender", 362 | "type": "address" 363 | }, 364 | { 365 | "internalType": "uint256", 366 | "name": "value", 367 | "type": "uint256" 368 | }, 369 | { 370 | "internalType": "uint256", 371 | "name": "deadline", 372 | "type": "uint256" 373 | }, 374 | { 375 | "internalType": "uint8", 376 | "name": "v", 377 | "type": "uint8" 378 | }, 379 | { 380 | "internalType": "bytes32", 381 | "name": "r", 382 | "type": "bytes32" 383 | }, 384 | { 385 | "internalType": "bytes32", 386 | "name": "s", 387 | "type": "bytes32" 388 | } 389 | ], 390 | "name": "permit", 391 | "outputs": [], 392 | "stateMutability": "nonpayable", 393 | "type": "function" 394 | }, 395 | { 396 | "inputs": [], 397 | "name": "price0CumulativeLast", 398 | "outputs": [ 399 | { 400 | "internalType": "uint256", 401 | "name": "", 402 | "type": "uint256" 403 | } 404 | ], 405 | "stateMutability": "view", 406 | "type": "function" 407 | }, 408 | { 409 | "inputs": [], 410 | "name": "price1CumulativeLast", 411 | "outputs": [ 412 | { 413 | "internalType": "uint256", 414 | "name": "", 415 | "type": "uint256" 416 | } 417 | ], 418 | "stateMutability": "view", 419 | "type": "function" 420 | }, 421 | { 422 | "inputs": [], 423 | "name": "symbol", 424 | "outputs": [ 425 | { 426 | "internalType": "string", 427 | "name": "", 428 | "type": "string" 429 | } 430 | ], 431 | "stateMutability": "view", 432 | "type": "function" 433 | }, 434 | { 435 | "inputs": [], 436 | "name": "token0", 437 | "outputs": [ 438 | { 439 | "internalType": "address", 440 | "name": "", 441 | "type": "address" 442 | } 443 | ], 444 | "stateMutability": "view", 445 | "type": "function" 446 | }, 447 | { 448 | "inputs": [], 449 | "name": "token1", 450 | "outputs": [ 451 | { 452 | "internalType": "address", 453 | "name": "", 454 | "type": "address" 455 | } 456 | ], 457 | "stateMutability": "view", 458 | "type": "function" 459 | }, 460 | { 461 | "inputs": [], 462 | "name": "totalSupply", 463 | "outputs": [ 464 | { 465 | "internalType": "uint256", 466 | "name": "", 467 | "type": "uint256" 468 | } 469 | ], 470 | "stateMutability": "view", 471 | "type": "function" 472 | }, 473 | { 474 | "inputs": [ 475 | { 476 | "internalType": "address", 477 | "name": "to", 478 | "type": "address" 479 | }, 480 | { 481 | "internalType": "uint256", 482 | "name": "value", 483 | "type": "uint256" 484 | } 485 | ], 486 | "name": "transfer", 487 | "outputs": [ 488 | { 489 | "internalType": "bool", 490 | "name": "", 491 | "type": "bool" 492 | } 493 | ], 494 | "stateMutability": "nonpayable", 495 | "type": "function" 496 | }, 497 | { 498 | "inputs": [ 499 | { 500 | "internalType": "address", 501 | "name": "from", 502 | "type": "address" 503 | }, 504 | { 505 | "internalType": "address", 506 | "name": "to", 507 | "type": "address" 508 | }, 509 | { 510 | "internalType": "uint256", 511 | "name": "value", 512 | "type": "uint256" 513 | } 514 | ], 515 | "name": "transferFrom", 516 | "outputs": [ 517 | { 518 | "internalType": "bool", 519 | "name": "", 520 | "type": "bool" 521 | } 522 | ], 523 | "stateMutability": "nonpayable", 524 | "type": "function" 525 | }, 526 | { 527 | "inputs": [], 528 | "name": "getReserves", 529 | "outputs": [ 530 | { 531 | "internalType": "uint112", 532 | "name": "_reserve0", 533 | "type": "uint112" 534 | }, 535 | { 536 | "internalType": "uint112", 537 | "name": "_reserve1", 538 | "type": "uint112" 539 | }, 540 | { 541 | "internalType": "uint32", 542 | "name": "_blockTimestampLast", 543 | "type": "uint32" 544 | } 545 | ], 546 | "stateMutability": "view", 547 | "type": "function" 548 | }, 549 | { 550 | "inputs": [ 551 | { 552 | "internalType": "address", 553 | "name": "_token0", 554 | "type": "address" 555 | }, 556 | { 557 | "internalType": "address", 558 | "name": "_token1", 559 | "type": "address" 560 | } 561 | ], 562 | "name": "initialize", 563 | "outputs": [], 564 | "stateMutability": "nonpayable", 565 | "type": "function" 566 | }, 567 | { 568 | "inputs": [ 569 | { 570 | "internalType": "address", 571 | "name": "to", 572 | "type": "address" 573 | } 574 | ], 575 | "name": "mint", 576 | "outputs": [ 577 | { 578 | "internalType": "uint256", 579 | "name": "liquidity", 580 | "type": "uint256" 581 | } 582 | ], 583 | "stateMutability": "nonpayable", 584 | "type": "function" 585 | }, 586 | { 587 | "inputs": [ 588 | { 589 | "internalType": "address", 590 | "name": "to", 591 | "type": "address" 592 | } 593 | ], 594 | "name": "burn", 595 | "outputs": [ 596 | { 597 | "internalType": "uint256", 598 | "name": "amount0", 599 | "type": "uint256" 600 | }, 601 | { 602 | "internalType": "uint256", 603 | "name": "amount1", 604 | "type": "uint256" 605 | } 606 | ], 607 | "stateMutability": "nonpayable", 608 | "type": "function" 609 | }, 610 | { 611 | "inputs": [ 612 | { 613 | "internalType": "uint256", 614 | "name": "amount0Out", 615 | "type": "uint256" 616 | }, 617 | { 618 | "internalType": "uint256", 619 | "name": "amount1Out", 620 | "type": "uint256" 621 | }, 622 | { 623 | "internalType": "address", 624 | "name": "to", 625 | "type": "address" 626 | }, 627 | { 628 | "internalType": "bytes", 629 | "name": "data", 630 | "type": "bytes" 631 | } 632 | ], 633 | "name": "swap", 634 | "outputs": [], 635 | "stateMutability": "nonpayable", 636 | "type": "function" 637 | }, 638 | { 639 | "inputs": [ 640 | { 641 | "internalType": "address", 642 | "name": "to", 643 | "type": "address" 644 | } 645 | ], 646 | "name": "skim", 647 | "outputs": [], 648 | "stateMutability": "nonpayable", 649 | "type": "function" 650 | }, 651 | { 652 | "inputs": [], 653 | "name": "sync", 654 | "outputs": [], 655 | "stateMutability": "nonpayable", 656 | "type": "function" 657 | } 658 | ] 659 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use ethers::contract::Abigen; 2 | 3 | // TODO: Figure out how to write the rerun-if-changed script properly 4 | fn main() { 5 | // Only re-run the builder script if the contract changes 6 | println!("cargo:rerun-if-changed=./abi/*.json"); 7 | // bindgen("Liquidations"); 8 | // bindgen("UniswapV2Pair"); 9 | // bindgen("Controller"); // TODO: Support I256 in ethers-rs 10 | } 11 | 12 | #[allow(dead_code)] 13 | fn bindgen(fname: &str) { 14 | let bindings = Abigen::new(fname, format!("./abi/{}.json", fname)) 15 | .expect("could not instantiate Abigen") 16 | .generate() 17 | .expect("could not generate bindings"); 18 | 19 | bindings 20 | .write_to_file(format!("./src/bindings/{}.rs", fname.to_lowercase())) 21 | .expect("could not write bindings to file"); 22 | } 23 | -------------------------------------------------------------------------------- /src/bindings/controller.rs: -------------------------------------------------------------------------------- 1 | pub use controller_mod::*; 2 | mod controller_mod { 3 | #![allow(dead_code)] 4 | #![allow(unused_imports)] 5 | use ethers::{ 6 | contract::{ 7 | builders::{ContractCall, Event}, 8 | Contract, Lazy, 9 | }, 10 | core::{ 11 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 12 | types::*, 13 | }, 14 | providers::Middleware, 15 | }; 16 | #[doc = "Controller was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 17 | use std::sync::Arc; 18 | pub static CONTROLLER_ABI: Lazy = Lazy::new(|| { 19 | serde_json :: from_str ("[\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"vat_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"pot_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"treasury_\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"constructor\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"int256\",\n \"name\": \"amount\",\n \"type\": \"int256\"\n }\n ],\n \"name\": \"Borrowed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"enabled\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"Delegate\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"access\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"GrantedAccess\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"int256\",\n \"name\": \"amount\",\n \"type\": \"int256\"\n }\n ],\n \"name\": \"Posted\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"CHAI\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DUST\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"THREE_MONTHS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"UNIT\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WETH\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"aboveDustOrZero\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"addDelegate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"yDaiContract\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"addSeries\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"authorized\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"yDaiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"borrow\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"containsSeries\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"debtDai\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"debtYDai\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"delegated\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"erase\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"yDaiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"inDai\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"daiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"inYDai\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"isCollateralized\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"live\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"locked\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"orchestrate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"post\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"posted\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"powerOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"daiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"repayDai\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"maturity\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"yDaiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"repayYDai\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeDelegate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"series\",\n \"outputs\": [\n {\n \"internalType\": \"contract IYDai\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"seriesIterator\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"shutdown\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"totalDebtDai\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSeries\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"collateral\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") 20 | }); 21 | #[derive(Clone)] 22 | pub struct Controller(Contract); 23 | impl std::ops::Deref for Controller { 24 | type Target = Contract; 25 | fn deref(&self) -> &Self::Target { 26 | &self.0 27 | } 28 | } 29 | impl std::fmt::Debug for Controller { 30 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 31 | f.debug_tuple(stringify!(Controller)) 32 | .field(&self.address()) 33 | .finish() 34 | } 35 | } 36 | impl<'a, M: Middleware> Controller { 37 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 38 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 39 | #[doc = r" object"] 40 | pub fn new>(address: T, client: Arc) -> Self { 41 | let contract = Contract::new(address.into(), CONTROLLER_ABI.clone(), client); 42 | Self(contract) 43 | } 44 | #[doc = "Calls the contract's `locked` (0x354d9fe0) function"] 45 | pub fn locked(&self, collateral: [u8; 32], user: Address) -> ContractCall { 46 | self.0 47 | .method_hash([53, 77, 159, 224], (collateral, user)) 48 | .expect("method not found (this should never happen)") 49 | } 50 | #[doc = "Calls the contract's `posted` (0xdd62f423) function"] 51 | pub fn posted(&self, p0: [u8; 32], p1: Address) -> ContractCall { 52 | self.0 53 | .method_hash([221, 98, 244, 35], (p0, p1)) 54 | .expect("method not found (this should never happen)") 55 | } 56 | #[doc = "Calls the contract's `isCollateralized` (0x7ad29f40) function"] 57 | pub fn is_collateralized( 58 | &self, 59 | collateral: [u8; 32], 60 | user: Address, 61 | ) -> ContractCall { 62 | self.0 63 | .method_hash([122, 210, 159, 64], (collateral, user)) 64 | .expect("method not found (this should never happen)") 65 | } 66 | #[doc = "Calls the contract's `WETH` (0xad5c4648) function"] 67 | pub fn weth(&self) -> ContractCall { 68 | self.0 69 | .method_hash([173, 92, 70, 72], ()) 70 | .expect("method not found (this should never happen)") 71 | } 72 | #[doc = "Calls the contract's `debtYDai` (0x98cdae5a) function"] 73 | pub fn debt_y_dai(&self, p0: [u8; 32], p1: U256, p2: Address) -> ContractCall { 74 | self.0 75 | .method_hash([152, 205, 174, 90], (p0, p1, p2)) 76 | .expect("method not found (this should never happen)") 77 | } 78 | #[doc = "Calls the contract's `seriesIterator` (0xdd102225) function"] 79 | pub fn series_iterator(&self, p0: U256) -> ContractCall { 80 | self.0 81 | .method_hash([221, 16, 34, 37], p0) 82 | .expect("method not found (this should never happen)") 83 | } 84 | #[doc = "Calls the contract's `inDai` (0x2f2ea5de) function"] 85 | pub fn in_dai( 86 | &self, 87 | collateral: [u8; 32], 88 | maturity: U256, 89 | y_dai_amount: U256, 90 | ) -> ContractCall { 91 | self.0 92 | .method_hash([47, 46, 165, 222], (collateral, maturity, y_dai_amount)) 93 | .expect("method not found (this should never happen)") 94 | } 95 | #[doc = "Calls the contract's `owner` (0x8da5cb5b) function"] 96 | pub fn owner(&self) -> ContractCall { 97 | self.0 98 | .method_hash([141, 165, 203, 91], ()) 99 | .expect("method not found (this should never happen)") 100 | } 101 | #[doc = "Calls the contract's `powerOf` (0xc06331dc) function"] 102 | pub fn power_of(&self, collateral: [u8; 32], user: Address) -> ContractCall { 103 | self.0 104 | .method_hash([192, 99, 49, 220], (collateral, user)) 105 | .expect("method not found (this should never happen)") 106 | } 107 | #[doc = "Calls the contract's `revokeDelegate` (0xfa352c00) function"] 108 | pub fn revoke_delegate(&self, delegate: Address) -> ContractCall { 109 | self.0 110 | .method_hash([250, 53, 44, 0], delegate) 111 | .expect("method not found (this should never happen)") 112 | } 113 | #[doc = "Calls the contract's `aboveDustOrZero` (0x4cd4423d) function"] 114 | pub fn above_dust_or_zero( 115 | &self, 116 | collateral: [u8; 32], 117 | user: Address, 118 | ) -> ContractCall { 119 | self.0 120 | .method_hash([76, 212, 66, 61], (collateral, user)) 121 | .expect("method not found (this should never happen)") 122 | } 123 | #[doc = "Calls the contract's `totalSeries` (0x0c6a595a) function"] 124 | pub fn total_series(&self) -> ContractCall { 125 | self.0 126 | .method_hash([12, 106, 89, 90], ()) 127 | .expect("method not found (this should never happen)") 128 | } 129 | #[doc = "Calls the contract's `addSeries` (0x7c43a201) function"] 130 | pub fn add_series(&self, y_dai_contract: Address) -> ContractCall { 131 | self.0 132 | .method_hash([124, 67, 162, 1], y_dai_contract) 133 | .expect("method not found (this should never happen)") 134 | } 135 | #[doc = "Calls the contract's `authorized` (0xb9181611) function"] 136 | pub fn authorized(&self, p0: Address) -> ContractCall { 137 | self.0 138 | .method_hash([185, 24, 22, 17], p0) 139 | .expect("method not found (this should never happen)") 140 | } 141 | #[doc = "Calls the contract's `repayDai` (0x25d3cd17) function"] 142 | pub fn repay_dai( 143 | &self, 144 | collateral: [u8; 32], 145 | maturity: U256, 146 | from: Address, 147 | to: Address, 148 | dai_amount: U256, 149 | ) -> ContractCall { 150 | self.0 151 | .method_hash( 152 | [37, 211, 205, 23], 153 | (collateral, maturity, from, to, dai_amount), 154 | ) 155 | .expect("method not found (this should never happen)") 156 | } 157 | #[doc = "Calls the contract's `shutdown` (0xfc0e74d1) function"] 158 | pub fn shutdown(&self) -> ContractCall { 159 | self.0 160 | .method_hash([252, 14, 116, 209], ()) 161 | .expect("method not found (this should never happen)") 162 | } 163 | #[doc = "Calls the contract's `UNIT` (0x9d8e2177) function"] 164 | pub fn unit(&self) -> ContractCall { 165 | self.0 166 | .method_hash([157, 142, 33, 119], ()) 167 | .expect("method not found (this should never happen)") 168 | } 169 | #[doc = "Calls the contract's `delegated` (0xf6bcbd31) function"] 170 | pub fn delegated(&self, p0: Address, p1: Address) -> ContractCall { 171 | self.0 172 | .method_hash([246, 188, 189, 49], (p0, p1)) 173 | .expect("method not found (this should never happen)") 174 | } 175 | #[doc = "Calls the contract's `DUST` (0x4e0cd799) function"] 176 | pub fn dust(&self) -> ContractCall { 177 | self.0 178 | .method_hash([78, 12, 215, 153], ()) 179 | .expect("method not found (this should never happen)") 180 | } 181 | #[doc = "Calls the contract's `CHAI` (0xb6dbf9ce) function"] 182 | pub fn chai(&self) -> ContractCall { 183 | self.0 184 | .method_hash([182, 219, 249, 206], ()) 185 | .expect("method not found (this should never happen)") 186 | } 187 | #[doc = "Calls the contract's `borrow` (0x801d325f) function"] 188 | pub fn borrow( 189 | &self, 190 | collateral: [u8; 32], 191 | maturity: U256, 192 | from: Address, 193 | to: Address, 194 | y_dai_amount: U256, 195 | ) -> ContractCall { 196 | self.0 197 | .method_hash( 198 | [128, 29, 50, 95], 199 | (collateral, maturity, from, to, y_dai_amount), 200 | ) 201 | .expect("method not found (this should never happen)") 202 | } 203 | #[doc = "Calls the contract's `debtDai` (0xc5ec0c17) function"] 204 | pub fn debt_dai( 205 | &self, 206 | collateral: [u8; 32], 207 | maturity: U256, 208 | user: Address, 209 | ) -> ContractCall { 210 | self.0 211 | .method_hash([197, 236, 12, 23], (collateral, maturity, user)) 212 | .expect("method not found (this should never happen)") 213 | } 214 | #[doc = "Calls the contract's `withdraw` (0x8e0cc176) function"] 215 | pub fn withdraw( 216 | &self, 217 | collateral: [u8; 32], 218 | from: Address, 219 | to: Address, 220 | amount: U256, 221 | ) -> ContractCall { 222 | self.0 223 | .method_hash([142, 12, 193, 118], (collateral, from, to, amount)) 224 | .expect("method not found (this should never happen)") 225 | } 226 | #[doc = "Calls the contract's `containsSeries` (0xd0a3a7e4) function"] 227 | pub fn contains_series(&self, maturity: U256) -> ContractCall { 228 | self.0 229 | .method_hash([208, 163, 167, 228], maturity) 230 | .expect("method not found (this should never happen)") 231 | } 232 | #[doc = "Calls the contract's `erase` (0x0d4c43be) function"] 233 | pub fn erase(&self, collateral: [u8; 32], user: Address) -> ContractCall { 234 | self.0 235 | .method_hash([13, 76, 67, 190], (collateral, user)) 236 | .expect("method not found (this should never happen)") 237 | } 238 | #[doc = "Calls the contract's `series` (0xdc22cb6a) function"] 239 | pub fn series(&self, p0: U256) -> ContractCall { 240 | self.0 241 | .method_hash([220, 34, 203, 106], p0) 242 | .expect("method not found (this should never happen)") 243 | } 244 | #[doc = "Calls the contract's `THREE_MONTHS` (0xecbefab7) function"] 245 | pub fn three_months(&self) -> ContractCall { 246 | self.0 247 | .method_hash([236, 190, 250, 183], ()) 248 | .expect("method not found (this should never happen)") 249 | } 250 | #[doc = "Calls the contract's `live` (0x957aa58c) function"] 251 | pub fn live(&self) -> ContractCall { 252 | self.0 253 | .method_hash([149, 122, 165, 140], ()) 254 | .expect("method not found (this should never happen)") 255 | } 256 | #[doc = "Calls the contract's `orchestrate` (0x80f5a440) function"] 257 | pub fn orchestrate(&self, user: Address) -> ContractCall { 258 | self.0 259 | .method_hash([128, 245, 164, 64], user) 260 | .expect("method not found (this should never happen)") 261 | } 262 | #[doc = "Calls the contract's `inYDai` (0xed7eebf2) function"] 263 | pub fn in_y_dai( 264 | &self, 265 | collateral: [u8; 32], 266 | maturity: U256, 267 | dai_amount: U256, 268 | ) -> ContractCall { 269 | self.0 270 | .method_hash([237, 126, 235, 242], (collateral, maturity, dai_amount)) 271 | .expect("method not found (this should never happen)") 272 | } 273 | #[doc = "Calls the contract's `transferOwnership` (0xf2fde38b) function"] 274 | pub fn transfer_ownership(&self, new_owner: Address) -> ContractCall { 275 | self.0 276 | .method_hash([242, 253, 227, 139], new_owner) 277 | .expect("method not found (this should never happen)") 278 | } 279 | #[doc = "Calls the contract's `addDelegate` (0xe71bdf41) function"] 280 | pub fn add_delegate(&self, delegate: Address) -> ContractCall { 281 | self.0 282 | .method_hash([231, 27, 223, 65], delegate) 283 | .expect("method not found (this should never happen)") 284 | } 285 | #[doc = "Calls the contract's `totalDebtDai` (0xe68b7cf4) function"] 286 | pub fn total_debt_dai(&self, collateral: [u8; 32], user: Address) -> ContractCall { 287 | self.0 288 | .method_hash([230, 139, 124, 244], (collateral, user)) 289 | .expect("method not found (this should never happen)") 290 | } 291 | #[doc = "Calls the contract's `post` (0xadb9e54e) function"] 292 | pub fn post( 293 | &self, 294 | collateral: [u8; 32], 295 | from: Address, 296 | to: Address, 297 | amount: U256, 298 | ) -> ContractCall { 299 | self.0 300 | .method_hash([173, 185, 229, 78], (collateral, from, to, amount)) 301 | .expect("method not found (this should never happen)") 302 | } 303 | #[doc = "Calls the contract's `renounceOwnership` (0x715018a6) function"] 304 | pub fn renounce_ownership(&self) -> ContractCall { 305 | self.0 306 | .method_hash([113, 80, 24, 166], ()) 307 | .expect("method not found (this should never happen)") 308 | } 309 | #[doc = "Calls the contract's `repayYDai` (0x91371ffb) function"] 310 | pub fn repay_y_dai( 311 | &self, 312 | collateral: [u8; 32], 313 | maturity: U256, 314 | from: Address, 315 | to: Address, 316 | y_dai_amount: U256, 317 | ) -> ContractCall { 318 | self.0 319 | .method_hash( 320 | [145, 55, 31, 251], 321 | (collateral, maturity, from, to, y_dai_amount), 322 | ) 323 | .expect("method not found (this should never happen)") 324 | } 325 | #[doc = "Gets the contract's `Posted` event"] 326 | pub fn posted_filter(&self) -> Event { 327 | self.0 328 | .event("Posted") 329 | .expect("event not found (this should never happen)") 330 | } 331 | #[doc = "Gets the contract's `Delegate` event"] 332 | pub fn delegate_filter(&self) -> Event { 333 | self.0 334 | .event("Delegate") 335 | .expect("event not found (this should never happen)") 336 | } 337 | #[doc = "Gets the contract's `OwnershipTransferred` event"] 338 | pub fn ownership_transferred_filter(&self) -> Event { 339 | self.0 340 | .event("OwnershipTransferred") 341 | .expect("event not found (this should never happen)") 342 | } 343 | #[doc = "Gets the contract's `Borrowed` event"] 344 | pub fn borrowed_filter(&self) -> Event { 345 | self.0 346 | .event("Borrowed") 347 | .expect("event not found (this should never happen)") 348 | } 349 | #[doc = "Gets the contract's `GrantedAccess` event"] 350 | pub fn granted_access_filter(&self) -> Event { 351 | self.0 352 | .event("GrantedAccess") 353 | .expect("event not found (this should never happen)") 354 | } 355 | } 356 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 357 | pub struct PostedFilter { 358 | pub collateral: [u8; 32], 359 | pub user: Address, 360 | pub amount: U256, 361 | } 362 | impl PostedFilter { 363 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 364 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 365 | #[doc = r" this event."] 366 | pub const fn signature() -> H256 { 367 | H256([ 368 | 206, 25, 148, 114, 124, 241, 100, 227, 8, 1, 241, 64, 179, 1, 158, 13, 72, 98, 212, 369 | 48, 67, 138, 180, 29, 225, 20, 75, 93, 183, 25, 197, 131, 370 | ]) 371 | } 372 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 373 | #[doc = r" to. For this event the value should always be:"] 374 | #[doc = r""] 375 | #[doc = "`Posted(bytes32,address,int256)`"] 376 | pub const fn abi_signature() -> &'static str { 377 | "Posted(bytes32,address,int256)" 378 | } 379 | } 380 | impl Detokenize for PostedFilter { 381 | fn from_tokens(tokens: Vec) -> Result { 382 | if tokens.len() != 3 { 383 | return Err(InvalidOutputType(format!( 384 | "Expected {} tokens, got {}: {:?}", 385 | 3, 386 | tokens.len(), 387 | tokens 388 | ))); 389 | } 390 | #[allow(unused_mut)] 391 | let mut tokens = tokens.into_iter(); 392 | let collateral = 393 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 394 | let user = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 395 | let amount = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 396 | Ok(PostedFilter { 397 | collateral, 398 | user, 399 | amount, 400 | }) 401 | } 402 | } 403 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 404 | pub struct DelegateFilter { 405 | pub user: Address, 406 | pub delegate: Address, 407 | pub enabled: bool, 408 | } 409 | impl DelegateFilter { 410 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 411 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 412 | #[doc = r" this event."] 413 | pub const fn signature() -> H256 { 414 | H256([ 415 | 4, 91, 15, 239, 1, 119, 45, 47, 187, 165, 61, 189, 56, 201, 119, 120, 6, 234, 192, 416 | 134, 91, 0, 175, 67, 171, 207, 188, 175, 80, 218, 146, 6, 417 | ]) 418 | } 419 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 420 | #[doc = r" to. For this event the value should always be:"] 421 | #[doc = r""] 422 | #[doc = "`Delegate(address,address,bool)`"] 423 | pub const fn abi_signature() -> &'static str { 424 | "Delegate(address,address,bool)" 425 | } 426 | } 427 | impl Detokenize for DelegateFilter { 428 | fn from_tokens(tokens: Vec) -> Result { 429 | if tokens.len() != 3 { 430 | return Err(InvalidOutputType(format!( 431 | "Expected {} tokens, got {}: {:?}", 432 | 3, 433 | tokens.len(), 434 | tokens 435 | ))); 436 | } 437 | #[allow(unused_mut)] 438 | let mut tokens = tokens.into_iter(); 439 | let user = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 440 | let delegate = 441 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 442 | let enabled = 443 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 444 | Ok(DelegateFilter { 445 | user, 446 | delegate, 447 | enabled, 448 | }) 449 | } 450 | } 451 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 452 | pub struct OwnershipTransferredFilter { 453 | pub previous_owner: Address, 454 | pub new_owner: Address, 455 | } 456 | impl OwnershipTransferredFilter { 457 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 458 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 459 | #[doc = r" this event."] 460 | pub const fn signature() -> H256 { 461 | H256([ 462 | 139, 224, 7, 156, 83, 22, 89, 20, 19, 68, 205, 31, 208, 164, 242, 132, 25, 73, 127, 463 | 151, 34, 163, 218, 175, 227, 180, 24, 111, 107, 100, 87, 224, 464 | ]) 465 | } 466 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 467 | #[doc = r" to. For this event the value should always be:"] 468 | #[doc = r""] 469 | #[doc = "`OwnershipTransferred(address,address)`"] 470 | pub const fn abi_signature() -> &'static str { 471 | "OwnershipTransferred(address,address)" 472 | } 473 | } 474 | impl Detokenize for OwnershipTransferredFilter { 475 | fn from_tokens(tokens: Vec) -> Result { 476 | if tokens.len() != 2 { 477 | return Err(InvalidOutputType(format!( 478 | "Expected {} tokens, got {}: {:?}", 479 | 2, 480 | tokens.len(), 481 | tokens 482 | ))); 483 | } 484 | #[allow(unused_mut)] 485 | let mut tokens = tokens.into_iter(); 486 | let previous_owner = 487 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 488 | let new_owner = 489 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 490 | Ok(OwnershipTransferredFilter { 491 | previous_owner, 492 | new_owner, 493 | }) 494 | } 495 | } 496 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 497 | pub struct BorrowedFilter { 498 | pub collateral: [u8; 32], 499 | pub maturity: U256, 500 | pub user: Address, 501 | pub amount: U256, 502 | } 503 | impl BorrowedFilter { 504 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 505 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 506 | #[doc = r" this event."] 507 | pub const fn signature() -> H256 { 508 | H256([ 509 | 61, 192, 237, 40, 107, 26, 251, 194, 34, 138, 30, 127, 129, 252, 63, 102, 170, 159, 510 | 66, 61, 202, 12, 106, 40, 62, 175, 165, 62, 147, 173, 239, 190, 511 | ]) 512 | } 513 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 514 | #[doc = r" to. For this event the value should always be:"] 515 | #[doc = r""] 516 | #[doc = "`Borrowed(bytes32,uint256,address,int256)`"] 517 | pub const fn abi_signature() -> &'static str { 518 | "Borrowed(bytes32,uint256,address,int256)" 519 | } 520 | } 521 | impl Detokenize for BorrowedFilter { 522 | fn from_tokens(tokens: Vec) -> Result { 523 | if tokens.len() != 4 { 524 | return Err(InvalidOutputType(format!( 525 | "Expected {} tokens, got {}: {:?}", 526 | 4, 527 | tokens.len(), 528 | tokens 529 | ))); 530 | } 531 | #[allow(unused_mut)] 532 | let mut tokens = tokens.into_iter(); 533 | let collateral = 534 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 535 | let maturity = 536 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 537 | let user = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 538 | let amount = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 539 | Ok(BorrowedFilter { 540 | collateral, 541 | maturity, 542 | user, 543 | amount, 544 | }) 545 | } 546 | } 547 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 548 | pub struct GrantedAccessFilter { 549 | pub access: Address, 550 | } 551 | impl GrantedAccessFilter { 552 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 553 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 554 | #[doc = r" this event."] 555 | pub const fn signature() -> H256 { 556 | H256([ 557 | 106, 124, 95, 40, 234, 86, 79, 175, 200, 176, 121, 102, 58, 42, 155, 157, 38, 254, 558 | 115, 93, 151, 201, 118, 17, 72, 76, 224, 68, 244, 10, 22, 226, 559 | ]) 560 | } 561 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 562 | #[doc = r" to. For this event the value should always be:"] 563 | #[doc = r""] 564 | #[doc = "`GrantedAccess(address)`"] 565 | pub const fn abi_signature() -> &'static str { 566 | "GrantedAccess(address)" 567 | } 568 | } 569 | impl Detokenize for GrantedAccessFilter { 570 | fn from_tokens(tokens: Vec) -> Result { 571 | if tokens.len() != 1 { 572 | return Err(InvalidOutputType(format!( 573 | "Expected {} tokens, got {}: {:?}", 574 | 1, 575 | tokens.len(), 576 | tokens 577 | ))); 578 | } 579 | #[allow(unused_mut)] 580 | let mut tokens = tokens.into_iter(); 581 | let access = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 582 | Ok(GrantedAccessFilter { access }) 583 | } 584 | } 585 | } 586 | -------------------------------------------------------------------------------- /src/bindings/liquidations.rs: -------------------------------------------------------------------------------- 1 | pub use liquidations_mod::*; 2 | mod liquidations_mod { 3 | #![allow(dead_code)] 4 | #![allow(unused_imports)] 5 | use ethers::{ 6 | contract::{ 7 | builders::{ContractCall, Event}, 8 | Contract, Lazy, 9 | }, 10 | core::{ 11 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 12 | types::*, 13 | }, 14 | providers::Middleware, 15 | }; 16 | #[doc = "Liquidations was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 17 | use std::sync::Arc; 18 | pub static LIQUIDATIONS_ABI: Lazy = Lazy::new(|| { 19 | serde_json :: from_str ("[\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"dai_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"treasury_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"controller_\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"constructor\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"enabled\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"Delegate\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"access\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"GrantedAccess\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"started\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"collateral\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"debt\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Liquidation\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"AUCTION_TIME\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DUST\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"UNIT\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WETH\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"aboveDustOrZero\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"addDelegate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"authorized\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"liquidated\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"daiAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"buy\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"delegated\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"erase\",\n \"outputs\": [\n {\n \"internalType\": \"uint128\",\n \"name\": \"\",\n \"type\": \"uint128\"\n },\n {\n \"internalType\": \"uint128\",\n \"name\": \"\",\n \"type\": \"uint128\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"liquidate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"liquidations\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"live\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"orchestrate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"price\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"delegate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeDelegate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"shutdown\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totals\",\n \"outputs\": [\n {\n \"internalType\": \"uint128\",\n \"name\": \"collateral\",\n \"type\": \"uint128\"\n },\n {\n \"internalType\": \"uint128\",\n \"name\": \"debt\",\n \"type\": \"uint128\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"vaults\",\n \"outputs\": [\n {\n \"internalType\": \"uint128\",\n \"name\": \"collateral\",\n \"type\": \"uint128\"\n },\n {\n \"internalType\": \"uint128\",\n \"name\": \"debt\",\n \"type\": \"uint128\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenAmount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") 20 | }); 21 | #[derive(Clone)] 22 | pub struct Liquidations(Contract); 23 | impl std::ops::Deref for Liquidations { 24 | type Target = Contract; 25 | fn deref(&self) -> &Self::Target { 26 | &self.0 27 | } 28 | } 29 | impl std::fmt::Debug for Liquidations { 30 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 31 | f.debug_tuple(stringify!(Liquidations)) 32 | .field(&self.address()) 33 | .finish() 34 | } 35 | } 36 | impl<'a, M: Middleware> Liquidations { 37 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 38 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 39 | #[doc = r" object"] 40 | pub fn new>(address: T, client: Arc) -> Self { 41 | let contract = Contract::new(address.into(), LIQUIDATIONS_ABI.clone(), client); 42 | Self(contract) 43 | } 44 | #[doc = "Calls the contract's `price` (0xaea91078) function"] 45 | pub fn price(&self, user: Address) -> ContractCall { 46 | self.0 47 | .method_hash([174, 169, 16, 120], user) 48 | .expect("method not found (this should never happen)") 49 | } 50 | #[doc = "Calls the contract's `authorized` (0xb9181611) function"] 51 | pub fn authorized(&self, p0: Address) -> ContractCall { 52 | self.0 53 | .method_hash([185, 24, 22, 17], p0) 54 | .expect("method not found (this should never happen)") 55 | } 56 | #[doc = "Calls the contract's `orchestrate` (0x80f5a440) function"] 57 | pub fn orchestrate(&self, user: Address) -> ContractCall { 58 | self.0 59 | .method_hash([128, 245, 164, 64], user) 60 | .expect("method not found (this should never happen)") 61 | } 62 | #[doc = "Calls the contract's `withdraw` (0xd9caed12) function"] 63 | pub fn withdraw( 64 | &self, 65 | from: Address, 66 | to: Address, 67 | token_amount: U256, 68 | ) -> ContractCall { 69 | self.0 70 | .method_hash([217, 202, 237, 18], (from, to, token_amount)) 71 | .expect("method not found (this should never happen)") 72 | } 73 | #[doc = "Calls the contract's `transferOwnership` (0xf2fde38b) function"] 74 | pub fn transfer_ownership(&self, new_owner: Address) -> ContractCall { 75 | self.0 76 | .method_hash([242, 253, 227, 139], new_owner) 77 | .expect("method not found (this should never happen)") 78 | } 79 | #[doc = "Calls the contract's `addDelegate` (0xe71bdf41) function"] 80 | pub fn add_delegate(&self, delegate: Address) -> ContractCall { 81 | self.0 82 | .method_hash([231, 27, 223, 65], delegate) 83 | .expect("method not found (this should never happen)") 84 | } 85 | #[doc = "Calls the contract's `buy` (0xe8cdcc99) function"] 86 | pub fn buy( 87 | &self, 88 | from: Address, 89 | to: Address, 90 | liquidated: Address, 91 | dai_amount: U256, 92 | ) -> ContractCall { 93 | self.0 94 | .method_hash([232, 205, 204, 153], (from, to, liquidated, dai_amount)) 95 | .expect("method not found (this should never happen)") 96 | } 97 | #[doc = "Calls the contract's `DUST` (0x4e0cd799) function"] 98 | pub fn dust(&self) -> ContractCall { 99 | self.0 100 | .method_hash([78, 12, 215, 153], ()) 101 | .expect("method not found (this should never happen)") 102 | } 103 | #[doc = "Calls the contract's `liquidate` (0x2f865568) function"] 104 | pub fn liquidate(&self, user: Address) -> ContractCall { 105 | self.0 106 | .method_hash([47, 134, 85, 104], user) 107 | .expect("method not found (this should never happen)") 108 | } 109 | #[doc = "Calls the contract's `totals` (0xc038a38e) function"] 110 | pub fn totals(&self) -> ContractCall { 111 | self.0 112 | .method_hash([192, 56, 163, 142], ()) 113 | .expect("method not found (this should never happen)") 114 | } 115 | #[doc = "Calls the contract's `erase` (0xe85b0080) function"] 116 | pub fn erase(&self, user: Address) -> ContractCall { 117 | self.0 118 | .method_hash([232, 91, 0, 128], user) 119 | .expect("method not found (this should never happen)") 120 | } 121 | #[doc = "Calls the contract's `renounceOwnership` (0x715018a6) function"] 122 | pub fn renounce_ownership(&self) -> ContractCall { 123 | self.0 124 | .method_hash([113, 80, 24, 166], ()) 125 | .expect("method not found (this should never happen)") 126 | } 127 | #[doc = "Calls the contract's `WETH` (0xad5c4648) function"] 128 | pub fn weth(&self) -> ContractCall { 129 | self.0 130 | .method_hash([173, 92, 70, 72], ()) 131 | .expect("method not found (this should never happen)") 132 | } 133 | #[doc = "Calls the contract's `liquidations` (0x937d4c42) function"] 134 | pub fn liquidations(&self, p0: Address) -> ContractCall { 135 | self.0 136 | .method_hash([147, 125, 76, 66], p0) 137 | .expect("method not found (this should never happen)") 138 | } 139 | #[doc = "Calls the contract's `owner` (0x8da5cb5b) function"] 140 | pub fn owner(&self) -> ContractCall { 141 | self.0 142 | .method_hash([141, 165, 203, 91], ()) 143 | .expect("method not found (this should never happen)") 144 | } 145 | #[doc = "Calls the contract's `aboveDustOrZero` (0xe5442a9e) function"] 146 | pub fn above_dust_or_zero(&self, user: Address) -> ContractCall { 147 | self.0 148 | .method_hash([229, 68, 42, 158], user) 149 | .expect("method not found (this should never happen)") 150 | } 151 | #[doc = "Calls the contract's `vaults` (0xa622ee7c) function"] 152 | pub fn vaults(&self, p0: Address) -> ContractCall { 153 | self.0 154 | .method_hash([166, 34, 238, 124], p0) 155 | .expect("method not found (this should never happen)") 156 | } 157 | #[doc = "Calls the contract's `AUCTION_TIME` (0xe592301a) function"] 158 | pub fn auction_time(&self) -> ContractCall { 159 | self.0 160 | .method_hash([229, 146, 48, 26], ()) 161 | .expect("method not found (this should never happen)") 162 | } 163 | #[doc = "Calls the contract's `live` (0x957aa58c) function"] 164 | pub fn live(&self) -> ContractCall { 165 | self.0 166 | .method_hash([149, 122, 165, 140], ()) 167 | .expect("method not found (this should never happen)") 168 | } 169 | #[doc = "Calls the contract's `revokeDelegate` (0xfa352c00) function"] 170 | pub fn revoke_delegate(&self, delegate: Address) -> ContractCall { 171 | self.0 172 | .method_hash([250, 53, 44, 0], delegate) 173 | .expect("method not found (this should never happen)") 174 | } 175 | #[doc = "Calls the contract's `shutdown` (0xfc0e74d1) function"] 176 | pub fn shutdown(&self) -> ContractCall { 177 | self.0 178 | .method_hash([252, 14, 116, 209], ()) 179 | .expect("method not found (this should never happen)") 180 | } 181 | #[doc = "Calls the contract's `UNIT` (0x9d8e2177) function"] 182 | pub fn unit(&self) -> ContractCall { 183 | self.0 184 | .method_hash([157, 142, 33, 119], ()) 185 | .expect("method not found (this should never happen)") 186 | } 187 | #[doc = "Calls the contract's `delegated` (0xf6bcbd31) function"] 188 | pub fn delegated(&self, p0: Address, p1: Address) -> ContractCall { 189 | self.0 190 | .method_hash([246, 188, 189, 49], (p0, p1)) 191 | .expect("method not found (this should never happen)") 192 | } 193 | #[doc = "Gets the contract's `Delegate` event"] 194 | pub fn delegate_filter(&self) -> Event { 195 | self.0 196 | .event("Delegate") 197 | .expect("event not found (this should never happen)") 198 | } 199 | #[doc = "Gets the contract's `GrantedAccess` event"] 200 | pub fn granted_access_filter(&self) -> Event { 201 | self.0 202 | .event("GrantedAccess") 203 | .expect("event not found (this should never happen)") 204 | } 205 | #[doc = "Gets the contract's `OwnershipTransferred` event"] 206 | pub fn ownership_transferred_filter(&self) -> Event { 207 | self.0 208 | .event("OwnershipTransferred") 209 | .expect("event not found (this should never happen)") 210 | } 211 | #[doc = "Gets the contract's `Liquidation` event"] 212 | pub fn liquidation_filter(&self) -> Event { 213 | self.0 214 | .event("Liquidation") 215 | .expect("event not found (this should never happen)") 216 | } 217 | } 218 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 219 | pub struct DelegateFilter { 220 | pub user: Address, 221 | pub delegate: Address, 222 | pub enabled: bool, 223 | } 224 | impl DelegateFilter { 225 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 226 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 227 | #[doc = r" this event."] 228 | pub const fn signature() -> H256 { 229 | H256([ 230 | 4, 91, 15, 239, 1, 119, 45, 47, 187, 165, 61, 189, 56, 201, 119, 120, 6, 234, 192, 231 | 134, 91, 0, 175, 67, 171, 207, 188, 175, 80, 218, 146, 6, 232 | ]) 233 | } 234 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 235 | #[doc = r" to. For this event the value should always be:"] 236 | #[doc = r""] 237 | #[doc = "`Delegate(address,address,bool)`"] 238 | pub const fn abi_signature() -> &'static str { 239 | "Delegate(address,address,bool)" 240 | } 241 | } 242 | impl Detokenize for DelegateFilter { 243 | fn from_tokens(tokens: Vec) -> Result { 244 | if tokens.len() != 3 { 245 | return Err(InvalidOutputType(format!( 246 | "Expected {} tokens, got {}: {:?}", 247 | 3, 248 | tokens.len(), 249 | tokens 250 | ))); 251 | } 252 | #[allow(unused_mut)] 253 | let mut tokens = tokens.into_iter(); 254 | let user = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 255 | let delegate = 256 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 257 | let enabled = 258 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 259 | Ok(DelegateFilter { 260 | user, 261 | delegate, 262 | enabled, 263 | }) 264 | } 265 | } 266 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 267 | pub struct GrantedAccessFilter { 268 | pub access: Address, 269 | } 270 | impl GrantedAccessFilter { 271 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 272 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 273 | #[doc = r" this event."] 274 | pub const fn signature() -> H256 { 275 | H256([ 276 | 106, 124, 95, 40, 234, 86, 79, 175, 200, 176, 121, 102, 58, 42, 155, 157, 38, 254, 277 | 115, 93, 151, 201, 118, 17, 72, 76, 224, 68, 244, 10, 22, 226, 278 | ]) 279 | } 280 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 281 | #[doc = r" to. For this event the value should always be:"] 282 | #[doc = r""] 283 | #[doc = "`GrantedAccess(address)`"] 284 | pub const fn abi_signature() -> &'static str { 285 | "GrantedAccess(address)" 286 | } 287 | } 288 | impl Detokenize for GrantedAccessFilter { 289 | fn from_tokens(tokens: Vec) -> Result { 290 | if tokens.len() != 1 { 291 | return Err(InvalidOutputType(format!( 292 | "Expected {} tokens, got {}: {:?}", 293 | 1, 294 | tokens.len(), 295 | tokens 296 | ))); 297 | } 298 | #[allow(unused_mut)] 299 | let mut tokens = tokens.into_iter(); 300 | let access = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 301 | Ok(GrantedAccessFilter { access }) 302 | } 303 | } 304 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 305 | pub struct OwnershipTransferredFilter { 306 | pub previous_owner: Address, 307 | pub new_owner: Address, 308 | } 309 | impl OwnershipTransferredFilter { 310 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 311 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 312 | #[doc = r" this event."] 313 | pub const fn signature() -> H256 { 314 | H256([ 315 | 139, 224, 7, 156, 83, 22, 89, 20, 19, 68, 205, 31, 208, 164, 242, 132, 25, 73, 127, 316 | 151, 34, 163, 218, 175, 227, 180, 24, 111, 107, 100, 87, 224, 317 | ]) 318 | } 319 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 320 | #[doc = r" to. For this event the value should always be:"] 321 | #[doc = r""] 322 | #[doc = "`OwnershipTransferred(address,address)`"] 323 | pub const fn abi_signature() -> &'static str { 324 | "OwnershipTransferred(address,address)" 325 | } 326 | } 327 | impl Detokenize for OwnershipTransferredFilter { 328 | fn from_tokens(tokens: Vec) -> Result { 329 | if tokens.len() != 2 { 330 | return Err(InvalidOutputType(format!( 331 | "Expected {} tokens, got {}: {:?}", 332 | 2, 333 | tokens.len(), 334 | tokens 335 | ))); 336 | } 337 | #[allow(unused_mut)] 338 | let mut tokens = tokens.into_iter(); 339 | let previous_owner = 340 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 341 | let new_owner = 342 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 343 | Ok(OwnershipTransferredFilter { 344 | previous_owner, 345 | new_owner, 346 | }) 347 | } 348 | } 349 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 350 | pub struct LiquidationFilter { 351 | pub user: Address, 352 | pub started: U256, 353 | pub collateral: U256, 354 | pub debt: U256, 355 | } 356 | impl LiquidationFilter { 357 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 358 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 359 | #[doc = r" this event."] 360 | pub const fn signature() -> H256 { 361 | H256([ 362 | 26, 16, 114, 235, 152, 66, 79, 81, 217, 173, 86, 82, 111, 5, 205, 130, 220, 70, 363 | 248, 150, 90, 150, 183, 196, 33, 241, 130, 117, 117, 61, 36, 140, 364 | ]) 365 | } 366 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 367 | #[doc = r" to. For this event the value should always be:"] 368 | #[doc = r""] 369 | #[doc = "`Liquidation(address,uint256,uint256,uint256)`"] 370 | pub const fn abi_signature() -> &'static str { 371 | "Liquidation(address,uint256,uint256,uint256)" 372 | } 373 | } 374 | impl Detokenize for LiquidationFilter { 375 | fn from_tokens(tokens: Vec) -> Result { 376 | if tokens.len() != 4 { 377 | return Err(InvalidOutputType(format!( 378 | "Expected {} tokens, got {}: {:?}", 379 | 4, 380 | tokens.len(), 381 | tokens 382 | ))); 383 | } 384 | #[allow(unused_mut)] 385 | let mut tokens = tokens.into_iter(); 386 | let user = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 387 | let started = 388 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 389 | let collateral = 390 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 391 | let debt = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 392 | Ok(LiquidationFilter { 393 | user, 394 | started, 395 | collateral, 396 | debt, 397 | }) 398 | } 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/bindings/mod.rs: -------------------------------------------------------------------------------- 1 | mod controller; 2 | pub use controller::*; 3 | 4 | mod liquidations; 5 | pub use liquidations::*; 6 | 7 | mod uniswapv2pair; 8 | pub use uniswapv2pair::*; 9 | -------------------------------------------------------------------------------- /src/bindings/uniswapv2pair.rs: -------------------------------------------------------------------------------- 1 | pub use uniswapv2pair_mod::*; 2 | mod uniswapv2pair_mod { 3 | #![allow(dead_code)] 4 | #![allow(unused_imports)] 5 | use ethers::{ 6 | contract::{ 7 | builders::{ContractCall, Event}, 8 | Contract, Lazy, 9 | }, 10 | core::{ 11 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 12 | types::*, 13 | }, 14 | providers::Middleware, 15 | }; 16 | #[doc = "UniswapV2Pair was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 17 | use std::sync::Arc; 18 | pub static UNISWAPV2PAIR_ABI: Lazy = Lazy::new(|| { 19 | serde_json :: from_str ("[\n {\n \"inputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"constructor\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount0\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount1\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Burn\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount0\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount1\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Mint\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount0In\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount1In\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount0Out\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount1Out\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Swap\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint112\",\n \"name\": \"reserve0\",\n \"type\": \"uint112\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint112\",\n \"name\": \"reserve1\",\n \"type\": \"uint112\"\n }\n ],\n \"name\": \"Sync\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DOMAIN_SEPARATOR\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MINIMUM_LIQUIDITY\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"PERMIT_TYPEHASH\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"factory\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"kLast\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"nonces\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"deadline\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"v\",\n \"type\": \"uint8\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"r\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"s\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"permit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"price0CumulativeLast\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"price1CumulativeLast\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"token0\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"token1\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"getReserves\",\n \"outputs\": [\n {\n \"internalType\": \"uint112\",\n \"name\": \"_reserve0\",\n \"type\": \"uint112\"\n },\n {\n \"internalType\": \"uint112\",\n \"name\": \"_reserve1\",\n \"type\": \"uint112\"\n },\n {\n \"internalType\": \"uint32\",\n \"name\": \"_blockTimestampLast\",\n \"type\": \"uint32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_token0\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"_token1\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"liquidity\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount0\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount1\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount0Out\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount1Out\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"swap\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"skim\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"sync\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") 20 | }); 21 | #[derive(Clone)] 22 | pub struct UniswapV2Pair(Contract); 23 | impl std::ops::Deref for UniswapV2Pair { 24 | type Target = Contract; 25 | fn deref(&self) -> &Self::Target { 26 | &self.0 27 | } 28 | } 29 | impl std::fmt::Debug for UniswapV2Pair { 30 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 31 | f.debug_tuple(stringify!(UniswapV2Pair)) 32 | .field(&self.address()) 33 | .finish() 34 | } 35 | } 36 | impl<'a, M: Middleware> UniswapV2Pair { 37 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 38 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 39 | #[doc = r" object"] 40 | pub fn new>(address: T, client: Arc) -> Self { 41 | let contract = Contract::new(address.into(), UNISWAPV2PAIR_ABI.clone(), client); 42 | Self(contract) 43 | } 44 | #[doc = "Calls the contract's `factory` (0xc45a0155) function"] 45 | pub fn factory(&self) -> ContractCall { 46 | self.0 47 | .method_hash([196, 90, 1, 85], ()) 48 | .expect("method not found (this should never happen)") 49 | } 50 | #[doc = "Calls the contract's `MINIMUM_LIQUIDITY` (0xba9a7a56) function"] 51 | pub fn minimum_liquidity(&self) -> ContractCall { 52 | self.0 53 | .method_hash([186, 154, 122, 86], ()) 54 | .expect("method not found (this should never happen)") 55 | } 56 | #[doc = "Calls the contract's `symbol` (0x95d89b41) function"] 57 | pub fn symbol(&self) -> ContractCall { 58 | self.0 59 | .method_hash([149, 216, 155, 65], ()) 60 | .expect("method not found (this should never happen)") 61 | } 62 | #[doc = "Calls the contract's `allowance` (0xdd62ed3e) function"] 63 | pub fn allowance(&self, p0: Address, p1: Address) -> ContractCall { 64 | self.0 65 | .method_hash([221, 98, 237, 62], (p0, p1)) 66 | .expect("method not found (this should never happen)") 67 | } 68 | #[doc = "Calls the contract's `mint` (0x6a627842) function"] 69 | pub fn mint(&self, to: Address) -> ContractCall { 70 | self.0 71 | .method_hash([106, 98, 120, 66], to) 72 | .expect("method not found (this should never happen)") 73 | } 74 | #[doc = "Calls the contract's `price1CumulativeLast` (0x5a3d5493) function"] 75 | pub fn price_1_cumulative_last(&self) -> ContractCall { 76 | self.0 77 | .method_hash([90, 61, 84, 147], ()) 78 | .expect("method not found (this should never happen)") 79 | } 80 | #[doc = "Calls the contract's `totalSupply` (0x18160ddd) function"] 81 | pub fn total_supply(&self) -> ContractCall { 82 | self.0 83 | .method_hash([24, 22, 13, 221], ()) 84 | .expect("method not found (this should never happen)") 85 | } 86 | #[doc = "Calls the contract's `burn` (0x89afcb44) function"] 87 | pub fn burn(&self, to: Address) -> ContractCall { 88 | self.0 89 | .method_hash([137, 175, 203, 68], to) 90 | .expect("method not found (this should never happen)") 91 | } 92 | #[doc = "Calls the contract's `kLast` (0x7464fc3d) function"] 93 | pub fn k_last(&self) -> ContractCall { 94 | self.0 95 | .method_hash([116, 100, 252, 61], ()) 96 | .expect("method not found (this should never happen)") 97 | } 98 | #[doc = "Calls the contract's `getReserves` (0x0902f1ac) function"] 99 | pub fn get_reserves(&self) -> ContractCall { 100 | self.0 101 | .method_hash([9, 2, 241, 172], ()) 102 | .expect("method not found (this should never happen)") 103 | } 104 | #[doc = "Calls the contract's `initialize` (0x485cc955) function"] 105 | pub fn initialize(&self, token_0: Address, token_1: Address) -> ContractCall { 106 | self.0 107 | .method_hash([72, 92, 201, 85], (token_0, token_1)) 108 | .expect("method not found (this should never happen)") 109 | } 110 | #[doc = "Calls the contract's `nonces` (0x7ecebe00) function"] 111 | pub fn nonces(&self, p0: Address) -> ContractCall { 112 | self.0 113 | .method_hash([126, 206, 190, 0], p0) 114 | .expect("method not found (this should never happen)") 115 | } 116 | #[doc = "Calls the contract's `skim` (0xbc25cf77) function"] 117 | pub fn skim(&self, to: Address) -> ContractCall { 118 | self.0 119 | .method_hash([188, 37, 207, 119], to) 120 | .expect("method not found (this should never happen)") 121 | } 122 | #[doc = "Calls the contract's `permit` (0xd505accf) function"] 123 | pub fn permit( 124 | &self, 125 | owner: Address, 126 | spender: Address, 127 | value: U256, 128 | deadline: U256, 129 | v: u8, 130 | r: [u8; 32], 131 | s: [u8; 32], 132 | ) -> ContractCall { 133 | self.0 134 | .method_hash( 135 | [213, 5, 172, 207], 136 | (owner, spender, value, deadline, v, r, s), 137 | ) 138 | .expect("method not found (this should never happen)") 139 | } 140 | #[doc = "Calls the contract's `token1` (0xd21220a7) function"] 141 | pub fn token_1(&self) -> ContractCall { 142 | self.0 143 | .method_hash([210, 18, 32, 167], ()) 144 | .expect("method not found (this should never happen)") 145 | } 146 | #[doc = "Calls the contract's `sync` (0xfff6cae9) function"] 147 | pub fn sync(&self) -> ContractCall { 148 | self.0 149 | .method_hash([255, 246, 202, 233], ()) 150 | .expect("method not found (this should never happen)") 151 | } 152 | #[doc = "Calls the contract's `PERMIT_TYPEHASH` (0x30adf81f) function"] 153 | pub fn permit_typehash(&self) -> ContractCall { 154 | self.0 155 | .method_hash([48, 173, 248, 31], ()) 156 | .expect("method not found (this should never happen)") 157 | } 158 | #[doc = "Calls the contract's `decimals` (0x313ce567) function"] 159 | pub fn decimals(&self) -> ContractCall { 160 | self.0 161 | .method_hash([49, 60, 229, 103], ()) 162 | .expect("method not found (this should never happen)") 163 | } 164 | #[doc = "Calls the contract's `name` (0x06fdde03) function"] 165 | pub fn name(&self) -> ContractCall { 166 | self.0 167 | .method_hash([6, 253, 222, 3], ()) 168 | .expect("method not found (this should never happen)") 169 | } 170 | #[doc = "Calls the contract's `transferFrom` (0x23b872dd) function"] 171 | pub fn transfer_from( 172 | &self, 173 | from: Address, 174 | to: Address, 175 | value: U256, 176 | ) -> ContractCall { 177 | self.0 178 | .method_hash([35, 184, 114, 221], (from, to, value)) 179 | .expect("method not found (this should never happen)") 180 | } 181 | #[doc = "Calls the contract's `balanceOf` (0x70a08231) function"] 182 | pub fn balance_of(&self, p0: Address) -> ContractCall { 183 | self.0 184 | .method_hash([112, 160, 130, 49], p0) 185 | .expect("method not found (this should never happen)") 186 | } 187 | #[doc = "Calls the contract's `price0CumulativeLast` (0x5909c0d5) function"] 188 | pub fn price_0_cumulative_last(&self) -> ContractCall { 189 | self.0 190 | .method_hash([89, 9, 192, 213], ()) 191 | .expect("method not found (this should never happen)") 192 | } 193 | #[doc = "Calls the contract's `transfer` (0xa9059cbb) function"] 194 | pub fn transfer(&self, to: Address, value: U256) -> ContractCall { 195 | self.0 196 | .method_hash([169, 5, 156, 187], (to, value)) 197 | .expect("method not found (this should never happen)") 198 | } 199 | #[doc = "Calls the contract's `token0` (0x0dfe1681) function"] 200 | pub fn token_0(&self) -> ContractCall { 201 | self.0 202 | .method_hash([13, 254, 22, 129], ()) 203 | .expect("method not found (this should never happen)") 204 | } 205 | #[doc = "Calls the contract's `swap` (0x022c0d9f) function"] 206 | pub fn swap( 207 | &self, 208 | amount_0_out: U256, 209 | amount_1_out: U256, 210 | to: Address, 211 | data: Vec, 212 | ) -> ContractCall { 213 | self.0 214 | .method_hash([2, 44, 13, 159], (amount_0_out, amount_1_out, to, data)) 215 | .expect("method not found (this should never happen)") 216 | } 217 | #[doc = "Calls the contract's `DOMAIN_SEPARATOR` (0x3644e515) function"] 218 | pub fn domain_separator(&self) -> ContractCall { 219 | self.0 220 | .method_hash([54, 68, 229, 21], ()) 221 | .expect("method not found (this should never happen)") 222 | } 223 | #[doc = "Calls the contract's `approve` (0x095ea7b3) function"] 224 | pub fn approve(&self, spender: Address, value: U256) -> ContractCall { 225 | self.0 226 | .method_hash([9, 94, 167, 179], (spender, value)) 227 | .expect("method not found (this should never happen)") 228 | } 229 | #[doc = "Gets the contract's `Sync` event"] 230 | pub fn sync_filter(&self) -> Event { 231 | self.0 232 | .event("Sync") 233 | .expect("event not found (this should never happen)") 234 | } 235 | #[doc = "Gets the contract's `Transfer` event"] 236 | pub fn transfer_filter(&self) -> Event { 237 | self.0 238 | .event("Transfer") 239 | .expect("event not found (this should never happen)") 240 | } 241 | #[doc = "Gets the contract's `Burn` event"] 242 | pub fn burn_filter(&self) -> Event { 243 | self.0 244 | .event("Burn") 245 | .expect("event not found (this should never happen)") 246 | } 247 | #[doc = "Gets the contract's `Swap` event"] 248 | pub fn swap_filter(&self) -> Event { 249 | self.0 250 | .event("Swap") 251 | .expect("event not found (this should never happen)") 252 | } 253 | #[doc = "Gets the contract's `Approval` event"] 254 | pub fn approval_filter(&self) -> Event { 255 | self.0 256 | .event("Approval") 257 | .expect("event not found (this should never happen)") 258 | } 259 | #[doc = "Gets the contract's `Mint` event"] 260 | pub fn mint_filter(&self) -> Event { 261 | self.0 262 | .event("Mint") 263 | .expect("event not found (this should never happen)") 264 | } 265 | } 266 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 267 | pub struct SyncFilter { 268 | pub reserve_0: u128, 269 | pub reserve_1: u128, 270 | } 271 | impl SyncFilter { 272 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 273 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 274 | #[doc = r" this event."] 275 | pub const fn signature() -> H256 { 276 | H256([ 277 | 28, 65, 30, 154, 150, 224, 113, 36, 28, 47, 33, 247, 114, 107, 23, 174, 137, 227, 278 | 202, 180, 199, 139, 229, 14, 6, 43, 3, 169, 255, 251, 186, 209, 279 | ]) 280 | } 281 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 282 | #[doc = r" to. For this event the value should always be:"] 283 | #[doc = r""] 284 | #[doc = "`Sync(uint112,uint112)`"] 285 | pub const fn abi_signature() -> &'static str { 286 | "Sync(uint112,uint112)" 287 | } 288 | } 289 | impl Detokenize for SyncFilter { 290 | fn from_tokens(tokens: Vec) -> Result { 291 | if tokens.len() != 2 { 292 | return Err(InvalidOutputType(format!( 293 | "Expected {} tokens, got {}: {:?}", 294 | 2, 295 | tokens.len(), 296 | tokens 297 | ))); 298 | } 299 | #[allow(unused_mut)] 300 | let mut tokens = tokens.into_iter(); 301 | let reserve_0 = 302 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 303 | let reserve_1 = 304 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 305 | Ok(SyncFilter { 306 | reserve_0, 307 | reserve_1, 308 | }) 309 | } 310 | } 311 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 312 | pub struct TransferFilter { 313 | pub from: Address, 314 | pub to: Address, 315 | pub value: U256, 316 | } 317 | impl TransferFilter { 318 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 319 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 320 | #[doc = r" this event."] 321 | pub const fn signature() -> H256 { 322 | H256([ 323 | 221, 242, 82, 173, 27, 226, 200, 155, 105, 194, 176, 104, 252, 55, 141, 170, 149, 324 | 43, 167, 241, 99, 196, 161, 22, 40, 245, 90, 77, 245, 35, 179, 239, 325 | ]) 326 | } 327 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 328 | #[doc = r" to. For this event the value should always be:"] 329 | #[doc = r""] 330 | #[doc = "`Transfer(address,address,uint256)`"] 331 | pub const fn abi_signature() -> &'static str { 332 | "Transfer(address,address,uint256)" 333 | } 334 | } 335 | impl Detokenize for TransferFilter { 336 | fn from_tokens(tokens: Vec) -> Result { 337 | if tokens.len() != 3 { 338 | return Err(InvalidOutputType(format!( 339 | "Expected {} tokens, got {}: {:?}", 340 | 3, 341 | tokens.len(), 342 | tokens 343 | ))); 344 | } 345 | #[allow(unused_mut)] 346 | let mut tokens = tokens.into_iter(); 347 | let from = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 348 | let to = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 349 | let value = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 350 | Ok(TransferFilter { from, to, value }) 351 | } 352 | } 353 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 354 | pub struct BurnFilter { 355 | pub sender: Address, 356 | pub amount_0: U256, 357 | pub amount_1: U256, 358 | pub to: Address, 359 | } 360 | impl BurnFilter { 361 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 362 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 363 | #[doc = r" this event."] 364 | pub const fn signature() -> H256 { 365 | H256([ 366 | 220, 205, 65, 47, 11, 18, 82, 129, 156, 177, 253, 51, 11, 147, 34, 76, 164, 38, 18, 367 | 137, 43, 179, 244, 247, 137, 151, 110, 109, 129, 147, 100, 150, 368 | ]) 369 | } 370 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 371 | #[doc = r" to. For this event the value should always be:"] 372 | #[doc = r""] 373 | #[doc = "`Burn(address,uint256,uint256,address)`"] 374 | pub const fn abi_signature() -> &'static str { 375 | "Burn(address,uint256,uint256,address)" 376 | } 377 | } 378 | impl Detokenize for BurnFilter { 379 | fn from_tokens(tokens: Vec) -> Result { 380 | if tokens.len() != 4 { 381 | return Err(InvalidOutputType(format!( 382 | "Expected {} tokens, got {}: {:?}", 383 | 4, 384 | tokens.len(), 385 | tokens 386 | ))); 387 | } 388 | #[allow(unused_mut)] 389 | let mut tokens = tokens.into_iter(); 390 | let sender = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 391 | let amount_0 = 392 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 393 | let amount_1 = 394 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 395 | let to = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 396 | Ok(BurnFilter { 397 | sender, 398 | amount_0, 399 | amount_1, 400 | to, 401 | }) 402 | } 403 | } 404 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 405 | pub struct SwapFilter { 406 | pub sender: Address, 407 | pub amount_0_in: U256, 408 | pub amount_1_in: U256, 409 | pub amount_0_out: U256, 410 | pub amount_1_out: U256, 411 | pub to: Address, 412 | } 413 | impl SwapFilter { 414 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 415 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 416 | #[doc = r" this event."] 417 | pub const fn signature() -> H256 { 418 | H256([ 419 | 215, 138, 217, 95, 164, 108, 153, 75, 101, 81, 208, 218, 133, 252, 39, 95, 230, 19, 420 | 206, 55, 101, 127, 184, 213, 227, 209, 48, 132, 1, 89, 216, 34, 421 | ]) 422 | } 423 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 424 | #[doc = r" to. For this event the value should always be:"] 425 | #[doc = r""] 426 | #[doc = "`Swap(address,uint256,uint256,uint256,uint256,address)`"] 427 | pub const fn abi_signature() -> &'static str { 428 | "Swap(address,uint256,uint256,uint256,uint256,address)" 429 | } 430 | } 431 | impl Detokenize for SwapFilter { 432 | fn from_tokens(tokens: Vec) -> Result { 433 | if tokens.len() != 6 { 434 | return Err(InvalidOutputType(format!( 435 | "Expected {} tokens, got {}: {:?}", 436 | 6, 437 | tokens.len(), 438 | tokens 439 | ))); 440 | } 441 | #[allow(unused_mut)] 442 | let mut tokens = tokens.into_iter(); 443 | let sender = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 444 | let amount_0_in = 445 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 446 | let amount_1_in = 447 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 448 | let amount_0_out = 449 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 450 | let amount_1_out = 451 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 452 | let to = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 453 | Ok(SwapFilter { 454 | sender, 455 | amount_0_in, 456 | amount_1_in, 457 | amount_0_out, 458 | amount_1_out, 459 | to, 460 | }) 461 | } 462 | } 463 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 464 | pub struct ApprovalFilter { 465 | pub owner: Address, 466 | pub spender: Address, 467 | pub value: U256, 468 | } 469 | impl ApprovalFilter { 470 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 471 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 472 | #[doc = r" this event."] 473 | pub const fn signature() -> H256 { 474 | H256([ 475 | 140, 91, 225, 229, 235, 236, 125, 91, 209, 79, 113, 66, 125, 30, 132, 243, 221, 3, 476 | 20, 192, 247, 178, 41, 30, 91, 32, 10, 200, 199, 195, 185, 37, 477 | ]) 478 | } 479 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 480 | #[doc = r" to. For this event the value should always be:"] 481 | #[doc = r""] 482 | #[doc = "`Approval(address,address,uint256)`"] 483 | pub const fn abi_signature() -> &'static str { 484 | "Approval(address,address,uint256)" 485 | } 486 | } 487 | impl Detokenize for ApprovalFilter { 488 | fn from_tokens(tokens: Vec) -> Result { 489 | if tokens.len() != 3 { 490 | return Err(InvalidOutputType(format!( 491 | "Expected {} tokens, got {}: {:?}", 492 | 3, 493 | tokens.len(), 494 | tokens 495 | ))); 496 | } 497 | #[allow(unused_mut)] 498 | let mut tokens = tokens.into_iter(); 499 | let owner = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 500 | let spender = 501 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 502 | let value = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 503 | Ok(ApprovalFilter { 504 | owner, 505 | spender, 506 | value, 507 | }) 508 | } 509 | } 510 | #[derive(Clone, Debug, Default, Eq, PartialEq)] 511 | pub struct MintFilter { 512 | pub sender: Address, 513 | pub amount_0: U256, 514 | pub amount_1: U256, 515 | } 516 | impl MintFilter { 517 | #[doc = r" Retrieves the signature for the event this data corresponds to."] 518 | #[doc = r" This signature is the Keccak-256 hash of the ABI signature of"] 519 | #[doc = r" this event."] 520 | pub const fn signature() -> H256 { 521 | H256([ 522 | 76, 32, 155, 95, 200, 173, 80, 117, 143, 19, 226, 225, 8, 139, 165, 106, 86, 13, 523 | 255, 105, 10, 28, 111, 239, 38, 57, 79, 76, 3, 130, 28, 79, 524 | ]) 525 | } 526 | #[doc = r" Retrieves the ABI signature for the event this data corresponds"] 527 | #[doc = r" to. For this event the value should always be:"] 528 | #[doc = r""] 529 | #[doc = "`Mint(address,uint256,uint256)`"] 530 | pub const fn abi_signature() -> &'static str { 531 | "Mint(address,uint256,uint256)" 532 | } 533 | } 534 | impl Detokenize for MintFilter { 535 | fn from_tokens(tokens: Vec) -> Result { 536 | if tokens.len() != 3 { 537 | return Err(InvalidOutputType(format!( 538 | "Expected {} tokens, got {}: {:?}", 539 | 3, 540 | tokens.len(), 541 | tokens 542 | ))); 543 | } 544 | #[allow(unused_mut)] 545 | let mut tokens = tokens.into_iter(); 546 | let sender = Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 547 | let amount_0 = 548 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 549 | let amount_1 = 550 | Tokenizable::from_token(tokens.next().expect("this should never happen"))?; 551 | Ok(MintFilter { 552 | sender, 553 | amount_0, 554 | amount_1, 555 | }) 556 | } 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /src/borrowers.rs: -------------------------------------------------------------------------------- 1 | //! Borrowers / Users 2 | //! 3 | //! This module is responsible for keeping track of the users that have open 4 | //! positions and observing their debt healthiness. 5 | use crate::{bindings::Controller, Result, WETH}; 6 | 7 | use ethers::prelude::*; 8 | use serde::{Deserialize, Serialize}; 9 | use std::{collections::HashMap, sync::Arc}; 10 | use tracing::{debug, debug_span}; 11 | 12 | #[derive(Clone)] 13 | pub struct Borrowers { 14 | /// The controller smart contract 15 | pub controller: Controller, 16 | 17 | /// Mapping of the addresses that have taken loans from the system and might 18 | /// be susceptible to liquidations 19 | pub borrowers: HashMap, 20 | 21 | /// We use multicall to batch together calls and have reduced stress on 22 | /// our RPC endpoint 23 | multicall: Multicall, 24 | } 25 | 26 | #[derive(Clone, Debug, Default, Serialize, Deserialize)] 27 | /// A user's details 28 | pub struct Borrower { 29 | /// Is the position collateralized? Produced by calling `isCollateralized` 30 | /// on the controller 31 | pub is_collateralized: bool, 32 | 33 | /// The user's currently posted ETH collateral. Produced by calling `posted` 34 | /// on the controller 35 | pub posted_collateral: U256, 36 | 37 | /// The user's total DAI debt. Produced by calling `totalDebtDai` 38 | /// on the controller 39 | pub debt: U256, 40 | 41 | /// The maximum YDAI amount a user can borrow. Produced by calling `powerOf` 42 | /// on the controller 43 | pub max_borrowing_power: U256, 44 | } 45 | 46 | impl Borrowers { 47 | /// Constructor 48 | pub async fn new( 49 | controller: Address, 50 | multicall: Option
, 51 | client: Arc, 52 | borrowers: HashMap, 53 | ) -> Self { 54 | let multicall = Multicall::new(client.clone(), multicall) 55 | .await 56 | .expect("could not initialize multicall"); 57 | Borrowers { 58 | controller: Controller::new(controller, client), 59 | borrowers, 60 | multicall, 61 | } 62 | } 63 | 64 | /// Gets any new borrowers which may have joined the system since we last 65 | /// made this call and then proceeds to get the latest account details for 66 | /// each user 67 | pub async fn update_borrowers(&mut self, from_block: U64, to_block: U64) -> Result<(), M> { 68 | let span = debug_span!("monitoring"); 69 | let _enter = span.enter(); 70 | 71 | // get the new users 72 | // TODO: Improve this logic to be more optimized 73 | let new_users = self 74 | .controller 75 | .borrowed_filter() 76 | .from_block(from_block) 77 | .to_block(to_block) 78 | .query() 79 | .await? 80 | .into_iter() 81 | .map(|log| log.user) 82 | .collect::>(); 83 | 84 | let all_users = crate::merge(new_users, &self.borrowers); 85 | 86 | // update all the accounts' details 87 | for user in all_users { 88 | let details = self.get_borrower(user).await?; 89 | if self.borrowers.insert(user, details.clone()).is_none() { 90 | debug!(new_borrower = ?user, collateral_eth = %details.posted_collateral, debt_dai = %details.debt); 91 | } 92 | } 93 | 94 | Ok(()) 95 | } 96 | 97 | /// Updates the user's details by calling: 98 | /// 1. powerOf 99 | /// 2. isCollateralized 100 | /// 3. posted 101 | /// 4. totalDebtDai 102 | pub async fn get_borrower(&mut self, user: Address) -> Result { 103 | let power = self.controller.power_of(WETH, user); 104 | let is_collateralized = self.controller.is_collateralized(WETH, user); 105 | let posted_collateral = self.controller.posted(WETH, user); 106 | let debt = self.controller.total_debt_dai(WETH, user); 107 | 108 | // batch the calls together 109 | let multicall = self 110 | .multicall 111 | .clear_calls() 112 | .add_call(is_collateralized) 113 | .add_call(posted_collateral) 114 | .add_call(debt) 115 | .add_call(power); 116 | let (is_collateralized, posted_collateral, debt, max_borrowing_power) = 117 | multicall.call().await?; 118 | 119 | Ok(Borrower { 120 | is_collateralized, 121 | posted_collateral, 122 | debt, 123 | max_borrowing_power, 124 | }) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/escalator.rs: -------------------------------------------------------------------------------- 1 | use ethers::types::U256; 2 | 3 | /// Geometrically increasing gas price. 4 | /// 5 | /// Start with `initial_price`, then increase it every 'every_secs' seconds by a fixed coefficient. 6 | /// Coefficient defaults to 1.125 (12.5%), the minimum increase for Parity to replace a transaction. 7 | /// Coefficient can be adjusted, and there is an optional upper limit. 8 | /// https://github.com/makerdao/pymaker/blob/master/pymaker/gas.py#L168 9 | #[derive(Clone, Debug)] 10 | pub struct GeometricGasPrice { 11 | pub every_secs: u64, 12 | pub coefficient: f64, 13 | pub max_price: Option, 14 | } 15 | 16 | impl GeometricGasPrice { 17 | pub fn new() -> Self { 18 | GeometricGasPrice { 19 | every_secs: 30, 20 | coefficient: 1.125, 21 | max_price: None, 22 | } 23 | } 24 | 25 | pub fn get_gas_price(&self, initial_price: U256, time_elapsed: u64) -> U256 { 26 | let mut result = initial_price.as_u64() as f64; 27 | 28 | if time_elapsed >= self.every_secs { 29 | let iters = time_elapsed / self.every_secs; 30 | for _ in 0..iters { 31 | result *= self.coefficient; 32 | } 33 | } 34 | 35 | let mut result = U256::from(result.ceil() as u64); 36 | if let Some(max_price) = self.max_price { 37 | result = std::cmp::min(result, max_price); 38 | } 39 | result 40 | } 41 | } 42 | 43 | #[cfg(test)] 44 | // https://github.com/makerdao/pymaker/blob/master/tests/test_gas.py#L165 45 | mod tests { 46 | use super::*; 47 | 48 | #[test] 49 | fn gas_price_increases_with_time() { 50 | let mut oracle = GeometricGasPrice::new(); 51 | oracle.every_secs = 10; 52 | let initial_price = U256::from(100); 53 | 54 | assert_eq!(oracle.get_gas_price(initial_price, 0), 100.into()); 55 | assert_eq!(oracle.get_gas_price(initial_price, 1), 100.into()); 56 | assert_eq!(oracle.get_gas_price(initial_price, 10), 113.into()); 57 | assert_eq!(oracle.get_gas_price(initial_price, 15), 113.into()); 58 | assert_eq!(oracle.get_gas_price(initial_price, 20), 127.into()); 59 | assert_eq!(oracle.get_gas_price(initial_price, 30), 143.into()); 60 | assert_eq!(oracle.get_gas_price(initial_price, 50), 181.into()); 61 | assert_eq!(oracle.get_gas_price(initial_price, 100), 325.into()); 62 | } 63 | 64 | #[test] 65 | fn gas_price_should_obey_max_value() { 66 | let mut oracle = GeometricGasPrice::new(); 67 | oracle.every_secs = 60; 68 | oracle.max_price = Some(2500.into()); 69 | let initial_price = U256::from(1000); 70 | 71 | assert_eq!(oracle.get_gas_price(initial_price, 0), 1000.into()); 72 | assert_eq!(oracle.get_gas_price(initial_price, 1), 1000.into()); 73 | assert_eq!(oracle.get_gas_price(initial_price, 59), 1000.into()); 74 | assert_eq!(oracle.get_gas_price(initial_price, 60), 1125.into()); 75 | assert_eq!(oracle.get_gas_price(initial_price, 119), 1125.into()); 76 | assert_eq!(oracle.get_gas_price(initial_price, 120), 1266.into()); 77 | assert_eq!(oracle.get_gas_price(initial_price, 1200), 2500.into()); 78 | assert_eq!(oracle.get_gas_price(initial_price, 3000), 2500.into()); 79 | assert_eq!(oracle.get_gas_price(initial_price, 1000000), 2500.into()); 80 | } 81 | 82 | #[test] 83 | fn behaves_with_realistic_values() { 84 | let mut oracle = GeometricGasPrice::new(); 85 | oracle.every_secs = 10; 86 | oracle.coefficient = 1.25; 87 | const GWEI: f64 = 1000000000.0; 88 | let initial_price = U256::from(100 * GWEI as u64); 89 | 90 | for seconds in &[0u64, 1, 10, 12, 30, 60] { 91 | println!( 92 | "gas price after {} seconds is {}", 93 | seconds, 94 | oracle.get_gas_price(initial_price, *seconds).as_u64() as f64 / GWEI 95 | ); 96 | } 97 | 98 | let normalized = |time| oracle.get_gas_price(initial_price, time).as_u64() as f64 / GWEI; 99 | 100 | assert_eq!(normalized(0), 100.0); 101 | assert_eq!(normalized(1), 100.0); 102 | assert_eq!(normalized(10), 125.0); 103 | assert_eq!(normalized(12), 125.0); 104 | assert_eq!(normalized(30), 195.3125); 105 | assert_eq!(normalized(60), 381.469726563); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/keeper.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | borrowers::{Borrower, Borrowers}, 3 | escalator::GeometricGasPrice, 4 | liquidations::{Auction, Liquidator}, 5 | Result, 6 | }; 7 | 8 | use ethers::prelude::*; 9 | use serde::{Deserialize, Serialize}; 10 | use std::{collections::HashMap, io::Write, path::PathBuf, sync::Arc}; 11 | use tracing::debug_span; 12 | 13 | #[derive(Serialize, Deserialize, Default)] 14 | /// The state which is stored in our logs 15 | pub struct State { 16 | /// The auctions being monitored 17 | auctions: HashMap, 18 | /// The borrowers being monitored 19 | borrowers: HashMap, 20 | /// The last observed block 21 | last_block: u64, 22 | } 23 | 24 | /// The keeper monitors the chain for both liquidation opportunities and for 25 | /// participation in auctions using Uniswap as a liquidity source 26 | pub struct Keeper { 27 | client: Arc, 28 | last_block: U64, 29 | 30 | borrowers: Borrowers, 31 | liquidator: Liquidator, 32 | } 33 | 34 | impl Keeper { 35 | /// Instantiates the keeper. `state` should be passed if there is previous 36 | /// data which should be taken into account from a previous run 37 | pub async fn new( 38 | client: Arc, 39 | controller: Address, 40 | liquidations: Address, 41 | uniswap: Address, 42 | flashloan: Address, 43 | multicall: Option
, 44 | min_profit: U256, 45 | gas_escalator: GeometricGasPrice, 46 | state: Option, 47 | ) -> Result, M> { 48 | let (borrowers, vaults, last_block) = match state { 49 | Some(state) => (state.borrowers, state.auctions, state.last_block.into()), 50 | None => (HashMap::new(), HashMap::new(), 0.into()), 51 | }; 52 | 53 | let borrowers = Borrowers::new(controller, multicall, client.clone(), borrowers).await; 54 | let liquidator = Liquidator::new( 55 | liquidations, 56 | uniswap, 57 | flashloan, 58 | multicall, 59 | min_profit, 60 | client.clone(), 61 | vaults, 62 | gas_escalator, 63 | ) 64 | .await; 65 | 66 | Ok(Self { 67 | client, 68 | borrowers, 69 | liquidator, 70 | last_block, 71 | }) 72 | } 73 | 74 | pub async fn run(&mut self, fname: PathBuf, start_block: Option) -> Result<(), M> { 75 | // Create the initial list of borrowers from the start_block, if provided 76 | if let Some(start_block) = start_block { 77 | self.last_block = start_block.into(); 78 | } 79 | 80 | let watcher = self.client.clone(); 81 | let mut on_block = watcher 82 | .watch_blocks() 83 | .await 84 | .map_err(ContractError::MiddlewareError)? 85 | .stream(); 86 | 87 | let mut file: Option = None; 88 | while on_block.next().await.is_some() { 89 | let block_number = self 90 | .client 91 | .get_block_number() 92 | .await 93 | .map_err(ContractError::MiddlewareError)?; 94 | 95 | if block_number % 10 == 0.into() { 96 | // on each new block we open a new file handler to dump our state. 97 | // we should just have a database connection instead here... 98 | file = Some( 99 | std::fs::OpenOptions::new() 100 | .read(true) 101 | .write(true) 102 | .create(true) 103 | .open(&fname) 104 | .unwrap(), 105 | ); 106 | } 107 | 108 | let span = debug_span!("eloop", block = %block_number); 109 | let _enter = span.enter(); 110 | 111 | // run the logic for this block 112 | self.on_block(block_number).await?; 113 | 114 | // update our last block 115 | self.last_block = block_number; 116 | 117 | // Log once every 10 blocks 118 | if let Some(file) = file.take() { 119 | self.log(file); 120 | } 121 | } 122 | 123 | Ok(()) 124 | } 125 | 126 | /// Runs the liquidation business logic for the specified block 127 | async fn on_block(&mut self, block_number: U64) -> Result<(), M> { 128 | // Get the gas price - TODO: Replace with gas price oracle 129 | let gas_price = self 130 | .client 131 | .get_gas_price() 132 | .await 133 | .map_err(ContractError::MiddlewareError)?; 134 | 135 | // 1. Check if our transactions have been mined 136 | self.liquidator.remove_or_bump().await?; 137 | 138 | // 2. update our dataset with the new block's data 139 | self.borrowers 140 | .update_borrowers(self.last_block, block_number) 141 | .await?; 142 | 143 | // 3. trigger the auction for any undercollateralized borrowers 144 | self.liquidator 145 | .trigger_liquidations(self.borrowers.borrowers.iter(), gas_price) 146 | .await?; 147 | 148 | // 4. try buying the ones which are worth buying 149 | self.liquidator 150 | .buy_opportunities(self.last_block, block_number, gas_price) 151 | .await?; 152 | 153 | Ok(()) 154 | } 155 | 156 | fn log(&self, w: W) { 157 | serde_json::to_writer( 158 | w, 159 | &State { 160 | auctions: self.liquidator.auctions.clone(), 161 | borrowers: self.borrowers.borrowers.clone(), 162 | last_block: self.last_block.as_u64(), 163 | }, 164 | ) 165 | .unwrap(); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bindings; 2 | pub mod borrowers; 3 | pub mod escalator; 4 | pub mod keeper; 5 | pub mod liquidations; 6 | 7 | use ethers::prelude::*; 8 | use std::collections::HashMap; 9 | 10 | /// "ETH-A" collateral type in hex, right padded to 32 bytes 11 | pub const WETH: [u8; 32] = [ 12 | 0x45, 0x54, 0x48, 0x2d, 0x41, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 13 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 14 | ]; 15 | 16 | // merge & deduplicate the 2 data structs 17 | pub fn merge(a: Vec
, b: &HashMap) -> Vec
{ 18 | let keys = b.keys().cloned().collect::>(); 19 | let mut all = [a, keys].concat(); 20 | all.sort_unstable(); 21 | all.dedup(); 22 | all 23 | } 24 | 25 | pub type Result = std::result::Result>; 26 | -------------------------------------------------------------------------------- /src/liquidations.rs: -------------------------------------------------------------------------------- 1 | //! Auctions Module 2 | //! 3 | //! This module is responsible for triggering and participating in a Auction's 4 | //! dutch auction 5 | use crate::{ 6 | bindings::{Liquidations, UniswapV2Pair as Uniswap}, 7 | borrowers::Borrower, 8 | escalator::GeometricGasPrice, 9 | merge, Result, 10 | }; 11 | 12 | use ethers::{ 13 | core::abi::{self, Tokenize}, 14 | prelude::*, 15 | }; 16 | use serde::{Deserialize, Serialize}; 17 | use std::{collections::HashMap, fmt, sync::Arc, time::Instant}; 18 | use tracing::{debug, debug_span, error, info, trace}; 19 | 20 | #[derive(Clone)] 21 | pub struct Liquidator { 22 | liquidations: Liquidations, 23 | uniswap: Uniswap, 24 | flashloan: Address, 25 | 26 | /// The currently active auctions 27 | pub auctions: HashMap, 28 | 29 | /// We use multicall to batch together calls and have reduced stress on 30 | /// our RPC endpoint 31 | multicall: Multicall, 32 | 33 | /// The minimum profit to be extracted per liquidation 34 | min_profit: U256, 35 | 36 | pending_liquidations: HashMap, 37 | pending_auctions: HashMap, 38 | gas_escalator: GeometricGasPrice, 39 | } 40 | 41 | /// Tx / Hash/ Submitted at time 42 | type PendingTransaction = (TransactionRequest, TxHash, Instant); 43 | 44 | /// An initiated auction 45 | #[derive(Clone, Debug, Default, Serialize, Deserialize)] 46 | pub struct Auction { 47 | /// The start time of the auction 48 | started: U256, 49 | /// The debt which can be repaid 50 | debt: u128, 51 | /// The collateral which can be seized 52 | collateral: u128, 53 | } 54 | 55 | #[derive(Clone, Debug, Serialize, Deserialize)] 56 | enum TxType { 57 | Auction, 58 | Liquidation, 59 | } 60 | 61 | impl fmt::Display for TxType { 62 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 63 | let string = match self { 64 | TxType::Auction => "auction", 65 | TxType::Liquidation => "liquidation", 66 | }; 67 | write!(f, "{}", string) 68 | } 69 | } 70 | 71 | impl Liquidator { 72 | /// Constructor 73 | pub async fn new( 74 | liquidations: Address, 75 | uniswap: Address, 76 | flashloan: Address, 77 | multicall: Option
, 78 | min_profit: U256, 79 | client: Arc, 80 | auctions: HashMap, 81 | gas_escalator: GeometricGasPrice, 82 | ) -> Self { 83 | let multicall = Multicall::new(client.clone(), multicall) 84 | .await 85 | .expect("could not initialize multicall"); 86 | 87 | Self { 88 | liquidations: Liquidations::new(liquidations, client.clone()), 89 | uniswap: Uniswap::new(uniswap, client.clone()), 90 | flashloan, 91 | multicall, 92 | min_profit, 93 | auctions, 94 | 95 | pending_liquidations: HashMap::new(), 96 | pending_auctions: HashMap::new(), 97 | gas_escalator, 98 | } 99 | } 100 | 101 | /// Checks if any transactions which have been submitted are mined, removes 102 | /// them if they were successful, otherwise bumps their gas price 103 | pub async fn remove_or_bump(&mut self) -> Result<(), M> { 104 | let now = Instant::now(); 105 | 106 | // Check all the pending liquidations 107 | self.remove_or_bump_inner(now, TxType::Liquidation).await?; 108 | 109 | // Check all the pending auctions 110 | self.remove_or_bump_inner(now, TxType::Auction).await?; 111 | 112 | Ok(()) 113 | } 114 | 115 | async fn remove_or_bump_inner(&mut self, now: Instant, tx_type: TxType) -> Result<(), M> { 116 | let client = self.liquidations.client(); 117 | 118 | let pending_txs = match tx_type { 119 | TxType::Liquidation => &mut self.pending_liquidations, 120 | TxType::Auction => &mut self.pending_auctions, 121 | }; 122 | 123 | for (addr, pending_tx) in pending_txs.clone().into_iter() { 124 | debug_assert!( 125 | pending_tx.0.gas_price.is_some(), 126 | "gas price must be set in pending txs" 127 | ); 128 | 129 | // get the receipt and check inclusion, or bump its gas price 130 | let receipt = client 131 | .get_transaction_receipt(pending_tx.1) 132 | .await 133 | .map_err(ContractError::MiddlewareError)?; 134 | if let Some(receipt) = receipt { 135 | pending_txs.remove(&addr); 136 | let status = if receipt.status == Some(1.into()) { 137 | "success" 138 | } else { 139 | "fail" 140 | }; 141 | trace!(tx_hash = ?pending_tx.1, gas_used = %receipt.gas_used.unwrap_or_default(), user = ?addr, status = status, tx_type = %tx_type, "confirmed"); 142 | } else { 143 | // Get the new gas price based on how much time passed since the 144 | // tx was last broadcast 145 | let new_gas_price = self.gas_escalator.get_gas_price( 146 | pending_tx.0.gas_price.expect("gas price must be set"), 147 | now.duration_since(pending_tx.2).as_secs(), 148 | ); 149 | 150 | let replacement_tx = pending_txs 151 | .get_mut(&addr) 152 | .expect("tx will always be found since we're iterating over the map"); 153 | 154 | // bump the gas price 155 | replacement_tx.0.gas_price = Some(new_gas_price); 156 | 157 | // rebroadcast (TODO: Can we avoid cloning?) 158 | replacement_tx.1 = *client 159 | .send_transaction(replacement_tx.0.clone(), None) 160 | .await 161 | .map_err(ContractError::MiddlewareError)?; 162 | 163 | trace!(tx_hash = ?pending_tx.1, new_gas_price = %new_gas_price, user = ?addr, tx_type = %tx_type, "replaced"); 164 | } 165 | } 166 | 167 | Ok(()) 168 | } 169 | 170 | /// Sends a bid for any of the liquidation auctions. 171 | pub async fn buy_opportunities( 172 | &mut self, 173 | from_block: U64, 174 | to_block: U64, 175 | gas_price: U256, 176 | ) -> Result<(), M> { 177 | let all_users = { 178 | let liquidations = self 179 | .liquidations 180 | .liquidation_filter() 181 | .from_block(from_block) 182 | .to_block(to_block) 183 | .query() 184 | .await?; 185 | let new_users = liquidations.iter().map(|log| log.user).collect::>(); 186 | merge(new_users, &self.auctions) 187 | }; 188 | 189 | for user in all_users { 190 | self.buy(user, Instant::now(), gas_price).await?; 191 | } 192 | 193 | Ok(()) 194 | } 195 | 196 | /// Tries to buy the collateral associated with a user's liquidation auction 197 | /// via a flashloan funded by Uniswap's DAI/WETH pair. 198 | async fn buy(&mut self, user: Address, now: Instant, gas_price: U256) -> Result<(), M> { 199 | // only iterate over users that do not have active auctions 200 | if let Some(pending_tx) = self.pending_auctions.get(&user) { 201 | trace!(tx_hash = ?pending_tx.1, user = ?user, "bid not confirmed yet"); 202 | return Ok(()); 203 | } 204 | 205 | // Get the vault's info 206 | let vault = self.get_vault(user).await?; 207 | // Skip auctions which do not have any outstanding debt 208 | if vault.debt == 0 { 209 | return Ok(()); 210 | } 211 | 212 | if self.auctions.insert(user, vault.clone()).is_none() { 213 | debug!(user = ?user, vault = ?vault, "new auction"); 214 | } 215 | let span = debug_span!("buying", user = ?user, auction_start = %vault.started, auction_end = %(vault.started + 3600), debt = %vault.debt); 216 | let _enter = span.enter(); 217 | 218 | // Craft the flashloan contract's arguments 219 | let args = abi::encode(&(user, self.min_profit).into_tokens()); 220 | 221 | // Calls Uniswap's `swap` function which will optimistically let us 222 | // borrow the debt, which will then make a callback to the flashloan 223 | // contract which will execute the liquidation 224 | let call = self 225 | .uniswap 226 | .swap(vault.debt.into(), 0.into(), self.flashloan, args) 227 | .gas_price(gas_price) 228 | .block(BlockNumber::Pending); 229 | 230 | let tx = call.tx.clone(); 231 | 232 | match call.send().await { 233 | Ok(hash) => { 234 | // record the tx 235 | trace!(tx_hash = ?hash, "Submitted buy order"); 236 | self.pending_auctions 237 | .entry(user) 238 | .or_insert((tx, *hash, now)); 239 | } 240 | Err(err) => { 241 | let err = err.to_string(); 242 | if err.contains("NOT_ENOUGH_PROFIT") { 243 | let price = self.liquidations.price(user).call().await?; 244 | debug!(price = %price, "Auction not yet profitable via Uniswap flash swaps."); 245 | } else if err.contains("Below dust") { 246 | debug!("Proceeds are below the dust limit, ignoring.."); 247 | } else { 248 | error!("Error: {}", err); 249 | } 250 | } 251 | }; 252 | 253 | Ok(()) 254 | } 255 | 256 | /// Triggers liquidations for any vulnerable positions which were fetched from the 257 | /// controller 258 | pub async fn trigger_liquidations( 259 | &mut self, 260 | borrowers: impl Iterator, 261 | gas_price: U256, 262 | ) -> Result<(), M> { 263 | debug!("checking for undercollateralized positions..."); 264 | 265 | let now = Instant::now(); 266 | 267 | for (user, details) in borrowers { 268 | // only iterate over users that do not have pending liquidations 269 | if let Some(pending_tx) = self.pending_liquidations.get(&user) { 270 | trace!(tx_hash = ?pending_tx.1, user = ?user, "liquidation not confirmed yet"); 271 | continue; 272 | } 273 | 274 | if !details.is_collateralized { 275 | info!( 276 | user = ?user, 277 | debt_dai = %details.debt, 278 | max_debt_dai = %details.max_borrowing_power, 279 | "found undercollateralized user. triggering liquidation", 280 | ); 281 | 282 | // Send the tx and track it 283 | let call = self.liquidations.liquidate(*user).gas_price(gas_price); 284 | let tx = call.tx.clone(); 285 | let tx_hash = call.send().await?; 286 | trace!(tx_hash = ?tx_hash, user = ?user, "Submitted liquidation"); 287 | self.pending_liquidations 288 | .entry(*user) 289 | .or_insert((tx, *tx_hash, now)); 290 | } 291 | } 292 | 293 | Ok(()) 294 | } 295 | 296 | async fn get_vault(&mut self, user: Address) -> Result { 297 | let vault = self.liquidations.vaults(user); 298 | let timestamp = self.liquidations.liquidations(user); 299 | 300 | let multicall = self 301 | .multicall 302 | .clear_calls() 303 | .add_call(vault) 304 | .add_call(timestamp); 305 | let (vault, timestamp): ((u128, u128), U256) = multicall.call().await?; 306 | 307 | Ok(Auction { 308 | started: timestamp, 309 | collateral: vault.0, 310 | debt: vault.1, 311 | }) 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use ethers::prelude::*; 2 | use yield_liquidator::{escalator::GeometricGasPrice, keeper::Keeper}; 3 | 4 | use gumdrop::Options; 5 | use serde::Deserialize; 6 | use std::{convert::TryFrom, path::PathBuf, sync::Arc, time::Duration}; 7 | use tracing::info; 8 | use tracing_subscriber::{filter::EnvFilter, fmt::Subscriber}; 9 | 10 | // CLI Options 11 | #[derive(Debug, Options, Clone)] 12 | struct Opts { 13 | help: bool, 14 | 15 | #[options(help = "path to json file with the contract addresses")] 16 | config: PathBuf, 17 | 18 | #[options( 19 | help = "the Ethereum node endpoint (HTTP or WS)", 20 | default = "http://localhost:8545" 21 | )] 22 | url: String, 23 | 24 | #[options(help = "path to your private key")] 25 | private_key: PathBuf, 26 | 27 | #[options(help = "polling interval (ms)", default = "1000")] 28 | interval: u64, 29 | 30 | #[options(help = "the file to be used for persistence", default = "data.json")] 31 | file: PathBuf, 32 | 33 | #[options(help = "the minimum profit per liquidation", default = "0")] 34 | min_profit: U256, 35 | 36 | #[options(help = "the block to start watching from")] 37 | start_block: Option, 38 | } 39 | 40 | #[derive(Deserialize)] 41 | struct Config { 42 | #[serde(rename = "Controller")] 43 | controller: Address, 44 | #[serde(rename = "Liquidations")] 45 | liquidations: Address, 46 | #[serde(rename = "Uniswap")] 47 | uniswap: Address, 48 | #[serde(rename = "Flash")] 49 | flashloan: Address, 50 | #[serde(rename = "Multicall")] 51 | multicall: Option
, 52 | } 53 | 54 | #[tokio::main] 55 | async fn main() -> anyhow::Result<()> { 56 | Subscriber::builder() 57 | .with_env_filter(EnvFilter::from_default_env()) 58 | .init(); 59 | 60 | let opts = Opts::parse_args_default_or_exit(); 61 | 62 | if opts.url.starts_with("http") { 63 | let provider = Provider::::try_from(opts.url.clone())?; 64 | run(opts, provider).await?; 65 | } else { 66 | let ws = Ws::connect(opts.url.clone()).await?; 67 | let provider = Provider::new(ws); 68 | run(opts, provider).await?; 69 | } 70 | 71 | Ok(()) 72 | } 73 | 74 | async fn run(opts: Opts, provider: Provider

) -> anyhow::Result<()> { 75 | info!("Starting Yield Liquidator."); 76 | let provider = provider.interval(Duration::from_millis(opts.interval)); 77 | let wallet: LocalWallet = std::fs::read_to_string(opts.private_key)?.parse()?; 78 | let address = wallet.address(); 79 | let client = SignerMiddleware::new(provider, wallet); 80 | let client = NonceManagerMiddleware::new(client, address); 81 | let client = Arc::new(client); 82 | info!("Profits will be sent to {:?}", address); 83 | 84 | info!("Node: {}", opts.url); 85 | 86 | let cfg: Config = serde_json::from_reader(std::fs::File::open(opts.config)?)?; 87 | info!("Controller: {:?}", cfg.controller); 88 | info!("Liquidations: {:?}", cfg.liquidations); 89 | info!("Uniswap: {:?}", cfg.uniswap); 90 | info!("Multicall: {:?}", cfg.multicall); 91 | info!("FlashLiquidator {:?}", cfg.flashloan); 92 | info!("Persistent data will be stored at: {:?}", opts.file); 93 | 94 | let file = std::fs::OpenOptions::new() 95 | .read(true) 96 | .write(true) 97 | .create(true) 98 | .open(&opts.file) 99 | .unwrap(); 100 | let state = serde_json::from_reader(&file).unwrap_or_default(); 101 | 102 | let mut gas_escalator = GeometricGasPrice::new(); 103 | gas_escalator.coefficient = 1.12501; 104 | gas_escalator.every_secs = 5; // TODO: Make this be 90s 105 | gas_escalator.max_price = Some(U256::from(5000 * 1e9 as u64)); // 5k gwei 106 | 107 | let mut keeper = Keeper::new( 108 | client, 109 | cfg.controller, 110 | cfg.liquidations, 111 | cfg.uniswap, 112 | cfg.flashloan, 113 | cfg.multicall, 114 | opts.min_profit, 115 | gas_escalator, 116 | state, 117 | ) 118 | .await?; 119 | 120 | keeper.run(opts.file, opts.start_block).await?; 121 | 122 | Ok(()) 123 | } 124 | --------------------------------------------------------------------------------