diff --git a/main.ts b/main.ts index 6a499ea..83ec517 100644 --- a/main.ts +++ b/main.ts @@ -17,7 +17,6 @@ import { passAndExecuteProposal, } from "./src/governance"; import { executeL2Payload } from "./src/l2Gov"; -import * as allConfigs from "@bgd-labs/aave-address-book"; inquirer.registerPrompt("fuzzypath", require("inquirer-fuzzy-path")); @@ -47,7 +46,6 @@ type CommonOptions = { enterArtifactPath: boolean; artifactPath?: string; // - pool: string; userAddress?: string; keepAlive?: boolean | string; }; @@ -198,23 +196,6 @@ const questions: { [key: string]: InquirerQuestion | YargsQuestion } = { !args.proposalId && !args.payloadAddress, }, - // get the correct acl - pool: { - type: "list", - message: "Select the target pool", - describe: "Select the target pool", - staticChoices: Object.keys(allConfigs), - choices: (args) => { - return Object.keys(allConfigs).filter( - (key) => (allConfigs as any)[key].CHAIN_ID === Number(args.networkId) - ); - }, - when: (args) => - !!( - (args.artifactPath || args.proposalId || args.payloadAddress) && - Number(args.networkId) !== ChainId.mainnet - ), - }, userAddress: { message: "Enter an address you want to fund with 1000 native currency on the fork?", @@ -367,7 +348,7 @@ function getName(options: Options) { await executeL2Payload({ payloadAddress: argv.payloadAddress, provider: fork.provider, - pool: argv.pool, + networkId: argv.networkId, }); } } else if (argv.artifactPath) { @@ -388,7 +369,7 @@ function getName(options: Options) { await executeL2Payload({ payloadAddress, provider: fork.provider, - pool: argv.pool, + networkId: argv.networkId, }); } } diff --git a/package.json b/package.json index 56a9d00..401dde6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "scripts": { "start": "yarn build && node dist/index.js", "build": "ncc build ./main.ts -o dist --minify", - "publish:local": "yarn build && npm pack && npm i -g bgd-labs-aave-tenderly-cli-0.0.9.tgz && rm bgd-labs-aave-tenderly-cli-0.0.9.tgz", + "publish:local": "yarn build && npm pack && npm i -g bgd-labs-aave-tenderly-cli-0.0.10.tgz && rm bgd-labs-aave-tenderly-cli-0.0.10.tgz", "ci:publish": "yarn build && npm publish --access=public" }, "repository": { diff --git a/src/l2Gov.ts b/src/l2Gov.ts index c8c9a57..a79202e 100644 --- a/src/l2Gov.ts +++ b/src/l2Gov.ts @@ -1,131 +1,60 @@ -import { providers, BigNumber, utils, Contract } from "ethers"; -import { - keccak256, - toUtf8Bytes, - defaultAbiCoder, - formatBytes32String, -} from "ethers/lib/utils"; +import { providers, Contract } from "ethers"; import * as allConfigs from "@bgd-labs/aave-address-book"; +// https://github.com/bgd-labs/aave-helpers/blob/master/src/GovHelpers.sol#L179 +const mockExecutorBytes = + "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80634b64e49214610030575b600080fd5b61004361003e366004610120565b610045565b005b60408051600481526024810182526020810180516001600160e01b0316631851865560e21b17905290516000916001600160a01b038416916100879190610150565b600060405180830381855af49150503d80600081146100c2576040519150601f19603f3d011682016040523d82523d6000602084013e6100c7565b606091505b505090508061011c5760405162461bcd60e51b815260206004820152601960248201527f50524f504f53414c5f455845435554494f4e5f4641494c454400000000000000604482015260640160405180910390fd5b5050565b60006020828403121561013257600080fd5b81356001600160a01b038116811461014957600080fd5b9392505050565b6000825160005b818110156101715760208186018101518583015201610157565b81811115610180576000828501525b50919091019291505056fea2646970667358221220b5e76617250f070df5d6bc01dcf608005afb0c19aa2776724a1b25684f561c4664736f6c634300080a0033"; +const MOCK_EXECUTOR_ABI = [ + { + inputs: [ + { + internalType: "address", + name: "payload", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "function", + name: "execute", + }, +]; + interface DefaultInterface { provider: providers.StaticJsonRpcProvider; } interface ExecuteL2Payload extends DefaultInterface { payloadAddress: string; - pool: string; -} - -function getPoolAdminSlot() { - const slot = "0x2"; - const role = formatBytes32String("POOL_ADMIN"); - const encodedSlot = defaultAbiCoder.encode( - ["bytes32", "uint256"], - [role, slot] - ); - return keccak256(encodedSlot); -} - -function getACLRoleAddressSlot(_role: string, address: string) { - const slot = "0x0"; - const role = keccak256(toUtf8Bytes(_role)); - - const encodedSlot = defaultAbiCoder.encode( - ["bytes32", "uint256"], - [role, slot] - ); - - return keccak256( - defaultAbiCoder.encode( - ["address", "bytes32"], - [address, keccak256(encodedSlot)] - ) - ); + networkId: number; } export async function executeL2Payload({ payloadAddress, provider, - pool, + networkId, }: ExecuteL2Payload) { - const config = allConfigs[pool as keyof typeof allConfigs]; - const aclManagerAddress = (config as typeof allConfigs.AaveV3Optimism) - .ACL_MANAGER; - const isV2 = !aclManagerAddress; + const key = Object.keys(allConfigs).find( + (key) => + ( + allConfigs[ + key as keyof typeof allConfigs + ] as typeof allConfigs.AaveV3Optimism + ).CHAIN_ID === Number(networkId) + ) as keyof typeof allConfigs; + const config = allConfigs[key]; + const executor = + (config as typeof allConfigs.AaveV3Optimism).ACL_ADMIN || + (config as typeof allConfigs.AaveV2Polygon).POOL_ADMIN; try { - if (aclManagerAddress) { - const listingAdminSlot = getACLRoleAddressSlot( - "ASSET_LISTING_ADMIN", - payloadAddress - ); - await provider.send("tenderly_setStorageAt", [ - aclManagerAddress, - listingAdminSlot, - utils.hexZeroPad(BigNumber.from(1).toHexString(), 32), - ]); - console.log("added role ASSET_LISTING_ADMIN"); - - const riskAdminSlot = getACLRoleAddressSlot("RISK_ADMIN", payloadAddress); - await provider.send("tenderly_setStorageAt", [ - aclManagerAddress, - riskAdminSlot, - utils.hexZeroPad(BigNumber.from(1).toHexString(), 32), - ]); - console.log("added role RISK_ADMIN"); - - const poolAdminSlot = getACLRoleAddressSlot("POOL_ADMIN", payloadAddress); - await provider.send("tenderly_setStorageAt", [ - aclManagerAddress, - poolAdminSlot, - utils.hexZeroPad(BigNumber.from(1).toHexString(), 32), - ]); - console.log("added role POOL_ADMIN"); - } - const payload = new Contract( - payloadAddress, - [ - { - inputs: [], - name: "owner", - outputs: [{ internalType: "address", name: "", type: "address" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "execute", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - ], + await provider.send("tenderly_setCode", [executor, mockExecutorBytes]); + const mockExecutor = new Contract( + executor, + MOCK_EXECUTOR_ABI, provider.getSigner() ); + console.log("replaced executor"); - // sometimes payloads use ownable and onlyOwner modifier on `execute` - // therefore we check if we can fetch owner and set the owner as signer - try { - const owner = await payload.owner(); - if (isV2) { - console.log("### WARNING ###"); - console.log("Cannot simulate l2 proposals with owner guard"); - } - const payloadWithOwner = payload.connect(provider.getSigner(owner)); - await payloadWithOwner.execute(); - } catch (e) { - if (isV2) { - const adminSlot = getPoolAdminSlot(); - await provider.send("tenderly_setStorageAt", [ - (config as typeof allConfigs.AaveV2Ethereum).POOL_ADDRESSES_PROVIDER, - adminSlot, - utils.hexZeroPad(payloadAddress, 32), - ]); - await payload.execute(); - } else { - await payload.execute(); - } - } - + await mockExecutor.execute(payloadAddress); console.log("executed payload"); } catch (e: any) { console.log(e.message);