diff --git a/foundry.toml b/foundry.toml index 90c534f..0ae651a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ src = 'src' out = 'out' libs = ['lib'] verbosity = 3 -solc-version = '0.8.21' +solc-version = '0.8.19' via_ir = true optimizer = true optimizer_runs = 100000000 diff --git a/script/DeployCometWrapper.s.sol b/script/DeployCometWrapper.s.sol index fe0161c..194c265 100644 --- a/script/DeployCometWrapper.s.sol +++ b/script/DeployCometWrapper.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import "forge-std/Script.sol"; import "forge-std/console.sol"; diff --git a/src/CometHelpers.sol b/src/CometHelpers.sol index 90edf15..df131fe 100644 --- a/src/CometHelpers.sol +++ b/src/CometHelpers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import {CometMath} from "./vendor/CometMath.sol"; diff --git a/src/CometWrapper.sol b/src/CometWrapper.sol index 1226545..94ac9ca 100644 --- a/src/CometWrapper.sol +++ b/src/CometWrapper.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; -import { CometInterface, TotalsBasic } from "./vendor/CometInterface.sol"; +import { CometInterface } from "./vendor/CometInterface.sol"; import { CometHelpers } from "./CometHelpers.sol"; import { ICometRewards } from "./vendor/ICometRewards.sol"; -import { IERC7246 } from "./vendor/IERC7246.sol"; import { ERC4626Upgradeable, ERC20Upgradeable as ERC20, @@ -13,16 +12,17 @@ import { } from "openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC4626Upgradeable.sol"; import { SafeERC20Upgradeable } from "openzeppelin-contracts-upgradeable/contracts/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { ECDSA } from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; +import { IERC1271 } from "openzeppelin-contracts/contracts/interfaces/IERC1271.sol"; /** * @title Comet Wrapper - * @notice Wrapper contract that adds ERC4626 and ERC7246 functionality to the rebasing Comet token (e.g. cUSDCv3) + * @notice Wrapper contract that adds ERC4626 functionality to the rebasing Comet token (e.g. cUSDCv3) * @author Compound & gjaldon */ -contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { +contract CometWrapper is ERC4626Upgradeable, CometHelpers { using SafeERC20Upgradeable for IERC20; - struct UserBasic { + struct UserBasicTracking { uint64 baseTrackingAccrued; uint64 baseTrackingIndex; } @@ -45,19 +45,13 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; /// @notice Mapping of users to basic data - mapping(address => UserBasic) public userBasic; + mapping(address user => UserBasicTracking basicTrackingData) public userBasic; /// @notice Mapping of users to their rewards claimed - mapping(address => uint256) public rewardsClaimed; + mapping(address owner => uint256 amount) public rewardsClaimed; - /// @notice Amount of an address's token balance that is encumbered - mapping (address => uint256) public encumberedBalanceOf; - - /// @notice Amount encumbered from owner to taker (owner => taker => balance) - mapping (address => mapping (address => uint256)) public encumbrances; - - /// @notice The next expected nonce for an address, for validating authorizations and encumbrances via signature - mapping(address => uint256) public nonces; + /// @notice The next expected nonce for an address, for validating authorizations via signature + mapping(address sender => uint256 nonce) public nonces; /// @notice The Comet address that this contract wraps CometInterface public immutable comet; @@ -77,11 +71,11 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { error EIP1271VerificationFailed(); error InsufficientAllowance(); error InsufficientAvailableBalance(); - error InsufficientEncumbrance(); error InvalidSignatureS(); error SignatureExpired(); error TimestampTooLarge(); error UninitializedReward(); + error Unauthorized(); error ZeroShares(); /** Custom events **/ @@ -134,6 +128,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return The amount of shares that are minted to the receiver */ function deposit(uint256 assets, address receiver) public override returns (uint256) { + if (assets == type(uint256).max) assets = IERC20(asset()).balanceOf(msg.sender); IERC20(asset()).safeTransferFrom(msg.sender, address(this), assets); accrueInternal(receiver); @@ -180,9 +175,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { uint256 shares = previewWithdraw(assets); if (shares == 0) revert ZeroShares(); - if (msg.sender != owner) { - spendEncumbranceThenAllowanceInternal(owner, msg.sender, shares); - } + if(owner != msg.sender) spendAllowanceInternal(owner, receiver, shares); _burn(owner, shares); IERC20(asset()).safeTransfer(receiver, assets); @@ -202,13 +195,12 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { */ function redeem(uint256 shares, address receiver, address owner) public override returns (uint256) { if (shares == 0) revert ZeroShares(); - if (msg.sender != owner) { - spendEncumbranceThenAllowanceInternal(owner, msg.sender, shares); - } accrueInternal(owner); uint256 assets = previewRedeem(shares); + if(owner != msg.sender) spendAllowanceInternal(owner, receiver, shares); + _burn(owner, shares); IERC20(asset()).safeTransfer(receiver, assets); @@ -225,21 +217,19 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return bool Indicates success of the transfer */ function transfer(address to, uint256 amount) public override(ERC20, IERC20) returns (bool) { - if (availableBalanceOf(msg.sender) < amount) revert InsufficientAvailableBalance(); transferInternal(msg.sender, to, amount); return true; } /** - * @notice Transfer shares from a specified source to a recipient using the encumbrance and allowance of the caller - * @dev Spends the caller's encumbrance from `from` first, then their allowance from `from` (if necessary) + * @notice Transfer shares from a specified source to a recipient * @param from The source of the shares to be transferred * @param to The receiver of the shares to be transferred * @param amount The amount of shares to be transferred * @return bool Indicates success of the transfer */ function transferFrom(address from, address to, uint256 amount) public override(ERC20, IERC20) returns (bool) { - spendEncumbranceThenAllowanceInternal(from, msg.sender, amount); + if(from != msg.sender) spendAllowanceInternal(from, to, amount); transferInternal(from, to, amount); return true; } @@ -277,7 +267,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * that supply the base asset to Comet. */ function updateTrackingIndex(address account) internal { - UserBasic memory basic = userBasic[account]; + UserBasicTracking memory basic = userBasic[account]; uint256 principal = balanceOf(account); (, uint64 trackingSupplyIndex,) = getSupplyIndices(); @@ -318,7 +308,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { function getRewardOwedInternal(ICometRewards.RewardConfig memory config, address account) internal returns (uint256) { if (config.token == address(0)) revert UninitializedReward(); - UserBasic memory basic = accrueRewards(account); + UserBasicTracking memory basic = accrueRewards(account); uint256 claimed = rewardsClaimed[account]; uint256 accrued = basic.baseTrackingAccrued; @@ -362,7 +352,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @param account The address to whose rewards we want to accrue * @return The UserBasic struct with updated baseTrackingIndex and/or baseTrackingAccrued fields */ - function accrueRewards(address account) public returns (UserBasic memory) { + function accrueRewards(address account) public returns (UserBasicTracking memory) { comet.accrueAccount(address(this)); updateTrackingIndex(account); return userBasic[account]; @@ -370,7 +360,7 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { /** * @dev This returns latest baseSupplyIndex regardless of whether comet.accrueAccount has been called for the - * current block. This works like `Comet.accruedInterestedIndices` at but not including computation of + * current block. This works like `Comet.accruedInterestIndices` at but not including computation of * `baseBorrowIndex` since we do not need that index in CometWrapper: * https://github.com/compound-finance/comet/blob/63e98e5d231ef50c755a9489eb346a561fc7663c/contracts/Comet.sol#L383-L394 */ @@ -390,11 +380,34 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * baseSupplyIndex is used on the principal to get the user's latest balance including interest accruals. * trackingSupplyIndex is used to compute for rewards accruals. */ - function getSupplyIndices() internal view returns (uint64 baseSupplyIndex_, uint64 trackingSupplyIndex_, uint40 lastAccrualTime_) { - TotalsBasic memory totals = comet.totalsBasic(); - baseSupplyIndex_ = totals.baseSupplyIndex; - trackingSupplyIndex_ = totals.trackingSupplyIndex; - lastAccrualTime_ = totals.lastAccrualTime; + function getSupplyIndices() internal view returns (uint64, uint64, uint40) { + CometInterface.TotalsBasic memory totals = comet.totalsBasic(); + return (totals.baseSupplyIndex, totals.trackingSupplyIndex, totals.lastAccrualTime); + } + + /** @dev See {IERC4626-maxDeposit}. */ + function maxDeposit(address) public pure override returns (uint256) { + return uint256(type(uint104).max); + } + + /** @dev See {IERC4626-maxMint}. */ + function maxMint(address) public pure override returns (uint256) { + return uint256(type(uint104).max); + } + + /** + * @notice Sets Comet's ERC20 allowance of an asset for a manager + * @dev Only callable by governor + * @dev Note: Setting the `asset` as Comet's address will allow the manager + * to withdraw from Comet's Comet balance + * @param asset The asset that the manager will gain approval of + * @param manager The account which will be allowed or disallowed + * @param amount The amount of an asset to approve + */ + function approveThis(address manager, address asset, uint amount) external { + if (msg.sender != comet.governor()) revert Unauthorized(); + + ERC20(asset).approve(manager, amount); } /** @@ -429,8 +442,11 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return The total amount of shares that would be minted by the deposit */ function previewDeposit(uint256 assets) public view override returns (uint256) { + if (comet.isTransferPaused()) return 0; + if (assets == type(uint256).max) assets = IERC20(asset()).balanceOf(msg.sender); // Calculate shares to mint by calculating the new principal amount uint64 baseSupplyIndex_ = accruedSupplyIndex(); + if(baseSupplyIndex_ == 0) return 0; uint256 currentPrincipal = totalSupply(); uint256 newBalance = totalAssets() + assets; // Round down so accounting is in the wrapper's favor @@ -446,8 +462,10 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return The total amount of assets required to mint the given shares */ function previewMint(uint256 shares) public view override returns (uint256) { + if (comet.isTransferPaused()) return 0; // Back out the quantity of assets to deposit in order to increment principal by `shares` uint64 baseSupplyIndex_ = accruedSupplyIndex(); + if(baseSupplyIndex_ == 0) return 0; uint256 currentPrincipal = totalSupply(); uint256 newPrincipal = currentPrincipal + shares; // Round up so accounting is in the wrapper's favor @@ -463,13 +481,16 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return The total amount of shares required to withdraw the given assets */ function previewWithdraw(uint256 assets) public view override returns (uint256) { + if (comet.isTransferPaused()) return 0; // Calculate the quantity of shares to burn by calculating the new principal amount uint64 baseSupplyIndex_ = accruedSupplyIndex(); + if(baseSupplyIndex_ == 0) return 0; uint256 currentPrincipal = totalSupply(); - uint256 newBalance = totalAssets() - assets; + uint256 currentBalance = totalAssets(); + uint256 newBalance = currentBalance > assets ? currentBalance - assets : 0; // Round down so accounting is in the wrapper's favor uint104 newPrincipal = principalValueSupply(baseSupplyIndex_, newBalance, Rounding.DOWN); - return currentPrincipal - newPrincipal; + return currentPrincipal > newPrincipal ? currentPrincipal - newPrincipal : 0; } /** @@ -479,13 +500,16 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { * @return The total amount of assets that would be withdrawn by the redemption */ function previewRedeem(uint256 shares) public view override returns (uint256) { + if (comet.isTransferPaused()) return 0; // Back out the quantity of assets to withdraw in order to decrement principal by `shares` uint64 baseSupplyIndex_ = accruedSupplyIndex(); + if(baseSupplyIndex_ == 0) return 0; uint256 currentPrincipal = totalSupply(); - uint256 newPrincipal = currentPrincipal - shares; + uint256 newPrincipal = currentPrincipal > shares ? currentPrincipal - shares : 0; // Round up so accounting is in the wrapper's favor uint256 newBalance = presentValueSupply(baseSupplyIndex_, newPrincipal, Rounding.UP); - return totalAssets() - newBalance; + uint256 currentBalance = totalAssets(); + return currentBalance > newBalance ? currentBalance - newBalance : 0; } /** @@ -520,105 +544,11 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { address spender, uint256 amount ) internal { + if(owner == spender) return; uint256 allowed = allowance(owner, spender); if (allowed < amount) revert InsufficientAllowance(); if (allowed != type(uint256).max) { - _approve(owner, spender, allowed - amount); - } - } - - /** ERC7246 Functions **/ - - /** - * @notice Amount of an address's token balance that is not encumbered - * @param owner Address to check the available balance of - * @return uint256 Unencumbered balance - */ - function availableBalanceOf(address owner) public view returns (uint256) { - return (balanceOf(owner) - encumberedBalanceOf[owner]); - } - - /** - * @notice Increases the amount of tokens that the caller has encumbered to - * `taker` by `amount` - * @param taker Address to increase encumbrance to - * @param amount Amount of tokens to increase the encumbrance by - */ - function encumber(address taker, uint256 amount) external { - encumberInternal(msg.sender, taker, amount); - } - - /** - * @dev Increase `owner`'s encumbrance to `taker` by `amount` - */ - function encumberInternal(address owner, address taker, uint256 amount) internal { - if (availableBalanceOf(owner) < amount) revert InsufficientAvailableBalance(); - encumbrances[owner][taker] += amount; - encumberedBalanceOf[owner] += amount; - emit Encumber(owner, taker, amount); - } - - /** - * @notice Increases the amount of tokens that `owner` has encumbered to - * `taker` by `amount`. - * @dev Spends the caller's `allowance` - * @param owner Address to increase encumbrance from - * @param taker Address to increase encumbrance to - * @param amount Amount of tokens to increase the encumbrance to `taker` by - */ - function encumberFrom(address owner, address taker, uint256 amount) external { - spendAllowanceInternal(owner, msg.sender, amount); - encumberInternal(owner, taker , amount); - } - - /** - * @notice Reduces amount of tokens encumbered from `owner` to caller by - * `amount` - * @dev Spends all of the encumbrance if `amount` is greater than `owner`'s - * current encumbrance to caller - * @param owner Address to decrease encumbrance from - * @param amount Amount of tokens to decrease the encumbrance by - */ - function release(address owner, uint256 amount) external { - releaseEncumbranceInternal(owner, msg.sender, amount); - } - - /** - * @dev Reduce `owner`'s encumbrance to `taker` by `amount` - */ - function releaseEncumbranceInternal(address owner, address taker, uint256 amount) internal { - if (encumbrances[owner][taker] < amount) revert InsufficientEncumbrance(); - encumbrances[owner][taker] -= amount; - encumberedBalanceOf[owner] -= amount; - emit Release(owner, taker, amount); - } - - /** - * @notice Spends an amount of an `owner`'s encumbrance to `spender`, falling back to their allowance for any - * amount not covered by the encumbrance - * @param owner The address that encumbrances and allowances are spent from - * @param spender The address that is spending the encumbrance and allowance - * @param amount The amount of encumbrance and/or allowance to be spent - */ - function spendEncumbranceThenAllowanceInternal(address owner, address spender, uint256 amount) internal { - uint256 encumberedToTaker = encumbrances[owner][spender]; - if (amount > encumberedToTaker) { - uint256 excessAmount = amount - encumberedToTaker; - - // WARNING: This check needs to happen BEFORE releaseEncumbranceInternal, - // otherwise the released encumbrance will increase availableBalanceOf(from), - // allowing msg.sender to transfer tokens that are encumbered to someone else - - // Check to make sure that the owner has enough available balance to move around - // so as not to move tokens encumbered to others - if (availableBalanceOf(owner) < excessAmount) revert InsufficientAvailableBalance(); - - // Exceeds Encumbrance, so spend all of it - releaseEncumbranceInternal(owner, spender, encumberedToTaker); - - spendAllowanceInternal(owner, spender, excessAmount); - } else { - releaseEncumbranceInternal(owner, spender, amount); + _spendAllowance(owner, spender, amount); } } @@ -662,38 +592,6 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { } } - /** - * @notice Sets an encumbrance from owner to taker via signature from signatory - * @param owner The address that signed the signature - * @param taker The address to create an encumbrance to - * @param amount Amount that owner is encumbering to taker - * @param expiry Expiration time for the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function encumberBySig( - address owner, - address taker, - uint256 amount, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) external { - if (block.timestamp >= expiry) revert SignatureExpired(); - - uint256 nonce = nonces[owner]; - bytes32 structHash = keccak256(abi.encode(ENCUMBER_TYPEHASH, owner, taker, amount, nonce, expiry)); - bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash)); - if (isValidSignature(owner, digest, v, r, s)) { - nonces[owner]++; - encumberInternal(owner, taker, amount); - } else { - revert BadSignatory(); - } - } - /** * @notice Checks if a signature is valid * @dev Supports EIP-1271 signatures for smart contracts @@ -714,9 +612,10 @@ contract CometWrapper is ERC4626Upgradeable, IERC7246, CometHelpers { if (hasCode(signer)) { bytes memory signature = abi.encodePacked(r, s, v); (bool success, bytes memory data) = signer.staticcall( - abi.encodeWithSelector(EIP1271_MAGIC_VALUE, digest, signature) + // abi.encodeCall(EIP1271_MAGIC_VALUE, digest, signature) + abi.encodeCall(IERC1271.isValidSignature, (digest, signature)) ); - if (success == false) revert EIP1271VerificationFailed(); + if (!success) revert EIP1271VerificationFailed(); bytes4 returnValue = abi.decode(data, (bytes4)); return returnValue == EIP1271_MAGIC_VALUE; } else { diff --git a/src/test/EIP1271Signer.sol b/src/test/EIP1271Signer.sol index ed4d320..2fa9e2f 100644 --- a/src/test/EIP1271Signer.sol +++ b/src/test/EIP1271Signer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; contract EIP1271Signer { bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; diff --git a/src/vendor/CometConfiguration.sol b/src/vendor/CometConfiguration.sol new file mode 100644 index 0000000..056eef6 --- /dev/null +++ b/src/vendor/CometConfiguration.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +/** + * @title Compound's Comet Configuration Interface + * @author Compound + */ +contract CometConfiguration { + struct ExtConfiguration { + bytes32 name32; + bytes32 symbol32; + } + + struct Configuration { + address governor; + address pauseGuardian; + address baseToken; + address baseTokenPriceFeed; + address extensionDelegate; + + uint64 supplyKink; + uint64 supplyPerYearInterestRateSlopeLow; + uint64 supplyPerYearInterestRateSlopeHigh; + uint64 supplyPerYearInterestRateBase; + uint64 borrowKink; + uint64 borrowPerYearInterestRateSlopeLow; + uint64 borrowPerYearInterestRateSlopeHigh; + uint64 borrowPerYearInterestRateBase; + uint64 storeFrontPriceFactor; + uint64 trackingIndexScale; + uint64 baseTrackingSupplySpeed; + uint64 baseTrackingBorrowSpeed; + uint104 baseMinForRewards; + uint104 baseBorrowMin; + uint104 targetReserves; + + AssetConfig[] assetConfigs; + } + + struct AssetConfig { + address asset; + address priceFeed; + uint8 decimals; + uint64 borrowCollateralFactor; + uint64 liquidateCollateralFactor; + uint64 liquidationFactor; + uint128 supplyCap; + } +} diff --git a/src/vendor/CometCore.sol b/src/vendor/CometCore.sol new file mode 100644 index 0000000..3c78c8e --- /dev/null +++ b/src/vendor/CometCore.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +import "./CometConfiguration.sol"; +import "./CometStorage.sol"; +import "./CometMath.sol"; + +abstract contract CometCore is CometConfiguration, CometStorage, CometMath { + struct AssetInfo { + uint8 offset; + address asset; + address priceFeed; + uint64 scale; + uint64 borrowCollateralFactor; + uint64 liquidateCollateralFactor; + uint64 liquidationFactor; + uint128 supplyCap; + } + + /** Internal constants **/ + + /// @dev The max number of assets this contract is hardcoded to support + /// Do not change this variable without updating all the fields throughout the contract, + // including the size of UserBasic.assetsIn and corresponding integer conversions. + uint8 internal constant MAX_ASSETS = 15; + + /// @dev The max number of decimals base token can have + /// Note this cannot just be increased arbitrarily. + uint8 internal constant MAX_BASE_DECIMALS = 18; + + /// @dev The max value for a collateral factor (1) + uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE; + + /// @dev Offsets for specific actions in the pause flag bit array + uint8 internal constant PAUSE_SUPPLY_OFFSET = 0; + uint8 internal constant PAUSE_TRANSFER_OFFSET = 1; + uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2; + uint8 internal constant PAUSE_ABSORB_OFFSET = 3; + uint8 internal constant PAUSE_BUY_OFFSET = 4; + + /// @dev The decimals required for a price feed + uint8 internal constant PRICE_FEED_DECIMALS = 8; + + /// @dev 365 days * 24 hours * 60 minutes * 60 seconds + uint64 internal constant SECONDS_PER_YEAR = 31_536_000; + + /// @dev The scale for base tracking accrual + uint64 internal constant BASE_ACCRUAL_SCALE = 1e6; + + /// @dev The scale for base index (depends on time/rate scales, not base token) + uint64 internal constant BASE_INDEX_SCALE = 1e15; + + /// @dev The scale for prices (in USD) + uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS); + + /// @dev The scale for factors + uint64 internal constant FACTOR_SCALE = 1e18; + + /// @dev The storage slot for reentrancy guard flags + bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard")); + + /// @dev The reentrancy guard statuses + uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0; + uint256 internal constant REENTRANCY_GUARD_ENTERED = 1; + + /** + * @notice Determine if the manager has permission to act on behalf of the owner + * @param owner The owner account + * @param manager The manager account + * @return Whether or not the manager has permission + */ + function hasPermission(address owner, address manager) public view returns (bool) { + return owner == manager || isAllowed[owner][manager]; + } + + /** + * @dev The positive present supply balance if positive or the negative borrow balance if negative + */ + function presentValue(int104 principalValue_) internal view returns (int256) { + if (principalValue_ >= 0) { + return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_))); + } else { + return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_))); + } + } + + /** + * @dev The principal amount projected forward by the supply index + */ + function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) { + return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE; + } + + /** + * @dev The principal amount projected forward by the borrow index + */ + function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) { + return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE; + } + + /** + * @dev The positive principal if positive or the negative principal if negative + */ + function principalValue(int256 presentValue_) internal view returns (int104) { + if (presentValue_ >= 0) { + return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_))); + } else { + return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_))); + } + } + + /** + * @dev The present value projected backward by the supply index (rounded down) + * Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals. + */ + function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) { + return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_); + } + + /** + * @dev The present value projected backward by the borrow index (rounded up) + * Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals. + */ + function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) { + return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_); + } +} diff --git a/src/vendor/CometExtInterface.sol b/src/vendor/CometExtInterface.sol index 5e3e2e3..ad62352 100644 --- a/src/vendor/CometExtInterface.sol +++ b/src/vendor/CometExtInterface.sol @@ -1,23 +1,14 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; -struct TotalsBasic { - uint64 baseSupplyIndex; - uint64 baseBorrowIndex; - uint64 trackingSupplyIndex; - uint64 trackingBorrowIndex; - uint104 totalSupplyBase; - uint104 totalBorrowBase; - uint40 lastAccrualTime; - uint8 pauseFlags; -} +import "./CometCore.sol"; /** * @title Compound's Comet Ext Interface * @notice An efficient monolithic money market protocol * @author Compound */ -abstract contract CometExtInterface { +abstract contract CometExtInterface is CometCore { error BadAmount(); error BadNonce(); error BadSignatory(); @@ -25,68 +16,53 @@ abstract contract CometExtInterface { error InvalidValueV(); error SignatureExpired(); - function allow(address manager, bool isAllowed) external virtual; + function allow(address manager, bool isAllowed) virtual external; + function allowBySig(address owner, address manager, bool isAllowed, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) virtual external; - function allowBySig( - address owner, - address manager, - bool isAllowed, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) external virtual; + function collateralBalanceOf(address account, address asset) virtual external view returns (uint128); + function baseTrackingAccrued(address account) virtual external view returns (uint64); - function collateralBalanceOf(address account, address asset) external view virtual returns (uint128); + function baseAccrualScale() virtual external view returns (uint64); + function baseIndexScale() virtual external view returns (uint64); + function factorScale() virtual external view returns (uint64); + function priceScale() virtual external view returns (uint64); - function baseTrackingAccrued(address account) external view virtual returns (uint64); + function maxAssets() virtual external view returns (uint8); - function baseAccrualScale() external view virtual returns (uint64); + function totalsBasic() virtual external view returns (TotalsBasic memory); - function baseIndexScale() external view virtual returns (uint64); - - function factorScale() external view virtual returns (uint64); - - function priceScale() external view virtual returns (uint64); - - function maxAssets() external view virtual returns (uint8); - - function totalsBasic() external view virtual returns (TotalsBasic memory); - - function version() external view virtual returns (string memory); + function version() virtual external view returns (string memory); /** - * ===== ERC20 interfaces ===== - * Does not include the following functions/events, which are defined in `CometMainInterface` instead: - * - function decimals() virtual external view returns (uint8) - * - function totalSupply() virtual external view returns (uint256) - * - function transfer(address dst, uint amount) virtual external returns (bool) - * - function transferFrom(address src, address dst, uint amount) virtual external returns (bool) - * - function balanceOf(address owner) virtual external view returns (uint256) - * - event Transfer(address indexed from, address indexed to, uint256 amount) - */ - function name() external view virtual returns (string memory); - - function symbol() external view virtual returns (string memory); + * ===== ERC20 interfaces ===== + * Does not include the following functions/events, which are defined in `CometMainInterface` instead: + * - function decimals() virtual external view returns (uint8) + * - function totalSupply() virtual external view returns (uint256) + * - function transfer(address dst, uint amount) virtual external returns (bool) + * - function transferFrom(address src, address dst, uint amount) virtual external returns (bool) + * - function balanceOf(address owner) virtual external view returns (uint256) + * - event Transfer(address indexed from, address indexed to, uint256 amount) + */ + function name() virtual external view returns (string memory); + function symbol() virtual external view returns (string memory); /** - * @notice Approve `spender` to transfer up to `amount` from `src` - * @dev This will overwrite the approval amount for `spender` - * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) - * @param spender The address of the account which may transfer tokens - * @param amount The number of tokens that are approved (-1 means infinite) - * @return Whether or not the approval succeeded - */ - function approve(address spender, uint256 amount) external virtual returns (bool); + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param amount The number of tokens that are approved (-1 means infinite) + * @return Whether or not the approval succeeded + */ + function approve(address spender, uint256 amount) virtual external returns (bool); /** - * @notice Get the current allowance from `owner` for `spender` - * @param owner The address of the account which owns the tokens to be spent - * @param spender The address of the account which may transfer tokens - * @return The number of tokens allowed to be spent (-1 means infinite) - */ - function allowance(address owner, address spender) external view virtual returns (uint256); + * @notice Get the current allowance from `owner` for `spender` + * @param owner The address of the account which owns the tokens to be spent + * @param spender The address of the account which may transfer tokens + * @return The number of tokens allowed to be spent (-1 means infinite) + */ + function allowance(address owner, address spender) virtual external view returns (uint256); event Approval(address indexed owner, address indexed spender, uint256 amount); -} +} \ No newline at end of file diff --git a/src/vendor/CometInterface.sol b/src/vendor/CometInterface.sol index 7138d57..c77a105 100644 --- a/src/vendor/CometInterface.sol +++ b/src/vendor/CometInterface.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; import "./CometMainInterface.sol"; import "./CometExtInterface.sol"; @@ -9,21 +9,4 @@ import "./CometExtInterface.sol"; * @notice An efficient monolithic money market protocol * @author Compound */ -abstract contract CometInterface is CometMainInterface, CometExtInterface { - struct UserBasic { - int104 principal; - uint64 baseTrackingIndex; - uint64 baseTrackingAccrued; - uint16 assetsIn; - uint8 _reserved; - } - - function userBasic(address account) external view virtual returns (UserBasic memory); - - struct TotalsCollateral { - uint128 totalSupplyAsset; - uint128 _reserved; - } - - function totalsCollateral(address) external virtual returns (TotalsCollateral memory); -} +abstract contract CometInterface is CometMainInterface, CometExtInterface {} diff --git a/src/vendor/CometMainInterface.sol b/src/vendor/CometMainInterface.sol index 487015d..6e165c2 100644 --- a/src/vendor/CometMainInterface.sol +++ b/src/vendor/CometMainInterface.sol @@ -1,23 +1,14 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -struct AssetInfo { - uint8 offset; - address asset; - address priceFeed; - uint64 scale; - uint64 borrowCollateralFactor; - uint64 liquidateCollateralFactor; - uint64 liquidationFactor; - uint128 supplyCap; -} +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +import "./CometCore.sol"; /** * @title Compound's Comet Main Interface (without Ext) * @notice An efficient monolithic money market protocol * @author Compound */ -abstract contract CometMainInterface { +abstract contract CometMainInterface is CometCore { error Absurd(); error AlreadyInitialized(); error BadAsset(); @@ -34,6 +25,7 @@ abstract contract CometMainInterface { error NotForSale(); error NotLiquidatable(); error Paused(); + error ReentrantCallBlocked(); error SupplyCapExceeded(); error TimestampTooLarge(); error TooManyAssets(); @@ -42,168 +34,119 @@ abstract contract CometMainInterface { error TransferOutFailed(); error Unauthorized(); - event Supply(address indexed from, address indexed dst, uint256 amount); - event Transfer(address indexed from, address indexed to, uint256 amount); - event Withdraw(address indexed src, address indexed to, uint256 amount); + event Supply(address indexed from, address indexed dst, uint amount); + event Transfer(address indexed from, address indexed to, uint amount); + event Withdraw(address indexed src, address indexed to, uint amount); - event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint256 amount); - event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint256 amount); - event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint256 amount); + event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount); + event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount); + event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount); /// @notice Event emitted when a borrow position is absorbed by the protocol - event AbsorbDebt(address indexed absorber, address indexed borrower, uint256 basePaidOut, uint256 usdValue); + event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue); /// @notice Event emitted when a user's collateral is absorbed by the protocol - event AbsorbCollateral( - address indexed absorber, - address indexed borrower, - address indexed asset, - uint256 collateralAbsorbed, - uint256 usdValue - ); + event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue); /// @notice Event emitted when a collateral asset is purchased from the protocol - event BuyCollateral(address indexed buyer, address indexed asset, uint256 baseAmount, uint256 collateralAmount); + event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount); /// @notice Event emitted when an action is paused/unpaused event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused); /// @notice Event emitted when reserves are withdrawn by the governor - event WithdrawReserves(address indexed to, uint256 amount); - - function supply(address asset, uint256 amount) external virtual; - - function supplyTo(address dst, address asset, uint256 amount) external virtual; - - function supplyFrom(address from, address dst, address asset, uint256 amount) external virtual; - - function transfer(address dst, uint256 amount) external virtual returns (bool); - - function transferFrom(address src, address dst, uint256 amount) external virtual returns (bool); - - function transferAsset(address dst, address asset, uint256 amount) external virtual; - - function transferAssetFrom(address src, address dst, address asset, uint256 amount) external virtual; - - function withdraw(address asset, uint256 amount) external virtual; - - function withdrawTo(address to, address asset, uint256 amount) external virtual; - - function withdrawFrom(address src, address to, address asset, uint256 amount) external virtual; - - function approveThis(address manager, address asset, uint256 amount) external virtual; - - function withdrawReserves(address to, uint256 amount) external virtual; - - function absorb(address absorber, address[] calldata accounts) external virtual; - - function buyCollateral(address asset, uint256 minAmount, uint256 baseAmount, address recipient) external virtual; - - function quoteCollateral(address asset, uint256 baseAmount) public view virtual returns (uint256); - - function getAssetInfo(uint8 i) public view virtual returns (AssetInfo memory); - - function getAssetInfoByAddress(address asset) public view virtual returns (AssetInfo memory); - - function getReserves() public view virtual returns (int256); - - function getPrice(address priceFeed) public view virtual returns (uint256); - - function isBorrowCollateralized(address account) public view virtual returns (bool); - - function isLiquidatable(address account) public view virtual returns (bool); + event WithdrawReserves(address indexed to, uint amount); - function totalSupply() external view virtual returns (uint256); + function supply(address asset, uint amount) virtual external; + function supplyTo(address dst, address asset, uint amount) virtual external; + function supplyFrom(address from, address dst, address asset, uint amount) virtual external; - function totalBorrow() external view virtual returns (uint256); + function transfer(address dst, uint amount) virtual external returns (bool); + function transferFrom(address src, address dst, uint amount) virtual external returns (bool); - function balanceOf(address owner) public view virtual returns (uint256); + function transferAsset(address dst, address asset, uint amount) virtual external; + function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external; - function borrowBalanceOf(address account) public view virtual returns (uint256); + function withdraw(address asset, uint amount) virtual external; + function withdrawTo(address to, address asset, uint amount) virtual external; + function withdrawFrom(address src, address to, address asset, uint amount) virtual external; - function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) - external - virtual; + function approveThis(address manager, address asset, uint amount) virtual external; + function withdrawReserves(address to, uint amount) virtual external; - function isSupplyPaused() public view virtual returns (bool); + function absorb(address absorber, address[] calldata accounts) virtual external; + function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external; + function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint); - function isTransferPaused() public view virtual returns (bool); + function getAssetInfo(uint8 i) virtual public view returns (AssetInfo memory); + function getAssetInfoByAddress(address asset) virtual public view returns (AssetInfo memory); + function getCollateralReserves(address asset) virtual public view returns (uint); + function getReserves() virtual public view returns (int); + function getPrice(address priceFeed) virtual public view returns (uint); - function isWithdrawPaused() public view virtual returns (bool); + function isBorrowCollateralized(address account) virtual public view returns (bool); + function isLiquidatable(address account) virtual public view returns (bool); - function isAbsorbPaused() public view virtual returns (bool); + function totalSupply() virtual external view returns (uint256); + function totalBorrow() virtual external view returns (uint256); + function balanceOf(address owner) virtual public view returns (uint256); + function borrowBalanceOf(address account) virtual public view returns (uint256); - function isBuyPaused() public view virtual returns (bool); + function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external; + function isSupplyPaused() virtual public view returns (bool); + function isTransferPaused() virtual public view returns (bool); + function isWithdrawPaused() virtual public view returns (bool); + function isAbsorbPaused() virtual public view returns (bool); + function isBuyPaused() virtual public view returns (bool); - function accrueAccount(address account) external virtual; + function accrueAccount(address account) virtual external; + function getSupplyRate(uint utilization) virtual public view returns (uint64); + function getBorrowRate(uint utilization) virtual public view returns (uint64); + function getUtilization() virtual public view returns (uint); - function getSupplyRate(uint256 utilization) public view virtual returns (uint64); - - function getBorrowRate(uint256 utilization) public view virtual returns (uint64); - - function getUtilization() public view virtual returns (uint256); - - function governor() external view virtual returns (address); - - function pauseGuardian() external view virtual returns (address); - - function baseToken() external view virtual returns (address); - - function baseTokenPriceFeed() external view virtual returns (address); - - function extensionDelegate() external view virtual returns (address); + function governor() virtual external view returns (address); + function pauseGuardian() virtual external view returns (address); + function baseToken() virtual external view returns (address); + function baseTokenPriceFeed() virtual external view returns (address); + function extensionDelegate() virtual external view returns (address); /// @dev uint64 - function supplyKink() external view virtual returns (uint256); - + function supplyKink() virtual external view returns (uint); /// @dev uint64 - function supplyPerSecondInterestRateSlopeLow() external view virtual returns (uint256); - + function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint); /// @dev uint64 - function supplyPerSecondInterestRateSlopeHigh() external view virtual returns (uint256); - + function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint); /// @dev uint64 - function supplyPerSecondInterestRateBase() external view virtual returns (uint256); - + function supplyPerSecondInterestRateBase() virtual external view returns (uint); /// @dev uint64 - function borrowKink() external view virtual returns (uint256); - + function borrowKink() virtual external view returns (uint); /// @dev uint64 - function borrowPerSecondInterestRateSlopeLow() external view virtual returns (uint256); - + function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint); /// @dev uint64 - function borrowPerSecondInterestRateSlopeHigh() external view virtual returns (uint256); - + function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint); /// @dev uint64 - function borrowPerSecondInterestRateBase() external view virtual returns (uint256); - + function borrowPerSecondInterestRateBase() virtual external view returns (uint); /// @dev uint64 - function storeFrontPriceFactor() external view virtual returns (uint256); + function storeFrontPriceFactor() virtual external view returns (uint); /// @dev uint64 - function baseScale() external view virtual returns (uint256); - + function baseScale() virtual external view returns (uint); /// @dev uint64 - function trackingIndexScale() external view virtual returns (uint256); + function trackingIndexScale() virtual external view returns (uint); /// @dev uint64 - function baseTrackingSupplySpeed() external view virtual returns (uint256); - + function baseTrackingSupplySpeed() virtual external view returns (uint); /// @dev uint64 - function baseTrackingBorrowSpeed() external view virtual returns (uint256); - + function baseTrackingBorrowSpeed() virtual external view returns (uint); /// @dev uint104 - function baseMinForRewards() external view virtual returns (uint256); - + function baseMinForRewards() virtual external view returns (uint); /// @dev uint104 - function baseBorrowMin() external view virtual returns (uint256); - + function baseBorrowMin() virtual external view returns (uint); /// @dev uint104 - function targetReserves() external view virtual returns (uint256); - - function numAssets() external view virtual returns (uint8); + function targetReserves() virtual external view returns (uint); - function decimals() external view virtual returns (uint8); + function numAssets() virtual external view returns (uint8); + function decimals() virtual external view returns (uint8); - function initializeStorage() external virtual; -} + function initializeStorage() virtual external; +} \ No newline at end of file diff --git a/src/vendor/CometMath.sol b/src/vendor/CometMath.sol index 4d326fb..c6d9dfd 100644 --- a/src/vendor/CometMath.sol +++ b/src/vendor/CometMath.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; /** * @title Compound's Comet Math Contract @@ -7,9 +7,7 @@ pragma solidity 0.8.21; * @author Compound */ contract CometMath { - /** - * Custom errors * - */ + /** Custom errors **/ error InvalidUInt64(); error InvalidUInt104(); @@ -18,17 +16,17 @@ contract CometMath { error InvalidInt256(); error NegativeNumber(); - function safe64(uint256 n) internal pure returns (uint64) { + function safe64(uint n) internal pure returns (uint64) { if (n > type(uint64).max) revert InvalidUInt64(); return uint64(n); } - function safe104(uint256 n) internal pure returns (uint104) { + function safe104(uint n) internal pure returns (uint104) { if (n > type(uint104).max) revert InvalidUInt104(); return uint104(n); } - function safe128(uint256 n) internal pure returns (uint128) { + function safe128(uint n) internal pure returns (uint128) { if (n > type(uint128).max) revert InvalidUInt128(); return uint128(n); } diff --git a/src/vendor/CometStorage.sol b/src/vendor/CometStorage.sol new file mode 100644 index 0000000..f0846e1 --- /dev/null +++ b/src/vendor/CometStorage.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +/** + * @title Compound's Comet Storage Interface + * @dev Versions can enforce append-only storage slots via inheritance. + * @author Compound + */ +contract CometStorage { + // 512 bits total = 2 slots + struct TotalsBasic { + // 1st slot + uint64 baseSupplyIndex; + uint64 baseBorrowIndex; + uint64 trackingSupplyIndex; + uint64 trackingBorrowIndex; + // 2nd slot + uint104 totalSupplyBase; + uint104 totalBorrowBase; + uint40 lastAccrualTime; + uint8 pauseFlags; + } + + struct TotalsCollateral { + uint128 totalSupplyAsset; + uint128 _reserved; + } + + struct UserBasic { + int104 principal; + uint64 baseTrackingIndex; + uint64 baseTrackingAccrued; + uint16 assetsIn; + uint8 _reserved; + } + + struct UserCollateral { + uint128 balance; + uint128 _reserved; + } + + struct LiquidatorPoints { + uint32 numAbsorbs; + uint64 numAbsorbed; + uint128 approxSpend; + uint32 _reserved; + } + + /// @dev Aggregate variables tracked for the entire market + uint64 internal baseSupplyIndex; + uint64 internal baseBorrowIndex; + uint64 internal trackingSupplyIndex; + uint64 internal trackingBorrowIndex; + uint104 internal totalSupplyBase; + uint104 internal totalBorrowBase; + uint40 internal lastAccrualTime; + uint8 internal pauseFlags; + + /// @notice Aggregate variables tracked for each collateral asset + mapping(address => TotalsCollateral) public totalsCollateral; + + /// @notice Mapping of users to accounts which may be permitted to manage the user account + mapping(address => mapping(address => bool)) public isAllowed; + + /// @notice The next expected nonce for an address, for validating authorizations via signature + mapping(address => uint) public userNonce; + + /// @notice Mapping of users to base principal and other basic data + mapping(address => UserBasic) public userBasic; + + /// @notice Mapping of users to collateral data per collateral asset + mapping(address => mapping(address => UserCollateral)) public userCollateral; + + /// @notice Mapping of magic liquidator points + mapping(address => LiquidatorPoints) public liquidatorPoints; +} diff --git a/src/vendor/ICometConfigurator.sol b/src/vendor/ICometConfigurator.sol index da41066..2b19276 100644 --- a/src/vendor/ICometConfigurator.sol +++ b/src/vendor/ICometConfigurator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; interface ICometConfigurator { struct Configuration { diff --git a/src/vendor/ICometRewards.sol b/src/vendor/ICometRewards.sol index 02c35a5..d3a9890 100644 --- a/src/vendor/ICometRewards.sol +++ b/src/vendor/ICometRewards.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; interface ICometRewards { struct RewardConfig { diff --git a/src/vendor/IERC7246.sol b/src/vendor/IERC7246.sol deleted file mode 100644 index 3b5e9f8..0000000 --- a/src/vendor/IERC7246.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; - -/** - * @dev Interface of the ERC7246 standard. - */ -interface IERC7246 { - /** - * @dev Emitted when `amount` tokens are encumbered from `owner` to `taker`. - */ - event Encumber(address indexed owner, address indexed taker, uint256 amount); - - /** - * @dev Emitted when the encumbrance of an `owner` to a `taker` is reduced - * by `amount`. - */ - event Release(address indexed owner, address indexed taker, uint256 amount); - - /** - * @dev Returns the total amount of tokens owned by `owner` that are - * currently encumbered. MUST never exceed `balanceOf(owner)` - * - * Any function which would reduce balanceOf(owner) below - * encumberedBalanceOf(owner) MUST revert - */ - function encumberedBalanceOf(address owner) external view returns (uint256); - - /** - * @dev Returns the number of tokens that `owner` has encumbered to `taker`. - * - * This value increases when {encumber} or {encumberFrom} are called by the - * `owner` or by another permitted account. - * This value decreases when {release} and {transferFrom} are called by - * `taker`. - */ - function encumbrances(address owner, address taker) external view returns (uint256); - - /** - * @dev Increases the amount of tokens that the caller has encumbered to - * `taker` by `amount`. - * Grants to `taker` a guaranteed right to transfer `amount` from the - * caller's balance by using `transferFrom`. - * - * MUST revert if caller does not have `amount` tokens available (e.g. if - * `balanceOf(caller) - encumbrances(caller) < amount`). - * - * Emits an {Encumber} event. - */ - function encumber(address taker, uint256 amount) external; - - /** - * @dev Increases the amount of tokens that `owner` has encumbered to - * `taker` by `amount`. - * Grants to `taker` a guaranteed right to transfer `amount` from `owner` - * using transferFrom - * - * The function SHOULD revert unless the owner account has deliberately - * authorized the sender of the message via some mechanism. - * - * MUST revert if `owner` does not have `amount` tokens available (e.g. if - * `balanceOf(owner) - encumbrances(owner) < amount`). - * - * Emits an {Encumber} event. - */ - function encumberFrom(address owner, address taker, uint256 amount) external; - - /** - * @dev Reduces amount of tokens encumbered from `owner` to caller by - * `amount`. - * - * Emits a {Release} event. - */ - function release(address owner, uint256 amount) external; - - /** - * @dev Convenience function for reading the unencumbered balance of an address. - * Trivially implemented as `balanceOf(owner) - encumberedBalanceOf(owner)` - */ - function availableBalanceOf(address owner) external view returns (uint256); -} diff --git a/test/BaseUSDbCTest.t.sol b/test/BaseUSDbCTest.t.sol index 0ac6d83..60b2e35 100644 --- a/test/BaseUSDbCTest.t.sol +++ b/test/BaseUSDbCTest.t.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { Test } from "forge-std/Test.sol"; import { CometWrapper, CometInterface, ICometRewards, CometHelpers } from "../src/CometWrapper.sol"; import { BySigTest } from "./BySig.t.sol"; import { CometWrapperTest } from "./CometWrapper.t.sol"; import { CometWrapperInvariantTest } from "./CometWrapperInvariant.t.sol"; -import { EncumberTest } from "./Encumber.t.sol"; import { RewardsTest } from "./Rewards.t.sol"; -contract BaseUSDbCTest is CometWrapperTest, CometWrapperInvariantTest, EncumberTest, RewardsTest, BySigTest { +contract BaseUSDbCTest is CometWrapperTest, CometWrapperInvariantTest, RewardsTest, BySigTest { string public override NETWORK = "base"; uint256 public override FORK_BLOCK_NUMBER = 4791144; diff --git a/test/BySig.t.sol b/test/BySig.t.sol index a1b2bae..2b0ceb2 100644 --- a/test/BySig.t.sol +++ b/test/BySig.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; +pragma solidity ^0.8.15; import { CoreTest, CometHelpers, CometWrapper, ICometRewards } from "./CoreTest.sol"; @@ -254,326 +254,6 @@ abstract contract BySigTest is CoreTest { assertEq(cometWrapper.nonces(alice), nonce); } - /* ===== EncumberBySig ===== */ - - function test_encumberBySig() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature - vm.prank(bob); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, s); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(alice), encumbranceAmount); - assertEq(cometWrapper.encumbrances(alice, bob), encumbranceAmount); - - // alice's nonce is incremented - assertEq(cometWrapper.nonces(alice), nonce + 1); - } - - function test_encumberBySig_revertsForBadOwner() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the owner - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(charlie, bob, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsForBadSpender() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the spender - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(alice, charlie, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsForBadAmount() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the encumbranceAmount - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount + 1 wei, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsForBadExpiry() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry + 1, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsForBadNonce() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice signs an authorization with an invalid nonce - uint256 nonce = cometWrapper.nonces(alice); - uint256 badNonce = nonce + 1; - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, badNonce, expiry); - - // bob calls encumberBySig with the signature with an invalid nonce - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsOnRepeatedCall() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - uint256 transferAmount = 30e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature - vm.startPrank(bob); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, s); - - // the encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(alice), encumbranceAmount); - assertEq(cometWrapper.encumbrances(alice, bob), encumbranceAmount); - - // alice's nonce is incremented - assertEq(cometWrapper.nonces(alice), nonce + 1); - - // bob uses some of the encumbrance to transfer to himself - cometWrapper.transferFrom(alice, bob, transferAmount); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance - transferAmount); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(alice), encumbranceAmount - transferAmount); - assertEq(cometWrapper.encumbrances(alice, bob), encumbranceAmount - transferAmount); - - // bob tries to reuse the same signature twice - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, s); - - // no new encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance - transferAmount); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(alice), encumbranceAmount - transferAmount); - assertEq(cometWrapper.encumbrances(alice, bob), encumbranceAmount - transferAmount); - - // alice's nonce is not incremented a second time - assertEq(cometWrapper.nonces(alice), nonce + 1); - - vm.stopPrank(); - } - - function test_encumberBySig_revertsForExpiredSignature() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - // Fix for via-IR issue: https://github.com/foundry-rs/foundry/issues/3312#issuecomment-1255264273 - uint256 expiry = uint248(block.timestamp + 1000); - - (uint8 v, bytes32 r, bytes32 s) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // the expiry block arrives - vm.warp(expiry); - - // bob calls encumberBySig with the signature after the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.SignatureExpired.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - - function test_encumberBySig_revertsInvalidS() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice has 100 wrapped tokens - deal(address(cometWrapper), alice, aliceBalance); - - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, ) = aliceEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // 1 greater than the max value of s - bytes32 invalidS = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1; - - // bob calls encumberBySig with the signature, but he manipulates the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.InvalidSignatureS.selector); - cometWrapper.encumberBySig(alice, bob, encumbranceAmount, expiry, v, r, invalidS); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(alice), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(alice), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // alice's nonce is not incremented - assertEq(cometWrapper.nonces(alice), nonce); - } - /* ===== EIP1271 Tests ===== */ function test_permitEIP1271() public { @@ -818,323 +498,4 @@ abstract contract BySigTest is CoreTest { // alice's contract's nonce is not incremented assertEq(cometWrapper.nonces(aliceContract), nonce); } - - function test_encumberBySigEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature - vm.prank(bob); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, s); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), encumbranceAmount); - assertEq(cometWrapper.encumbrances(aliceContract, bob), encumbranceAmount); - - // alice's contract's nonce is incremented - assertEq(cometWrapper.nonces(aliceContract), nonce + 1); - } - - function test_encumberBySig_revertsForBadSpenderEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the spender - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(aliceContract, charlie, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsForBadAmountEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the encumbranceAmount - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount + 1 wei, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsForBadExpiryEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature, but he manipulates the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry + 1, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsForBadNonceEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice signs an authorization with an invalid nonce - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 badNonce = nonce + 1; - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, badNonce, expiry); - - // bob calls encumberBySig with the signature with an invalid nonce - vm.prank(bob); - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsOnRepeatedCallEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - uint256 transferAmount = 30e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(alice); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // bob calls encumberBySig with the signature - vm.startPrank(bob); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, s); - - // the encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), encumbranceAmount); - assertEq(cometWrapper.encumbrances(aliceContract, bob), encumbranceAmount); - - // alice's contract's nonce is incremented - assertEq(cometWrapper.nonces(aliceContract), nonce + 1); - - // bob uses some of the encumbrance to transfer to himself - cometWrapper.transferFrom(aliceContract, bob, transferAmount); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance - transferAmount); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), encumbranceAmount - transferAmount); - assertEq(cometWrapper.encumbrances(aliceContract, bob), encumbranceAmount - transferAmount); - - // bob tries to reuse the same signature twice - vm.expectRevert(CometWrapper.BadSignatory.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, s); - - // no new encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance - transferAmount); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance - encumbranceAmount); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), encumbranceAmount - transferAmount); - assertEq(cometWrapper.encumbrances(aliceContract, bob), encumbranceAmount - transferAmount); - - // alice's contract's nonce is not incremented a second time - assertEq(cometWrapper.nonces(aliceContract), nonce + 1); - - vm.stopPrank(); - } - - function test_encumberBySig_revertsForExpiredSignatureEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - // Fix for via-IR issue: https://github.com/foundry-rs/foundry/issues/3312#issuecomment-1255264273 - uint256 expiry = uint248(block.timestamp + 1000); - - (uint8 v, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // the expiry block arrives - vm.warp(expiry); - - // bob calls encumberBySig with the signature after the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.SignatureExpired.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsInvalidVEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (, bytes32 r, bytes32 s) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - uint8 invalidV = 26; - - // bob calls encumberBySig with the signature with an invalid `v` value - vm.prank(bob); - vm.expectRevert(CometWrapper.EIP1271VerificationFailed.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, invalidV, r, s); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } - - function test_encumberBySig_revertsInvalidSEIP1271() public { - uint256 aliceBalance = 100e18; - uint256 encumbranceAmount = 60e18; - - // alice's contract has 100 wrapped tokens - deal(address(cometWrapper), aliceContract, aliceBalance); - - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - uint256 nonce = cometWrapper.nonces(aliceContract); - uint256 expiry = block.timestamp + 1000; - - (uint8 v, bytes32 r, ) = aliceContractEncumberAuthorization(encumbranceAmount, nonce, expiry); - - // 1 greater than the max value of s - bytes32 invalidS = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1; - - // bob calls encumberBySig with the signature, but he manipulates the expiry - vm.prank(bob); - vm.expectRevert(CometWrapper.EIP1271VerificationFailed.selector); - cometWrapper.encumberBySig(aliceContract, bob, encumbranceAmount, expiry, v, r, invalidS); - - // no encumbrance is created - assertEq(cometWrapper.balanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.availableBalanceOf(aliceContract), aliceBalance); - assertEq(cometWrapper.encumberedBalanceOf(aliceContract), 0); - assertEq(cometWrapper.encumbrances(aliceContract, bob), 0); - - // alice's contract's nonce is not incremented - assertEq(cometWrapper.nonces(aliceContract), nonce); - } } diff --git a/test/CometWrapper.t.sol b/test/CometWrapper.t.sol index cf56a5e..ee0ec56 100644 --- a/test/CometWrapper.t.sol +++ b/test/CometWrapper.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { CoreTest, CometHelpers, CometInterface, CometWrapper, IERC20, ICometRewards } from "./CoreTest.sol"; import { CometMath } from "../src/vendor/CometMath.sol"; @@ -457,7 +457,9 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.withdraw(aliceAssets, alice, alice); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertEq(cometWrapper.underlyingBalance(alice), 0); assertApproxEqAbs(comet.balanceOf(alice), aliceCometBalance + aliceAssets, 2); @@ -469,7 +471,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.withdraw(bobAssets, bob, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertEq(cometWrapper.underlyingBalance(bob), 0); assertApproxEqAbs(comet.balanceOf(bob), bobCometBalance + bobAssets, 2); @@ -502,7 +505,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.withdraw(assetsToWithdraw, bob, alice); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertApproxEqAbs(cometWrapper.underlyingBalance(alice), expectedAliceWrapperAssets, 1); assertLe(cometWrapper.underlyingBalance(alice), expectedAliceWrapperAssets); @@ -541,7 +545,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.withdraw(assetsToWithdraw, alice, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertApproxEqAbs(cometWrapper.underlyingBalance(bob), expectedBobWrapperAssets, 1); assertLe(cometWrapper.underlyingBalance(bob), expectedBobWrapperAssets); @@ -676,7 +681,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.deposit(amount2, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); skip(500 days); @@ -704,7 +710,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { assertLe(bobAssetsWithdrawn, bobSharesToAssets); // Ensure that the wrapper is fully backed by the underlying Comet asset - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); } @@ -721,7 +728,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.deposit(3_555 * decimalScale, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); skip(500 days); @@ -739,7 +747,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.redeem(sharesToRedeem, bob, alice); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertEq(cometWrapper.balanceOf(alice), expectedAliceWrapperBalance); // Bob receives 1 wei less due to rounding down behavior in Comet transfer logic @@ -760,7 +769,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.deposit(3_555 * decimalScale, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); skip(250 days); @@ -781,7 +791,8 @@ abstract contract CometWrapperTest is CoreTest, CometMath { cometWrapper.redeem(sharesToRedeem, alice, bob); vm.stopPrank(); - assertEq(cometWrapper.totalSupply(), unsigned104(comet.userBasic(wrapperAddress).principal)); + (principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned104(principal)); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertEq(cometWrapper.balanceOf(bob), expectedBobWrapperBalance); // Alice receives 1 wei less due to rounding down behavior in Comet transfer logic @@ -894,8 +905,9 @@ abstract contract CometWrapperTest is CoreTest, CometMath { skip(30 days); assertEq(cometWrapper.totalAssets(), comet.balanceOf(wrapperAddress)); assertEq(cometWrapper.totalSupply(), 9_000 * decimalScale); - uint256 totalPrincipal = unsigned256(comet.userBasic(address(cometWrapper)).principal); - assertEq(cometWrapper.totalSupply(), totalPrincipal); + + (int104 principal,,,,) = comet.userBasic(wrapperAddress); + assertEq(cometWrapper.totalSupply(), unsigned256(principal)); } function test_transferFromWorksForSender() public { @@ -904,13 +916,9 @@ abstract contract CometWrapperTest is CoreTest, CometMath { vm.startPrank(alice); comet.allow(wrapperAddress, true); cometWrapper.mint(5_000 * decimalScale, alice); - // Alice needs to give approval to herself in order to `transferFrom` - vm.expectEmit(true, true, true, true); - emit Approval(alice, alice, 2_500 * decimalScale); - cometWrapper.approve(alice, 2_500 * decimalScale); vm.expectEmit(true, true, true, true); - emit Approval(alice, alice, 0); + emit Transfer(alice, bob, 2_500 * decimalScale); cometWrapper.transferFrom(alice, bob, 2_500 * decimalScale); vm.stopPrank(); diff --git a/test/CometWrapperInvariant.t.sol b/test/CometWrapperInvariant.t.sol index 96d5cd1..d095e5f 100644 --- a/test/CometWrapperInvariant.t.sol +++ b/test/CometWrapperInvariant.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { CoreTest, CometHelpers, CometWrapper, ICometRewards } from "./CoreTest.sol"; import { CometMath } from "../src/vendor/CometMath.sol"; @@ -40,8 +40,9 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { vm.prank(bob); cometWrapper.mint(bobBalance/3, bob); assertEq(comet.balanceOf(address(cometWrapper)), cometWrapper.totalAssets()); - - assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(comet.userBasic(address(cometWrapper)).principal)); + + (int104 principal,,,,) = comet.userBasic(address(cometWrapper)); + assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(principal)); vm.prank(alice); cometWrapper.withdraw(aliceBalance/4, alice, alice); @@ -50,8 +51,9 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { vm.prank(bob); cometWrapper.withdraw(bobBalance/4, bob, bob); assertEq(comet.balanceOf(address(cometWrapper)), cometWrapper.totalAssets()); - - assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(comet.userBasic(address(cometWrapper)).principal)); + + (principal,,,,) = comet.userBasic(address(cometWrapper)); + assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(principal)); vm.prank(alice); cometWrapper.redeem(aliceBalance/5, alice, alice); @@ -61,7 +63,8 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { cometWrapper.redeem(bobBalance/5, bob, bob); assertEq(comet.balanceOf(address(cometWrapper)), cometWrapper.totalAssets()); - assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(comet.userBasic(address(cometWrapper)).principal)); + (principal,,,,) = comet.userBasic(address(cometWrapper)); + assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(principal)); vm.startPrank(alice); cometWrapper.redeem(cometWrapper.maxRedeem(alice), alice, alice); @@ -73,7 +76,8 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { vm.stopPrank(); assertEq(comet.balanceOf(address(cometWrapper)), cometWrapper.totalAssets()); - assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(comet.userBasic(address(cometWrapper)).principal)); + (principal,,,,) = comet.userBasic(address(cometWrapper)); + assertEq(cometWrapper.balanceOf(alice) + cometWrapper.balanceOf(bob), unsigned256(principal)); } // Invariants: @@ -95,11 +99,12 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { vm.startPrank(alice); - int256 preWrapperCometPrincipal = comet.userBasic(address(cometWrapper)).principal; + (int104 preWrapperCometPrincipal,,,,) = comet.userBasic(address(cometWrapper)); uint256 preAliceShares = cometWrapper.balanceOf(alice); uint256 preTotalSupply = cometWrapper.totalSupply(); cometWrapper.redeem(aliceBalance/5, alice, alice); - uint256 decreaseInWrapperCometPrincipal = uint256(preWrapperCometPrincipal - comet.userBasic(address(cometWrapper)).principal); + (int104 principal,,,,) = comet.userBasic(address(cometWrapper)); + uint256 decreaseInWrapperCometPrincipal = uint256(unsigned256(preWrapperCometPrincipal - principal)); uint256 aliceSharesBurnt = preAliceShares - cometWrapper.balanceOf(alice); uint256 decreaseInTotalSupply = preTotalSupply - cometWrapper.totalSupply(); // Check that principal is decreased by the amount of shares burnt @@ -111,11 +116,12 @@ abstract contract CometWrapperInvariantTest is CoreTest, CometMath { vm.stopPrank(); vm.startPrank(alice); - preWrapperCometPrincipal = comet.userBasic(address(cometWrapper)).principal; + (preWrapperCometPrincipal,,,,) = comet.userBasic(address(cometWrapper)); preAliceShares = cometWrapper.balanceOf(alice); preTotalSupply = cometWrapper.totalSupply(); cometWrapper.redeem(cometWrapper.maxRedeem(alice), alice, alice); - decreaseInWrapperCometPrincipal = uint256(preWrapperCometPrincipal - comet.userBasic(address(cometWrapper)).principal); + (principal,,,,) = comet.userBasic(address(cometWrapper)); + decreaseInWrapperCometPrincipal = uint256(unsigned256(preWrapperCometPrincipal - principal)); aliceSharesBurnt = preAliceShares - cometWrapper.balanceOf(alice); decreaseInTotalSupply = preTotalSupply - cometWrapper.totalSupply(); // Check that principal is decreased by the amount of shares burnt diff --git a/test/CoreTest.sol b/test/CoreTest.sol index 6f807eb..173a761 100644 --- a/test/CoreTest.sol +++ b/test/CoreTest.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { Test } from "forge-std/Test.sol"; import { TransparentUpgradeableProxy } from "openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/test/Encumber.t.sol b/test/Encumber.t.sol deleted file mode 100644 index 42943c6..0000000 --- a/test/Encumber.t.sol +++ /dev/null @@ -1,495 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; - -import { CoreTest, CometHelpers, CometWrapper, ICometRewards } from "./CoreTest.sol"; - -abstract contract EncumberTest is CoreTest { - event Encumber(address indexed owner, address indexed taker, uint amount); - event Release(address indexed owner, address indexed taker, uint amount); - - function setUpAliceCometBalance() public { - deal(address(underlyingToken), address(cometHolder), 20_000 * decimalScale); - vm.startPrank(cometHolder); - underlyingToken.approve(address(comet), 20_000 * decimalScale); - comet.supply(address(underlyingToken), 20_000 * decimalScale); - - comet.transfer(alice, 10_000 * decimalScale); - assertGt(comet.balanceOf(alice), 9999 * decimalScale); - vm.stopPrank(); - } - - function test_availableBalanceOf() public { - vm.startPrank(alice); - - // availableBalanceOf is 0 by default - assertEq(cometWrapper.availableBalanceOf(alice), 0); - - // reflects balance when there are no encumbrances - deal(address(cometWrapper), alice, 100e18); - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 100e18); - - // is reduced by encumbrances - cometWrapper.encumber(bob, 20e18); - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 80e18); - - // is reduced by transfers - cometWrapper.transfer(bob, 20e18); - assertEq(cometWrapper.balanceOf(alice), 80e18); - assertEq(cometWrapper.availableBalanceOf(alice), 60e18); - - vm.stopPrank(); - - vm.startPrank(bob); - - // is NOT reduced by transferFrom (from an encumbered address) - cometWrapper.transferFrom(alice, charlie, 10e18); - assertEq(cometWrapper.balanceOf(alice), 70e18); - assertEq(cometWrapper.availableBalanceOf(alice), 60e18); - assertEq(cometWrapper.encumbrances(alice, bob), 10e18); - assertEq(cometWrapper.balanceOf(charlie), 10e18); - - // is increased by a release - cometWrapper.release(alice, 5e18); - assertEq(cometWrapper.balanceOf(alice), 70e18); - assertEq(cometWrapper.availableBalanceOf(alice), 65e18); - assertEq(cometWrapper.encumbrances(alice, bob), 5e18); - - vm.stopPrank(); - } - - function test_transfer_revertsOnInsufficentAvailableBalance() public { - deal(address(cometWrapper), alice, 100e18); - vm.startPrank(alice); - - // alice encumbers half her balance to bob - cometWrapper.encumber(bob, 50e18); - - // alice attempts to transfer her entire balance - vm.expectRevert(CometWrapper.InsufficientAvailableBalance.selector); - cometWrapper.transfer(charlie, 100e18); - - vm.stopPrank(); - } - - function test_encumber_revertsOnInsufficientAvailableBalance() public { - deal(address(cometWrapper), alice, 100e18); - vm.startPrank(alice); - - // alice encumbers half her balance to bob - cometWrapper.encumber(bob, 50e18); - - // alice attempts to encumber more than her remaining available balance - vm.expectRevert(CometWrapper.InsufficientAvailableBalance.selector); - cometWrapper.encumber(charlie, 60e18); - - vm.stopPrank(); - } - - function test_encumber() public { - deal(address(cometWrapper), alice, 100e18); - vm.startPrank(alice); - - // emits Encumber event - vm.expectEmit(true, true, true, true); - emit Encumber(alice, bob, 60e18); - - // alice encumbers some of her balance to bob - cometWrapper.encumber(bob, 60e18); - - // balance is unchanged - assertEq(cometWrapper.balanceOf(alice), 100e18); - // available balance is reduced - assertEq(cometWrapper.availableBalanceOf(alice), 40e18); - - // creates encumbrance for taker - assertEq(cometWrapper.encumbrances(alice, bob), 60e18); - - // updates encumbered balance of owner - assertEq(cometWrapper.encumberedBalanceOf(alice), 60e18); - } - - function test_transferFromWithSufficientEncumbrance() public { - deal(address(cometWrapper), alice, 100e18); - vm.prank(alice); - - // alice encumbers some of her balance to bob - cometWrapper.encumber(bob, 60e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 40e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 60e18); - assertEq(cometWrapper.encumbrances(alice, bob), 60e18); - assertEq(cometWrapper.balanceOf(charlie), 0); - - // bob calls transfers from alice to charlie - vm.prank(bob); - vm.expectEmit(true, true, true, true); - emit Release(alice, bob, 40e18); - cometWrapper.transferFrom(alice, charlie, 40e18); - - // alice balance is reduced - assertEq(cometWrapper.balanceOf(alice), 60e18); - // alice encumbrance to bob is reduced - assertEq(cometWrapper.availableBalanceOf(alice), 40e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 20e18); - assertEq(cometWrapper.encumbrances(alice, bob), 20e18); - // transfer is completed - assertEq(cometWrapper.balanceOf(charlie), 40e18); - } - - function test_transferFromUsesEncumbranceAndAllowance() public { - deal(address(cometWrapper), alice, 100e18); - vm.startPrank(alice); - - // alice encumbers some of her balance to bob - cometWrapper.encumber(bob, 20e18); - - // she also grants him an approval - cometWrapper.approve(bob, 30e18); - - vm.stopPrank(); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 80e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 20e18); - assertEq(cometWrapper.encumbrances(alice, bob), 20e18); - assertEq(cometWrapper.allowance(alice, bob), 30e18); - assertEq(cometWrapper.balanceOf(charlie), 0); - - // bob calls transfers from alice to charlie - vm.prank(bob); - vm.expectEmit(true, true, true, true); - emit Release(alice, bob, 20e18); - cometWrapper.transferFrom(alice, charlie, 40e18); - - // alice balance is reduced - assertEq(cometWrapper.balanceOf(alice), 60e18); - - // her encumbrance to bob has been fully spent - assertEq(cometWrapper.availableBalanceOf(alice), 60e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - - // her allowance to bob has been partially spent - assertEq(cometWrapper.allowance(alice, bob), 10e18); - - // the dst receives the transfer - assertEq(cometWrapper.balanceOf(charlie), 40e18); - } - - function test_transferFrom_revertsIfSpendingTokensEncumberedToOthers() public { - deal(address(cometWrapper), alice, 200e18); - vm.startPrank(alice); - - // alice encumbers some of her balance to bob - cometWrapper.encumber(bob, 50e18); - - // she also grants him an approval - cometWrapper.approve(bob, type(uint256).max); - - // alice encumbers the remainder of her balance to charlie - cometWrapper.encumber(charlie, 150e18); - - vm.stopPrank(); - - assertEq(cometWrapper.balanceOf(alice), 200e18); - assertEq(cometWrapper.availableBalanceOf(alice), 0); - assertEq(cometWrapper.encumberedBalanceOf(alice), 200e18); - assertEq(cometWrapper.encumbrances(alice, bob), 50e18); - assertEq(cometWrapper.encumbrances(alice, charlie), 150e18); - assertEq(cometWrapper.allowance(alice, bob), type(uint256).max); - - // bob calls transfers from alice, attempting to transfer his encumbered - // tokens and also transfer tokens encumbered to charlie - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientAvailableBalance.selector); - cometWrapper.transferFrom(alice, bob, 100e18); - } - - function test_transferFrom_revertsIfInsufficientAllowance() public { - deal(address(cometWrapper), alice, 100e18); - - vm.startPrank(alice); - - // alice encumbers some of her balance to bob - cometWrapper.encumber(bob, 10e18); - - // she also grants him an approval - cometWrapper.approve(bob, 20e18); - - vm.stopPrank(); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 90e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 10e18); - assertEq(cometWrapper.encumbrances(alice, bob), 10e18); - assertEq(cometWrapper.allowance(alice, bob), 20e18); - assertEq(cometWrapper.balanceOf(charlie), 0); - - // bob tries to transfer more than his encumbered and allowed balances - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.transferFrom(alice, charlie, 40e18); - } - - function test_encumberFrom_revertsOnInsufficientAllowance() public { - deal(address(cometWrapper), alice, 100e18); - - // alice grants bob an approval - vm.prank(alice); - cometWrapper.approve(bob, 50e18); - - // but bob tries to encumber more than his allowance - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.encumberFrom(alice, charlie, 60e18); - } - - function test_encumberFrom() public { - deal(address(cometWrapper), alice, 100e18); - - // alice grants bob an approval - vm.prank(alice); - cometWrapper.approve(bob, 100e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 100e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 0e18); - assertEq(cometWrapper.encumbrances(alice, bob), 0e18); - assertEq(cometWrapper.allowance(alice, bob), 100e18); - assertEq(cometWrapper.balanceOf(charlie), 0); - - // bob encumbers part of his allowance from alice to charlie - vm.prank(bob); - // emits an Encumber event - vm.expectEmit(true, true, true, true); - emit Encumber(alice, charlie, 60e18); - cometWrapper.encumberFrom(alice, charlie, 60e18); - - // no balance is transferred - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.balanceOf(charlie), 0); - // but available balance is reduced - assertEq(cometWrapper.availableBalanceOf(alice), 40e18); - // encumbrance to charlie is created - assertEq(cometWrapper.encumberedBalanceOf(alice), 60e18); - assertEq(cometWrapper.encumbrances(alice, bob), 0e18); - assertEq(cometWrapper.encumbrances(alice, charlie), 60e18); - // allowance is partially spent - assertEq(cometWrapper.allowance(alice, bob), 40e18); - } - - function test_release() public { - deal(address(cometWrapper), alice, 100e18); - - vm.prank(alice); - - // alice encumbers her balance to bob - cometWrapper.encumber(bob, 100e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 0); - assertEq(cometWrapper.encumberedBalanceOf(alice), 100e18); - assertEq(cometWrapper.encumbrances(alice, bob), 100e18); - - // bob releases part of the encumbrance - vm.prank(bob); - // emits Release event - vm.expectEmit(true, true, true, true); - emit Release(alice, bob, 40e18); - cometWrapper.release(alice, 40e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 40e18); - assertEq(cometWrapper.encumberedBalanceOf(alice), 60e18); - assertEq(cometWrapper.encumbrances(alice, bob), 60e18); - } - - function test_release_revertsOnInsufficientEncumbrance() public { - deal(address(cometWrapper), alice, 100e18); - - vm.prank(alice); - - // alice encumbers her balance to bob - cometWrapper.encumber(bob, 100e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 0); - assertEq(cometWrapper.encumberedBalanceOf(alice), 100e18); - assertEq(cometWrapper.encumbrances(alice, bob), 100e18); - - // bob releases a greater amount than is encumbered to him - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientEncumbrance.selector); - cometWrapper.release(alice, 200e18); - - assertEq(cometWrapper.balanceOf(alice), 100e18); - assertEq(cometWrapper.availableBalanceOf(alice), 0); - assertEq(cometWrapper.encumberedBalanceOf(alice), 100e18); - assertEq(cometWrapper.encumbrances(alice, bob), 100e18); - } - - /* ===== ERC4626 + Encumbrance Tests ===== */ - - function test_withdrawFromUsesOnlyEncumbrance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.mint(5_000 * decimalScale, alice); - vm.stopPrank(); - - uint256 sharesToEncumber = 2_700 * decimalScale; - uint256 sharesToRedeem = 2_500 * decimalScale; - uint256 assetsToWithdraw = cometWrapper.previewRedeem(sharesToRedeem); - - vm.prank(alice); - cometWrapper.encumber(bob, sharesToEncumber); - - vm.startPrank(bob); - // Encumbrance should be updated when withdraw is done - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber); - cometWrapper.withdraw(assetsToWithdraw, bob, alice); - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber - sharesToRedeem); - assertEq(cometWrapper.balanceOf(alice), 5_000 * decimalScale - sharesToRedeem); - - // Reverts if trying to withdraw again now that encumbrance is used up - assetsToWithdraw = cometWrapper.previewRedeem(sharesToRedeem); - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.withdraw(assetsToWithdraw, bob, alice); - vm.stopPrank(); - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber - sharesToRedeem); - } - - function test_withdrawFromUsesEncumbranceAndAllowance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.mint(5_000 * decimalScale, alice); - vm.stopPrank(); - - uint256 sharesToEncumber = 1_000 * decimalScale; - uint256 sharesToApprove = 1_700 * decimalScale; - uint256 sharesToRedeem = 2_500 * decimalScale; - uint256 assetsToWithdraw = cometWrapper.previewRedeem(sharesToRedeem); - - vm.startPrank(alice); - cometWrapper.encumber(bob, sharesToEncumber); - cometWrapper.approve(bob, sharesToApprove); - vm.stopPrank(); - - vm.startPrank(bob); - // Encumbrance and allowance should be updated when withdraw is done - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber); - assertEq(cometWrapper.allowance(alice, bob), sharesToApprove); - cometWrapper.withdraw(assetsToWithdraw, bob, alice); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - assertEq(cometWrapper.allowance(alice, bob), sharesToEncumber + sharesToApprove - sharesToRedeem); - assertEq(cometWrapper.balanceOf(alice), 5_000 * decimalScale - sharesToRedeem); - - // Reverts if trying to withdraw again now that encumbrance and allowance is used up - assetsToWithdraw = cometWrapper.previewRedeem(sharesToRedeem); - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.withdraw(assetsToWithdraw, bob, alice); - vm.stopPrank(); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - assertEq(cometWrapper.allowance(alice, bob), sharesToEncumber + sharesToApprove - sharesToRedeem); - } - - function test_withdrawFrom_revertsOnInsufficientAvailableBalance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.deposit(1_000 * decimalScale, alice); - // Encumber to Charlie so Alice's available balance is only 100 - cometWrapper.encumber(charlie, 900 * decimalScale); - cometWrapper.approve(bob, 200 * decimalScale); - vm.stopPrank(); - - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientAvailableBalance.selector); - cometWrapper.withdraw(200 * decimalScale, bob, alice); - } - - function test_redeemFromUsesOnlyEncumbrance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.mint(5_000 * decimalScale, alice); - vm.stopPrank(); - - uint256 sharesToEncumber = 2_700 * decimalScale; - uint256 sharesToRedeem = 2_500 * decimalScale; - - vm.prank(alice); - cometWrapper.encumber(bob, sharesToEncumber); - - vm.startPrank(bob); - // Encumbrances should be updated when redeem is done - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber); - cometWrapper.redeem(sharesToRedeem, bob, alice); - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber - sharesToRedeem); - assertEq(cometWrapper.balanceOf(alice), 5_000 * decimalScale - sharesToRedeem); - - // Reverts if trying to redeem again now that encumbrance is used up - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.redeem(sharesToRedeem, bob, alice); - vm.stopPrank(); - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber - sharesToRedeem); - } - - function test_redeemFromUsesEncumbranceAndAllowance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.mint(5_000 * decimalScale, alice); - vm.stopPrank(); - - uint256 sharesToEncumber = 1_000 * decimalScale; - uint256 sharesToApprove = 1_700 * decimalScale; - uint256 sharesToRedeem = 2_500 * decimalScale; - - vm.startPrank(alice); - cometWrapper.encumber(bob, sharesToEncumber); - cometWrapper.approve(bob, sharesToApprove); - vm.stopPrank(); - - vm.startPrank(bob); - // Encumbrances and allowances should be updated when redeem is done - assertEq(cometWrapper.encumbrances(alice, bob), sharesToEncumber); - assertEq(cometWrapper.allowance(alice, bob), sharesToApprove); - cometWrapper.redeem(sharesToRedeem, bob, alice); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - assertEq(cometWrapper.allowance(alice, bob), sharesToEncumber + sharesToApprove - sharesToRedeem); - assertEq(cometWrapper.balanceOf(alice), 5_000 * decimalScale - sharesToRedeem); - - // Reverts if trying to redeem again now that encumbrance and allowance is used up - vm.expectRevert(CometWrapper.InsufficientAllowance.selector); - cometWrapper.redeem(sharesToRedeem, bob, alice); - vm.stopPrank(); - assertEq(cometWrapper.encumbrances(alice, bob), 0); - assertEq(cometWrapper.allowance(alice, bob), sharesToEncumber + sharesToApprove - sharesToRedeem); - } - - function test_redeemFrom_revertsOnInsufficientAvailableBalance() public { - setUpAliceCometBalance(); - - vm.startPrank(alice); - comet.allow(wrapperAddress, true); - cometWrapper.mint(1_000 * decimalScale, alice); - // Encumber to Charlie so Alice's available balance is only 100 - cometWrapper.encumber(charlie, 900 * decimalScale); - cometWrapper.approve(bob, 200 * decimalScale); - vm.stopPrank(); - - vm.prank(bob); - vm.expectRevert(CometWrapper.InsufficientAvailableBalance.selector); - cometWrapper.redeem(200 * decimalScale, bob, alice); - } -} diff --git a/test/MainnetUSDCTest.t.sol b/test/MainnetUSDCTest.t.sol index beeb67c..dc20319 100644 --- a/test/MainnetUSDCTest.t.sol +++ b/test/MainnetUSDCTest.t.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { Test } from "forge-std/Test.sol"; import { CometWrapper, CometInterface, ICometRewards, CometHelpers } from "../src/CometWrapper.sol"; import { BySigTest } from "./BySig.t.sol"; import { CometWrapperTest } from "./CometWrapper.t.sol"; import { CometWrapperInvariantTest } from "./CometWrapperInvariant.t.sol"; -import { EncumberTest } from "./Encumber.t.sol"; import { RewardsTest } from "./Rewards.t.sol"; -contract MainnetUSDCTest is CometWrapperTest, CometWrapperInvariantTest, EncumberTest, RewardsTest, BySigTest { +contract MainnetUSDCTest is CometWrapperTest, CometWrapperInvariantTest, RewardsTest, BySigTest { string public override NETWORK = "mainnet"; uint256 public override FORK_BLOCK_NUMBER = 16617900; diff --git a/test/MainnetWETHTest.t.sol b/test/MainnetWETHTest.t.sol index c26ef70..ab8fa9d 100644 --- a/test/MainnetWETHTest.t.sol +++ b/test/MainnetWETHTest.t.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { Test } from "forge-std/Test.sol"; import { CometWrapper, CometInterface, ICometRewards, CometHelpers } from "../src/CometWrapper.sol"; import { BySigTest } from "./BySig.t.sol"; import { CometWrapperTest } from "./CometWrapper.t.sol"; import { CometWrapperInvariantTest } from "./CometWrapperInvariant.t.sol"; -import { EncumberTest } from "./Encumber.t.sol"; import { RewardsTest } from "./Rewards.t.sol"; -contract MainnetWETHTest is CometWrapperTest, CometWrapperInvariantTest, EncumberTest, RewardsTest, BySigTest { +contract MainnetWETHTest is CometWrapperTest, CometWrapperInvariantTest, RewardsTest, BySigTest { string public override NETWORK = "mainnet"; uint256 public override FORK_BLOCK_NUMBER = 18285773; diff --git a/test/Rewards.t.sol b/test/Rewards.t.sol index c550325..d46386d 100644 --- a/test/Rewards.t.sol +++ b/test/Rewards.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.21; +pragma solidity 0.8.19; import { CoreTest, TransparentUpgradeableProxy } from "./CoreTest.sol"; import { CometWrapper, ICometRewards, CometHelpers, IERC20 } from "../src/CometWrapper.sol"; @@ -35,12 +35,14 @@ abstract contract RewardsTest is CoreTest { // Make sure that Alice and Bob have the same amount of shares in Comet and the CometWrapper // We do this because `comet.transfer` can burn 1 extra principal from the sender - uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(comet.userBasic(alice).principal)); + (int104 principal,,,,) = comet.userBasic(alice); + uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(principal)); if (diffInShares > 0) { vm.prank(alice); cometWrapper.redeem(diffInShares, address(0), alice); } - diffInShares = cometWrapper.balanceOf(bob) - uint256(int256(comet.userBasic(bob).principal)); + (principal,,,,) = comet.userBasic(bob); + diffInShares = cometWrapper.balanceOf(bob) - uint256(int256(principal)); if (diffInShares > 0) { vm.prank(bob); cometWrapper.redeem(diffInShares, address(0), bob); @@ -116,12 +118,14 @@ abstract contract RewardsTest is CoreTest { // Make sure that Alice and Bob have the same amount of shares in Comet and the CometWrapper // We do this because `comet.transfer` can burn 1 extra principal from the sender - uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(comet.userBasic(alice).principal)); + (int104 principal,,,,) = comet.userBasic(alice); + uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(principal)); if (diffInShares > 0) { vm.prank(alice); cometWrapper.redeem(diffInShares, address(0), alice); } - diffInShares = cometWrapper.balanceOf(bob) - uint256(int256(comet.userBasic(bob).principal)); + (principal,,,,) = comet.userBasic(bob); + diffInShares = cometWrapper.balanceOf(bob) - uint256(int256(principal)); if (diffInShares > 0) { vm.prank(bob); cometWrapper.redeem(diffInShares, address(0), bob); @@ -193,7 +197,8 @@ abstract contract RewardsTest is CoreTest { // Make sure that Alice has the same amount of shares in Comet and the CometWrapper // We do this because `comet.transfer` can burn 1 extra principal from the sender - uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(comet.userBasic(alice).principal)); + (int104 principal,,,,) = comet.userBasic(alice); + uint256 diffInShares = cometWrapper.balanceOf(alice) - uint256(int256(principal)); if (diffInShares > 0) { vm.prank(alice); cometWrapper.redeem(diffInShares, address(0), alice);