-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xERC4626 support #241
xERC4626 support #241
Conversation
xERC4626 adds support for rewards (yield) distribution gradually over the rewards cycle length period.
xERC4626 introduces gradual distribution of yield (rewards). In this commit we check if the distribution was handled correctly mid cycle after the syncRewards was called.
These functions will change once the allocator contract is added, but for now they are almost exact copy from ERC4626 with beforeWithdraw function added to comply with xERC4626 extention. Added tests.
Moved 2 events from this interface to implementation file Removed this inteface because there's no direct usage of it in our project.
Simulated rewards sync after half a cycle passed.
|
Name | Link |
---|---|
🔨 Latest commit | 668f5fc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For each deposit
, mint
, redeem
, and withdraw
we should add checks that storedTotalAssets
values got updated, to confirm that beforeWithdraw
and afterDeposit
were called correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
storedTotalAssets
is an internal var that is checked through the public functions. If you comment out the code inside of beforeWithdraw
and afterDeposit
20 out of 44 tests in stBTC
will fail (as of writing this comment). These failed tests touch deposit
, withdraw
, mint
, and redeem
. I think it's a good check that storedTotalAssets
is being updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests check indirectly the storedTotalAssets
being updated by checking totalAssets()
.
I don't want to block this PR, but when working on further updates to xERC4626 and Allocator assets tracking we should revisit this discussion.
xERC4626 introduced a 7 days linear distribution of rewards. Now we need to call a syncRewards simulation test function to jump 7 days ahead so that minted "rewards" in tests mimic the real world scenario.
await tbtc.mint(await stbtc.getAddress(), currentTotalAssets) | ||
await syncRewards(1n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we want to simulate a deposit here we should switch to use the exact way the deposit is being made. The previous solution was simplification, minting tokens directly to stBTC contract, but it no longer work with how total assets are calculated in xERC4626.
I propose we update these two lines:
await tbtc.mint(await stbtc.getAddress(), currentTotalAssets) | |
await syncRewards(1n) | |
await simulateDeposit(currentTotalAssets) |
And replace syncRewards
helper function with simulateDeposit
:
async function simulateDeposit(amountToDeposit: bigint) {
await tbtc.mint(await thirdParty.getAddress(), amountToDeposit)
await tbtc
.connect(thirdParty)
.approve(await stbtc.getAddress(), amountToDeposit)
await stbtc
.connect(thirdParty)
.deposit(amountToDeposit, await thirdParty.getAddress())
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core/test/stBTC.test.ts
Outdated
// check approximate value +1% | ||
expect(await stbtc.totalAssets()).to.be.lt( | ||
((actualDepositAmount1 + | ||
actualDepositAmount2 + | ||
earnedYield / 2n) * | ||
101n) / | ||
100n, | ||
) | ||
// check approximate value -1% | ||
expect(await stbtc.totalAssets()).to.be.gt( | ||
((actualDepositAmount1 + | ||
actualDepositAmount2 + | ||
earnedYield / 2n) * | ||
99n) / | ||
100n, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For approximate values, we could use chai's closeTo function, since it expects exact values as delta we could define a helper function:
function expectCloseTo(actual: bigint, expected: bigint, deltaPercentage = 1) {
return expect(actual).to.be.closeTo(
actual,
(expected * BigInt(deltaPercentage)) / 100n,
)
}
and use it in tests:
// check approximate value +1% | |
expect(await stbtc.totalAssets()).to.be.lt( | |
((actualDepositAmount1 + | |
actualDepositAmount2 + | |
earnedYield / 2n) * | |
101n) / | |
100n, | |
) | |
// check approximate value -1% | |
expect(await stbtc.totalAssets()).to.be.gt( | |
((actualDepositAmount1 + | |
actualDepositAmount2 + | |
earnedYield / 2n) * | |
99n) / | |
100n, | |
) | |
expectCloseTo( | |
await stbtc.totalAssets(), | |
actualDepositAmount1 + | |
actualDepositAmount2 + | |
earnedYield / 2n), | |
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I knew it has to exist such function, but couldn't find it and that's why I implemented it myself. Changed in 1650a42
core/test/stBTC.test.ts
Outdated
async function syncRewards(intervalDivisor: bigint) { | ||
// sync rewards | ||
await stbtc.syncRewards() | ||
const blockTimestamp = BigInt(await time.latest()) | ||
const rewardsCycleEnd = await stbtc.rewardsCycleEnd() | ||
await time.setNextBlockTimestamp( | ||
blockTimestamp + (rewardsCycleEnd - blockTimestamp) / intervalDivisor, | ||
) | ||
await mine(1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function not only calls the syncRewards
but also progresses the next cycle maybe we could rename it to something like syncAndReleaseRewards
?
Another idea I had is to replace the interval divisor with percentage progress, so instead of using 2n
divisor we would use 50
, and instead of 1n
we would use 100
:
async function syncRewards(intervalDivisor: bigint) { | |
// sync rewards | |
await stbtc.syncRewards() | |
const blockTimestamp = BigInt(await time.latest()) | |
const rewardsCycleEnd = await stbtc.rewardsCycleEnd() | |
await time.setNextBlockTimestamp( | |
blockTimestamp + (rewardsCycleEnd - blockTimestamp) / intervalDivisor, | |
) | |
await mine(1) | |
} | |
async function syncAndReleaseRewards(nextCycleProgress: number) { | |
// sync rewards | |
await stbtc.syncRewards() | |
// progress the next cycle to release rewards | |
if (nextCycleProgress > 0) { | |
const blockTimestamp = BigInt(await time.latest()) | |
const rewardsCycleEnd = await stbtc.rewardsCycleEnd() | |
await time.setNextBlockTimestamp( | |
blockTimestamp + | |
((rewardsCycleEnd - blockTimestamp) * BigInt(nextCycleProgress)) / | |
100n, | |
) | |
await mine(1) | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Replaced in-house approximation function with chai's closeTo function - Refactored syncRewards to use cycle progress instead of interval divisors. Renamed a helpre function to syncAndReleaseRewards
We're not introducing this feature. |
xERC4626
adds support for rewards (yield) distribution gradually over the rewards cycle length period.