Skip to content

Commit

Permalink
[NES-255] make pUSD a ComponentToken (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
ungaro authored Dec 2, 2024
1 parent b36b3c7 commit 6cb9967
Show file tree
Hide file tree
Showing 22 changed files with 2,771 additions and 124 deletions.
41 changes: 0 additions & 41 deletions nest/script/DeployNestContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,37 +43,8 @@ contract DeployNestContracts is Script, Test {

function run() external {
vm.startBroadcast(NEST_ADMIN_ADDRESS);

// Deploy pUSD
/*
pUSD pUSDToken = new pUSD();
ERC1967Proxy pUSDProxy =
new ERC1967Proxy(address(pUSDToken), abi.encodeCall(pUSD.initialize, (VAULT_ADDRESS, NEST_ADMIN_ADDRESS)));
console2.log("pUSDProxy deployed to:", address(pUSDProxy));
*/
ERC1967Proxy pUSDProxy = ERC1967Proxy(payable(PUSD_ADDRESS));

// Deploy ConcreteComponentToken
/*
ConcreteComponentToken componentToken = new ConcreteComponentToken();
ERC1967Proxy componentTokenProxy = new ERC1967Proxy(
address(componentToken),
abi.encodeCall(
ComponentToken.initialize,
(
NEST_ADMIN_ADDRESS, // owner
"Banana", // name
"BAN", // symbol
IERC20(address(pUSDProxy)), // asset token
false, // async deposit
false // async redeem
)
)
);
console2.log("ComponentTokenProxy deployed to:", address(componentTokenProxy));
*/

// Deploy AggregateToken with both component tokens
AggregateToken aggregateToken = new AggregateToken();
AggregateTokenProxy aggregateTokenProxy = new AggregateTokenProxy(
address(aggregateToken),
Expand All @@ -91,18 +62,6 @@ contract DeployNestContracts is Script, Test {
);
console2.log("AggregateTokenProxy deployed to:", address(aggregateTokenProxy));

// Add new component tokens
// AggregateToken(address(aggregateTokenProxy)).addComponentToken(IComponentToken(address(pUSDProxy)));
// AggregateToken(address(aggregateTokenProxy)).addComponentToken(IComponentToken(address(componentTokenProxy)));

// Deploy NestStaking
/*
NestStaking nestStaking = new NestStaking();
NestStakingProxy nestStakingProxy =
new NestStakingProxy(address(nestStaking), abi.encodeCall(NestStaking.initialize, (NEST_ADMIN_ADDRESS)));
console2.log("NestStakingProxy deployed to:", address(nestStakingProxy));
*/

vm.stopBroadcast();
}

Expand Down
53 changes: 53 additions & 0 deletions nest/script/DeploypUSD.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Script } from "forge-std/Script.sol";
import { console2 } from "forge-std/console2.sol";

import { pUSDProxy } from "../src/proxy/pUSDProxy.sol";
import { pUSD } from "../src/token/pUSD.sol";

contract DeploypUSD is Script {

address private constant NEST_ADMIN_ADDRESS = 0xb015762405De8fD24d29A6e0799c12e0Ea81c1Ff;
address private constant USDC_ADDRESS = 0x401eCb1D350407f13ba348573E5630B83638E30D;
address private constant USDT_ADDRESS = 0x2413b8C79Ce60045882559f63d308aE3DFE0903d;

address private constant VAULT_TOKEN = 0xe644F07B1316f28a7F134998e021eA9f7135F351;
address private constant ATOMIC_QUEUE = 0x9fEcc2dFA8B64c27B42757B0B9F725fe881Ddb2a;
address private constant TELLER_ADDRESS = 0xE010B6fdcB0C1A8Bf00699d2002aD31B4bf20B86;
address private constant LENS_ADDRESS = 0x39e4A070c3af7Ea1Cc51377D6790ED09D761d274;
address private constant ACCOUNTANT_ADDRESS = 0x607e6E4dC179Bf754f88094C09d9ee9Af990482a;

function run() external {
vm.startBroadcast(NEST_ADMIN_ADDRESS);

// Deploy pUSD implementation
pUSD pUSDToken = new pUSD();
console2.log("pUSD implementation deployed to:", address(pUSDToken));

// Deploy pUSD proxy
ERC1967Proxy pUSDProxyContract = new ERC1967Proxy(
address(pUSDToken),
abi.encodeCall(
pUSD.initialize,
(
NEST_ADMIN_ADDRESS,
IERC20(USDC_ADDRESS),
IERC20(USDT_ADDRESS),
address(VAULT_TOKEN),
TELLER_ADDRESS,
ATOMIC_QUEUE,
LENS_ADDRESS,
ACCOUNTANT_ADDRESS
)
)
);
console2.log("pUSD proxy deployed to:", address(pUSDProxyContract));

vm.stopBroadcast();
}

}
31 changes: 31 additions & 0 deletions nest/script/UpgradeNestContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Test } from "forge-std/Test.sol";
import { console2 } from "forge-std/console2.sol";

import { AggregateToken } from "../src/AggregateToken.sol";

import { IComponentToken } from "../src/interfaces/IComponentToken.sol";
import { AggregateTokenProxy } from "../src/proxy/AggregateTokenProxy.sol";

contract UpgradeNestContracts is Script, Test {
Expand All @@ -15,18 +17,47 @@ contract UpgradeNestContracts is Script, Test {
UUPSUpgradeable private constant AGGREGATE_TOKEN_PROXY =
UUPSUpgradeable(payable(0x659619AEdf381c3739B0375082C2d61eC1fD8835));

// Add the component token addresses
address private constant ASSET_TOKEN = 0xF66DFD0A9304D3D6ba76Ac578c31C84Dc0bd4A00;

// LiquidContinuousMultiTokenVault
address private constant COMPONENT_TOKEN = 0x4B1fC984F324D2A0fDD5cD83925124b61175f5C6;

function test() public { }

function run() external {
vm.startBroadcast(NEST_ADMIN_ADDRESS);

// Deploy new implementation
AggregateToken newAggregateTokenImpl = new AggregateToken();
assertGt(address(newAggregateTokenImpl).code.length, 0, "AggregateToken should be deployed");
console2.log("New AggregateToken Implementation deployed to:", address(newAggregateTokenImpl));

// Upgrade to new implementation
AGGREGATE_TOKEN_PROXY.upgradeToAndCall(address(newAggregateTokenImpl), "");

// Get the upgraded contract instance
AggregateToken aggregateToken = AggregateToken(address(AGGREGATE_TOKEN_PROXY));

// Add component tokens if they're not already in the list
if (!aggregateToken.getComponentToken(IComponentToken(ASSET_TOKEN))) {
aggregateToken.addComponentToken(IComponentToken(ASSET_TOKEN));
console2.log("Added ASSET_TOKEN to component list");
}

if (!aggregateToken.getComponentToken(IComponentToken(COMPONENT_TOKEN))) {
aggregateToken.addComponentToken(IComponentToken(COMPONENT_TOKEN));
console2.log("Added SECOND_TOKEN to component list");
}

vm.stopBroadcast();

// Verify the component tokens are in the list
IComponentToken[] memory tokens = aggregateToken.getComponentTokenList();
console2.log("Number of component tokens:", tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
console2.log("Component token", i, ":", address(tokens[i]));
}
}

}
139 changes: 139 additions & 0 deletions nest/script/UpgradepUSD.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { ERC1967Utils } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";

import { Script } from "forge-std/Script.sol";
import { Test } from "forge-std/Test.sol";
import { console2 } from "forge-std/console2.sol";

import { pUSDProxy } from "../src/proxy/pUSDProxy.sol";
import { pUSD } from "../src/token/pUSD.sol";

import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";

contract UpgradePUSD is Script, Test {

// Constants
address private constant ADMIN_ADDRESS = 0xb015762405De8fD24d29A6e0799c12e0Ea81c1Ff;
address private constant PUSD_PROXY = 0x2DEc3B6AdFCCC094C31a2DCc83a43b5042220Ea2;
address private constant USDC_ADDRESS = 0x401eCb1D350407f13ba348573E5630B83638E30D;
address private constant USDT_ADDRESS = 0x2413b8C79Ce60045882559f63d308aE3DFE0903d;

address private constant VAULT_TOKEN = 0xe644F07B1316f28a7F134998e021eA9f7135F351;
address private constant ATOMIC_QUEUE = 0x9fEcc2dFA8B64c27B42757B0B9F725fe881Ddb2a;
address private constant TELLER_ADDRESS = 0xE010B6fdcB0C1A8Bf00699d2002aD31B4bf20B86;
address private constant LENS_ADDRESS = 0x39e4A070c3af7Ea1Cc51377D6790ED09D761d274;
address private constant ACCOUNTANT_ADDRESS = 0x607e6E4dC179Bf754f88094C09d9ee9Af990482a;

// Current state tracking
pUSD public currentImplementation;
string public currentName;
string public currentSymbol;
uint8 public currentDecimals;
address public currentVault;
uint256 public currentTotalSupply;
bool public isConnected;

function setUp() public {
// Try to read implementation slot from proxy, this only works with RPC
try vm.load(PUSD_PROXY, ERC1967Utils.IMPLEMENTATION_SLOT) returns (bytes32 implementation) {
if (implementation != bytes32(0)) {
address currentImplementationAddr = address(uint160(uint256(implementation)));
console2.log("Found implementation at:", currentImplementationAddr);
isConnected = true;

currentImplementation = pUSD(PUSD_PROXY);
currentName = currentImplementation.name();
currentSymbol = currentImplementation.symbol();
currentDecimals = currentImplementation.decimals();
currentTotalSupply = currentImplementation.totalSupply();

console2.log("Current Implementation State:");
console2.log("Name:", currentName);
console2.log("Symbol:", currentSymbol);
console2.log("Decimals:", currentDecimals);
console2.log("Vault:", currentVault);
console2.log("Total Supply:", currentTotalSupply);
} else {
vm.assume(true);
isConnected = false;
}
} catch {
console2.log("No implementation found - skipping");
vm.assume(true);
isConnected = false;
}
}

function testSimulateUpgrade() public {
// Deploy new implementation in test environment
if (!isConnected) {
vm.assume(true);
} else {
vm.startPrank(ADMIN_ADDRESS);

pUSD newImplementation = new pUSD();
UUPSUpgradeable(payable(PUSD_PROXY)).upgradeToAndCall(address(newImplementation), "");

pUSD upgradedToken = pUSD(PUSD_PROXY);

vm.stopPrank();
console2.log("Upgrade simulation successful");
}
}

function run() external {
if (!isConnected) {
vm.assume(true);
} else {
vm.startBroadcast(ADMIN_ADDRESS);

// Deploy new implementation
pUSD newImplementation = new pUSD();
console2.log("New Implementation Address:", address(newImplementation));

// Get current version
pUSD currentProxy = pUSD(PUSD_PROXY);
uint256 currentVersion = currentProxy.version();
console2.log("Current Version:", currentVersion);

// First upgrade the implementation
UUPSUpgradeable(payable(PUSD_PROXY)).upgradeToAndCall(
address(newImplementation),
"" // No initialization data for the upgrade
);

// Then call reinitialize separately
pUSD(PUSD_PROXY).reinitialize(
ADMIN_ADDRESS,
IERC20(USDC_ADDRESS),
IERC20(USDT_ADDRESS),
VAULT_TOKEN,
TELLER_ADDRESS,
ATOMIC_QUEUE,
LENS_ADDRESS,
ACCOUNTANT_ADDRESS
);

// Verify the upgrade
uint256 newVersion = pUSD(PUSD_PROXY).version();

pUSD upgradedToken = pUSD(PUSD_PROXY);

//require(newVersion == currentVersion + 1, "Version not incremented");
console2.log("Updated Implementation State:");
console2.log("Name:", upgradedToken.name());
console2.log("Symbol:", upgradedToken.symbol());
console2.log("Decimals:", upgradedToken.decimals());
console2.log("Vault:", currentVault);
console2.log("Total Supply:", upgradedToken.totalSupply());

console2.log("New Version:", newVersion);

vm.stopBroadcast();
}
}

}
13 changes: 9 additions & 4 deletions nest/src/ComponentToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { console } from "forge-std/console.sol";

import { IComponentToken } from "./interfaces/IComponentToken.sol";
import { IERC7540 } from "./interfaces/IERC7540.sol";
Expand Down Expand Up @@ -73,6 +74,8 @@ abstract contract ComponentToken is
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
/// @notice Role for the upgrader of the ComponentToken
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
/// @notice Base that is used to divide all price inputs in order to represent e.g. 1.000001 as 1000001e12
uint256 private constant _BASE = 1e18;

// Events

Expand Down Expand Up @@ -153,7 +156,7 @@ abstract contract ComponentToken is
IERC20 asset_,
bool asyncDeposit,
bool asyncRedeem
) public initializer {
) public onlyInitializing {
__ERC20_init(name, symbol);
__ERC4626_init(asset_);
__AccessControl_init();
Expand All @@ -177,7 +180,7 @@ abstract contract ComponentToken is
*/
function _authorizeUpgrade(
address newImplementation
) internal override(UUPSUpgradeable) onlyRole(UPGRADER_ROLE) { }
) internal virtual override(UUPSUpgradeable) onlyRole(UPGRADER_ROLE) { }

/// @inheritdoc IERC165
function supportsInterface(
Expand Down Expand Up @@ -513,7 +516,8 @@ abstract contract ComponentToken is
if (_getComponentTokenStorage().asyncDeposit) {
revert Unimplemented();
}
shares = super.previewDeposit(assets);
// Returns how many shares would be minted for given assets
return convertToShares(assets);
}

/**
Expand All @@ -539,7 +543,8 @@ abstract contract ComponentToken is
if (_getComponentTokenStorage().asyncRedeem) {
revert Unimplemented();
}
assets = super.previewRedeem(shares);
// Returns how many assets would be withdrawn for given shares
return convertToAssets(shares);
}

/**
Expand Down
Loading

0 comments on commit 6cb9967

Please sign in to comment.