Skip to content

Commit a9676f4

Browse files
authored
Hardhat tasks (#2234)
* Added bulk Hardhat tasks exitValidators and removeValidators * Added base support for vault hardhat tasks * Added manuallyFixAccounting hardhat task (#2229) Added simulation Hardhat tasks deployForceEtherSender and forceSend * manuallyFixAccounting now supports using scaled up amounts Added mine Hardhat task * Added snapAero Hardhat task * Added strategy's tick positions * More data to snapAero HH task * Prettier * Added missing blockTag params * review comments * prettier
1 parent 8163e3a commit a9676f4

File tree

9 files changed

+503
-13
lines changed

9 files changed

+503
-13
lines changed

contracts/contracts/interfaces/aerodrome/ICLPool.sol

+30
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,34 @@ interface ICLPool {
3535
/// @dev This value has no relationship to the total liquidity across all ticks
3636
/// @dev This value includes staked liquidity
3737
function liquidity() external view returns (uint128);
38+
39+
/// @notice Look up information about a specific tick in the pool
40+
/// @param tick The tick to look up
41+
/// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
42+
/// tick upper,
43+
/// liquidityNet how much liquidity changes when the pool price crosses the tick,
44+
/// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
45+
/// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
46+
/// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
47+
/// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from
48+
/// the current tick,
49+
/// secondsOutside the seconds spent on the other side of the tick from the current tick,
50+
/// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise
51+
/// equal to false.
52+
/// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
53+
/// In addition, these values are only relative and must be used only in comparison to previous snapshots for
54+
/// a specific position.
55+
function ticks(int24 tick)
56+
external
57+
view
58+
returns (
59+
uint128 liquidityGross,
60+
int128 liquidityNet,
61+
uint256 feeGrowthOutside0X128,
62+
uint256 feeGrowthOutside1X128,
63+
int56 tickCumulativeOutside,
64+
uint160 secondsPerLiquidityOutsideX128,
65+
uint32 secondsOutside,
66+
bool initialized
67+
);
3868
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
contract ForceEtherSender {
5+
// Constructor to optionally receive Ether upon deployment
6+
constructor() payable {}
7+
8+
// Function to allow the contract to receive Ether
9+
receive() external payable {}
10+
11+
// Function to self-destruct and force-send Ether to an address
12+
function forceSend(address payable recipient) external {
13+
// Requires that the contract has a balance greater than 0
14+
require(address(this).balance > 0, "No Ether to send");
15+
16+
// selfdestruct sends all Ether held by the contract to the recipient
17+
selfdestruct(recipient);
18+
}
19+
}

contracts/tasks/aero.js

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
const { formatUnits } = require("ethers").utils;
2+
const { BigNumber } = require("ethers");
3+
const { getBlock } = require("./block");
4+
const { resolveAsset, resolveContract } = require("../utils/resolvers");
5+
const { getSigner } = require("../utils/signers");
6+
const { base } = require("../utils/addresses");
7+
8+
const snapAero = async ({ block }) => {
9+
const signer = await getSigner();
10+
const blockTag = await getBlock(block);
11+
12+
const weth = await resolveAsset("WETH");
13+
const vault = await resolveContract("OETHBaseVaultProxy", "IVault");
14+
const oeth = await resolveContract("OETHBaseProxy", "OETHBase");
15+
const pool = await resolveContract(base.aerodromeOETHbWETHClPool, "ICLPool");
16+
const aeroStrat = await resolveContract(
17+
`AerodromeAMOStrategyProxy`,
18+
"AerodromeAMOStrategy"
19+
);
20+
const sugarHelper = await resolveContract(base.sugarHelper, "ISugarHelper");
21+
22+
const Q96 = BigNumber.from(2).pow(96);
23+
const sqrtRatioX96TickLower = await aeroStrat
24+
.connect(signer)
25+
.sqrtRatioX96TickLower({ blockTag });
26+
const sqrtRatioX96TickHigher = await aeroStrat
27+
.connect(signer)
28+
.sqrtRatioX96TickHigher({ blockTag });
29+
const lowerTick = await aeroStrat.connect(signer).lowerTick({ blockTag });
30+
31+
const { tick, sqrtPriceX96 } = await pool.connect(signer).slot0({ blockTag });
32+
const { liquidityGross } = await pool
33+
.connect(signer)
34+
.ticks(lowerTick, { blockTag });
35+
const { amount0: tickWethBalance, amount1: tickOethBalance } =
36+
await sugarHelper
37+
.connect(signer)
38+
.getAmountsForLiquidity(
39+
sqrtPriceX96,
40+
sqrtRatioX96TickLower,
41+
sqrtRatioX96TickHigher,
42+
liquidityGross,
43+
{ blockTag }
44+
);
45+
46+
// Pool balances
47+
const poolPrice = sqrtPriceX96
48+
.mul(sqrtPriceX96)
49+
.mul(10000000000)
50+
.div(Q96)
51+
.div(Q96);
52+
const poolWethBalance = await weth
53+
.connect(signer)
54+
.balanceOf(base.aerodromeOETHbWETHClPool, { blockTag });
55+
const poolOethBalance = await oeth
56+
.connect(signer)
57+
.balanceOf(base.aerodromeOETHbWETHClPool, { blockTag });
58+
const poolTotal = poolWethBalance.add(poolOethBalance);
59+
const poolWethPercentage = poolWethBalance.mul(10000).div(poolTotal);
60+
const poolOethPercentage = poolOethBalance.mul(10000).div(poolTotal);
61+
62+
// Tick balances
63+
const tickTotal = tickWethBalance.add(tickOethBalance);
64+
const tickWethPercentage = tickWethBalance.mul(10000).div(tickTotal);
65+
const tickOethPercentage = tickOethBalance.mul(10000).div(tickTotal);
66+
const tickTotalPercentage = tickTotal.mul(10000).div(poolTotal);
67+
68+
// Strategy's tick position
69+
const {
70+
_amountWeth: tickStratWethBalance,
71+
_amountOethb: tickStratOethBalance,
72+
} = await aeroStrat.getPositionPrincipal();
73+
const tickStratTotal = tickStratWethBalance.add(tickStratOethBalance);
74+
const tickStratWethPercentage = tickStratWethBalance
75+
.mul(10000)
76+
.div(tickStratTotal);
77+
const tickStratOethPercentage = tickStratOethBalance
78+
.mul(10000)
79+
.div(tickStratTotal);
80+
const tickStratTotalOfTickPercentage = tickStratTotal
81+
.mul(10000)
82+
.div(tickTotal);
83+
const tickStratTotalOfPoolPercentage = tickStratTotal
84+
.mul(10000)
85+
.div(poolTotal);
86+
87+
const checkBalance = await aeroStrat
88+
.connect(signer)
89+
.checkBalance(weth.address, { blockTag });
90+
91+
const vaultWethBalance = await weth
92+
.connect(signer)
93+
.balanceOf(vault.address, { blockTag });
94+
95+
// Pool balances
96+
console.log(
97+
`Pool price : ${formatUnits(poolPrice, 10)} OETHb/WETH, ${tick} tick`
98+
);
99+
console.log(
100+
`Pool WETH : ${formatUnits(poolWethBalance)} (${formatUnits(
101+
poolWethPercentage,
102+
2
103+
)}%), ${poolWethBalance} wei (includes unclaimed WETH)`
104+
);
105+
console.log(
106+
`Pool OETH : ${formatUnits(poolOethBalance)} (${formatUnits(
107+
poolOethPercentage,
108+
2
109+
)}%), ${poolOethBalance} wei`
110+
);
111+
console.log(`Pool total : ${formatUnits(poolTotal)}`);
112+
113+
// Tick balances
114+
console.log(
115+
`\nTick WETH : ${formatUnits(tickWethBalance)} (${formatUnits(
116+
tickWethPercentage,
117+
2
118+
)}%), ${tickWethBalance} wei`
119+
);
120+
console.log(
121+
`Tick OETH : ${formatUnits(tickOethBalance)} (${formatUnits(
122+
tickOethPercentage,
123+
2
124+
)}%), ${tickOethBalance} wei`
125+
);
126+
console.log(
127+
`Tick total : ${formatUnits(tickStratTotal)} ${formatUnits(
128+
tickTotalPercentage,
129+
2
130+
)}% of pool`
131+
);
132+
133+
// Strategy's tick position
134+
console.log(
135+
`\nTick strat WETH : ${formatUnits(tickStratWethBalance)} (${formatUnits(
136+
tickStratWethPercentage,
137+
2
138+
)}%), ${poolWethBalance} wei`
139+
);
140+
console.log(
141+
`Tick strat OETH : ${formatUnits(tickStratOethBalance)} (${formatUnits(
142+
tickStratOethPercentage,
143+
2
144+
)}%), ${poolOethBalance} wei`
145+
);
146+
console.log(
147+
`Tick strat total : ${formatUnits(tickStratTotal)} ${formatUnits(
148+
tickStratTotalOfTickPercentage,
149+
2
150+
)}% of tick, ${formatUnits(tickStratTotalOfPoolPercentage, 2)}% of pool`
151+
);
152+
153+
console.log(
154+
`\nStrategy balance : ${formatUnits(
155+
checkBalance
156+
)} ether, ${checkBalance} wei`
157+
);
158+
console.log(
159+
`Vault WETH : ${formatUnits(
160+
vaultWethBalance
161+
)}, ${vaultWethBalance} wei`
162+
);
163+
};
164+
165+
module.exports = {
166+
snapAero,
167+
};

contracts/tasks/block.js

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { mine } = require("@nomicfoundation/hardhat-network-helpers");
2+
13
const log = require("../utils/logger")("task:block");
24

35
async function getBlock(block) {
@@ -26,7 +28,13 @@ async function getDiffBlocks(taskArguments) {
2628
};
2729
}
2830

31+
async function advanceBlocks(blocks) {
32+
log(`Advancing ${blocks} blocks`);
33+
await mine(blocks);
34+
}
35+
2936
module.exports = {
37+
advanceBlocks,
3038
getBlock,
3139
getDiffBlocks,
3240
};

contracts/tasks/simulation.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const { formatUnits } = require("ethers").utils;
2+
const { getSigner } = require("../utils/signers");
3+
const { logTxDetails } = require("../utils/txLogger");
4+
5+
const log = require("../utils/logger")("task:simulation");
6+
7+
const deployForceEtherSender = async () => {
8+
const signer = await getSigner();
9+
10+
log(`About to deploy the ForceEtherSender contract`);
11+
12+
// Get the contract factory
13+
const ForceEtherSenderFactory = await ethers.getContractFactory(
14+
"ForceEtherSender",
15+
signer
16+
);
17+
18+
// Deploy the contract with an initial message
19+
const forceEtherSender = await ForceEtherSenderFactory.deploy();
20+
21+
// Wait for the contract to be deployed
22+
await forceEtherSender.deployed();
23+
24+
log("ForceEtherSender contract deployed to:", forceEtherSender.address);
25+
};
26+
27+
const forceSend = async ({ sender, recipient }) => {
28+
const signer = await getSigner();
29+
const balance = await ethers.provider.getBalance(sender);
30+
log(`About to forceSend ${formatUnits(balance)} ETH to ${recipient}`);
31+
32+
const forceEtherSender = await ethers.getContractAt(
33+
"ForceEtherSender",
34+
sender
35+
);
36+
const tx = await forceEtherSender.connect(signer).forceSend(recipient);
37+
await logTxDetails(tx, "forceSend");
38+
};
39+
40+
module.exports = {
41+
deployForceEtherSender,
42+
forceSend,
43+
};

0 commit comments

Comments
 (0)