Skip to content
This repository has been archived by the owner on Oct 9, 2024. It is now read-only.

feat: use mock executor on l2s #13

Merged
merged 2 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 2 additions & 21 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"));

Expand Down Expand Up @@ -47,7 +46,6 @@ type CommonOptions = {
enterArtifactPath: boolean;
artifactPath?: string;
//
pool: string;
userAddress?: string;
keepAlive?: boolean | string;
};
Expand Down Expand Up @@ -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?",
Expand Down Expand Up @@ -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) {
Expand All @@ -388,7 +369,7 @@ function getName(options: Options) {
await executeL2Payload({
payloadAddress,
provider: fork.provider,
pool: argv.pool,
networkId: argv.networkId,
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
149 changes: 39 additions & 110 deletions src/l2Gov.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down