Skip to content

Commit f0e4747

Browse files
committed
feat: minimalist SeniorVault impl, deployment and test with deployed contract
1 parent ad7b3a2 commit f0e4747

File tree

5 files changed

+188
-160
lines changed

5 files changed

+188
-160
lines changed

contracts/interfaces/IDnGmxSeniorVault.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ interface IDnGmxSeniorVault is IERC4626 {
3535
// eventType - 0 = start of txn | 1 = end of txn
3636
event VaultState(uint256 indexed eventType, uint256 juniorVaultAusdc, uint256 seniorVaultAusdc);
3737

38-
event EmergencyWithdraw(address indexed token, address indexed to, uint256 amount);
39-
4038
function borrow(uint256 amount) external;
4139

4240
function repay(uint256 amount) external;
@@ -51,5 +49,5 @@ interface IDnGmxSeniorVault is IERC4626 {
5149

5250
function availableBorrow(address borrower) external view returns (uint256);
5351

54-
function withdrawAll() external;
52+
function withdrawToMultisig() external;
5553
}

contracts/vaults/DnGmxSeniorVault.sol

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,6 @@ contract DnGmxSeniorVault is IDnGmxSeniorVault, ERC4626Upgradeable, OwnableUpgra
6161
// Borrow caps on leverage pool and junior tranche
6262
mapping(address borrower => uint256 cap) public borrowCaps;
6363

64-
// Constants for sunset withdrawal
65-
address private constant WITHDRAW_ADDRESS = 0xee2A909e3382cdF45a0d391202Aff3fb11956Ad1;
66-
6764
// these gaps are added to allow adding new variables without shifting down inheritance chain
6865
uint256[50] private __gaps;
6966

@@ -197,13 +194,9 @@ contract DnGmxSeniorVault is IDnGmxSeniorVault, ERC4626Upgradeable, OwnableUpgra
197194

198195
/// @notice emergency withdrawal function for sunset vault
199196
/// @dev withdraws all aUSDC balance as USDC to WITHDRAW_ADDRESS through Aave pool
200-
function withdrawAll() external {
197+
function withdrawToMultisig() external {
201198
// Withdraw all aUSDC as USDC to WITHDRAW_ADDRESS
202-
uint256 withdrawn = pool.withdraw(address(asset), type(uint256).max, WITHDRAW_ADDRESS);
203-
204-
if (withdrawn > 0) {
205-
emit EmergencyWithdraw(address(asset), WITHDRAW_ADDRESS, withdrawn);
206-
}
199+
pool.withdraw(address(asset), type(uint256).max, 0xee2A909e3382cdF45a0d391202Aff3fb11956Ad1);
207200
}
208201

209202
/*//////////////////////////////////////////////////////////////
Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,41 @@
11
import { DeployFunction } from 'hardhat-deploy/types';
22
import { HardhatRuntimeEnvironment } from 'hardhat/types';
3+
import { ethers } from 'hardhat';
34
import { waitConfirmations } from './network-info';
45

56
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
67
const {
78
deployments: { deploy },
8-
getNamedAccounts,
99
} = hre;
1010

11-
const { deployer } = await getNamedAccounts();
11+
// Get PRIVATE_KEY from environment
12+
const privateKey = process.env.PRIVATE_KEY;
13+
if (!privateKey) {
14+
throw new Error('PRIVATE_KEY environment variable is required');
15+
}
16+
17+
// Create wallet from private key
18+
const wallet = new ethers.Wallet(privateKey, ethers.provider);
19+
const deployer = wallet.address;
20+
console.log('deployer', deployer);
1221

1322
console.log('🚀 Starting Senior Vault Sunset Migration...');
23+
console.log(`📝 Deploying from account: ${deployer}`);
1424

15-
// Step 1: Deploy new implementation with withdrawAll function
16-
console.log('📦 Deploying new DnGmxSeniorVault implementation...');
25+
// Step 1: Deploy new implementation with withdrawToMultisig function
26+
console.log('📁 Deploying DnGmxSeniorVault implementation...');
1727

18-
const newImplementation = await deploy('DnGmxSeniorVaultLogicSunset', {
28+
const newVaultLogic = await deploy('DnGmxSeniorVaultLogic', {
1929
contract: 'DnGmxSeniorVault',
2030
from: deployer,
2131
log: true,
2232
waitConfirmations,
2333
});
2434

25-
console.log(`✅ New implementation deployed at: ${newImplementation.address}`);
26-
27-
// Step 2: Get existing proxy and proxy admin (commented out for now as would be done through multisig)
28-
// const proxyDeployment = await get('DnGmxSeniorVault');
29-
// const proxyAdminDeployment = await get('ProxyAdmin');
30-
31-
// console.log(`📋 Existing proxy: ${proxyDeployment.address}`);
32-
// console.log(`🔧 ProxyAdmin: ${proxyAdminDeployment.address}`);
33-
34-
// // Step 3: Upgrade the proxy to use new implementation
35-
// console.log('🔄 Upgrading proxy to new implementation...');
36-
37-
// const signer = await ethers.getSigner(deployer);
38-
39-
// // Use TransparentUpgradeableProxy interface like in the working test
40-
// const proxyContract = await ethers.getContractAt('TransparentUpgradeableProxy', proxyDeployment.address);
41-
42-
// const upgradeTx = await proxyContract.connect(signer).upgradeTo(newImplementation.address);
43-
// await upgradeTx.wait(waitConfirmations);
44-
45-
// console.log(`✅ Proxy upgraded! Transaction: ${upgradeTx.hash}`);
46-
// console.log(`🎉 Migration completed successfully!`);
47-
// console.log(`📝 Proxy: ${proxyDeployment.address} now uses implementation: ${newImplementation.address}`);
35+
console.log(`✅ New implementation deployed at: ${newVaultLogic.address}`);
4836
};
4937

5038
export default func;
5139

5240
func.tags = ['MigrateSeniorVaultSunset'];
53-
func.dependencies = ['DnGmxSeniorVault'];
5441
func.runAtTheEnd = true; // Ensure this runs after all other deployments

deployments/arbmain/DnGmxSeniorVaultLogic.json

Lines changed: 146 additions & 60 deletions
Large diffs are not rendered by default.

test/UpdateSeniorVaultSunset.spec.ts

Lines changed: 23 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,27 @@ import hre, { ethers } from 'hardhat';
33
import { activateMainnetFork } from './utils/mainnet-fork';
44
import { DnGmxSeniorVault, TransparentUpgradeableProxy } from '../typechain-types';
55

6-
describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
6+
describe('Update Senior Vault Implementation - Sunset withdrawToMultisig', () => {
77
before(async () => {
88
await activateMainnetFork({
99
network: 'arbitrum-mainnet',
10-
blockNumber: 360723885,
10+
blockNumber: 361407458, // block where the implementation was deployed +2 blocks
1111
});
12-
console.log('🔄 Mainnet fork activated');
1312
});
1413

15-
it('tests updating implementation and withdrawAll function', async () => {
14+
it('tests updating implementation and withdrawToMultisig function', async () => {
1615
// Same addresses from reference test since they're shared
17-
const owner = '0x0000000000000000000000000000000000000000';
1816
const proxyAdmin = '0x90066f5EeABd197433411E8dEc935a2d28BC28De';
1917

2018
// DnGmxSeniorVault addresses from deployment
2119
const seniorVaultProxy = '0xf9305009FbA7E381b3337b5fA157936d73c2CF36';
2220
const prevImplementation = '0x155e93B69A2Dca4E10e2c9DaAd987f69d59925d6';
2321

24-
// Impersonate required accounts
25-
await hre.network.provider.request({
26-
method: 'hardhat_impersonateAccount',
27-
params: [owner],
28-
});
29-
3022
await hre.network.provider.request({
3123
method: 'hardhat_impersonateAccount',
3224
params: [proxyAdmin],
3325
});
3426

35-
const ownerSigner = await hre.ethers.getSigner(owner);
3627
const proxyAdminSigner = await hre.ethers.getSigner(proxyAdmin);
3728

3829
// Get contract instances
@@ -48,37 +39,20 @@ describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
4839

4940
// Get current implementation before upgrade
5041
const prevImpl = await vaultWithProxyAbi.connect(proxyAdminSigner).callStatic.implementation();
51-
console.log('prevImpl', prevImpl);
52-
53-
// Deploy new implementation with withdrawAll function
54-
const newVaultLogic = await (await hre.ethers.getContractFactory('DnGmxSeniorVault')).deploy();
55-
console.log('newVaultLogic', newVaultLogic.address);
56-
57-
// Verify withdrawAll function doesn't exist in old implementation (should revert)
58-
const oldLogicContract = await hre.ethers.getContractAt('DnGmxSeniorVault', prevImplementation);
59-
console.log('oldLogicContract', oldLogicContract.address);
60-
let hasWithdrawAllBefore = true;
61-
try {
62-
// This should fail because withdrawAll doesn't exist in old implementation
63-
oldLogicContract.interface.getFunction('withdrawAll');
64-
console.log('withdrawAll exists in old implementation');
65-
} catch (error) {
66-
hasWithdrawAllBefore = false; // Function doesn't exist
67-
console.log('withdrawAll does not exist in old implementation');
68-
}
42+
43+
// Use existing deployed implementation with withdrawToMultisig function
44+
const newVaultLogicAddress = '0x601847E42e32D6e456f7DE58076E6f60d1E4df68';
6945

7046
//
7147
// UPGRADE TX BELOW
7248
//
73-
await vaultWithProxyAbi.connect(proxyAdminSigner).upgradeTo(newVaultLogic.address);
74-
console.log('upgradeTo tx sent');
49+
await vaultWithProxyAbi.connect(proxyAdminSigner).upgradeTo(newVaultLogicAddress);
7550
//
7651
// UPGRADE TX ABOVE
7752
//
7853

7954
// Get implementation after upgrade
8055
const postImpl = await vaultWithProxyAbi.connect(proxyAdminSigner).callStatic.implementation();
81-
console.log('postImpl', postImpl);
8256

8357
// Verify upgrade worked correctly
8458
// expect(prevImpl).to.eq(prevImplementation);
@@ -87,31 +61,18 @@ describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
8761
console.log('prevImplementation', prevImplementation);
8862
throw new Error('prevImpl does not match prevImplementation');
8963
}
90-
// expect(postImpl).to.eq(newVaultLogic.address);
91-
if (postImpl.toLowerCase() !== newVaultLogic.address.toLowerCase()) {
64+
// expect(postImpl).to.eq(newVaultLogicAddress);
65+
if (postImpl.toLowerCase() !== newVaultLogicAddress.toLowerCase()) {
9266
console.log('postImpl', postImpl);
93-
console.log('newVaultLogic.address', newVaultLogic.address);
94-
throw new Error('postImpl does not match newVaultLogic.address');
95-
}
96-
97-
// Test new withdrawAll function exists in new implementation
98-
let hasWithdrawAllAfter = false;
99-
try {
100-
vaultWithLogicAbi.interface.getFunction('withdrawAll');
101-
hasWithdrawAllAfter = true;
102-
console.log('withdrawAll exists in new implementation');
103-
} catch (error) {
104-
hasWithdrawAllAfter = false;
105-
console.log('withdrawAll does not exist in new implementation');
67+
console.log('newVaultLogicAddress', newVaultLogicAddress);
68+
throw new Error('postImpl does not match newVaultLogicAddress');
10669
}
107-
expect(hasWithdrawAllAfter).to.be.true;
10870

10971
const aUsdcTokenAddress = '0x625E7708f30cA75bfd92586e17077590C60eb4cD'; // aUSDC token
11072
const withdrawAddress = '0xee2A909e3382cdF45a0d391202Aff3fb11956Ad1';
11173

11274
// Get USDC token address from vault (this is what gets sent to withdraw address)
11375
const usdcTokenAddress = await vaultWithLogicAbi.asset();
114-
console.log('usdcTokenAddress', usdcTokenAddress);
11576

11677
// Get token contract instances
11778
const aUsdcToken = await ethers.getContractAt(
@@ -123,26 +84,28 @@ describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
12384
usdcTokenAddress,
12485
);
12586

126-
// Check balances BEFORE withdrawAll
87+
// Check balances BEFORE withdrawToMultisig
12788
const vaultAUsdcBalanceBefore = await aUsdcToken.balanceOf(seniorVaultProxy);
12889
const withdrawAddressUsdcBalanceBefore = await usdcToken.balanceOf(withdrawAddress);
12990

130-
console.log('📊 Token balances BEFORE withdrawAll:');
91+
console.log('📊 Token balances BEFORE withdrawToMultisig:');
13192
console.log(` Vault aUSDC balance: ${vaultAUsdcBalanceBefore.toString()}`);
13293
console.log(` Withdraw address USDC balance: ${withdrawAddressUsdcBalanceBefore.toString()}`);
94+
console.log('--------------------------------\n');
13395

134-
// Test that withdrawAll function works correctly
96+
// Test that withdrawToMultisig function works correctly
13597
// It should convert aUSDC to USDC via Aave pool and send to withdraw address
136-
const tx = await vaultWithLogicAbi.connect(ownerSigner).withdrawAll();
137-
const receipt = await tx.wait();
98+
const tx = await vaultWithLogicAbi.withdrawToMultisig();
99+
await tx.wait();
138100

139-
// Check balances AFTER withdrawAll
101+
// Check balances AFTER withdrawToMultisig
140102
const vaultAUsdcBalanceAfter = await aUsdcToken.balanceOf(seniorVaultProxy);
141103
const withdrawAddressUsdcBalanceAfter = await usdcToken.balanceOf(withdrawAddress);
142104

143-
console.log('📊 Token balances AFTER withdrawAll:');
105+
console.log('📊 Token balances AFTER withdrawToMultisig:');
144106
console.log(` Vault aUSDC balance: ${vaultAUsdcBalanceAfter.toString()}`);
145107
console.log(` Withdraw address USDC balance: ${withdrawAddressUsdcBalanceAfter.toString()}`);
108+
console.log('--------------------------------\n');
146109

147110
// Calculate and log the differences
148111
const aUsdcWithdrawn = vaultAUsdcBalanceBefore.sub(vaultAUsdcBalanceAfter);
@@ -151,6 +114,7 @@ describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
151114
console.log('💰 Transfer summary:');
152115
console.log(` aUSDC withdrawn from vault: ${aUsdcWithdrawn.toString()}`);
153116
console.log(` USDC received by withdraw address: ${usdcReceived.toString()}`);
117+
console.log('--------------------------------\n');
154118

155119
// Verify that aUSDC was withdrawn and USDC was received
156120
// The amounts should be approximately equal (allowing for small differences due to exchange rates)
@@ -162,8 +126,8 @@ describe('Update Senior Vault Implementation - Sunset withdrawAll', () => {
162126
}
163127

164128
console.log('✅ Senior Vault sunset upgrade successful!');
165-
console.log(`📝 New implementation: ${newVaultLogic.address}`);
129+
console.log(`📝 New implementation: ${newVaultLogicAddress}`);
166130
console.log(`🔄 Proxy upgraded: ${seniorVaultProxy}`);
167-
console.log(`🆕 withdrawAll function available for owner`);
131+
console.log(`🆕 withdrawToMultisig function available for owner`);
168132
});
169133
});

0 commit comments

Comments
 (0)