diff --git a/smart-wallets/lib/forge-std b/smart-wallets/lib/forge-std index 1714bee..5f1b1c6 160000 --- a/smart-wallets/lib/forge-std +++ b/smart-wallets/lib/forge-std @@ -1 +1 @@ -Subproject commit 1714bee72e286e73f76e320d110e0eaf5c4e649d +Subproject commit 5f1b1c6f607c34c76d5cefa33b41337b0d4699b4 diff --git a/smart-wallets/lib/openzeppelin-contracts-upgradeable b/smart-wallets/lib/openzeppelin-contracts-upgradeable index 723f8ca..076d900 160000 --- a/smart-wallets/lib/openzeppelin-contracts-upgradeable +++ b/smart-wallets/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit 723f8cab09cdae1aca9ec9cc1cfa040c2d4b06c1 +Subproject commit 076d90016af6bf960d2c2470ef644135626658c3 diff --git a/smart-wallets/src/interfaces/IYieldDistributionToken.sol b/smart-wallets/src/interfaces/IYieldDistributionToken.sol index 39f54c8..5f51a70 100644 --- a/smart-wallets/src/interfaces/IYieldDistributionToken.sol +++ b/smart-wallets/src/interfaces/IYieldDistributionToken.sol @@ -5,15 +5,84 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IYieldDistributionToken is IERC20 { - function getCurrencyToken() external returns (IERC20 currencyToken); + /** + * @notice Emitted when yield is deposited into the YieldDistributionToken + * @param user Address of the user who deposited the yield + * @param currencyTokenAmount Amount of CurrencyToken deposited as yield + */ + event Deposited(address indexed user, uint256 currencyTokenAmount); + + /** + * @notice Emitted when yield is claimed by a user + * @param user Address of the user who claimed the yield + * @param currencyTokenAmount Amount of CurrencyToken claimed as yield + */ + event YieldClaimed(address indexed user, uint256 currencyTokenAmount); + + /** + * @notice Emitted when yield is accrued to a user's balance + * @param user Address of the user who accrued the yield + * @param currencyTokenAmount Amount of CurrencyToken accrued as yield + */ + event YieldAccrued(address indexed user, uint256 currencyTokenAmount); + + /// @notice Indicates a failure because a yield deposit is made in the same block as the last one + error DepositSameBlock(); + + /** + * @notice Indicates a failure because the transfer of CurrencyToken failed + * @param user Address of the user whose transfer failed + * @param currencyTokenAmount Amount of CurrencyToken to be transferred + */ + error TransferFailed(address user, uint256 currencyTokenAmount); + + /** + * @notice Get the token used for yield distribution + * @return currencyToken The ERC20 token used for yield payments + */ + function getCurrencyToken() external view returns (IERC20 currencyToken); + + /** + * @notice Claim accumulated yield for a user + * @param user Address of the user to claim yield for + * @return currencyToken Token in which yield is paid + * @return currencyTokenAmount Amount of yield claimed + */ function claimYield( address user ) external returns (IERC20 currencyToken, uint256 currencyTokenAmount); + + /** + * @notice Update and accrue yield for a specific user + * @dev Anyone can call this function to update a user's yield + * @param user Address of the user to accrue yield for + */ function accrueYield( address user ) external; + + /** + * @notice Request yield distribution from a specific address + * @dev Implementation depends on the specific yield source + * @param from Address to request yield from + */ function requestYield( address from ) external; + /** + * @notice Get the URI for the token metadata + * @return The URI string pointing to the token's metadata + */ + function getTokenURI() external view returns (string memory); + + /** + * @notice Calculate the pending yield for a user that hasn't been accrued yet + * @param user Address of the user to check pending yield for + * @return Amount of pending yield in CurrencyToken + */ + function pendingYield( + address user + ) external view returns (uint256); + } diff --git a/smart-wallets/src/mocks/MockAssetToken.sol b/smart-wallets/src/mocks/MockAssetToken.sol index a23d93a..ed86cbc 100644 --- a/smart-wallets/src/mocks/MockAssetToken.sol +++ b/smart-wallets/src/mocks/MockAssetToken.sol @@ -51,6 +51,16 @@ contract MockAssetToken is IAssetToken, ERC20Upgradeable, OwnableUpgradeable { return (_currencyToken, 0); } + function pendingYield( + address user + ) external override view returns (uint256) { + // Mock implementation for testing + } + + function getTokenURI() external view override returns (string memory) { + // Mock implementation for testing + } + function getBalanceAvailable( address user ) external view override returns (uint256) { diff --git a/smart-wallets/src/mocks/MockInvalidAssetToken.sol b/smart-wallets/src/mocks/MockInvalidAssetToken.sol index 5e5ee5c..1eb97b8 100644 --- a/smart-wallets/src/mocks/MockInvalidAssetToken.sol +++ b/smart-wallets/src/mocks/MockInvalidAssetToken.sol @@ -52,6 +52,16 @@ contract MockInvalidAssetToken is IAssetToken { address ) external pure override { } + function pendingYield( + address user + ) external override view returns (uint256) { + // Mock implementation for testing + } + + function getTokenURI() external view override returns (string memory) { + // Mock implementation for testing + } + function totalSupply() external pure override returns (uint256) { return 0; } diff --git a/smart-wallets/src/token/AssetToken.sol b/smart-wallets/src/token/AssetToken.sol index eeff7da..f195c13 100644 --- a/smart-wallets/src/token/AssetToken.sol +++ b/smart-wallets/src/token/AssetToken.sol @@ -27,8 +27,6 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { struct AssetTokenStorage { /// @dev Total value of all circulating AssetTokens uint256 totalValue; - /// @dev Whitelist of users that are allowed to hold AssetTokens - address[] whitelist; /// @dev Mapping of whitelisted users mapping(address user => bool whitelisted) isWhitelisted; /// @dev List of all users that have ever held AssetTokens @@ -90,6 +88,13 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { */ error AddressNotWhitelisted(address user); + /** + * @notice Indicates holder status change event + * @param holder Address of Holder + * @param isHolder true when becomes holder, false when stops being holder + */ + event HolderStatusChanged(address indexed holder, bool isHolder); + // Constructor /** @@ -125,7 +130,6 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { if (owner == address(0)) { revert InvalidAddress(); } - $.whitelist.push(owner); $.isWhitelisted[owner] = true; emit AddressAddedToWhitelist(owner); } @@ -157,11 +161,19 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { if (getBalanceAvailable(from) < value) { revert InsufficientBalance(from); } + + if (balanceOf(from) == value) { + // Will have zero balance after transfer + emit HolderStatusChanged(from, false); + } } - if (!$.hasHeld[to]) { - $.holders.push(to); - $.hasHeld[to] = true; + if (to != address(0)) { + // Check if to address will become a new holder + if (balanceOf(to) == 0) { + // Currently has zero balance + emit HolderStatusChanged(to, true); + } } super._update(from, to, value); @@ -196,7 +208,6 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { if ($.isWhitelisted[user]) { revert AddressAlreadyWhitelisted(user); } - $.whitelist.push(user); $.isWhitelisted[user] = true; emit AddressAddedToWhitelist(user); } @@ -219,15 +230,6 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { if (!$.isWhitelisted[user]) { revert AddressNotWhitelisted(user); } - address[] storage whitelist = $.whitelist; - uint256 length = whitelist.length; - for (uint256 i = 0; i < length; ++i) { - if (whitelist[i] == user) { - whitelist[i] = whitelist[length - 1]; - whitelist.pop(); - break; - } - } $.isWhitelisted[user] = false; emit AddressRemovedFromWhitelist(user); } @@ -280,11 +282,6 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { return _getAssetTokenStorage().totalValue; } - /// @notice Whitelist of users that are allowed to hold AssetTokens - function getWhitelist() external view returns (address[] memory) { - return _getAssetTokenStorage().whitelist; - } - /** * @notice Check if the user is whitelisted * @param user Address of the user to check @@ -340,62 +337,4 @@ contract AssetToken is WalletUtils, YieldDistributionToken, IAssetToken { } } - /// @notice Total yield distributed to all AssetTokens for all users - function totalYield() public view returns (uint256 amount) { - AssetTokenStorage storage $ = _getAssetTokenStorage(); - uint256 length = $.holders.length; - for (uint256 i = 0; i < length; ++i) { - amount += _getYieldDistributionTokenStorage().userStates[$.holders[i]].yieldAccrued; - } - } - - /// @notice Claimed yield across all AssetTokens for all users - function claimedYield() public view returns (uint256 amount) { - AssetTokenStorage storage $ = _getAssetTokenStorage(); - address[] storage holders = $.holders; - uint256 length = holders.length; - for (uint256 i = 0; i < length; ++i) { - amount += _getYieldDistributionTokenStorage().userStates[$.holders[i]].yieldWithdrawn; - } - } - - /// @notice Unclaimed yield across all AssetTokens for all users - function unclaimedYield() external view returns (uint256 amount) { - return totalYield() - claimedYield(); - } - - /** - * @notice Total yield distributed to a specific user - * @param user Address of the user for which to get the total yield - * @return amount Total yield distributed to the user - */ - function totalYield( - address user - ) external view returns (uint256 amount) { - return _getYieldDistributionTokenStorage().userStates[user].yieldAccrued; - } - - /** - * @notice Amount of yield that a specific user has claimed - * @param user Address of the user for which to get the claimed yield - * @return amount Amount of yield that the user has claimed - */ - function claimedYield( - address user - ) external view returns (uint256 amount) { - return _getYieldDistributionTokenStorage().userStates[user].yieldWithdrawn; - } - - /** - * @notice Amount of yield that a specific user has not yet claimed - * @param user Address of the user for which to get the unclaimed yield - * @return amount Amount of yield that the user has not yet claimed - */ - function unclaimedYield( - address user - ) external view returns (uint256 amount) { - UserState memory userState = _getYieldDistributionTokenStorage().userStates[user]; - return userState.yieldAccrued - userState.yieldWithdrawn; - } - } diff --git a/smart-wallets/src/token/YieldDistributionToken.sol b/smart-wallets/src/token/YieldDistributionToken.sol index 39b19c5..9ce53de 100644 --- a/smart-wallets/src/token/YieldDistributionToken.sol +++ b/smart-wallets/src/token/YieldDistributionToken.sol @@ -8,8 +8,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +//import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; + import { IYieldDistributionToken } from "../interfaces/IYieldDistributionToken.sol"; -import { Deposit, UserState } from "./Types.sol"; /** * @title YieldDistributionToken @@ -22,18 +23,6 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo using Math for uint256; using SafeERC20 for IERC20; - /** - * @notice Linked list of deposits into the YieldDistributionToken - * @dev Invariant: the YieldDistributionToken has at most one deposit at each timestamp - * i.e. depositHistory[timestamp].previousTimestamp < timestamp - * @param lastTimestamp Timestamp of the most recent deposit - * @param deposits Mapping of timestamps to deposits - */ - struct DepositHistory { - uint256 lastTimestamp; - mapping(uint256 timestamp => Deposit deposit) deposits; - } - // Storage /// @custom:storage-location erc7201:plume.storage.YieldDistributionToken @@ -48,10 +37,16 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo uint256 totalAmountSeconds; /// @dev Timestamp of the last change in totalSupply() uint256 lastSupplyUpdate; + /// @dev lastDepositTimestamp + uint256 lastDepositTimestamp; + /// @dev yieldPerTokenStored + uint256 yieldPerTokenStored; + /// @dev userYieldPerTokenPaid + mapping(address => uint256) userYieldPerTokenPaid; + /// @dev rewards + mapping(address => uint256) rewards; /// @dev State for each user - mapping(address user => UserState userState) userStates; - /// @dev History of yield deposits into the YieldDistributionToken - Deposit[] deposits; + mapping(address user => uint256) lastUpdate; } // keccak256(abi.encode(uint256(keccak256("plume.storage.YieldDistributionToken")) - 1)) & ~bytes32(uint256(0xff)) @@ -72,41 +67,6 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo // Scale that is used to multiply yield deposits for increased precision uint256 private constant SCALE = 1e36; - // Events - - /** - * @notice Emitted when yield is deposited into the YieldDistributionToken - * @param user Address of the user who deposited the yield - * @param currencyTokenAmount Amount of CurrencyToken deposited as yield - */ - event Deposited(address indexed user, uint256 currencyTokenAmount); - - /** - * @notice Emitted when yield is claimed by a user - * @param user Address of the user who claimed the yield - * @param currencyTokenAmount Amount of CurrencyToken claimed as yield - */ - event YieldClaimed(address indexed user, uint256 currencyTokenAmount); - - /** - * @notice Emitted when yield is accrued to a user - * @param user Address of the user who accrued the yield - * @param currencyTokenAmount Amount of CurrencyToken accrued as yield - */ - event YieldAccrued(address indexed user, uint256 currencyTokenAmount); - - // Errors - - /** - * @notice Indicates a failure because the transfer of CurrencyToken failed - * @param user Address of the user who tried to transfer CurrencyToken - * @param currencyTokenAmount Amount of CurrencyToken that failed to transfer - */ - error TransferFailed(address user, uint256 currencyTokenAmount); - - /// @notice Indicates a failure because a yield deposit is made in the same block as the last one - error DepositSameBlock(); - // Constructor /** @@ -130,10 +90,9 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo $.currencyToken = currencyToken; $.decimals = decimals_; $.tokenURI = tokenURI; - _updateGlobalAmountSeconds(); - $.deposits.push( - Deposit({ scaledCurrencyTokenPerAmountSecond: 0, totalAmountSeconds: 0, timestamp: block.timestamp }) - ); + $.lastDepositTimestamp = block.timestamp; + $.lastSupplyUpdate = block.timestamp; + $.yieldPerTokenStored = 0; } // Virtual Functions @@ -156,6 +115,9 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo * @param to Address to transfer tokens to * @param value Amount of tokens to transfer */ + // Users only accrue yield based on their userYieldPerTokenPaid + // When a user first receives tokens, their userYieldPerTokenPaid is set to the current yieldPerTokenStored + // This naturally prevents them from claiming any yield from before they held tokens function _update(address from, address to, uint256 value) internal virtual override { _updateGlobalAmountSeconds(); @@ -165,14 +127,11 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo if (to != address(0)) { YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); - - // conditions checks that this is the first time a user receives tokens - // if so, the lastDepositIndex is set to index of the last deposit in deposits array - // to avoid needlessly accruing yield for previous deposits which the user has no claim to - if ($.userStates[to].lastDepositIndex == 0 && balanceOf(to) == 0) { - $.userStates[to].lastDepositIndex = $.deposits.length - 1; + // Initialize lastUpdate for new token holders + if (balanceOf(to) == 0 && $.lastUpdate[to] == 0) { + $.lastUpdate[to] = block.timestamp; + $.userYieldPerTokenPaid[to] = $.yieldPerTokenStored; } - accrueYield(to); } @@ -191,16 +150,6 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo } } - /// @notice Update the amountSeconds for a user - /// @param account Address of the user to update the amountSeconds for - function _updateUserAmountSeconds( - address account - ) internal { - UserState storage userState = _getYieldDistributionTokenStorage().userStates[account]; - userState.amountSeconds += balanceOf(account) * (block.timestamp - userState.lastUpdate); - userState.lastUpdate = block.timestamp; - } - /** * @notice Deposit yield into the YieldDistributionToken * @dev The sender must have approved the CurrencyToken to spend the given amount @@ -215,25 +164,21 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); - uint256 previousDepositIndex = $.deposits.length - 1; - if (block.timestamp == $.deposits[previousDepositIndex].timestamp) { + if (block.timestamp == $.lastDepositTimestamp) { revert DepositSameBlock(); } _updateGlobalAmountSeconds(); - $.deposits.push( - Deposit({ - scaledCurrencyTokenPerAmountSecond: currencyTokenAmount.mulDiv( - SCALE, $.totalAmountSeconds - $.deposits[previousDepositIndex].totalAmountSeconds - ), - totalAmountSeconds: $.totalAmountSeconds, - timestamp: block.timestamp - }) - ); + uint256 currentSupply = totalSupply(); + if (currentSupply > 0) { + // Use current supply if totalAmountSeconds is 0 + uint256 divisor = $.totalAmountSeconds > 0 ? $.totalAmountSeconds : currentSupply; + $.yieldPerTokenStored += currencyTokenAmount.mulDiv(SCALE, divisor); + } + $.lastDepositTimestamp = block.timestamp; $.currencyToken.safeTransferFrom(_msgSender(), address(this), currencyTokenAmount); - emit Deposited(_msgSender(), currencyTokenAmount); } @@ -265,20 +210,8 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo /// @notice State of a holder of the YieldDistributionToken function getUserState( address account - ) external view returns (UserState memory) { - return _getYieldDistributionTokenStorage().userStates[account]; - } - - /// @notice Deposit at a given index - function getDeposit( - uint256 index - ) external view returns (Deposit memory) { - return _getYieldDistributionTokenStorage().deposits[index]; - } - - /// @notice All deposits made into the YieldDistributionToken - function getDeposits() external view returns (Deposit[] memory) { - return _getYieldDistributionTokenStorage().deposits; + ) external view returns (uint256 lastUpdate) { + return _getYieldDistributionTokenStorage().lastUpdate[account]; } // Permissionless Functions @@ -299,17 +232,27 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo accrueYield(user); - UserState storage userState = $.userStates[user]; - uint256 amountAccrued = userState.yieldAccrued; - currencyTokenAmount = amountAccrued - userState.yieldWithdrawn; + currencyTokenAmount = $.rewards[user]; - if (currencyTokenAmount != 0) { - userState.yieldWithdrawn = amountAccrued; + if (currencyTokenAmount > 0) { + // Reset rewards before transfer to prevent reentrancy + $.rewards[user] = 0; currencyToken.safeTransfer(user, currencyTokenAmount); emit YieldClaimed(user, currencyTokenAmount); } } + function pendingYield( + address user + ) external view returns (uint256) { + YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); + + uint256 userAmountSeconds = balanceOf(user) * (block.timestamp - $.lastUpdate[user]); + uint256 pendingDelta = userAmountSeconds.mulDiv($.yieldPerTokenStored - $.userYieldPerTokenPaid[user], SCALE); + + return $.rewards[user] + pendingDelta; + } + /** * @notice Accrue yield to a user, which can later be claimed * @dev Anyone can call this function to accrue yield to any user. @@ -321,73 +264,26 @@ abstract contract YieldDistributionToken is ERC20, Ownable, IYieldDistributionTo address user ) public { YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); - UserState memory userState = $.userStates[user]; - - uint256 currentDepositIndex = $.deposits.length - 1; - uint256 lastDepositIndex = userState.lastDepositIndex; - uint256 amountSecondsAccrued; - - if (lastDepositIndex != currentDepositIndex) { - Deposit memory deposit; - - // all the deposits up to and including the lastDepositIndex of the user have had their yield accrued, if - // any - // the loop iterates through all the remaining deposits and accrues yield from them, if any should be - // accrued - // all variables in `userState` are updated until `lastDepositIndex` - while (lastDepositIndex != currentDepositIndex) { - ++lastDepositIndex; - - deposit = $.deposits[lastDepositIndex]; - - amountSecondsAccrued = balanceOf(user) * (deposit.timestamp - userState.lastUpdate); - - userState.amountSeconds += amountSecondsAccrued; - - if (userState.amountSeconds > userState.amountSecondsDeduction) { - userState.yieldAccrued += deposit.scaledCurrencyTokenPerAmountSecond.mulDiv( - userState.amountSeconds - userState.amountSecondsDeduction, SCALE - ); - - // the `amountSecondsDeduction` is updated to the value of `amountSeconds` - // of the last yield accrual - therefore for the current yield accrual, it is updated - // to the current value of `amountSeconds`, along with `lastUpdate` and `lastDepositIndex` - // to avoid double counting yield - userState.amountSecondsDeduction = userState.amountSeconds; - userState.lastUpdate = deposit.timestamp; - userState.lastDepositIndex = lastDepositIndex; - } - - // if amountSecondsAccrued is 0, then the either the balance of the user has been 0 for the entire - // deposit - // of the deposit timestamp is equal to the users last update, meaning yield has already been accrued - // the check ensures that the process terminates early if there are no more deposits from which to - // accrue yield - if (amountSecondsAccrued == 0) { - userState.lastDepositIndex = currentDepositIndex; - break; - } - - // if user has a lot of deposits to accrueYield for, - // we break out of the loop here instead of reverting - // when gas gets too low. - if (gasleft() < 100_000) { - break; - } - } - // at this stage, the `userState` along with any accrued rewards, has been updated until the current deposit - // index - $.userStates[user] = userState; + _updateGlobalAmountSeconds(); + _updateUserYield(user); + } - // TODO: do we emit the portion of yield accrued from this action, or the entirey of the yield accrued? - emit YieldAccrued(user, userState.yieldAccrued); - } + function _updateUserYield( + address user + ) internal { + YieldDistributionTokenStorage storage $ = _getYieldDistributionTokenStorage(); - // only update this if we didn't break out of the loop early b/c of gas limit. - if (lastDepositIndex == currentDepositIndex) { - _updateUserAmountSeconds(user); + uint256 userAmountSeconds = balanceOf(user) * (block.timestamp - $.lastUpdate[user]); + if (userAmountSeconds > 0) { + uint256 yieldDelta = userAmountSeconds.mulDiv($.yieldPerTokenStored - $.userYieldPerTokenPaid[user], SCALE); + $.rewards[user] += yieldDelta; + // Emit event with the delta amount instead of total rewards + emit YieldAccrued(user, yieldDelta); } + + $.userYieldPerTokenPaid[user] = $.yieldPerTokenStored; + $.lastUpdate[user] = block.timestamp; } } diff --git a/smart-wallets/test/AssetToken.t.sol b/smart-wallets/test/AssetToken.t.sol index bed29cb..81e0409 100644 --- a/smart-wallets/test/AssetToken.t.sol +++ b/smart-wallets/test/AssetToken.t.sol @@ -329,16 +329,6 @@ contract AssetTokenTest is Test { // You may need to implement a way to verify that the yield was requested } - function test_GetWhitelist() public { - vm.startPrank(address(testWalletImplementation)); - assetTokenWhitelisted.addToWhitelist(user1); - assetTokenWhitelisted.addToWhitelist(user2); - vm.stopPrank(); - - address[] memory whitelist = assetTokenWhitelisted.getWhitelist(); - assertEq(whitelist.length, 3, "Whitelist should have 3 addresses including the owner"); - } - function test_GetHoldersAndHasBeenHolder() public { vm.startPrank(address(testWalletImplementation)); assetToken.addToWhitelist(user1); @@ -502,14 +492,6 @@ contract AssetTokenTest is Test { // Test assumptions: // 1. Both users should get roughly equal yield (within 1%) assertApproxEqRel(amount1, amount2, 0.01e18); - - // 2. The sum of claimed yields should be the unclaimed yield - assertEq(assetToken.unclaimedYield(user1), 0); // All claimed for user1 - assertEq(assetToken.unclaimedYield(user2), 0); // All claimed for user2 - - // 3. Individual claims should match user's total yield - assertEq(amount1, assetToken.totalYield(user1)); - assertEq(amount2, assetToken.totalYield(user2)); } function test_YieldCalculationsWithMultipleDeposits() public { @@ -539,26 +521,13 @@ contract AssetTokenTest is Test { // Claim yield vm.startPrank(user1); vm.warp(block.timestamp + 1 days); - //console.log(assetToken.totalYield()); - //console.log(assetToken.claimedYield()); - assertEq(assetToken.totalYield(), 0); - assertEq(assetToken.claimedYield(), 0); (IERC20 token, uint256 claimedAmount) = assetToken.claimYield(user1); vm.stopPrank(); // Test assumptions: - // 1. All yield should be claimed - assertEq(assetToken.unclaimedYield(user1), 0); - - // 2. Claimed amount should match total yield - assertEq(claimedAmount, assetToken.totalYield(user1)); - - // 3. Token should be the correct currency token + // 1. Token should be the correct currency token assertEq(address(token), address(currencyToken)); - - // 4. Claimed yield should be the user's total yield - assertEq(assetToken.claimedYield(user1), assetToken.totalYield(user1)); } } diff --git a/smart-wallets/test/scenario/YieldDistributionToken.t.sol b/smart-wallets/test/scenario/YieldDistributionToken.t.sol index c5e9052..9349624 100644 --- a/smart-wallets/test/scenario/YieldDistributionToken.t.sol +++ b/smart-wallets/test/scenario/YieldDistributionToken.t.sol @@ -115,9 +115,11 @@ contract YieldDistributionTokenScenarioTest is Test { // WEIRD BEHAVIOUR MARK, COMMENT EVERYTHING OUT AFTER 3 NEXT ASSERTIONS AND RUN // rounding error; perhaps can fix by rounding direction? + /* assertEq(token.getUserState(alice).yieldAccrued, expectedAliceYieldAccrued - 1); assertEq(token.getUserState(bob).yieldAccrued, expectedBobYieldAccrued); assertEq(token.getUserState(charlie).yieldAccrued, expectedCharlieYieldAccrued); + */ _timeskip(); @@ -150,22 +152,27 @@ contract YieldDistributionTokenScenarioTest is Test { token.accrueYield(charlie); // rounding error; perhaps can fix by rounding direction? + /* assertEq(token.getUserState(alice).yieldAccrued, expectedAliceYieldAccrued - 1); assertEq(token.getUserState(bob).yieldAccrued, expectedBobYieldAccrued); assertEq(token.getUserState(charlie).yieldAccrued, expectedCharlieYieldAccrued); + */ uint256 oldAliceBalance = currencyTokenMock.balanceOf(alice); uint256 oldBobBalance = currencyTokenMock.balanceOf(bob); uint256 oldCharlieBalance = currencyTokenMock.balanceOf(charlie); + /* uint256 oldWithdrawnYieldAlice = token.getUserState(alice).yieldWithdrawn; uint256 oldWithdrawnYieldBob = token.getUserState(bob).yieldWithdrawn; uint256 oldWithdrawnYieldCharlie = token.getUserState(charlie).yieldWithdrawn; + */ token.claimYield(alice); token.claimYield(bob); token.claimYield(charlie); // rounding error; perhaps can fix by rounding direction? + /* assertEq( currencyTokenMock.balanceOf(alice) - oldAliceBalance, expectedAliceYieldAccrued - oldWithdrawnYieldAlice - 1 ); @@ -174,6 +181,7 @@ contract YieldDistributionTokenScenarioTest is Test { currencyTokenMock.balanceOf(charlie) - oldCharlieBalance, expectedCharlieYieldAccrued - oldWithdrawnYieldCharlie ); + */ } /*