Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NES-255] make pUSD a ComponentToken #97

Merged
merged 68 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
2131910
[NES-254] add adapter contract for pUSD
eyqs Nov 13, 2024
e415bc9
add vault for pUSD
ungaro Nov 13, 2024
51e5d53
remove incorrect include
ungaro Nov 13, 2024
9656816
keep pUSD as ERC20 and remove unnecessary functions
ungaro Nov 13, 2024
69467dd
remove comment
ungaro Nov 13, 2024
35ca154
fmt
ungaro Nov 13, 2024
c613ac9
remove hook
ungaro Nov 13, 2024
697c4f9
make pUSD a ComponentToken
ungaro Nov 13, 2024
03dcdd1
make pUSD a ComponentToken and update Deployment Script
ungaro Nov 13, 2024
2452ef9
change storage location
ungaro Nov 13, 2024
9fc98c6
remove erc4626
ungaro Nov 13, 2024
1636d22
update pUSD storage slot
ungaro Nov 13, 2024
300f1b4
pUSD is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UU…
ungaro Nov 13, 2024
9e4f883
merge main
ungaro Nov 13, 2024
00cd67b
fix overrides
ungaro Nov 13, 2024
270dd48
update description
ungaro Nov 13, 2024
5bc1b2f
add test for pUSD - WIP
ungaro Nov 13, 2024
1ce0e5a
add mockvault for pUSD
ungaro Nov 13, 2024
47cb601
change initialization modifier to onlyInitializing
ungaro Nov 14, 2024
f5773db
remove pausable
ungaro Nov 14, 2024
b00649d
finish preliminary tests, fix some bugs with MockVault and pUSD
ungaro Nov 14, 2024
013f0eb
93.9% coverage for pUSD - rest is just assembly
ungaro Nov 14, 2024
f034359
remove comments
ungaro Nov 14, 2024
5521e69
add IVault interface
ungaro Nov 14, 2024
2ab5bb8
forge fmt
ungaro Nov 14, 2024
4fdd93f
better handling of convertToShares, convertToAssets, make tests 100% …
ungaro Nov 14, 2024
030869c
forge fmt
ungaro Nov 14, 2024
ff2f659
add extra comment
ungaro Nov 14, 2024
93a2f34
add reentrancy check
ungaro Nov 14, 2024
269841d
implementing some audit findings & ComponentToken precision test checks
ungaro Nov 14, 2024
396cff3
leave conversion functions unimplemented and force integrators to imp…
ungaro Nov 14, 2024
d6537de
add NatSpec comments for functions
ungaro Nov 14, 2024
d5d2a61
remove componenttoken comments
ungaro Nov 14, 2024
999adcb
deployment script for pUSD
ungaro Nov 14, 2024
114516a
add pUSD contract update
ungaro Nov 15, 2024
5e1f0cf
add more tests from pUSD
ungaro Nov 18, 2024
354bc4d
forge install: solmate
ungaro Nov 18, 2024
9093df0
change vault to teller
ungaro Nov 18, 2024
5d827b6
change deploy&upgrade pUSD scripts, update componenttoken _authorizeU…
ungaro Nov 18, 2024
7ba1fe4
change deposit and redeem functions
ungaro Nov 19, 2024
9dae01f
final changes, tests etc.
ungaro Nov 19, 2024
3111677
confirm teller.deposit works, add working test-case on-chain (pUSDPlu…
ungaro Nov 20, 2024
e0f73a8
redeem works through AtomicRequest, change proxy comments
ungaro Nov 21, 2024
e2a9c25
add boringvault struct, change related deployment and upgrade address…
ungaro Nov 22, 2024
bb540e8
fix tests and deployment/upgrade scripts
ungaro Nov 22, 2024
38608c3
remove pUSD deployment from DeployNestContracts
ungaro Nov 22, 2024
200ac3d
remove setBeforeTransferHook from mockvault
ungaro Nov 22, 2024
1deb5b9
fix conflicts
ungaro Nov 22, 2024
bb8000c
fix conflict that doesn't exist
ungaro Nov 22, 2024
fc49f7c
100% coverage on pUSD + added missing mocks
ungaro Nov 22, 2024
72b82cd
add pragma to MockUSDC
ungaro Nov 22, 2024
d2a1785
run everything without errors even RPC address is not provided for on…
ungaro Nov 25, 2024
db3516c
change balanceof to return vault's balance
ungaro Nov 25, 2024
0a0a9a8
change balanceOf, previewDeposit and previewRedeem functions
ungaro Nov 25, 2024
761855b
add decimals to interface
ungaro Nov 27, 2024
c270097
passing tests
ungaro Nov 29, 2024
0ea586a
add usdc & usdt, update deploy scripts, add missing tests
ungaro Dec 1, 2024
fcb7a30
forge fmt
ungaro Dec 1, 2024
d85a529
add IAccountantWithRateProviders, IRateProvider, Ilens and mock contr…
ungaro Dec 1, 2024
e152ec0
add lens and accountant
ungaro Dec 1, 2024
34b4546
balanceof and balanceofinassets
ungaro Dec 1, 2024
e8cbe26
all tests pass
ungaro Dec 1, 2024
145244a
100% coverage for pUSD, real calculations for converttoshares, conver…
ungaro Dec 1, 2024
4ed12dc
add nonreentrant
ungaro Dec 1, 2024
723a392
add assetsof
ungaro Dec 1, 2024
ee714c1
balanceOfInAssets to be renamed assetsof
ungaro Dec 1, 2024
8ae47f0
merge main
ungaro Dec 1, 2024
869fd2f
formatting
ungaro Dec 1, 2024
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
41 changes: 0 additions & 41 deletions nest/script/DeployNestContracts.s.sol
ungaro marked this conversation as resolved.
Show resolved Hide resolved
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;
ungaro marked this conversation as resolved.
Show resolved Hide resolved

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(
ungaro marked this conversation as resolved.
Show resolved Hide resolved
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");
ungaro marked this conversation as resolved.
Show resolved Hide resolved
}

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);
ungaro marked this conversation as resolved.
Show resolved Hide resolved
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");
ungaro marked this conversation as resolved.
Show resolved Hide resolved
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();
}
}

}
17 changes: 12 additions & 5 deletions nest/src/ComponentToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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";
ungaro marked this conversation as resolved.
Show resolved Hide resolved

import { IComponentToken } from "./interfaces/IComponentToken.sol";
import { IERC7540 } from "./interfaces/IERC7540.sol";
Expand Down Expand Up @@ -70,6 +71,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;
eyqs marked this conversation as resolved.
Show resolved Hide resolved

// Events

Expand Down Expand Up @@ -150,7 +153,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 @@ -173,7 +176,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 @@ -209,7 +212,9 @@ abstract contract ComponentToken is
/// @dev Reverts with Unimplemented() until convertToAssets is implemented by the concrete contract
/// @param owner Address to query the balance of
/// @return assets Total value held by the owner
function assetsOf(address owner) public view virtual returns (uint256 assets) {
function assetsOf(
address owner
) public view virtual returns (uint256 assets) {
return convertToAssets(balanceOf(owner));
}

Expand Down Expand Up @@ -499,7 +504,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 @@ -525,7 +531,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