From a9c8e445e6f197be77303e0b7187b22f65ece247 Mon Sep 17 00:00:00 2001 From: "Eugene Y. Q. Shen" Date: Mon, 23 Sep 2024 07:12:47 -0700 Subject: [PATCH] [NES-218] update smart contracts to use interfaces (#26) --- README.md | 1 + nest/script/DeployNestContracts.s.sol | 11 ++++---- nest/src/AggregateToken.sol | 28 +++++++++---------- nest/src/FakeComponentToken.sol | 20 ++++++------- nest/src/NestStaking.sol | 8 +++--- p/src/P.sol | 3 -- plume/script/DeployDevnetContracts.s.sol | 1 - smart-wallets/src/SmartWallet.sol | 24 ++++++++++------ smart-wallets/src/WalletFactory.sol | 8 +++--- smart-wallets/src/WalletProxy.sol | 4 +-- smart-wallets/src/WalletUtils.sol | 11 ++++---- smart-wallets/src/extensions/AssetVault.sol | 8 +++--- .../src/extensions/SignedOperations.sol | 2 +- smart-wallets/src/interfaces/ISmartWallet.sol | 10 +++---- .../interfaces/IYieldDistributionToken.sol | 5 ++-- .../src/interfaces/IYieldReceiver.sol | 4 +-- smart-wallets/src/token/AssetToken.sol | 2 +- .../src/token/YieldDistributionToken.sol | 9 +++--- smart-wallets/src/token/YieldToken.sol | 8 +++--- 19 files changed, 81 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 729d076..63f7f68 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # contracts + Monorepo for all Plume contracts diff --git a/nest/script/DeployNestContracts.s.sol b/nest/script/DeployNestContracts.s.sol index b8239da..29530b9 100644 --- a/nest/script/DeployNestContracts.s.sol +++ b/nest/script/DeployNestContracts.s.sol @@ -3,11 +3,10 @@ pragma solidity ^0.8.25; import "forge-std/Script.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - import { AggregateToken } from "../src/AggregateToken.sol"; import { FakeComponentToken } from "../src/FakeComponentToken.sol"; import { NestStaking } from "../src/NestStaking.sol"; +import { IComponentToken } from "../src/interfaces/IComponentToken.sol"; import { AggregateTokenProxy } from "../src/proxy/AggregateTokenProxy.sol"; import { FakeComponentTokenProxy } from "../src/proxy/FakeComponentTokenProxy.sol"; import { NestStakingProxy } from "../src/proxy/NestStakingProxy.sol"; @@ -21,12 +20,12 @@ contract DeployNestContracts is Script { function run() external { vm.startBroadcast(ARC_ADMIN_ADDRESS); + IComponentToken currencyToken = IComponentToken(USDC_ADDRESS); + FakeComponentToken fakeComponentToken = new FakeComponentToken(); FakeComponentTokenProxy fakeComponentTokenProxy = new FakeComponentTokenProxy( address(fakeComponentToken), - abi.encodeCall( - FakeComponentToken.initialize, (ARC_ADMIN_ADDRESS, "Banana", "BAN", IERC20(USDC_ADDRESS), 18) - ) + abi.encodeCall(FakeComponentToken.initialize, (ARC_ADMIN_ADDRESS, "Banana", "BAN", currencyToken, 18)) ); console.log("FakeComponentTokenProxy deployed to:", address(fakeComponentTokenProxy)); @@ -39,7 +38,7 @@ contract DeployNestContracts is Script { NEST_ADMIN_ADDRESS, "Apple", "AAPL", - USDC_ADDRESS, + currencyToken, 18, 15e17, 12e17, diff --git a/nest/src/AggregateToken.sol b/nest/src/AggregateToken.sol index bc16d18..c5972e7 100644 --- a/nest/src/AggregateToken.sol +++ b/nest/src/AggregateToken.sol @@ -184,7 +184,7 @@ contract AggregateToken is * @param owner Address of the owner of the AggregateToken * @param name Name of the AggregateToken * @param symbol Symbol of the AggregateToken - * @param currencyAddress Address of the CurrencyToken used to mint and burn the AggregateToken + * @param currencyToken CurrencyToken used to mint and burn the AggregateToken * @param decimals_ Number of decimals of the AggregateToken * @param askPrice Price at which users can buy the AggregateToken using CurrencyToken, times the base * @param bidPrice Price at which users can sell the AggregateToken to receive CurrencyToken, times the base @@ -194,7 +194,7 @@ contract AggregateToken is address owner, string memory name, string memory symbol, - address currencyAddress, + IComponentToken currencyToken, uint8 decimals_, uint256 askPrice, uint256 bidPrice, @@ -208,9 +208,9 @@ contract AggregateToken is _grantRole(UPGRADER_ROLE, owner); AggregateTokenStorage storage $ = _getAggregateTokenStorage(); - $.componentTokenList.push(IComponentToken(currencyAddress)); - $.componentTokenMap[IComponentToken(currencyAddress)] = true; - $.currencyToken = IERC20(currencyAddress); + $.componentTokenList.push(currencyToken); + $.componentTokenMap[currencyToken] = true; + $.currencyToken = IERC20(currencyToken); $.decimals = decimals_; $.askPrice = askPrice; $.bidPrice = bidPrice; @@ -235,16 +235,15 @@ contract AggregateToken is /** * @notice Buy AggregateToken using CurrencyToken * @dev The user must approve the contract to spend the CurrencyToken - * @param currencyToken_ CurrencyToken used to buy the AggregateToken + * @param currencyToken CurrencyToken used to buy the AggregateToken * @param currencyTokenAmount Amount of CurrencyToken to pay for the AggregateToken * @return aggregateTokenAmount Amount of AggregateToken received */ - function buy(IERC20 currencyToken_, uint256 currencyTokenAmount) public returns (uint256 aggregateTokenAmount) { + function buy(IERC20 currencyToken, uint256 currencyTokenAmount) public returns (uint256 aggregateTokenAmount) { AggregateTokenStorage storage $ = _getAggregateTokenStorage(); - IERC20 currencyToken = $.currencyToken; - if (currencyToken_ != currencyToken) { - revert InvalidCurrencyToken(currencyToken_, currencyToken); + if (currencyToken != $.currencyToken) { + revert InvalidCurrencyToken(currencyToken, $.currencyToken); } if (!currencyToken.transferFrom(msg.sender, address(this), currencyTokenAmount)) { revert UserCurrencyTokenInsufficientBalance(currencyToken, msg.sender, currencyTokenAmount); @@ -259,16 +258,15 @@ contract AggregateToken is /** * @notice Sell AggregateToken to receive CurrencyToken - * @param currencyToken_ CurrencyToken received in exchange for the AggregateToken + * @param currencyToken CurrencyToken received in exchange for the AggregateToken * @param currencyTokenAmount Amount of CurrencyToken to receive in exchange for the AggregateToken * @return aggregateTokenAmount Amount of AggregateToken sold */ - function sell(IERC20 currencyToken_, uint256 currencyTokenAmount) public returns (uint256 aggregateTokenAmount) { + function sell(IERC20 currencyToken, uint256 currencyTokenAmount) public returns (uint256 aggregateTokenAmount) { AggregateTokenStorage storage $ = _getAggregateTokenStorage(); - IERC20 currencyToken = $.currencyToken; - if (currencyToken_ != currencyToken) { - revert InvalidCurrencyToken(currencyToken_, currencyToken); + if (currencyToken != $.currencyToken) { + revert InvalidCurrencyToken(currencyToken, $.currencyToken); } if (!currencyToken.transfer(msg.sender, currencyTokenAmount)) { revert CurrencyTokenInsufficientBalance(currencyToken, currencyTokenAmount); diff --git a/nest/src/FakeComponentToken.sol b/nest/src/FakeComponentToken.sol index b22a0b3..c9b017a 100644 --- a/nest/src/FakeComponentToken.sol +++ b/nest/src/FakeComponentToken.sol @@ -151,15 +151,13 @@ contract FakeComponentToken is /** * @notice Buy FakeComponentToken using CurrencyToken * @dev The user must approve the contract to spend the CurrencyToken - * @param currencyToken_ CurrencyToken used to buy the FakeComponentToken + * @param currencyToken CurrencyToken used to buy the FakeComponentToken * @param amount Amount of CurrencyToken to pay to receive the same amount of FakeComponentToken * @return componentTokenAmount Amount of FakeComponentToken received */ - function buy(IERC20 currencyToken_, uint256 amount) public returns (uint256 componentTokenAmount) { - IERC20 currencyToken = _getFakeComponentTokenStorage().currencyToken; - - if (currencyToken_ != currencyToken) { - revert InvalidCurrencyToken(currencyToken_, currencyToken); + function buy(IERC20 currencyToken, uint256 amount) public returns (uint256 componentTokenAmount) { + if (currencyToken != _getFakeComponentTokenStorage().currencyToken) { + revert InvalidCurrencyToken(currencyToken, _getFakeComponentTokenStorage().currencyToken); } if (!currencyToken.transferFrom(msg.sender, address(this), amount)) { revert UserCurrencyTokenInsufficientBalance(currencyToken, msg.sender, amount); @@ -172,15 +170,13 @@ contract FakeComponentToken is /** * @notice Sell FakeComponentToken to receive CurrencyToken - * @param currencyToken_ CurrencyToken received in exchange for the FakeComponentToken + * @param currencyToken CurrencyToken received in exchange for the FakeComponentToken * @param amount Amount of CurrencyToken to receive in exchange for the FakeComponentToken * @return componentTokenAmount Amount of FakeComponentToken sold */ - function sell(IERC20 currencyToken_, uint256 amount) public returns (uint256 componentTokenAmount) { - IERC20 currencyToken = _getFakeComponentTokenStorage().currencyToken; - - if (currencyToken_ != currencyToken) { - revert InvalidCurrencyToken(currencyToken_, currencyToken); + function sell(IERC20 currencyToken, uint256 amount) public returns (uint256 componentTokenAmount) { + if (currencyToken != _getFakeComponentTokenStorage().currencyToken) { + revert InvalidCurrencyToken(currencyToken, _getFakeComponentTokenStorage().currencyToken); } if (!currencyToken.transfer(msg.sender, amount)) { revert CurrencyTokenInsufficientBalance(currencyToken, amount); diff --git a/nest/src/NestStaking.sol b/nest/src/NestStaking.sol index bd403c9..babd5fc 100644 --- a/nest/src/NestStaking.sol +++ b/nest/src/NestStaking.sol @@ -7,6 +7,7 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils import { AggregateToken } from "./AggregateToken.sol"; import { IAggregateToken } from "./interfaces/IAggregateToken.sol"; +import { IComponentToken } from "./interfaces/IAggregateToken.sol"; import { AggregateTokenProxy } from "./proxy/AggregateTokenProxy.sol"; /** @@ -152,7 +153,7 @@ contract NestStaking is Initializable, AccessControlUpgradeable, UUPSUpgradeable * @param owner Address of the owner of the AggregateToken * @param name Name of the AggregateToken * @param symbol Symbol of the AggregateToken - * @param currencyAddress Address of the CurrencyToken used to mint and burn the AggregateToken + * @param currencyToken CurrencyToken used to mint and burn the AggregateToken * @param decimals_ Number of decimals of the AggregateToken * @param askPrice Price at which users can buy the AggregateToken using CurrencyToken, times the base * @param bidPrice Price at which users can sell the AggregateToken to receive CurrencyToken, times the base @@ -163,7 +164,7 @@ contract NestStaking is Initializable, AccessControlUpgradeable, UUPSUpgradeable address owner, string memory name, string memory symbol, - address currencyAddress, + IComponentToken currencyToken, uint8 decimals_, uint256 askPrice, uint256 bidPrice, @@ -175,8 +176,7 @@ contract NestStaking is Initializable, AccessControlUpgradeable, UUPSUpgradeable AggregateTokenProxy aggregateTokenProxy = new AggregateTokenProxy( address(aggregateTokenImplementation), abi.encodeCall( - AggregateToken.initialize, - (owner, name, symbol, currencyAddress, decimals_, askPrice, bidPrice, tokenURI) + AggregateToken.initialize, (owner, name, symbol, currencyToken, decimals_, askPrice, bidPrice, tokenURI) ) ); diff --git a/p/src/P.sol b/p/src/P.sol index 5646801..5d36376 100644 --- a/p/src/P.sol +++ b/p/src/P.sol @@ -29,8 +29,6 @@ contract P is // Constants - /// @notice Role for the admin of P - bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); /// @notice Role for the upgrader of P bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); /// @notice Role for the minter of P @@ -64,7 +62,6 @@ contract P is __UUPSUpgradeable_init(); _grantRole(DEFAULT_ADMIN_ROLE, owner); - _grantRole(ADMIN_ROLE, owner); _grantRole(MINTER_ROLE, owner); _grantRole(BURNER_ROLE, owner); _grantRole(PAUSER_ROLE, owner); diff --git a/plume/script/DeployDevnetContracts.s.sol b/plume/script/DeployDevnetContracts.s.sol index c64943a..46b2b9e 100644 --- a/plume/script/DeployDevnetContracts.s.sol +++ b/plume/script/DeployDevnetContracts.s.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.25; import "forge-std/Script.sol"; -import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol"; import { pUSD } from "../src/pUSD.sol"; diff --git a/smart-wallets/src/SmartWallet.sol b/smart-wallets/src/SmartWallet.sol index 56167b7..7ca644c 100644 --- a/smart-wallets/src/SmartWallet.sol +++ b/smart-wallets/src/SmartWallet.sol @@ -2,13 +2,14 @@ pragma solidity ^0.8.25; import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { WalletUtils } from "./WalletUtils.sol"; import { AssetVault } from "./extensions/AssetVault.sol"; import { SignedOperations } from "./extensions/SignedOperations.sol"; +import { IAssetToken } from "./interfaces/IAssetToken.sol"; +import { IAssetVault } from "./interfaces/IAssetVault.sol"; import { ISmartWallet } from "./interfaces/ISmartWallet.sol"; -import { AssetToken } from "./token/AssetToken.sol"; /** * @title SmartWallet @@ -35,7 +36,7 @@ contract SmartWallet is Proxy, WalletUtils, SignedOperations, ISmartWallet { /// @dev Address of the current user wallet implementation for each user address userWallet; /// @dev AssetVault associated with the smart wallet - AssetVault assetVault; + IAssetVault assetVault; } // keccak256(abi.encode(uint256(keccak256("plume.storage.SmartWallet")) - 1)) & ~bytes32(uint256(0xff)) @@ -58,11 +59,17 @@ contract SmartWallet is Proxy, WalletUtils, SignedOperations, ISmartWallet { // Errors + /** + * @notice Indicates a failure because the sender is not the AssetVault + * @param sender Address of the sender that is not the AssetVault + */ + error UnauthorizedAssetVault(address sender); + /** * @notice Indicates a failure because the AssetVault for the user already exists * @param assetVault Existing AssetVault for the user */ - error AssetVaultAlreadyExists(AssetVault assetVault); + error AssetVaultAlreadyExists(IAssetVault assetVault); // Base Smart Wallet Functions @@ -76,15 +83,16 @@ contract SmartWallet is Proxy, WalletUtils, SignedOperations, ISmartWallet { } /// @notice AssetVault associated with the smart wallet - function getAssetVault() external view returns (AssetVault assetVault) { + function getAssetVault() external view returns (IAssetVault assetVault) { return _getSmartWalletStorage().assetVault; } /** * @notice Get the number of AssetTokens that are currently locked in the AssetVault * @param assetToken AssetToken from which the yield is to be redistributed + * @return balanceLocked Amount of the AssetToken that is currently locked */ - function getBalanceLocked(AssetToken assetToken) public view returns (uint256 balanceLocked) { + function getBalanceLocked(IAssetToken assetToken) public view returns (uint256 balanceLocked) { return _getSmartWalletStorage().assetVault.getBalanceLocked(assetToken); } @@ -103,9 +111,9 @@ contract SmartWallet is Proxy, WalletUtils, SignedOperations, ISmartWallet { /** * @notice Fallback function to the user wallet implementation if * the function is not implemented in the base SmartWallet implementation - * @return Address of the user wallet implementation + * @return impl Address of the user wallet implementation */ - function _implementation() internal view virtual override returns (address) { + function _implementation() internal view virtual override returns (address impl) { return _getSmartWalletStorage().userWallet; } diff --git a/smart-wallets/src/WalletFactory.sol b/smart-wallets/src/WalletFactory.sol index e837136..e808ef4 100644 --- a/smart-wallets/src/WalletFactory.sol +++ b/smart-wallets/src/WalletFactory.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.25; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { SmartWallet } from "./SmartWallet.sol"; +import { ISmartWallet } from "./interfaces/ISmartWallet.sol"; /** * @title WalletFactory @@ -17,7 +17,7 @@ import { SmartWallet } from "./SmartWallet.sol"; contract WalletFactory is Ownable { /// @notice Address of the current SmartWallet implementation - SmartWallet public smartWallet; + ISmartWallet public smartWallet; /** * @notice Construct the WalletFactory @@ -25,7 +25,7 @@ contract WalletFactory is Ownable { * @param smartWallet_ Initial SmartWallet implementation * @dev The owner of the WalletFactory should be set to Plume Governance once ready */ - constructor(address owner_, SmartWallet smartWallet_) Ownable(owner_) { + constructor(address owner_, ISmartWallet smartWallet_) Ownable(owner_) { smartWallet = smartWallet_; } @@ -34,7 +34,7 @@ contract WalletFactory is Ownable { * @dev Only the WalletFactory owner can upgrade the SmartWallet implementation * @param smartWallet_ New SmartWallet implementation */ - function upgrade(SmartWallet smartWallet_) public onlyOwner { + function upgrade(ISmartWallet smartWallet_) public onlyOwner { smartWallet = smartWallet_; } diff --git a/smart-wallets/src/WalletProxy.sol b/smart-wallets/src/WalletProxy.sol index 9ba06c0..6fac167 100644 --- a/smart-wallets/src/WalletProxy.sol +++ b/smart-wallets/src/WalletProxy.sol @@ -34,9 +34,9 @@ contract WalletProxy is Proxy { /** * @notice Fallback function for the proxy implementation, which * delegates calls to the SmartWallet through the WalletFactory - * @return Address of the SmartWallet implementation + * @return impl Address of the SmartWallet implementation */ - function _implementation() internal view virtual override returns (address) { + function _implementation() internal view virtual override returns (address impl) { return address(walletFactory.smartWallet()); } diff --git a/smart-wallets/src/WalletUtils.sol b/smart-wallets/src/WalletUtils.sol index ea280ea..6d3dc35 100644 --- a/smart-wallets/src/WalletUtils.sol +++ b/smart-wallets/src/WalletUtils.sol @@ -19,18 +19,17 @@ contract WalletUtils { if (msg.sender != address(this)) { revert UnauthorizedCall(msg.sender); } - _; } /** - * @notice Checks if an address is a contract. + * @notice Checks if an address is a contract or smart wallet. * @dev This function uses the `extcodesize` opcode to check if the target address contains contract code. - * It returns false for externally owned accounts (EOA) and true for contracts. - * @param addr The address to check. - * @return bool Returns true if the address is a contract, and false if it's an externally owned account (EOA). + * It returns true for contracts and smart wallets, and false for EOAs that do not have smart wallets. + * @param addr Address to check + * @return hasCode True if the address is a contract or smart wallet, and false if it is not */ - function isContract(address addr) internal view returns (bool) { + function isContract(address addr) internal view returns (bool hasCode) { uint32 size; assembly { size := extcodesize(addr) diff --git a/smart-wallets/src/extensions/AssetVault.sol b/smart-wallets/src/extensions/AssetVault.sol index ae7c1ae..9d2f7ee 100644 --- a/smart-wallets/src/extensions/AssetVault.sol +++ b/smart-wallets/src/extensions/AssetVault.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IAssetToken } from "../interfaces/IAssetToken.sol"; import { IAssetVault } from "../interfaces/IAssetVault.sol"; +import { ISmartWallet } from "../interfaces/ISmartWallet.sol"; /** * @title AssetVault @@ -184,7 +185,6 @@ contract AssetVault is IAssetVault { if (msg.sender != wallet) { revert UnauthorizedCall(msg.sender); } - _; } @@ -214,7 +214,7 @@ contract AssetVault is IAssetVault { address beneficiary, uint256 amount, uint256 expiration - ) public onlyWallet { + ) external onlyWallet { if (address(assetToken) == address(0) || beneficiary == address(0)) { revert ZeroAddress(); } @@ -257,7 +257,7 @@ contract AssetVault is IAssetVault { while (amountLocked > 0) { if (distribution.yield.expiration > block.timestamp) { uint256 yieldShare = (currencyTokenAmount * amountLocked) / amountTotal; - // TODO: transfer yield from the user wallet to the beneficiary + // TODO transfer yield from the user wallet to the beneficiary emit YieldRedistributed(assetToken, distribution.beneficiary, currencyToken, yieldShare); } @@ -272,7 +272,7 @@ contract AssetVault is IAssetVault { * @notice Get the number of AssetTokens that are currently locked in the AssetVault * @param assetToken AssetToken from which the yield is to be redistributed */ - function getBalanceLocked(IAssetToken assetToken) public view returns (uint256 balanceLocked) { + function getBalanceLocked(IAssetToken assetToken) external view returns (uint256 balanceLocked) { // Iterate through the list and sum up the locked balance across all yield distributions YieldDistributionListItem storage distribution = _getAssetVaultStorage().yieldDistributions[assetToken]; uint256 amountLocked = distribution.yield.amount; diff --git a/smart-wallets/src/extensions/SignedOperations.sol b/smart-wallets/src/extensions/SignedOperations.sol index 2f60ffd..7dbce2c 100644 --- a/smart-wallets/src/extensions/SignedOperations.sol +++ b/smart-wallets/src/extensions/SignedOperations.sol @@ -198,7 +198,7 @@ contract SignedOperations is EIP712, WalletUtils, ISignedOperations { $.nonces[nonce] = 1; } - for (uint256 i = 0; i < length; i++) { + for (uint256 i = 0; i < length; ++i) { { (bool success,) = targets[i].call{ value: values[i] }(calls[i]); if (success) { diff --git a/smart-wallets/src/interfaces/ISmartWallet.sol b/smart-wallets/src/interfaces/ISmartWallet.sol index 0e07528..aa842f3 100644 --- a/smart-wallets/src/interfaces/ISmartWallet.sol +++ b/smart-wallets/src/interfaces/ISmartWallet.sol @@ -1,17 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -import { AssetVault } from "../extensions/AssetVault.sol"; -import { AssetToken } from "../token/AssetToken.sol"; +import { IAssetToken } from "./IAssetToken.sol"; +import { IAssetVault } from "./IAssetVault.sol"; import { ISignedOperations } from "./ISignedOperations.sol"; interface ISmartWallet is ISignedOperations { function deployAssetVault() external; - function getAssetVault() external view returns (AssetVault assetVault); - function getBalanceLocked(AssetToken assetToken) external view returns (uint256 balanceLocked); + function getAssetVault() external view returns (IAssetVault assetVault); + function getBalanceLocked(IAssetToken assetToken) external view returns (uint256 balanceLocked); function upgrade(address userWallet) external; } diff --git a/smart-wallets/src/interfaces/IYieldDistributionToken.sol b/smart-wallets/src/interfaces/IYieldDistributionToken.sol index 27b5a6b..19a9e93 100644 --- a/smart-wallets/src/interfaces/IYieldDistributionToken.sol +++ b/smart-wallets/src/interfaces/IYieldDistributionToken.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IYieldDistributionToken is IERC20 { - function getCurrencyToken() external returns (ERC20 currencyToken); - function claimYield(address user) external returns (ERC20 currencyToken, uint256 currencyTokenAmount); + function getCurrencyToken() external returns (IERC20 currencyToken); + function claimYield(address user) external returns (IERC20 currencyToken, uint256 currencyTokenAmount); function accrueYield(address user) external; } diff --git a/smart-wallets/src/interfaces/IYieldReceiver.sol b/smart-wallets/src/interfaces/IYieldReceiver.sol index 9de4ec4..7cb68ff 100644 --- a/smart-wallets/src/interfaces/IYieldReceiver.sol +++ b/smart-wallets/src/interfaces/IYieldReceiver.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IAssetToken } from "./IAssetToken.sol"; interface IYieldReceiver { - function receiveYield(IAssetToken assetToken, ERC20 currencyToken, uint256 currencyTokenAmount) external; + function receiveYield(IAssetToken assetToken, IERC20 currencyToken, uint256 currencyTokenAmount) external; } diff --git a/smart-wallets/src/token/AssetToken.sol b/smart-wallets/src/token/AssetToken.sol index 8f27c39..058354c 100644 --- a/smart-wallets/src/token/AssetToken.sol +++ b/smart-wallets/src/token/AssetToken.sol @@ -208,7 +208,7 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { revert AddressNotWhitelisted(user); } uint256 length = $.whitelist.length; - for (uint256 i = 0; i < length; i++) { + for (uint256 i = 0; i < length; ++i) { if ($.whitelist[i] == user) { $.whitelist[i] = $.whitelist[length - 1]; $.whitelist.pop(); diff --git a/smart-wallets/src/token/YieldDistributionToken.sol b/smart-wallets/src/token/YieldDistributionToken.sol index 0923aa9..bd75525 100644 --- a/smart-wallets/src/token/YieldDistributionToken.sol +++ b/smart-wallets/src/token/YieldDistributionToken.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.25; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IYieldDistributionToken } from "../interfaces/IYieldDistributionToken.sol"; @@ -69,7 +70,7 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo /// @custom:storage-location erc7201:plume.storage.YieldDistributionToken struct YieldDistributionTokenStorage { /// @dev CurrencyToken in which the yield is deposited and denominated - ERC20 currencyToken; + IERC20 currencyToken; /// @dev Number of decimals of the YieldDistributionToken uint8 decimals; /// @dev URI for the YieldDistributionToken metadata @@ -164,7 +165,7 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo address owner, string memory name, string memory symbol, - ERC20 currencyToken, + IERC20 currencyToken, uint8 decimals_, string memory tokenURI ) ERC20(name, symbol) Ownable(owner) { @@ -243,7 +244,7 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo // Getter View Functions /// @notice CurrencyToken in which the yield is deposited and denominated - function getCurrencyToken() external view returns (ERC20) { + function getCurrencyToken() external view returns (IERC20) { return _getYieldDistributionTokenStorage().currencyToken; } @@ -299,7 +300,7 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo * @return currencyToken CurrencyToken in which the yield is deposited and denominated * @return currencyTokenAmount Amount of CurrencyToken claimed as yield */ - function claimYield(address user) public returns (ERC20 currencyToken, uint256 currencyTokenAmount) { + function claimYield(address user) public returns (IERC20 currencyToken, uint256 currencyTokenAmount) { YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); currencyToken = $.currencyToken; diff --git a/smart-wallets/src/token/YieldToken.sol b/smart-wallets/src/token/YieldToken.sol index b45bd5f..7121077 100644 --- a/smart-wallets/src/token/YieldToken.sol +++ b/smart-wallets/src/token/YieldToken.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IAssetToken } from "../interfaces/IAssetToken.sol"; import { ISmartWallet } from "../interfaces/ISmartWallet.sol"; @@ -45,7 +45,7 @@ contract YieldToken is YieldDistributionToken, IYieldToken { * @param invalidCurrencyToken CurrencyToken that does not match the actual CurrencyToken * @param currencyToken Actual CurrencyToken used to mint and burn the AggregateToken */ - error InvalidCurrencyToken(ERC20 invalidCurrencyToken, ERC20 currencyToken); + error InvalidCurrencyToken(IERC20 invalidCurrencyToken, IERC20 currencyToken); /** * @notice Indicates a failure because the given AssetToken does not match the actual AssetToken @@ -71,7 +71,7 @@ contract YieldToken is YieldDistributionToken, IYieldToken { address owner, string memory name, string memory symbol, - ERC20 currencyToken, + IERC20 currencyToken, uint8 decimals_, string memory tokenURI_, IAssetToken assetToken, @@ -101,7 +101,7 @@ contract YieldToken is YieldDistributionToken, IYieldToken { * @param currencyToken CurrencyToken in which the yield is deposited and denominated * @param currencyTokenAmount Amount of CurrencyTokens to deposit as yield */ - function receiveYield(IAssetToken assetToken, ERC20 currencyToken, uint256 currencyTokenAmount) external { + function receiveYield(IAssetToken assetToken, IERC20 currencyToken, uint256 currencyTokenAmount) external { if (assetToken != _getYieldTokenStorage().assetToken) { revert InvalidAssetToken(assetToken, _getYieldTokenStorage().assetToken); }