Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ee65afb
current dev
MishaShWoof Jul 25, 2025
7e08ec9
fix: working dev
MishaShWoof Jul 25, 2025
2bb3587
fix: scenarios
MishaShWoof Jul 28, 2025
9f5564c
fix
MishaShWoof Jul 28, 2025
88fe803
fix
MishaShWoof Jul 28, 2025
8b5ee76
Update index.ts
MishaShWoof Jul 28, 2025
700a4c6
Update DeploymentManager.ts
MishaShWoof Jul 29, 2025
4cbf863
fix: unit tests
MishaShWoof Aug 14, 2025
2bc2dbf
fix: working linea scenarios and prepare workflow fix
MishaShWoof Aug 20, 2025
0313418
Merge branch 'main' of github.com:woof-software/comet into develop
MishaShWoof Sep 16, 2025
688d515
fix: remove linea markets from dev
MishaShWoof Sep 16, 2025
df8d724
fix: remove localhost deployment
MishaShWoof Sep 19, 2025
0001bd6
fix: unify import
MishaShWoof Sep 22, 2025
d04a40d
Merge branch 'main' of github.com:woof-software/comet into develop
MishaShWoof Sep 25, 2025
bd0c7f5
feat: capo and oev upgrade
MishaShWoof Sep 25, 2025
9394aec
feat: capo and oev upgrade
MishaShWoof Sep 25, 2025
08f4d89
Merge branch 'main' of github.com:woof-software/comet into woof-softw…
MishaShWoof Oct 22, 2025
beab8e3
feat: new migration and some fixes
MishaShWoof Oct 22, 2025
23cd222
fix
MishaShWoof Oct 22, 2025
391744a
Merge branch 'main' of github.com:woof-software/comet into woof-softw…
MishaShWoof Oct 23, 2025
737a54f
feat: description and scenario fixes
MishaShWoof Oct 23, 2025
2621df6
Merge branch 'main' of github.com:woof-software/comet into develop
MishaShWoof Nov 11, 2025
aceaf43
fixes from recent prs
MishaShWoof Nov 11, 2025
3f9caef
fix: change base rpc
MishaShWoof Nov 12, 2025
68f6aab
fix: change rpc
MishaShWoof Nov 14, 2025
d2801ea
fix: replace ankr with quicknode
MishaShWoof Nov 17, 2025
b3ff0d3
Merge branch 'develop' of github.com:woof-software/comet into woof-so…
MishaShWoof Nov 19, 2025
640eaf1
Merge branch 'develop' of github.com:woof-software/comet into woof-so…
MishaShWoof Nov 20, 2025
001b60c
Merge branch 'main' of github.com:woof-software/comet into develop
MishaShWoof Nov 24, 2025
38a9d9e
fix: working tests
MishaShWoof Nov 24, 2025
525e5a8
fix: working forge test
MishaShWoof Nov 24, 2025
d73df39
Update run-forge-tests.yaml
MishaShWoof Nov 24, 2025
640d956
Update run-forge-tests.yaml
MishaShWoof Nov 24, 2025
9d1f576
Modified migration from GitHub Actions
Nov 26, 2025
49ac136
Update run-scenarios.yaml
MishaShWoof Nov 27, 2025
a16813a
fix: env in scenario
MishaShWoof Nov 27, 2025
0407aa6
fix: use different keys for etherscan
MishaShWoof Nov 27, 2025
1a368d4
fix: strict order
MishaShWoof Nov 27, 2025
a34434f
fix: pass the prepared state
MishaShWoof Nov 27, 2025
9d6c077
fix: remove matrix
MishaShWoof Nov 27, 2025
58ed478
fix: pass node modules
MishaShWoof Nov 27, 2025
0e67e92
fix: add contracts to cache before scenario run
MishaShWoof Nov 28, 2025
bc0871e
fix: cache path fix
MishaShWoof Nov 28, 2025
5f4fc6f
fix: use hidden files
MishaShWoof Nov 28, 2025
5a77147
fix: fuji
MishaShWoof Nov 28, 2025
b287ff2
feat: rotate apikeys and some arbitrum fixes
MishaShWoof Dec 2, 2025
ef20089
Modified migration from GitHub Actions
Dec 2, 2025
070fda2
Merge pull request #279 from woof-software/speed-up-scenarios
MishaShWoof Dec 3, 2025
98e6783
fix: working arbitrum scenarios
MishaShWoof Dec 3, 2025
b2b05a2
fix: teth symbol fix
MishaShWoof Dec 3, 2025
a0fdad7
fix: add debug for spider
MishaShWoof Dec 3, 2025
9d630c2
Merge branch 'woof-software/capo-for-base-weth' of github.com:woof-so…
MishaShWoof Dec 19, 2025
f7de48a
Merge branch 'woof-software/capo-for-base-aero' of github.com:woof-so…
MishaShWoof Dec 19, 2025
8074818
fix: working scenarios
MishaShWoof Dec 19, 2025
0744e59
feat: migration
MishaShWoof Dec 22, 2025
541c14c
fix: force deployment of price feeds
MishaShWoof Dec 22, 2025
7206981
Merge branch 'main' of github.com:woof-software/comet into woof-softw…
MishaShWoof Dec 22, 2025
0cf69cd
Merge branch 'main' of github.com:woof-software/comet into develop
MishaShWoof Dec 22, 2025
e7f8ce6
fix: ronin and forge test fixes
MishaShWoof Dec 22, 2025
3679114
fix: update price feed description
MishaShWoof Dec 23, 2025
b3456da
fix: working arbitrum scenarios
MishaShWoof Dec 24, 2025
20193ea
Merge branch 'develop' of github.com:woof-software/comet into woof-so…
MishaShWoof Jan 7, 2026
a0b54a9
fix
MishaShWoof Jan 7, 2026
179eccf
feat: update wsteth to svr
MishaShWoof Jan 21, 2026
03bd011
Modified migration from GitHub Actions
Jan 26, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { expect } from 'chai';
import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager';
import { migration } from '../../../../plugins/deployment_manager/Migration';
import { calldata, proposal } from '../../../../src/deploy';
import { utils } from 'ethers';
import { Numeric } from '../../../../test/helpers';
import { AggregatorV3Interface } from '../../../../build/types';

export function exp(i: number, d: Numeric = 0, r: Numeric = 6): bigint {
return (BigInt(Math.floor(i * 10 ** Number(r))) * 10n ** BigInt(d)) / 10n ** BigInt(r);
}

const ETH_USD_PRICE_FEED = '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70';

const WSTETH_ADDRESS = '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452';
const WSTETH_STETH_PRICE_FEED_ADDRESS = '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061';

const FEED_DECIMALS = 8;
const blockToFetch = 36000000;

let newWstETHPriceFeed: string;
let oldWstETHPriceFeed: string;

export default migration('1761125221_upgrade_to_capo_price_feeds', {
async prepare(deploymentManager: DeploymentManager) {
const { timelock } = await deploymentManager.getContracts();
const blockToFetchTimestamp = (await deploymentManager.hre.ethers.provider.getBlock(blockToFetch))!.timestamp;

//1. wstEth
const rateProviderWstEth = await deploymentManager.existing('wstEth:priceFeed', WSTETH_STETH_PRICE_FEED_ADDRESS, 'base', 'contracts/capo/contracts/interfaces/AggregatorV3Interface.sol:AggregatorV3Interface') as AggregatorV3Interface;
const [, currentRatioWstEth] = await rateProviderWstEth.latestRoundData({ blockTag: blockToFetch });

const wstEthCapoPriceFeed = await deploymentManager.deploy(
'wstETH:priceFeed',
'capo/contracts/ChainlinkCorrelatedAssetsPriceOracle.sol',
[
timelock.address,
ETH_USD_PRICE_FEED,
WSTETH_STETH_PRICE_FEED_ADDRESS,
'wstETH / USD CAPO Price Feed',
FEED_DECIMALS,
3600,
{
snapshotRatio: currentRatioWstEth,
snapshotTimestamp: blockToFetchTimestamp,
maxYearlyRatioGrowthPercent: exp(0.0404, 4)
}
],
true
);

return {
wstEthCapoPriceFeedAddress: wstEthCapoPriceFeed.address
};
},

async enact(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, {
wstEthCapoPriceFeedAddress
}) {
newWstETHPriceFeed = wstEthCapoPriceFeedAddress;

const trace = deploymentManager.tracer();

const {
configurator,
comet,
bridgeReceiver,
cometAdmin
} = await deploymentManager.getContracts();

const {
governor,
baseL1CrossDomainMessenger
} = await govDeploymentManager.getContracts();

const updateWstEthPriceFeedCalldata = await calldata(
configurator.populateTransaction.updateAssetPriceFeed(
comet.address,
WSTETH_ADDRESS,
wstEthCapoPriceFeedAddress
)
);

const deployAndUpgradeToCalldata = await calldata(
cometAdmin.populateTransaction.deployAndUpgradeTo(
configurator.address,
comet.address
)
);

const l2ProposalData = utils.defaultAbiCoder.encode(
['address[]', 'uint256[]', 'string[]', 'bytes[]'],
[
[configurator.address, cometAdmin.address],
[0, 0],
['updateAssetPriceFeed(address,address,address)', 'deployAndUpgradeTo(address,address)'],
[updateWstEthPriceFeedCalldata, deployAndUpgradeToCalldata],
]
);

[,, oldWstETHPriceFeed] = await comet.getAssetInfoByAddress(WSTETH_ADDRESS);

const mainnetActions = [
{
contract: baseL1CrossDomainMessenger,
signature: 'sendMessage(address,bytes,uint32)',
args: [
bridgeReceiver.address,
l2ProposalData,
3_000_000
]
},
];

const description = `# Update wstETH price feed in cAEROv3 on Base with CAPO implementation.

## Proposal summary

This proposal updates existing price feeds for wstETH on the AERO market on Base.

### CAPO summary

CAPO is a price oracle adapter designed to support assets that grow gradually relative to a base asset - such as liquid staking tokens that accumulate yield over time. It provides a mechanism to track this expected growth while protecting downstream protocol from sudden or manipulated price spikes. wstETH price feed is updated to their CAPO implementations.

Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1038) and [forum discussion for CAPO](https://www.comp.xyz/t/woof-correlated-assets-price-oracle-capo/6245).

### CAPO audit

CAPO has been audited by [OpenZeppelin](https://www.comp.xyz/t/capo-price-feed-audit/6631, as well as the LST / LRT implementation [here](https://www.comp.xyz/t/capo-lst-lrt-audit/7118).

## Proposal actions

The first action updates wstETH price feed to the CAPO implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base.
`;

const txn = await deploymentManager.retry(async () =>
trace(
await governor.propose(...(await proposal(mainnetActions, description)))
)
);
const event = txn.events.find(
(event: { event: string }) => event.event === 'ProposalCreated'
);
const [proposalId] = event.args;
trace(`Created proposal ${proposalId}.`);
},

async enacted(deploymentManager: DeploymentManager): Promise<boolean> {
return true;
},

async verify(deploymentManager: DeploymentManager) {
const { comet, configurator } = await deploymentManager.getContracts();

const wstETHIndexInComet = await configurator.getAssetIndex(comet.address, WSTETH_ADDRESS);

// Check if the price feeds are set correctly.
const wstETHInCometInfo = await comet.getAssetInfoByAddress(WSTETH_ADDRESS);
const wstETHInConfiguratorInfoWETHComet = (await configurator.getConfiguration(comet.address)).assetConfigs[wstETHIndexInComet];

expect(wstETHInCometInfo.priceFeed).to.eq(newWstETHPriceFeed);
expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newWstETHPriceFeed);
expect(await comet.getPrice(newWstETHPriceFeed)).to.equal(await comet.getPrice(oldWstETHPriceFeed));
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import { expect } from 'chai';
import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager';
import { migration } from '../../../../plugins/deployment_manager/Migration';
import { calldata, proposal } from '../../../../src/deploy';
import { utils } from 'ethers';

const WSTETH_USD_PRICE_FEED_ADDRESS = '0x1738FCAe8D5A6aEf39985dF31Fe60e5Dc5e1a7b3';
const WETH_TO_USD_SVR_PRICE_FEED_ADDRESS = '0x1428C9E908e32dD2839F99D63C242c91329A58C0';
const USDC_TO_USD_SVR_PRICE_FEED_ADDRESS = '0x1401Fd60F9ba4F718a2fE6149aadf3d1F0dB1b0A';

let newPriceFeedWETHAddress: string;
let newPriceFeedUSDCAddress: string;

let oldWETHPriceFeed: string;
let oldUSDCPriceFeed: string;
let oldWstETHPriceFeed: string;

export default migration('1766363631_change_price_feeds_to_svr', {
async prepare(deploymentManager: DeploymentManager) {
const _WETHPriceFeed = await deploymentManager.deploy(
'WETH:priceFeed',
'pricefeeds/ScalingPriceFeedWithCustomDescription.sol',
[
WETH_TO_USD_SVR_PRICE_FEED_ADDRESS, // WETH / USD price feed
8, // decimals
'ETH / USD SVR Price Feed' // custom description
],
true
);

const _USDCPriceFeed = await deploymentManager.deploy(
'USDC:priceFeed',
'pricefeeds/ScalingPriceFeedWithCustomDescription.sol',
[
USDC_TO_USD_SVR_PRICE_FEED_ADDRESS, // USDC / USD price feed
8, // decimals
'USDC / USD SVR Price Feed' // custom description
],
true
);

return {
WETHPriceFeedAddress: _WETHPriceFeed.address,
USDCPriceFeedAddress: _USDCPriceFeed.address
};
},

enact: async (
deploymentManager: DeploymentManager,
govDeploymentManager: DeploymentManager,
{
WETHPriceFeedAddress,
USDCPriceFeedAddress
}
) => {
const trace = deploymentManager.tracer();
newPriceFeedWETHAddress = WETHPriceFeedAddress;
newPriceFeedUSDCAddress = USDCPriceFeedAddress;

const {
bridgeReceiver,
comet,
cometAdmin,
configurator,
WETH,
wstETH,
USDC
} = await deploymentManager.getContracts();

const { governor, baseL1CrossDomainMessenger } = await govDeploymentManager.getContracts();

const updateWEthPriceFeedCalldata = await calldata(
configurator.populateTransaction.updateAssetPriceFeed(
comet.address,
WETH.address,
newPriceFeedWETHAddress
)
);

const updateUSDCPriceFeedCalldata = await calldata(
configurator.populateTransaction.updateAssetPriceFeed(
comet.address,
USDC.address,
newPriceFeedUSDCAddress
)
);

const updateWstETHPriceFeedCalldata = await calldata(
configurator.populateTransaction.updateAssetPriceFeed(
comet.address,
wstETH.address,
WSTETH_USD_PRICE_FEED_ADDRESS
)
);

const deployAndUpgradeToCalldata = await calldata(
cometAdmin.populateTransaction.deployAndUpgradeTo(
configurator.address,
comet.address
)
);

const l2ProposalData = utils.defaultAbiCoder.encode(
['address[]', 'uint256[]', 'string[]', 'bytes[]'],
[
[configurator.address, configurator.address, configurator.address, cometAdmin.address],
[0, 0, 0, 0],
['updateAssetPriceFeed(address,address,address)', 'updateAssetPriceFeed(address,address,address)', 'updateAssetPriceFeed(address,address,address)', 'deployAndUpgradeTo(address,address)'],
[updateWEthPriceFeedCalldata, updateUSDCPriceFeedCalldata, updateWstETHPriceFeedCalldata, deployAndUpgradeToCalldata],
]
);

[,, oldWETHPriceFeed] = await comet.getAssetInfoByAddress(WETH.address);
[,, oldUSDCPriceFeed] = await comet.getAssetInfoByAddress(USDC.address);
[,, oldWstETHPriceFeed] = await comet.getAssetInfoByAddress(wstETH.address);

const mainnetActions = [
{
contract: baseL1CrossDomainMessenger,
signature: 'sendMessage(address,bytes,uint32)',
args: [
bridgeReceiver.address,
l2ProposalData,
3_000_000
]
},
];

const description = `# Update WETH, USDC, and wstETH price feeds in cAEROv3 on Base with SVR price feeds

## Proposal summary

This proposal updates existing price feeds for WETH, USDC, and wstETH assets on the AERO market on Base.

### SVR summary

[RFP process](https://www.comp.xyz/t/oev-rfp-process-update-july-2025/6945) and community [vote](https://snapshot.box/#/s:comp-vote.eth/proposal/0xffd84200f112926e8b21793ee3750f272fc40a3f90399f86d41971a44aa3edf3) passed and decided to implement Chainlink's SVR solution for BASE markets, this proposal updates WETH and USDC price feeds to support SVR implementations.

Further detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/1073) and [forum discussion for SVR](https://www.comp.xyz/t/request-for-proposal-rfp-oracle-extractable-value-oev-solution-for-compound-protocol/6786).

### SVR fee recipient

SVR generates revenue from liquidators and Compound DAO will receive that revenue as part of the protocol fee. The fee recipient for SVR is set to Compound DAO multisig: 0xd9496F2A3fd2a97d8A4531D92742F3C8F53183cB.

## Proposal actions

The first action updates WETH, USDC, and wstETH price feeds to the SVR implementation. This sends the encoded 'updateAssetPriceFeed' and 'deployAndUpgradeTo' calls across the bridge to the governance receiver on Base.
`;
const txn = await govDeploymentManager.retry(async () =>
trace(
await governor.propose(...(await proposal(mainnetActions, description)))
), 0, 300_000
);

const event = txn.events.find(
(event: { event: string }) => event.event === 'ProposalCreated'
);
const [proposalId] = event.args;
trace(`Created proposal ${proposalId}.`);
},

async enacted(deploymentManager: DeploymentManager): Promise<boolean> {
return true;
},

async verify(deploymentManager: DeploymentManager) {
const {
comet,
configurator,
WETH,
USDC,
wstETH,
} = await deploymentManager.getContracts();

// 1. WETH
const WETHIndexInComet = await configurator.getAssetIndex(
comet.address,
WETH.address
);
const WETHInCometInfo = await comet.getAssetInfoByAddress(WETH.address);
const WETHInConfiguratorInfoWETHComet = (
await configurator.getConfiguration(comet.address)
).assetConfigs[WETHIndexInComet];

expect(WETHInCometInfo.priceFeed).to.eq(newPriceFeedWETHAddress);
expect(WETHInConfiguratorInfoWETHComet.priceFeed).to.eq(newPriceFeedWETHAddress);

expect(await comet.getPrice(newPriceFeedWETHAddress)).to.be.closeTo(await comet.getPrice(oldWETHPriceFeed), 5e8); // 5$

// 2. USDC
const USDCIndexInComet = await configurator.getAssetIndex(
comet.address,
USDC.address
);
const USDCInCometInfo = await comet.getAssetInfoByAddress(USDC.address);
const USDCInConfiguratorInfoWETHComet = (
await configurator.getConfiguration(comet.address)
).assetConfigs[USDCIndexInComet];

expect(USDCInCometInfo.priceFeed).to.eq(newPriceFeedUSDCAddress);
expect(USDCInConfiguratorInfoWETHComet.priceFeed).to.eq(newPriceFeedUSDCAddress);

expect(await comet.getPrice(newPriceFeedUSDCAddress)).to.be.closeTo(await comet.getPrice(oldUSDCPriceFeed), 1e8); // 1$

// 3. wstETH
const wstETHIndexInComet = await configurator.getAssetIndex(
comet.address,
wstETH.address
);
const wstETHInCometInfo = await comet.getAssetInfoByAddress(wstETH.address);
const wstETHInConfiguratorInfoWETHComet = (
await configurator.getConfiguration(comet.address)
).assetConfigs[wstETHIndexInComet];

expect(wstETHInCometInfo.priceFeed).to.eq(WSTETH_USD_PRICE_FEED_ADDRESS);
expect(wstETHInConfiguratorInfoWETHComet.priceFeed).to.eq(WSTETH_USD_PRICE_FEED_ADDRESS);

expect(await comet.getPrice(WSTETH_USD_PRICE_FEED_ADDRESS)).to.be.closeTo(await comet.getPrice(oldWstETHPriceFeed), 5e8); // 5$
},
});
Loading