Skip to content
Open
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
ef3a9db
suplly vaults code from midas
vminkov Oct 9, 2024
a35863a
forge install: fuse-flywheel
vminkov Oct 9, 2024
a9010db
trying to make the vaults compile
vminkov Oct 12, 2024
c36ef11
not able to import fuse-flywheel yet
vminkov Oct 17, 2024
6b035f6
removed the lib fuse-flywheel
vminkov Oct 20, 2024
01bdca3
supply vaults almost fully compiling
vminkov Oct 20, 2024
9042720
compiling supply vaults
vminkov Oct 21, 2024
935ea59
Merge branch 'development' into feat/supply-vault-testing
vminkov Oct 22, 2024
c71bc0b
Merge remote-tracking branch 'origin/development' into feat/supply-va…
vminkov Oct 22, 2024
d69ed0f
first test
vminkov Oct 22, 2024
acd0105
more tests
vminkov Oct 23, 2024
7c8145c
almost the full test suit
vminkov Oct 23, 2024
5975626
test the market rewards integration for the supply vaults rewards cla…
vminkov Oct 23, 2024
c21f9df
Merge remote-tracking branch 'origin/development' into feat/supply-va…
vminkov Oct 25, 2024
292281e
market rewards claiming through a supply vault test
vminkov Oct 25, 2024
8bbe82d
non-compiling supply vaults with rewards apr
vminkov Oct 25, 2024
7242604
making view fns nonview to accommodate for the rewards apr calcs
vminkov Oct 25, 2024
18893b2
attempt to make all rewards apr fns view
vminkov Oct 26, 2024
aa90b90
forgotten view fn change
vminkov Oct 26, 2024
65d0ff3
rewards speed from the rewards contracts
vminkov Oct 29, 2024
c0494de
the vault rewards apr test goes through but fails
vminkov Oct 30, 2024
fc3b1ec
rewards debugging
vminkov Nov 1, 2024
8aa154d
printing the changing apr from the new flywheel rewards apr fn
vminkov Nov 10, 2024
d62c98e
verifying if the rewards apr view fn works from the supply vaults
vminkov Nov 11, 2024
a1ce687
debugging the wrong apr in the vaults test
vminkov Nov 11, 2024
03f415c
reinstalling forge-std
vminkov Nov 11, 2024
5d5b519
forge install: forge-std
vminkov Nov 11, 2024
24d5420
assertion that the test case works
vminkov Nov 11, 2024
376fd8f
possible solution for the rewards apr calcs
vminkov Nov 13, 2024
06341c9
refactoring the rewards boosters
vminkov Nov 13, 2024
0c87aab
refactored the lens router use of markets as strategies
vminkov Nov 13, 2024
02e55ed
configuring the supply market booster in the test
vminkov Nov 13, 2024
4817c8f
fixing the test for the static rewards case
vminkov Nov 13, 2024
29be9bb
minor test fixes
vminkov Nov 14, 2024
02cf4d9
Merge pull request #733 from ionicprotocol/feat/supply-vault-nonview-…
vminkov Nov 26, 2024
7c530e9
libs contents reorg
vminkov Nov 27, 2024
81aa042
Merge remote-tracking branch 'origin/feat/supply-vault-testing' into …
vminkov Nov 27, 2024
0b3915b
Switch getRewardsPerSecond to use real epoch duration
antisaa Dec 16, 2024
e288de4
check for real epoch duration
antisaa Dec 19, 2024
9237cdc
Merge pull request #860 from ionicprotocol/fix-getRewardsPerSecond
antisaa Dec 19, 2024
a650cc5
Change namings to Ionic
antisaa Dec 20, 2024
8fb7e72
change the check in order to prevent underflow errors
vminkov Dec 20, 2024
5cd0d81
flywheel upgrade scripts
antisaa Dec 20, 2024
facb3c4
fixing the failing balanceOf call in the supply vaults test accrues
vminkov Dec 20, 2024
597f333
merged
vminkov Dec 20, 2024
39398f2
Merge branch 'development' into feat/supply-vault-testing
rhlsthrm Dec 21, 2024
81654d7
feat: rename
rhlsthrm Dec 21, 2024
17cd981
fixing the supply vaults test
vminkov Dec 21, 2024
ecb3dce
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
vminkov Dec 21, 2024
85576ca
cleanup
rhlsthrm Dec 23, 2024
998e6f2
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
rhlsthrm Dec 23, 2024
6126744
fix: remove external code
rhlsthrm Dec 23, 2024
b9f145d
Migrate scripts to tasks
antisaa Dec 23, 2024
613699a
feat: deploy
rhlsthrm Dec 23, 2024
42fbc6d
feat: upgrade
rhlsthrm Dec 23, 2024
293e821
Update flywheel deploy scripts
antisaa Dec 24, 2024
85b0eda
Fix getRewardsPerSecond in flywheel static rewards contract
antisaa Dec 26, 2024
a644afa
Add flywheel static rewards deployment and setup to upgrade script
antisaa Dec 26, 2024
98888a0
feat: formatting
rhlsthrm Dec 27, 2024
9ccd1c7
Remove auth from flywheel static reward
antisaa Dec 27, 2024
762d7f6
tests fixes
vminkov Dec 27, 2024
65a0486
fix: deploy
rhlsthrm Dec 27, 2024
fd2780a
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
rhlsthrm Dec 27, 2024
a06d772
Merge branch 'development' into feat/supply-vault-testing
vminkov Dec 27, 2024
5744707
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
vminkov Dec 27, 2024
2e8a047
updated libs
vminkov Dec 27, 2024
c9864f1
fix: deploy script
antisaa Dec 27, 2024
e1e8f7c
feat: flywheel
rhlsthrm Dec 27, 2024
3bc67c7
fix: case issue
rhlsthrm Dec 27, 2024
5c3734b
fix: deploy script
antisaa Dec 27, 2024
bf776af
fix: deploy script
antisaa Dec 27, 2024
2966435
feat: flywheel upgrade
rhlsthrm Dec 28, 2024
0c78d61
feat: supply
rhlsthrm Dec 28, 2024
004f771
fix: decimal point error in getRewardsPerSecondPerToken
antisaa Dec 28, 2024
737fbe8
fix: update script
antisaa Dec 29, 2024
02301eb
feat: deployments
rhlsthrm Dec 30, 2024
9c81a0c
testing the supply vaults with smaller apr
vminkov Dec 30, 2024
1432972
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
vminkov Dec 30, 2024
77975d0
fix: SupplyVaultsTest
antisaa Dec 30, 2024
e459efd
feat: deploy
rhlsthrm Dec 30, 2024
62e98e2
supply vaults deploy scripts
antisaa Dec 30, 2024
ba63afc
feat: script
rhlsthrm Jan 2, 2025
0aa56f3
feat: wip script
rhlsthrm Jan 2, 2025
220ce9a
feat: deployments
rhlsthrm Jan 2, 2025
90d11d0
resolve conflicts
antisaa Jan 2, 2025
a568c1d
Merge branch 'feat/supply-vault-testing' of github.com:ionicprotocol/…
antisaa Jan 2, 2025
ae9705b
fix: part of deploy script
antisaa Jan 2, 2025
97415cc
fix: encoding params
antisaa Jan 3, 2025
fd6a000
fix: script
rhlsthrm Jan 3, 2025
745d39a
Merge branch 'development' into feat/supply-vault-testing
rhlsthrm Jan 3, 2025
43a95c7
fix: allocation type
antisaa Jan 3, 2025
598a279
fix: one adapter
rhlsthrm Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "packages/contracts/lib/forge-std"]
path = packages/contracts/lib/forge-std
url = https://github.com/brockelmore/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "packages/contracts/lib/openzeppelin-contracts-upgradeable"]
path = packages/contracts/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

import { IonicERC4626 } from "./IonicERC4626.sol";
import { ICErc20 } from "../../compound/CTokenInterfaces.sol";
import { IonicComptroller } from "../../compound/ComptrollerInterface.sol";
import { IGenericLender } from "../../external/angle/IGenericLender.sol";
import { OptimizedVaultsRegistry } from "../vault/OptimizedVaultsRegistry.sol";
import { OptimizedAPRVaultBase } from "../vault/OptimizedAPRVaultBase.sol";
import { IonicFlywheel } from "./flywheel/IonicFlywheel.sol";
import { IonicFlywheelLensRouter } from "./flywheel/IonicFlywheelLensRouter.sol";

import { ERC20Upgradeable } from "openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";

contract CompoundMarketERC4626 is IonicERC4626, IGenericLender {
ICErc20 public market;
uint256 public blocksPerYear;
OptimizedVaultsRegistry public registry;

event ClaimedVaultRewards(address indexed rewardToken, address indexed vault, uint256 amount);

modifier onlyRegisteredVaults() {
OptimizedAPRVaultBase[] memory vaults = registry.getAllVaults();
bool isMsgSender = false;
for (uint256 i = 0; i < vaults.length; i++) {
if (msg.sender == address(vaults[i])) {
isMsgSender = true;
break;
}
}
require(isMsgSender, "!caller not a vault");
_;
}

constructor() {
_disableInitializers();
}

function initialize(
ICErc20 market_,
uint256 blocksPerYear_,
OptimizedVaultsRegistry registry_
) public initializer {
__IonicER4626_init(ERC20Upgradeable(market_.underlying()));
market = market_;
blocksPerYear = blocksPerYear_;
registry = registry_;
}

function reinitialize(address registry_) public onlyOwnerOrAdmin {
registry = OptimizedVaultsRegistry(registry_);
}

function lenderName() public view returns (string memory) {
return string(bytes.concat("Ionic Optimized ", bytes(name())));
}

function totalAssets() public view override returns (uint256) {
return market.balanceOfUnderlying(address(this));
}

function balanceOfUnderlying(address account) public view returns (uint256) {
return convertToAssets(balanceOf(account));
}

function afterDeposit(uint256 amount, uint256) internal override onlyRegisteredVaults {
ERC20Upgradeable(asset()).approve(address(market), amount);
require(market.mint(amount) == 0, "deposit to market failed");
}

function beforeWithdraw(uint256 amount, uint256) internal override onlyRegisteredVaults {
require(market.redeemUnderlying(amount) == 0, "redeem from market failed");
}

function aprAfterDeposit(uint256 amount) public view returns (uint256) {
return _rewardsApr() + market.supplyRatePerBlockAfterDeposit(amount) * blocksPerYear;
}

function aprAfterWithdraw(uint256 amount) public view override returns (uint256) {
return _rewardsApr() + market.supplyRatePerBlockAfterWithdraw(amount) * blocksPerYear;
}

function emergencyWithdrawAndPause() external override {
require(msg.sender == owner() || msg.sender == address(registry), "not owner or vaults registry");
require(market.redeemUnderlying(type(uint256).max) == 0, "redeem all failed");
_pause();
}

function unpause() external override onlyOwner {
_unpause();
}

/*------------------------------------------------------------
IGenericLender FNs
------------------------------------------------------------*/

function rewardsApr() public view returns (uint256) {
return _rewardsApr();
}

/// @notice Returns an estimation of the current Annual Percentage Rate on the lender
function apr() public view override returns (uint256) {
return _rewardsApr() + market.supplyRatePerBlock() * blocksPerYear;
}

function _rewardsApr() internal view returns (uint256) {
return uint256(registry.flr().getRewardsAprForMarket(market));
}

/// @notice Returns an estimation of the current Annual Percentage Rate weighted by the assets under
/// management of the lender
function weightedApr() external view returns (uint256) {
return (apr() * totalAssets()) / 1e18;
}

/// @notice Returns an estimation of the hypothetical Annual Percentage Rate weighted by the assets under
/// management of the lender plus the amount, if deposited
function weightedAprAfterDeposit(uint256 amount) public view returns (uint256) {
return (aprAfterDeposit(amount) * (totalAssets() + amount)) / 1e18;
}

/// @notice Withdraws a given amount from lender
/// @param amount The amount the caller wants to withdraw
/// @return Amount actually withdrawn
function withdraw(uint256 amount) public override returns (uint256) {
withdraw(amount, msg.sender, msg.sender);
return amount;
}

/// @notice Withdraws as much as possible from the lending platform
/// @return Whether everything was withdrawn or not
function withdrawAll() public override returns (bool) {
return withdraw(maxWithdraw(msg.sender), msg.sender, msg.sender) > 0;
}

/// @notice Removes tokens from this Strategy that are not the type of tokens
/// managed by this Strategy. This may be used in case of accidentally
/// sending the wrong kind of token to this Strategy.
///
/// @param _token The token to transfer out of this poolManager.
/// @param to Address to send the tokens to.
function sweep(address _token, address to) public onlyOwner {
require(_token != asset(), "!asset");

ERC20Upgradeable token = ERC20Upgradeable(_token);
token.transfer(to, token.balanceOf(address(this)));
}

function claimRewards() public onlyRegisteredVaults {
IonicComptroller pool = IonicComptroller(market.comptroller());
address[] memory poolFlywheels = pool.getRewardsDistributors();

for (uint256 j = 0; j < poolFlywheels.length; j++) {
IonicFlywheel flywheel = IonicFlywheel(poolFlywheels[j]);
ERC20 rewardToken = flywheel.rewardToken();

// accrue and claim the rewards
flywheel.accrue(ERC20(address(market)), address(this));
flywheel.claimRewards(address(this));

uint256 totalRewards = rewardToken.balanceOf(address(this));
// avoid rounding errors for too little amounts
if (totalRewards > 1000) {
// the rewards that are in the underlying asset are autocompounded
if (address(rewardToken) == address(asset())) {
afterDeposit(totalRewards, 0);
} else {
// redistribute the claimed rewards among the vaults
OptimizedAPRVaultBase[] memory vaults = registry.getAllVaults();
for (uint256 i = 0; i < vaults.length; i++) {
address vaultAddress = address(vaults[i]);
uint256 vaultSharesInAdapter = balanceOf(vaultAddress);
uint256 vaultShareOfRewards = (vaultSharesInAdapter * totalRewards) / totalSupply();
if (vaultShareOfRewards > 0) {
rewardToken.transfer(vaultAddress, vaultShareOfRewards);
emit ClaimedVaultRewards(address(rewardToken), vaultAddress, vaultShareOfRewards);
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
pragma solidity ^0.8.10;

import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity ^0.8.10;
import { ERC20 } from "solmate/tokens/ERC20.sol";

interface IIonicFlywheel {
function isRewardsDistributor() external returns (bool);
function isRewardsDistributor() external view returns (bool);

function isFlywheel() external returns (bool);
function isFlywheel() external view returns (bool);

function flywheelPreSupplierAction(address market, address supplier) external;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.10;

import {ERC20} from "solmate/tokens/ERC20.sol";

import { ICErc20 } from "../../../compound/CTokenInterfaces.sol";
import "./IIonicFlywheelBorrowBooster.sol";
import "./IFlywheelBooster.sol";

contract IonicFlywheelBorrowBooster is IIonicFlywheelBorrowBooster {
string public constant BOOSTER_TYPE = "FlywheelBorrowBooster";
contract IonicFlywheelBorrowBooster is IFlywheelBooster {
string public constant BOOSTER_TYPE = "IonicFlywheelBorrowBooster";

/**
@notice calculate the boosted supply of a strategy.
@param strategy the strategy to calculate boosted supply of
@return the boosted supply
*/
function boostedTotalSupply(ICErc20 strategy) external view returns (uint256) {
return strategy.totalBorrows();
function boostedTotalSupply(ERC20 strategy) external view returns (uint256) {
ICErc20 asMarket = ICErc20(address(strategy));
return asMarket.totalBorrows();
}

/**
Expand All @@ -22,7 +25,8 @@ contract IonicFlywheelBorrowBooster is IIonicFlywheelBorrowBooster {
@param user the user to calculate boosted balance of
@return the boosted balance
*/
function boostedBalanceOf(ICErc20 strategy, address user) external view returns (uint256) {
return strategy.borrowBalanceCurrent(user);
function boostedBalanceOf(ERC20 strategy, address user) external view returns (uint256) {
ICErc20 asMarket = ICErc20(address(strategy));
return asMarket.borrowBalanceCurrent(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ contract IonicFlywheelCore is SafeOwnableUpgradeable {

if (strategyRewardsAccrued > 0) {
// use the booster or token supply to calculate reward index denominator
uint256 supplyTokens = address(flywheelBooster) != address(0)
uint256 totalTokens = address(flywheelBooster) != address(0)
? flywheelBooster.boostedTotalSupply(strategy)
: strategy.totalSupply();

Expand All @@ -264,8 +264,8 @@ contract IonicFlywheelCore is SafeOwnableUpgradeable {

uint224 deltaIndex;

if (supplyTokens != 0)
deltaIndex = ((strategyRewardsAccrued * (10**strategy.decimals())) / supplyTokens).safeCastTo224();
if (totalTokens != 0)
deltaIndex = ((strategyRewardsAccrued * (10**strategy.decimals())) / totalTokens).safeCastTo224();

// accumulate rewards per token onto the index, multiplied by fixed-point factor
rewardsState = RewardsState({
Expand Down Expand Up @@ -312,15 +312,23 @@ contract IonicFlywheelCore is SafeOwnableUpgradeable {
return supplierAccrued;
}

function rewardsAccrued(address user) public virtual returns (uint256) {
function rewardsAccrued(address user) public view virtual returns (uint256) {
return _rewardsAccrued[user];
}

function userIndex(ERC20 strategy, address user) public virtual returns (uint224) {
function userIndex(ERC20 strategy, address user) public view virtual returns (uint224) {
return _userIndex[strategy][user];
}

function strategyState(ERC20 strategy) public virtual returns (uint224 index, uint32 lastUpdatedTimestamp) {
function strategyState(ERC20 strategy) public view virtual returns (uint224 index, uint32 lastUpdatedTimestamp) {
return (_strategyState[strategy].index, _strategyState[strategy].lastUpdatedTimestamp);
}

function getRewardsPerSecondPerToken(ERC20 strategy) external view returns (uint256) {
uint256 totalTokens = address(flywheelBooster) != address(0)
? flywheelBooster.boostedTotalSupply(strategy)
: strategy.totalSupply();
if (totalTokens == 0) return 0;
return (flywheelRewards.getRewardsPerSecond(strategy) * 1e18) / totalTokens;
}
}
Loading
Loading