Skip to content
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

VAL-131 (Part 2) Add methods for previewing withdraw/redeem request fees #184

Merged
merged 1 commit into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions contracts/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,17 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation {
assets = withdrawController.previewRedeemRequest(shares);
}

/**
* @inheritdoc IRequestWithdrawable
*/
function previewRedeemRequestFees(uint256 shares)
external
view
returns (uint256 feeShares)
{
feeShares = withdrawController.previewRedeemRequestFees(shares);
}

/**
* @inheritdoc IRequestWithdrawable
*/
Expand All @@ -486,6 +497,17 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation {
shares = withdrawController.previewWithdrawRequest(assets);
}

/**
* @inheritdoc IRequestWithdrawable
*/
function previewWithdrawRequestFees(uint256 assets)
external
view
returns (uint256 feeShares)
{
feeShares = withdrawController.previewWithdrawRequestFees(assets);
}

/**
* @inheritdoc IRequestWithdrawable
*/
Expand Down
28 changes: 24 additions & 4 deletions contracts/controllers/WithdrawController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,21 @@ contract WithdrawController is IWithdrawController, BeaconImplementation {
view
returns (uint256 assets)
{
uint256 shareFees = PoolLib.calculateRequestFee(
assets = _pool.convertToAssets(shares);
}

/**
* @inheritdoc IWithdrawController
*/
function previewRedeemRequestFees(uint256 shares)
external
view
returns (uint256 feeShares)
{
feeShares = PoolLib.calculateRequestFee(
shares,
_pool.settings().requestFeeBps
);

assets = _pool.convertToAssets(shares - shareFees);
}

/**
Expand All @@ -224,13 +233,24 @@ contract WithdrawController is IWithdrawController, BeaconImplementation {
external
view
returns (uint256 shares)
{
shares = _pool.convertToShares(assets);
}

/**
* @inheritdoc IWithdrawController
*/
function previewWithdrawRequestFees(uint256 assets)
external
view
returns (uint256 feeShares)
{
uint256 assetFees = PoolLib.calculateRequestFee(
assets,
_pool.settings().requestFeeBps
);

shares = _pool.convertToShares(assets + assetFees);
feeShares = _pool.convertToShares(assetFees);
}

/**
Expand Down
19 changes: 19 additions & 0 deletions contracts/controllers/interfaces/IWithdrawController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ interface IWithdrawController {
*/
function previewRedeemRequest(uint256) external view returns (uint256);

/**
* @dev Returns the amount of fees (shares) that would be required to process
* a redeem request at this current block.
*
*/
function previewRedeemRequestFees(uint256 shares)
external
view
returns (uint256 feeShares);

/**
* @dev Simulate the effects of a withdrawal request at the current block.
* Returns the amount of `shares` that would be burned if this entire
Expand All @@ -125,6 +135,15 @@ interface IWithdrawController {
*/
function previewWithdrawRequest(uint256) external view returns (uint256);

/**
* @dev Returns the amount of fees that would be burned, in shares, to fulfill
* a withdraw request in this current block.
*/
function previewWithdrawRequestFees(uint256 assets)
external
view
returns (uint256 feeShares);

/**
* @dev Simulates the effects of their redeemption at the current block.
* Per EIP4626, should round DOWN.
Expand Down
19 changes: 19 additions & 0 deletions contracts/interfaces/IRequestWithdrawable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ interface IRequestWithdrawable {
view
returns (uint256 assets);

/**
* @dev Returns the amount of fees (shares) that would be required to process
* a redeem request at this current block.
*
*/
function previewRedeemRequestFees(uint256 shares)
external
view
returns (uint256 feeShares);

/**
* @dev Simulate the effects of a withdrawal request at the current block.
* Returns the amount of `shares` that would be burned if this entire
Expand All @@ -56,6 +66,15 @@ interface IRequestWithdrawable {
view
returns (uint256 shares);

/**
* @dev Returns the amount of fees that would be burned, in shares, to fulfill
* a withdraw request in this current block.
*/
function previewWithdrawRequestFees(uint256 assets)
external
view
returns (uint256 feeShares);

/**
* @dev Submits a withdrawal request, incurring a fee.
*/
Expand Down
35 changes: 24 additions & 11 deletions test/Pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,13 +642,19 @@ describe("Pool", () => {
});

describe("previewRedeemRequest", () => {
it("returns the number of assets, minus fees, rounded down, that would be transferred in this redeem request, regardless of caller balance", async () => {
const { pool, poolController, poolAdmin, liquidityAsset } =
await loadFixture(loadPoolFixture);
await poolController.connect(poolAdmin).setRequestFee(1000); // 10%
await activatePool(pool, poolAdmin, liquidityAsset);
it("returns the number of assets that would be transferred in this redeem request", async () => {
const { pool } = await loadFixture(loadPoolFixture);
expect(await pool.previewRedeemRequest(27)).to.equal(27);
});
});

expect(await pool.previewRedeemRequest(27)).to.equal(24);
describe("previewRedeemRequestFees(assets)", () => {
it("returns the fees required to request shares for redemption", async () => {
const { pool, poolController, poolAdmin } = await loadFixture(
loadPoolFixture
);
await poolController.connect(poolAdmin).setRequestFee(1000); // 10%
expect(await pool.previewRedeemRequestFees(30)).to.equal(3);
});
});

Expand Down Expand Up @@ -786,12 +792,19 @@ describe("Pool", () => {

describe("previewWithdrawRequest(assets)", () => {
it("returns the share value of the provided assets, minus fees, regardless of caller balance", async () => {
const { pool, poolController, poolAdmin, liquidityAsset } =
await loadFixture(loadPoolFixture);
await poolController.connect(poolAdmin).setRequestFee(1000); // 10%
await activatePool(pool, poolAdmin, liquidityAsset);
const { pool } = await loadFixture(loadPoolFixture);

expect(await pool.previewWithdrawRequest(30)).to.equal(30);
});
});

expect(await pool.previewWithdrawRequest(27)).to.equal(30);
describe("previewWithdrawRequestFees(assets)", () => {
it("returns the fees required to request assets for withdrawal", async () => {
const { pool, poolController, poolAdmin } = await loadFixture(
loadPoolFixture
);
await poolController.connect(poolAdmin).setRequestFee(1000); // 10%
expect(await pool.previewWithdrawRequestFees(30)).to.equal(3);
});
});

Expand Down
24 changes: 20 additions & 4 deletions test/scenarios/pool/direct-deposit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,18 @@ describe("Direct Deposit", () => {

// Check withdrawal amounts
expect(await pool.connect(lender).previewWithdrawRequest(100_000)).to.equal(
52_500 // 50_000 plus fees
50_000
);
expect(
await pool.connect(lender).previewWithdrawRequestFees(100_000)
).to.equal(2_500);
expect(await pool.connect(lender).previewRedeemRequest(100_000)).to.equal(
190_000 // 200_000 minus fees
200_000
);
expect(
await pool.connect(lender).previewRedeemRequestFees(100_000)
).to.equal(
5_000 // 5k shares, aka 10k assets
);
});

Expand Down Expand Up @@ -105,10 +113,18 @@ describe("Direct Deposit", () => {

// Check withdrawal amounts
expect(await pool.connect(lender).previewWithdrawRequest(100_000)).to.equal(
52_500 // 50_000 plus fees
50_000
);
expect(
await pool.connect(lender).previewWithdrawRequestFees(100_000)
).to.equal(2_500);
expect(await pool.connect(lender).previewRedeemRequest(100_000)).to.equal(
190_000 // 200_000 minus fees
200_000
);
expect(
await pool.connect(lender).previewRedeemRequestFees(100_000)
).to.equal(
5_000 // 5k shares, aka 10k assets
);
});

Expand Down