Skip to content
Open
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
8 changes: 0 additions & 8 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dotenv/config';
import { HardhatUserConfig, subtask, task } from 'hardhat/config';
import '@compound-finance/hardhat-import';
import '@nomiclabs/hardhat-etherscan';
import '@tenderly/hardhat-tenderly';
import '@nomiclabs/hardhat-ethers';
import '@typechain/hardhat';
import 'hardhat-chai-matchers';
Expand Down Expand Up @@ -704,13 +703,6 @@ const config: HardhatUserConfig = {
],
},

tenderly: {
project: 'comet',
username: process.env.TENDERLY_USERNAME || '',
accessKey: process.env.TENDERLY_ACCESS_KEY || '',
privateVerification: false,
},

mocha: {
reporter: 'mocha-multi-reporters',
reporterOptions: {
Expand Down
14 changes: 14 additions & 0 deletions plugins/deployment_manager/DeploymentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class DeploymentManager {
cache: Cache; // TODO: kind of a misnomer since its handling *all* path stuff
contractsCache: ContractMap | null;
_signers: SignerWithAddress[];
bridgedDeploymentManagers: Map<string, DeploymentManager> = new Map();

constructor(
network: string,
Expand All @@ -75,6 +76,19 @@ export class DeploymentManager {
this._signers = [];
}

async addBridgedDeploymentManager(network: string, deployment: string, hre?: HardhatRuntimeEnvironment): Promise<DeploymentManager> {
const key = `${network}:${deployment}`;
if (!this.bridgedDeploymentManagers.has(key)) {
if(!hre && this.network !== network) {
throw new Error(`Must provide hre to bridge to a different network deployment manager`);
}
const dm = new DeploymentManager(network, deployment, hre ?? this.hre, { writeCacheToDisk: true });
await dm.spider();
this.bridgedDeploymentManagers.set(key, dm);
}
return this.bridgedDeploymentManagers.get(key)!;
}

async getSigners(): Promise<SignerWithAddress[]> {
if (this._signers.length > 0) {
return this._signers;
Expand Down
22 changes: 17 additions & 5 deletions plugins/scenario/utils/hreForBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Environment } from 'hardhat/internal/core/runtime-environment';
import { ForkSpec } from '../World';
import { HttpNetworkUserConfig } from 'hardhat/types';
import { EthereumProvider } from 'hardhat/types/provider';
import { networkConfigs } from '../../../hardhat.config';

/*
mimics https://github.com/nomiclabs/hardhat/blob/master/packages/hardhat-core/src/internal/lib/hardhat-lib.ts
Expand Down Expand Up @@ -91,6 +92,12 @@ function getBlockRollback(base: ForkSpec) {
return 25;
}

let activeMigration = false;

export function migrationStarted() {
activeMigration = true;
}

export async function forkedHreForBase(base: ForkSpec): Promise<HardhatRuntimeEnvironment> {
const ctx: HardhatContext = HardhatContext.getHardhatContext();

Expand All @@ -103,16 +110,21 @@ export async function forkedHreForBase(base: ForkSpec): Promise<HardhatRuntimeEn

const baseNetwork = networks[base.network] as HttpNetworkUserConfig;

const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url);
if(baseNetwork.url)
const providerUrl = (() => {
if (activeMigration){
return networkConfigs.find(c => c.network === base.network)?.url;
}
return baseNetwork.url;
})();
const provider = new ethers.providers.JsonRpcProvider(providerUrl);
if(providerUrl)
console.log(`Forking from network: ${base.network} at block number: ${await provider.getBlockNumber() - (getBlockRollback(base) || 0)}`);

// noNetwork otherwise
if (!base.blockNumber && baseNetwork.url && getBlockRollback(base) !== undefined)
if (!base.blockNumber && providerUrl && getBlockRollback(base) !== undefined)
base.blockNumber = await provider.getBlockNumber() - getBlockRollback(base); // arbitrary number of blocks to go back

if (getBlockRollback(base) === 0) {
const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url);
const block = await provider.getBlockNumber();
base.blockNumber = block - 1;
}
Expand All @@ -126,7 +138,7 @@ export async function forkedHreForBase(base: ForkSpec): Promise<HardhatRuntimeEn
...{
forking: {
enabled: true,
url: baseNetwork.url,
url: providerUrl,
httpHeaders: {},
...(base.blockNumber && { blockNumber: base.blockNumber }),
},
Expand Down
16 changes: 6 additions & 10 deletions scenario/constraints/ProposalConstraint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IGovernorBravo, ProposalState, OpenProposal } from '../context/Gov';
import { CometContext } from '../context/CometContext';
import { fetchLogs } from '../utils';
import { DeploymentManager } from '../../plugins/deployment_manager';
import { isBridgedDeployment, executeOpenProposal, voteForOpenProposal, executeOpenProposalAndRelay } from '../utils';
import { isBridgedDeployment, voteForOpenProposal, executeOpenProposalAndRelay } from '../utils';
import { getOpenBridgedProposals, executeBridgedProposal } from '../utils/bridgeProposal';

export async function getOpenProposals(deploymentManager: DeploymentManager, governor: IGovernorBravo): Promise<OpenProposal[]> {
Expand Down Expand Up @@ -87,15 +87,11 @@ export class ProposalConstraint<T extends CometContext> implements StaticConstra
try {
// Execute the proposal
debug(`${label} Processing pending proposal ${proposal.id}`);
if (isBridged) {
await executeOpenProposalAndRelay(
governanceDeploymentManager,
ctx.world.deploymentManager,
proposal
);
} else {
await executeOpenProposal(governanceDeploymentManager, proposal);
}
await executeOpenProposalAndRelay(
governanceDeploymentManager,
ctx.world.deploymentManager,
proposal
);
debug(`${label} Open proposal ${proposal.id} was executed`);
} catch (err) {
debug(`${label} Failed to execute proposal ${proposal.id}`, err.message);
Expand Down
153 changes: 87 additions & 66 deletions scenario/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
utils,
} from 'ethers';
import { execSync } from 'child_process';
import { existsSync } from 'fs';
import { existsSync, unlinkSync } from 'fs';
import { CometContext } from '../context/CometContext';
import CometAsset from '../context/CometAsset';
import { exp } from '../../test/helpers';
Expand Down Expand Up @@ -912,8 +912,6 @@ export async function tenderlyExecute(
},
];

const chainId2 = bdm.hre.ethers.provider.network.chainId;

console.log(`\n========================== TENDERLY ==========================\n`);

console.log(`\nExecuting Tenderly simulation for proposal ${id}...`);
Expand All @@ -926,50 +924,68 @@ export async function tenderlyExecute(
console.log(` >>> PROPOSAL EXECUTED ${id} \n`);
console.log(`Simulation ${exec1.id} done, status: ${exec1.status}`);
console.log(`Link: https://www.tdly.co/shared/simulation/${exec1.id}`);
let proposals;
if (chainId1 !== chainId2) {
proposals = await relayMessage(gdm, bdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs);

debug(`Proposals relayed: ${proposals.length}`);
const timelockL2 = await bdm.getContractOrThrow('timelock');
const delay = await timelockL2.delay();
const relayMessages = loadCachedRelayMessages();
const latestL2 = await bdm.hre.ethers.provider.getBlock('latest');
const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber();
const T0L2 = BigInt(Math.max(latestL2.timestamp, maxEta + 1));
const B0L2 = Number(latestL2.number) + 1;
const simsL2 = relayMessages.map((msg, i, arr) => {
const isLast = i === arr.length - 1;

const timestamp = isLast
? Number(T0L2)
: latestL2.timestamp;

const block = isLast
? B0L2 : latestL2.number;

return {
network_id: chainId2.toString(),
from: msg.signer,
to: msg.messenger,
block_number: Number(block),
block_header: {
timestamp: bdm.hre.ethers.utils.hexlify(Number(timestamp))
},
input: msg.callData,
save: true,
save_if_fails: true,
gas_price: 0,
};
});

const bdms = [bdm];
for (const dm of gdm.bridgedDeploymentManagers.values()) {
if (!bdms.includes(dm)) {
bdms.push(dm);
}
}

if (simsL2.length > 0) {
const bundle2 = await simulateBundle(bdm, simsL2, Number(B0L2));
console.log(` >>> PROPOSAL RELAYED ${id} \n`);
const sim = bundle2[bundle2.length - 1];
await shareSimulation(bdm, sim.simulation.id);
console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`);
console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id}`);
for (const currentBdm of bdms) {
const chainId2 = currentBdm.hre.ethers.provider.network.chainId;
let proposals;
if (chainId1 !== chainId2) {
const relayPath = path.resolve(__dirname, '../../cache/relay.json');
if (existsSync(relayPath)) unlinkSync(relayPath);

proposals = await relayMessage(gdm, currentBdm, parseFloat(B0.toString()), bundle[bundle.length - 1].transaction.transaction_info.logs);

debug(`Proposals relayed to ${currentBdm.network}: ${proposals?.length ?? 0}`);

if (proposals && proposals.length > 0) {
const timelockL2 = await currentBdm.getContractOrThrow('timelock');
const delay = await timelockL2.delay();
const relayMessages = loadCachedRelayMessages();
const latestL2 = await currentBdm.hre.ethers.provider.getBlock('latest');
const maxEta = Math.max(...proposals.map(p => Number(p.eta || 0))) + delay.toNumber();
const T0L2 = BigInt(Math.max(latestL2.timestamp, maxEta + 1));
const B0L2 = Number(latestL2.number) + 1;

const simsL2 = relayMessages.map((msg, i, arr) => {
const isLast = i === arr.length - 1;

const timestamp = isLast
? Number(T0L2)
: latestL2.timestamp;

const block = isLast
? B0L2 : latestL2.number;

return {
network_id: chainId2.toString(),
from: msg.signer,
to: msg.messenger,
block_number: Number(block),
block_header: {
timestamp: currentBdm.hre.ethers.utils.hexlify(Number(timestamp))
},
input: msg.callData,
save: true,
save_if_fails: true,
gas_price: 0,
};
});

if (simsL2.length > 0) {
const bundle2 = await simulateBundle(currentBdm, simsL2, Number(B0L2));
const sim = bundle2[bundle2.length - 1];
await shareSimulation(currentBdm, sim.simulation.id);
console.log(`\nRelayed to ${currentBdm.network}`);
console.log(`Simulation ${sim.simulation.id} done, status: ${sim.simulation.status}`);
console.log(`Link: https://www.tdly.co/shared/simulation/${sim.simulation.id}`);
}
}
}
}

Expand All @@ -985,7 +1001,9 @@ async function simulateBundle(
const results = [];

for (const sim of simulations) {
const { username, project, accessKey } = (dm.hre.config as any).tenderly;
const project = 'comet';
const username = process.env.TENDERLY_USERNAME || '';
const accessKey = process.env.TENDERLY_ACCESS_KEY || '';

// Merge rolling state changes with simulation's own state_objects
const stateObjects = sim.state_objects
Expand Down Expand Up @@ -1043,7 +1061,9 @@ async function simulateBundle(
}

async function shareSimulation(dm: DeploymentManager, simulationId: string) {
const { username, project, accessKey } = (dm.hre.config as any).tenderly;
const project = 'comet';
const username = process.env.TENDERLY_USERNAME || '';
const accessKey = process.env.TENDERLY_ACCESS_KEY || '';
return axios.post(
`https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulations/${simulationId}/share`,
{},
Expand Down Expand Up @@ -1500,25 +1520,26 @@ export async function executeOpenProposalAndRelay(
await governanceDeploymentManager.hre.ethers.provider.getBlockNumber();
await executeOpenProposal(governanceDeploymentManager, openProposal);
console.log(`Executed proposal ${openProposal.id} on ${governanceDeploymentManager.network}, checking if relay to ${bridgeDeploymentManager.network} is needed...`);
await mockAllRedstoneOracles(bridgeDeploymentManager);
console.log(`All Redstone oracles on ${bridgeDeploymentManager.network} are mocked`);
if (
await isBridgeProposal(
governanceDeploymentManager,
bridgeDeploymentManager,
openProposal
)
) {
await relayMessage(
governanceDeploymentManager,
bridgeDeploymentManager,
startingBlockNumber
);
} else {
console.log(
`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying`
);
return;
const bridgeManagers = await isBridgeProposal(
governanceDeploymentManager,
bridgeDeploymentManager,
openProposal
);
for (const bridgeManager of bridgeManagers) {
await mockAllRedstoneOracles(bridgeManager);
if (bridgeManager) {
await relayMessage(
governanceDeploymentManager,
bridgeManager,
startingBlockNumber
);
} else {
console.log(
`[${governanceDeploymentManager.network} -> ${bridgeManager.network}] Proposal ${openProposal.id} doesn't target bridge; not relaying`
);
return;
}
}
}

Expand Down
Loading
Loading