From 8ccad40f06d61e783641b098d0400e287cc54738 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 11 Jan 2024 14:51:55 +0100 Subject: [PATCH] Format python files --- .pre-commit-config.yaml | 6 + auction-server/.gitignore | 1 - auction-server/README.md | 1 - auction-server/src/PERMulticall.json | 182 ++++++---------------- beacon/protocols/beacon_TokenVault.py | 12 +- beacon/protocols/beacon_template.py | 10 ++ beacon/searcher/searcherA.py | 33 ++-- beacon/searcher/searcher_utils.py | 24 +-- beacon/surface_opportunities.py | 11 +- beacon/utils/endpoints.py | 2 +- beacon/utils/types_liquidation_adapter.py | 9 +- per_multicall/README.md | 6 +- per_multicall/remappings.txt | 2 +- 13 files changed, 119 insertions(+), 180 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14ac2ce4..709f4b34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,3 +24,9 @@ repos: entry: cargo +nightly-2023-07-23 fmt --manifest-path ./auction-server/Cargo.toml --all -- --config-path rustfmt.toml pass_filenames: false files: auction-server + + # for python files + - repo: https://github.com/hhatto/autopep8 + rev: "v2.0.4" + hooks: + - id: autopep8 diff --git a/auction-server/.gitignore b/auction-server/.gitignore index d913617b..eb5a316c 100644 --- a/auction-server/.gitignore +++ b/auction-server/.gitignore @@ -1,2 +1 @@ target - diff --git a/auction-server/README.md b/auction-server/README.md index 745f508f..745356e9 100644 --- a/auction-server/README.md +++ b/auction-server/README.md @@ -8,7 +8,6 @@ Each blockchain is configured in `config.yaml`. This package uses Cargo for building and dependency management. Simply run `cargo build` and `cargo test` to build and test the project. - ## Local Development To start an instance of the webserver for local testing, you first need to perform a few setup steps: diff --git a/auction-server/src/PERMulticall.json b/auction-server/src/PERMulticall.json index 89fdeb7c..51b35e8b 100644 --- a/auction-server/src/PERMulticall.json +++ b/auction-server/src/PERMulticall.json @@ -526,75 +526,29 @@ "absolutePath": "src/PERMulticall.sol", "id": 48313, "exportedSymbols": { - "ExpiredSignature": [ - 47480 - ], - "IERC20": [ - 44053 - ], - "InvalidBid": [ - 47494 - ], - "InvalidLiquidation": [ - 47492 - ], - "InvalidPERSignature": [ - 47484 - ], - "InvalidSearcherSignature": [ - 47478 - ], - "InvalidTimestamp": [ - 47486 - ], - "InvalidVaultUpdate": [ - 47490 - ], - "LiquidationCallFailed": [ - 47498 - ], - "LiquidationCallParams": [ - 48752 - ], - "MulticallStatus": [ - 48731 - ], - "NotPEROperator": [ - 47474 - ], - "NotRegistered": [ - 47496 - ], - "OracleState": [ - 48702 - ], - "PERFeeReceiver": [ - 47910 - ], - "PERMulticall": [ - 48312 - ], - "SignatureAlreadyUsed": [ - 47482 - ], - "Strings": [ - 44822 - ], - "TokenQty": [ - 48724 - ], - "Unauthorized": [ - 47476 - ], - "UncollateralizedVaultCreation": [ - 47488 - ], - "Vault": [ - 48719 - ], - "console": [ - 22024 - ] + "ExpiredSignature": [47480], + "IERC20": [44053], + "InvalidBid": [47494], + "InvalidLiquidation": [47492], + "InvalidPERSignature": [47484], + "InvalidSearcherSignature": [47478], + "InvalidTimestamp": [47486], + "InvalidVaultUpdate": [47490], + "LiquidationCallFailed": [47498], + "LiquidationCallParams": [48752], + "MulticallStatus": [48731], + "NotPEROperator": [47474], + "NotRegistered": [47496], + "OracleState": [48702], + "PERFeeReceiver": [47910], + "PERMulticall": [48312], + "SignatureAlreadyUsed": [47482], + "Strings": [44822], + "TokenQty": [48724], + "Unauthorized": [47476], + "UncollateralizedVaultCreation": [47488], + "Vault": [48719], + "console": [22024] }, "nodeType": "SourceUnit", "src": "39:5523:37", @@ -604,12 +558,7 @@ "nodeType": "PragmaDirective", "src": "39:24:37", "nodes": [], - "literals": [ - "solidity", - "^", - "0.8", - ".13" - ] + "literals": ["solidity", "^", "0.8", ".13"] }, { "id": 47913, @@ -1582,10 +1531,7 @@ "id": 47991, "name": "require", "nodeType": "Identifier", - "overloadedDeclarations": [ - -18, - -18 - ], + "overloadedDeclarations": [-18, -18], "referencedDeclaration": -18, "src": "1747:7:37", "typeDescriptions": { @@ -1780,9 +1726,7 @@ "nodes": [], "statements": [ { - "assignments": [ - 48014 - ], + "assignments": [48014], "declarations": [ { "constant": false, @@ -2392,10 +2336,7 @@ "id": 48063, "name": "require", "nodeType": "Identifier", - "overloadedDeclarations": [ - -18, - -18 - ], + "overloadedDeclarations": [-18, -18], "referencedDeclaration": -18, "src": "2856:7:37", "typeDescriptions": { @@ -2518,10 +2459,7 @@ "id": 48071, "name": "require", "nodeType": "Identifier", - "overloadedDeclarations": [ - -18, - -18 - ], + "overloadedDeclarations": [-18, -18], "referencedDeclaration": -18, "src": "2945:7:37", "typeDescriptions": { @@ -2734,9 +2672,7 @@ "pathNode": { "id": 48088, "name": "MulticallStatus", - "nameLocations": [ - "3110:15:37" - ], + "nameLocations": ["3110:15:37"], "nodeType": "IdentifierPath", "referencedDeclaration": 48731, "src": "3110:15:37" @@ -2784,9 +2720,7 @@ "src": "3086:54:37" }, { - "assignments": [ - 48098 - ], + "assignments": [48098], "declarations": [ { "constant": false, @@ -3523,9 +3457,7 @@ }, "id": 48165, "initializationExpression": { - "assignments": [ - 48102 - ], + "assignments": [48102], "declarations": [ { "constant": false, @@ -3611,9 +3543,7 @@ "src": "3181:548:37" }, { - "assignments": [ - 48167 - ], + "assignments": [48167], "declarations": [ { "constant": false, @@ -3698,9 +3628,7 @@ "src": "3803:49:37" }, { - "assignments": [ - 48173 - ], + "assignments": [48173], "declarations": [ { "constant": false, @@ -3873,9 +3801,7 @@ } }, { - "assignments": [ - 48188 - ], + "assignments": [48188], "declarations": [ { "constant": false, @@ -4007,9 +3933,7 @@ "src": "4131:347:37", "statements": [ { - "assignments": [ - 48197 - ], + "assignments": [48197], "declarations": [ { "constant": false, @@ -4368,9 +4292,7 @@ "isLValue": false, "isPure": false, "lValueRequested": false, - "names": [ - "value" - ], + "names": ["value"], "nodeType": "FunctionCallOptions", "options": [ { @@ -4710,9 +4632,7 @@ "pathNode": { "id": 48058, "name": "MulticallStatus", - "nameLocations": [ - "2802:15:37" - ], + "nameLocations": ["2802:15:37"], "nodeType": "IdentifierPath", "referencedDeclaration": 48731, "src": "2802:15:37" @@ -4754,9 +4674,7 @@ "nodes": [], "statements": [ { - "assignments": [ - 48251 - ], + "assignments": [48251], "declarations": [ { "constant": false, @@ -4863,10 +4781,7 @@ "src": "5024:46:37" }, { - "assignments": [ - 48259, - 48261 - ], + "assignments": [48259, 48261], "declarations": [ { "constant": false, @@ -5013,9 +4928,7 @@ "src": "5169:258:37", "statements": [ { - "assignments": [ - 48269 - ], + "assignments": [48269], "declarations": [ { "constant": false, @@ -5349,10 +5262,7 @@ "id": 48276, "name": "require", "nodeType": "Identifier", - "overloadedDeclarations": [ - -18, - -18 - ], + "overloadedDeclarations": [-18, -18], "referencedDeclaration": -18, "src": "5311:7:37", "typeDescriptions": { @@ -5740,19 +5650,15 @@ "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, - "linearizedBaseContracts": [ - 48312 - ], + "linearizedBaseContracts": [48312], "name": "PERMulticall", "nameLocation": "327:12:37", "scope": 48313, "usedErrors": [], - "usedEvents": [ - 47925 - ] + "usedEvents": [47925] } ], "license": "UNLICENSED" }, "id": 37 -} \ No newline at end of file +} diff --git a/beacon/protocols/beacon_TokenVault.py b/beacon/protocols/beacon_TokenVault.py index e2e4e34a..94a1262a 100644 --- a/beacon/protocols/beacon_TokenVault.py +++ b/beacon/protocols/beacon_TokenVault.py @@ -9,6 +9,7 @@ TOKEN_VAULT_ADDRESS = "0x72A22FfcAfa6684d4EE449620270ac05afE963d0" CHAIN_RPC_ENDPOINT = "http://localhost:8545" + class LiquidationAccount(TypedDict): account_number: int token_address_collateral: str @@ -82,11 +83,13 @@ async def get_accounts() -> list[LiquidationAccount]: def create_liquidation_opp( account: LiquidationAccount, prices: list[PriceFeed]) -> LiquidationOpportunity: - price_updates = [] ## [bytes.fromhex(update['vaa']) for update in prices] ## TODO: uncomment this, to add back price updates + # [bytes.fromhex(update['vaa']) for update in prices] ## TODO: uncomment this, to add back price updates + price_updates = [] function_signature = web3.Web3.solidity_keccak( ["string"], ["liquidateWithPriceUpdate(uint256,bytes[])"])[:4].hex() calldata = function_signature + \ - encode(['uint256', 'bytes[]'], [account["account_number"], price_updates]).hex() + encode(['uint256', 'bytes[]'], [ + account["account_number"], price_updates]).hex() msg = encode(["uint256"], [account["account_number"]]) permission = '0x' + \ @@ -148,11 +151,8 @@ def get_liquidatable(accounts: list[LiquidationAccount], liquidatable.append( create_liquidation_opp( account, price_updates)) - - return liquidatable - - + return liquidatable async def main(): diff --git a/beacon/protocols/beacon_template.py b/beacon/protocols/beacon_template.py index a9d00e3f..54ae3fec 100644 --- a/beacon/protocols/beacon_template.py +++ b/beacon/protocols/beacon_template.py @@ -13,6 +13,8 @@ The protocol should implement a class called LiquidationAccount. This will be the type of the objects in the list returned by get_accounts() and fed into get_liquidatable. This class should contain all the relevant information about a vault/account on this protocol that is necessary for identifying whether it is eligible for liquidation and constructing a LiquidationOpportunity object. """ + + class LiquidationAccount(TypedDict): # Keys of the TypedDict and their types pass @@ -22,6 +24,8 @@ class LiquidationAccount(TypedDict): get_accounts() is the first method that the protocol should implement. It should take no arguments and return all the open accounts in the protocol in the form of a list of objects of type LiquidationAccount (defined above). Each LiquidationAccount object represents an account/vault in the protocol. This function can be implemented in any way, but it should be able to return all the open accounts in the protocol. For some protocols, this may be easily doable by just querying on-chain state; however, most protocols will likely need to maintain or access an off-chain indexer to get the list of all open accounts. """ + + async def get_accounts() -> list[LiquidationAccount]: # Fetch all vaults from on-chain state/indexer # Filter to just active vaults @@ -34,6 +38,8 @@ async def get_accounts() -> list[LiquidationAccount]: create_liquidation_opp is an optional helper function to construct a LiquidationOpportunity from a LiquidationAccount and a set of relevant Pyth PriceFeeds. If you choose to implement this function, you can call it within get_liquidatable whenever you find a LiquidationAccount eligible for liquidation. """ + + def create_liquidation_opp( account: LiquidationAccount, prices: list[PriceFeed]) -> LiquidationOpportunity: @@ -46,6 +52,8 @@ def create_liquidation_opp( prices should be a dictionary of Pyth prices, where the keys are Pyth feed IDs and the values are PriceFeed objects. prices can be retrieved from the provided price retrieval functions. This function should return a list of type LiquidationOpportunity. """ + + def get_liquidatable(accounts: list[LiquidationAccount], prices: dict[str, PriceFeed]) -> (list[LiquidationOpportunity]): @@ -58,6 +66,8 @@ def get_liquidatable(accounts: list[LiquidationAccount], """ The main loop below is a good mechanism to check if your implementations of the functions above are working properly. """ + + async def main(): # get all accounts accounts = await get_accounts() diff --git a/beacon/searcher/searcherA.py b/beacon/searcher/searcherA.py index 8fa4f0aa..4572b816 100644 --- a/beacon/searcher/searcherA.py +++ b/beacon/searcher/searcherA.py @@ -15,22 +15,26 @@ BID = 10 VALID_UNTIL = 1_000_000_000_000 + def create_liquidation_intent( - opp: LiquidationOpportunity, - sk_liquidator: str, - valid_until: int, - bid: int - ) -> LiquidationAdapterIntent: - repay_tokens = [(opp['repay_tokens'][0][0], int(opp['repay_tokens'][0][1],16))] - receipt_tokens = [(opp['receipt_tokens'][0][0], int(opp['receipt_tokens'][0][1],16))] + opp: LiquidationOpportunity, + sk_liquidator: str, + valid_until: int, + bid: int +) -> LiquidationAdapterIntent: + repay_tokens = [(opp['repay_tokens'][0][0], + int(opp['repay_tokens'][0][1], 16))] + receipt_tokens = [(opp['receipt_tokens'][0][0], + int(opp['receipt_tokens'][0][1], 16))] account: LocalAccount = Account.from_key(sk_liquidator) liquidator = account.address liq_calldata = bytes.fromhex( opp['calldata'][2:]) if opp['calldata'][:2] == "0x" else bytes.fromhex(opp['calldata']) - - signature_liquidator = construct_signature_liquidator(repay_tokens, receipt_tokens, opp['contract'], liq_calldata, bid, valid_until, sk_liquidator) - + + signature_liquidator = construct_signature_liquidator( + repay_tokens, receipt_tokens, opp['contract'], liq_calldata, bid, valid_until, sk_liquidator) + liquidation_adapter_calldata: LiquidationAdapterCalldata = { "repay_tokens": repay_tokens, "expected_receipt_tokens": receipt_tokens, @@ -41,7 +45,9 @@ def create_liquidation_intent( "bid": bid, "signature_liquidator": bytes(signature_liquidator.signature) } - calldata = LIQUIDATION_ADAPTER_FN_SIGNATURE + encode([LIQUIDATION_ADAPTER_CALLDATA_TYPES],[tuple(liquidation_adapter_calldata.values())]).hex() + calldata = LIQUIDATION_ADAPTER_FN_SIGNATURE + \ + encode([LIQUIDATION_ADAPTER_CALLDATA_TYPES], [ + tuple(liquidation_adapter_calldata.values())]).hex() intent: LiquidationAdapterIntent = { "bid": hex(bid), @@ -63,7 +69,8 @@ async def main(): # this is hardcoded to the searcher A SK sk_liquidator = "0x5b1efe5da513271c0d30cde7a2ad1d29456d68abd592efdaa7d2302e913b783f" - intent = create_liquidation_intent(liquidatable[0], sk_liquidator, VALID_UNTIL, BID) + intent = create_liquidation_intent( + liquidatable[0], sk_liquidator, VALID_UNTIL, BID) resp = await CLIENT.post( AUCTION_SERVER_ENDPOINT, @@ -76,4 +83,4 @@ async def main(): pdb.set_trace() if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/beacon/searcher/searcher_utils.py b/beacon/searcher/searcher_utils.py index c6f1eecc..b25caafc 100644 --- a/beacon/searcher/searcher_utils.py +++ b/beacon/searcher/searcher_utils.py @@ -2,22 +2,24 @@ from web3.auto import w3 from eth_abi import encode + def construct_signature_liquidator( - repay_tokens: list[(str, int)], - receipt_tokens: list[(str, int)], - address: str, - liq_calldata: bytes, - bid: int, - valid_until: int, - secret_key: str - ): + repay_tokens: list[(str, int)], + receipt_tokens: list[(str, int)], + address: str, + liq_calldata: bytes, + bid: int, + valid_until: int, + secret_key: str +): digest = encode( - ['(address,uint256)[]', '(address,uint256)[]', 'address', 'bytes', 'uint256'], + ['(address,uint256)[]', '(address,uint256)[]', + 'address', 'bytes', 'uint256'], [repay_tokens, receipt_tokens, address, liq_calldata, bid] ) msg_data = web3.Web3.solidity_keccak( ['bytes', 'uint256'], [digest, valid_until]) signature = w3.eth.account.signHash( msg_data, private_key=secret_key) - - return signature \ No newline at end of file + + return signature diff --git a/beacon/surface_opportunities.py b/beacon/surface_opportunities.py index 2aa0dcbc..8a607144 100644 --- a/beacon/surface_opportunities.py +++ b/beacon/surface_opportunities.py @@ -5,9 +5,11 @@ from pythresearch.per.beacon.utils.pyth_prices import * from pythresearch.per.beacon.utils.endpoints import * -OPERATOR_API_KEY = "password" ## TODO: turn on authorization in the surface post requests +# TODO: turn on authorization in the surface post requests +OPERATOR_API_KEY = "password" PROTOCOLS = [beacon_TokenVault] + async def main(): # get prices pyth_price_feed_ids = await get_price_feed_ids() @@ -24,8 +26,9 @@ async def main(): for protocol in PROTOCOLS: accounts = await protocol.get_accounts() - liquidatable_protocol = protocol.get_liquidatable(accounts, pyth_prices_latest) - + liquidatable_protocol = protocol.get_liquidatable( + accounts, pyth_prices_latest) + liquidatable += liquidatable_protocol CLIENT = httpx.AsyncClient() @@ -38,4 +41,4 @@ async def main(): print(f"Response PER post: {resp.text}") if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/beacon/utils/endpoints.py b/beacon/utils/endpoints.py index a1ac9dcc..b0c71992 100644 --- a/beacon/utils/endpoints.py +++ b/beacon/utils/endpoints.py @@ -2,4 +2,4 @@ AUCTION_SERVER_ENDPOINT = f"http://localhost:9000/bid" BEACON_SERVER_ENDPOINT_SURFACE = f"{BEACON_SERVER_ENDPOINT}/surface" -BEACON_SERVER_ENDPOINT_GETOPPS = f"{BEACON_SERVER_ENDPOINT}/getOpps" \ No newline at end of file +BEACON_SERVER_ENDPOINT_GETOPPS = f"{BEACON_SERVER_ENDPOINT}/getOpps" diff --git a/beacon/utils/types_liquidation_adapter.py b/beacon/utils/types_liquidation_adapter.py index 04d4f3f6..b2c9124a 100644 --- a/beacon/utils/types_liquidation_adapter.py +++ b/beacon/utils/types_liquidation_adapter.py @@ -5,6 +5,7 @@ LIQUIDATION_ADAPTER_ADDRESS = "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" + class LiquidationOpportunity(TypedDict): chain_id: str # Address of the contract where the liquidation method is called @@ -20,9 +21,10 @@ class LiquidationOpportunity(TypedDict): prices: list[PriceFeed] - LIQUIDATION_ADAPTER_CALLDATA_TYPES = '((address,uint256)[],(address,uint256)[],address,address,bytes,uint256,uint256,bytes)' -LIQUIDATION_ADAPTER_FN_SIGNATURE = web3.Web3.solidity_keccak(["string"], [f"callLiquidation({LIQUIDATION_ADAPTER_CALLDATA_TYPES})"])[:4].hex() +LIQUIDATION_ADAPTER_FN_SIGNATURE = web3.Web3.solidity_keccak( + ["string"], [f"callLiquidation({LIQUIDATION_ADAPTER_CALLDATA_TYPES})"])[:4].hex() + class LiquidationAdapterCalldata(TypedDict): repay_tokens: list[(str, int)] @@ -34,9 +36,10 @@ class LiquidationAdapterCalldata(TypedDict): bid: int signature_liquidator: bytes + class LiquidationAdapterIntent(TypedDict): bid: str calldata: str chain_id: str contract: str - permission_key: str \ No newline at end of file + permission_key: str diff --git a/per_multicall/README.md b/per_multicall/README.md index 70ac4667..64b20b8e 100644 --- a/per_multicall/README.md +++ b/per_multicall/README.md @@ -18,7 +18,7 @@ The multicall contract is in `PERMulticall.sol`. It includes functionality to ca Tests can be found in `test/`. These tests include checks that the protocol functions work, as well as checks around permissioning, bid conditions, and appropriate failing of components of the multicall bundle (without failing the whole bundle). -To run tests with the appropriate stack depth and console logging, run +To run tests with the appropriate stack depth and console logging, run ```shell $ forge test -vvv --via-ir @@ -29,21 +29,25 @@ You can also run a local validator via `anvil --gas-limit 500000000000000000 --b To run the script runs in `Vault.s.sol`, you should startup the local validator. Then, run the necessary setup commands: 1. Set up contracts and save to an environment JSON. + ```shell $ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 -vvv --sig 'setUpContracts()' --broadcast ``` 2. Set oracle prices to allow for vault creation. + ```shell $ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 --private-key 0xf46ea803192f16ef1c4f1d5fb0d6060535dbd571ea1afc7db6816f28961ba78a -vvv --sig 'setOraclePrice(int64,int64,uint64)' 110 110 190 --broadcast ``` 3. Vault creation. + ```shell $ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 -vvv --sig 'setUpVault(uint256,uint256,bool)' 100 80 true --broadcast ``` 4. Undercollateralize the vault by moving prices. + ```shell $ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 --private-key 0xf46ea803192f16ef1c4f1d5fb0d6060535dbd571ea1afc7db6816f28961ba78a -vvv --sig 'setOraclePrice(int64,int64,uint64)' 110 200 200 --broadcast ``` diff --git a/per_multicall/remappings.txt b/per_multicall/remappings.txt index 1381a220..821595eb 100644 --- a/per_multicall/remappings.txt +++ b/per_multicall/remappings.txt @@ -3,4 +3,4 @@ ds-test/=lib/forge-std/lib/ds-test/src/ erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/ forge-std/=lib/forge-std/src/ openzeppelin-contracts/=lib/openzeppelin-contracts/ -@pythnetwork/pyth-sdk-solidity=node_modules/@pythnetwork/pyth-sdk-solidity/ \ No newline at end of file +@pythnetwork/pyth-sdk-solidity=node_modules/@pythnetwork/pyth-sdk-solidity/