Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
MishaShWoof committed Feb 7, 2025
1 parent 7521336 commit d196a86
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 11 deletions.
1 change: 1 addition & 0 deletions contracts/IGovernorBravo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface IGovernorBravo {
function MIN_VOTING_DELAY() external view returns (uint256);

Check warning on line 49 in contracts/IGovernorBravo.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Function name must be in mixedCase
function MIN_PROPOSAL_THRESHOLD() external view returns (uint256);

Check warning on line 50 in contracts/IGovernorBravo.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Function name must be in mixedCase

function comp() external view returns (address); // for testnet only
function token() external view returns (address);
function proposalEta(uint256) external view returns (uint256);
function proposalCount() external view returns (uint256);
Expand Down
75 changes: 75 additions & 0 deletions contracts/IGovernorTestnet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
* @dev Interface for interacting with Governor bravo.
* Note Not a comprehensive interface
*/
interface IGovernorTestnet {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}

struct Proposal {
uint id;
address proposer;
uint eta;
uint startBlock;
uint endBlock;
uint forVotes;
uint againstVotes;
uint abstainVotes;
bool canceled;
bool executed;
}

event ProposalCreated(
uint256 proposalId,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 startBlock,
uint256 endBlock,
string description
);

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: compound.solidity.lack-of-indexed-parameter Warning

Event parameters with type 'address' should be indexed
event ProposalCanceled(uint256 proposalId);
event ProposalQueued(uint256 proposalId, uint256 eta);
event ProposalExecuted(uint256 proposalId);

function MIN_VOTING_PERIOD() external view returns (uint256);

Check warning on line 48 in contracts/IGovernorTestnet.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Function name must be in mixedCase
function MIN_VOTING_DELAY() external view returns (uint256);

Check warning on line 49 in contracts/IGovernorTestnet.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Function name must be in mixedCase
function MIN_PROPOSAL_THRESHOLD() external view returns (uint256);

Check warning on line 50 in contracts/IGovernorTestnet.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Function name must be in mixedCase

function comp() external view returns (address); // for testnet only
function proposalEta(uint256) external view returns (uint256);
function proposalCount() external view returns (uint256);
function proposals(uint256 proposalId) external view returns (Proposal memory);
function votingDelay() external view returns (uint256);
function votingPeriod() external view returns (uint256);
function state(uint256 proposalId) external view returns (ProposalState);
function propose(
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) external returns (uint256 proposalId); // for testnet only
function queue(uint256 proposalId) external;
function execute(uint256 proposalId) external;
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
function getActions(uint proposalId) external view returns (
address[] memory targets,
uint[] memory values,
string[] memory signatures,
bytes[] memory calldatas
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export default migration('1686953660_configurate_and_ens', {

const description = "# Initialize native USDC market cUSDCv3 on Arbitrum\n\nThis proposal takes the governance steps recommended and necessary to initialize a Compound III USDC (native USDC on Arbitrum) market on Arbitrum; upon execution, cUSDCv3 will be ready for use. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). Although real tests have also been run over the Goerli/Arbitrum Goerli, this will be the first proposal to mint native USDC on Arbitrum mainnet by burning USDC on mainnet via the `depositAndBurn` function on the Cross-Chain Transfer Protocol (CCTP) provided by Circle, and therefore includes risks not present in previous proposals.\n\nThe proposal sets the entire configuration in the Configurator to be the same as the existing bridged USDC.e market. Finally, the parameters include a migration of bridged USDC.e market supply-side COMP incentives to users in the new native USDC market.\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/789) and [forum discussion](https://www.comp.xyz/t/initialize-compound-iii-native-usdc-on-arbitrum/4542).\n\n\n## Proposal Actions\n\nThe first proposal action sets the Comet Factory, Comet configuration and deploys a new Comet implementation on Arbitrum. This sends the encoded `setFactory`, `setConfiguration` and `deployAndUpgradeTo` calls across the bridge to the governance receiver on Arbitrum. It also calls `setRewardConfig` on the Arbitrum rewards contract, to establish Arbitrum’s bridged version of COMP as the reward token for the deployment and set the initial supply speed to be 10 COMP/day and borrow speed to be 0 COMP/day. It calls another `setBaseTrackingSupplySpeed` and `setBaseTrackingBorrowSpeed` to set the supply speed and borrow speed of the existing USDC.e market to be 0 COMP/day. Lastly it calls `deployAndUpgradeTo` to deploy an updated Comet implementation for the existing bridged USDC.e market to have the new supply and borrow rewards speed.\n\nThe second action approves Circle’s Cross-Chain Transfer Protocol (CCTP)[TokenMessenger](https://etherscan.io/address/0xbd3fa81b58ba92a82136038b25adec7066af3155) to take the Timelock's USDC on Mainnet, in order to seed the market reserves through the CCTP.\n\nThe third action deposits and burns 10K USDC from mainnet via `depositForBurn` function on CCTP’s TokenMessenger contract to mint native USDC to Comet on Arbitrum.\n\nThe fourth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new native USDC market and renames the bridged USDC market’s baseSymbol to USDC.e from USDC.";
const txn = await govDeploymentManager.retry(async () =>
trace(await governor.propose(...(await proposal(mainnetActions, description))))
trace(await governor['propose(address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, string description)'](...(await proposal(mainnetActions, description))))
);

const event = txn.events.find(event => event.event === 'ProposalCreated');
Expand Down
5 changes: 4 additions & 1 deletion deployments/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ const relationConfigMap: RelationConfigMap = {
},
relations: {
COMP: {
field: async (governor) => governor.token(),
field: async (governor) => {
if (governor.address === '0x309a862bbC1A00e45506cB8A802D1ff10004c8C0') return governor.token();
return governor.comp();
},
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
calldata,
exp,
getConfigurationStruct,
proposal,
testnetProposal,
} from '../../../../src/deploy';
import { expect } from 'chai';
import { utils } from 'ethers';
import { Contract, utils } from 'ethers';

const sepoliaCOMP = '0xD3A6Ffc1fc9e7e4f34eD15Fb7Dd04102AC3470A2';

Expand Down Expand Up @@ -155,7 +155,13 @@ export default migration('1727774346_configurate_and_ens', {
];

const description = `DESCRIPTION`;
const txn = await(await governor.propose(...(await proposal(actions, description)))).wait();
const testnetGovernor = new Contract(
governor.address, [
'function propose(address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) external returns (uint256 proposalId)',
'event ProposalCreated(uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)'
], governor.signer
);
const txn = await(await testnetGovernor.propose(...(await testnetProposal(actions, description)))).wait();

const event = txn.events.find((event) => event.event === 'ProposalCreated');
const [proposalId] = event.args;
Expand Down
3 changes: 2 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,10 @@ const config: HardhatUserConfig = {
: { mnemonic: MNEMONIC, accountsBalance: (10n ** 36n).toString() },
// this should only be relied upon for test harnesses and coverage (which does not use viaIR flag)
allowUnlimitedContractSize: true,
hardfork: 'cancun',
hardfork: networkConfigs.some(({ chainId }) => chainId === 1) ? 'cancun' : 'shanghai',
chains: networkConfigs.reduce((acc, { chainId }) => {
if (chainId === 1) return acc;
if (chainId === 1301) return acc;
acc[chainId] = {
hardforkHistory: {
berlin: 1,
Expand Down
8 changes: 7 additions & 1 deletion plugins/scenario/utils/hreForBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function getBlockRollback(base: ForkSpec){
return undefined;
}
else if(base.network === 'unichain-sepolia'){
return 1;
return 0;
}
else if(base.network === 'base'){
return 200;
Expand All @@ -95,6 +95,12 @@ export async function forkedHreForBase(base: ForkSpec): Promise<HardhatRuntimeEn
if(!base.blockNumber && baseNetwork.url && 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;
}

if (!baseNetwork) {
throw new Error(`cannot find network config for network: ${base.network}`);
}
Expand Down
44 changes: 40 additions & 4 deletions scenario/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,15 @@ export async function executeOpenProposal(
// Execute proposal (maybe, w/ gas limit so we see if exec reverts, not a gas estimation error)
if (await governor.state(id) == ProposalState.Queued) {
const block = await dm.hre.ethers.provider.getBlock('latest');
const eta = await governor.proposalEta(id);

await setNextBlockTimestamp(dm, Math.max(block.timestamp, eta.toNumber()) + 1);

if(governor.address !== '0x309a862bbC1A00e45506cB8A802D1ff10004c8C0') {
const proposal = await governor.proposals(id);
await setNextBlockTimestamp(dm, Math.max(block.timestamp, proposal.eta.toNumber()) + 1);
}
else{
const eta = await governor.proposalEta(id);
await setNextBlockTimestamp(dm, Math.max(block.timestamp, eta.toNumber()) + 1);
}
await setNextBaseFeeToZero(dm);
await governor.execute(id, { gasPrice: 0, gasLimit: 120000000 });
}
Expand All @@ -486,6 +492,34 @@ export async function executeOpenProposal(
await dm.hre.ethers.provider.send('evm_mine', []);
}

async function testnetPropose(
dm: DeploymentManager,
proposer: SignerWithAddress,
targets: string[],
values: BigNumberish[],
signatures: string[],
calldatas: string[],
description: string,
gasPrice: BigNumberish
) {
const governor = await dm.getContractOrThrow('governor');
const testnetGovernor = new Contract(
governor.address, [
'function propose(address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) external returns (uint256 proposalId)',
'event ProposalCreated(uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)'
], governor.signer
);

return testnetGovernor.connect(proposer).propose(
targets,
values,
signatures,
calldatas,
description,
{ gasPrice }
);
}

// Instantly executes some actions through the governance proposal process
export async function fastGovernanceExecute(
dm: DeploymentManager,
Expand All @@ -499,7 +533,7 @@ export async function fastGovernanceExecute(

await setNextBaseFeeToZero(dm);

const proposeTxn = await (
const proposeTxn = dm.network === 'mainnet' ? await (
await governor.connect(proposer).propose(
targets,
values,
Expand All @@ -509,6 +543,8 @@ export async function fastGovernanceExecute(
'FastExecuteProposal',
{ gasPrice: 0 }
)
).wait() : await (
await testnetPropose(dm, proposer, targets, values, signatures, calldatas, 'FastExecuteProposal', 0)
).wait();
const proposeEvent = proposeTxn.events.find(event => event.event === 'ProposalCreated');
const [id, , , , , , startBlock, endBlock] = proposeEvent.args;
Expand Down
31 changes: 31 additions & 0 deletions src/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export type Proposal = [
string[], // calldatas
string // description
];
export type TestnetProposal = [
string[], // targets
BigNumberish[], // values
string[], // signatures
string[], // calldatas
string // description
];

// Note: this list could change over time
// Ideally these wouldn't be hardcoded, but other solutions are much more complex, and slower
Expand Down Expand Up @@ -162,6 +169,30 @@ export async function calldata(req: Promise<PopulatedTransaction>): Promise<stri
return '0x' + (await req).data.slice(2 + 8);
}

export async function testnetProposal(actions: ProposalAction[], description: string): Promise<TestnetProposal> {
const targets = [],
values = [],
signatures = [],
calldatas = [];
for (const action of actions) {
if (action['contract']) {
const { contract, value, signature, args } = action as ContractAction;
targets.push(contract.address);
values.push(value ?? 0);
signatures.push(signature);
calldatas.push(await calldata(contract.populateTransaction[signature](...args)));
} else {
const { target, value, signature, calldata } = action as TargetAction;
targets.push(target);
values.push(value ?? 0);
signatures.push(signature);
calldatas.push(calldata);
}
}
return [targets, values, signatures, calldatas, description];

}

export async function proposal(actions: ProposalAction[], description: string): Promise<Proposal> {
const targets = [],
values = [],
Expand Down

0 comments on commit d196a86

Please sign in to comment.