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 Updates to conform better to EIP 4626 #183

Merged
merged 7 commits into from
Feb 16, 2023
11 changes: 11 additions & 0 deletions contracts/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,9 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation {
override
returns (uint256)
{
if (_serviceConfiguration.paused() == true) {
return 0;
}
return
PoolLib.calculateMaxDeposit(
poolController.state(),
Expand Down Expand Up @@ -811,9 +814,13 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation {
function maxWithdraw(address owner)
public
view
virtual
override
returns (uint256 assets)
{
if (_serviceConfiguration.paused() == true) {
return 0;
}
assets = withdrawController.maxWithdraw(owner);
}

Expand Down Expand Up @@ -862,9 +869,13 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation {
function maxRedeem(address owner)
public
view
virtual
override
returns (uint256 maxShares)
{
if (_serviceConfiguration.paused() == true) {
return 0;
}
maxShares = withdrawController.maxRedeem(owner);
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/interfaces/IERC4626.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IERC4626 is IERC20Upgradeable {
* @dev Emitted when tokens are deposited into the vault via the mint and deposit methods.
*/
event Deposit(
address indexed caller,
address indexed sender,
address indexed owner,
uint256 assets,
uint256 shares
Expand All @@ -21,7 +21,7 @@ interface IERC4626 is IERC20Upgradeable {
* @dev Emitted when shares are withdrawn from the vault by a depositor in the redeem or withdraw methods.
*/
event Withdraw(
address indexed caller,
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
Expand Down
7 changes: 5 additions & 2 deletions contracts/libraries/PoolLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ library PoolLib {
* @dev See IERC4626
*/
event Deposit(
address indexed caller,
address indexed sender,
address indexed owner,
uint256 assets,
uint256 shares
Expand Down Expand Up @@ -342,9 +342,12 @@ library PoolLib {
uint256 poolMaxCapacity,
uint256 totalAvailableAssets
) external pure returns (uint256) {
uint256 remainingCapacity = poolMaxCapacity > totalAvailableAssets
? poolMaxCapacity - totalAvailableAssets
: 0;
return
poolLifeCycleState == IPoolLifeCycleState.Active
? poolMaxCapacity - totalAvailableAssets
? remainingCapacity
: 0;
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/PoolLibTestWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ contract PoolLibTestWrapper is ERC20("PoolLibTest", "PLT") {
uint256 amount
);
event Deposit(
address indexed caller,
address indexed sender,
address indexed owner,
uint256 assets,
uint256 shares
Expand Down
36 changes: 36 additions & 0 deletions contracts/permissioned/PermissionedPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,40 @@ contract PermissionedPool is Pool {

return super.maxMint(receiver);
}

/**
* @inheritdoc Pool
* @dev If a lender is not (currently) allowed, 0 assets are allowed to be
* withdrawn from the Pool.
*/
function maxWithdraw(address owner)
public
view
override
returns (uint256 assets)
{
if (!poolAccessControl.isAllowed(owner)) {
return 0;
}

return super.maxWithdraw(owner);
}

/**
* @inheritdoc Pool
* @dev If a lender is not (currently) allowed, 0 shares are allowed to be
* redeemed from the Pool.
*/
function maxRedeem(address owner)
public
view
override
returns (uint256 maxShares)
{
if (!poolAccessControl.isAllowed(owner)) {
return 0;
}

return super.maxRedeem(owner);
}
}
192 changes: 192 additions & 0 deletions test/Pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ describe("Pool", () => {
);
});

it("returns 0 when the pool is paused", async () => {
const {
pool,
pauser,
serviceConfiguration,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Pause
await serviceConfiguration.connect(pauser).setPaused(true);

expect(await pool.maxDeposit(otherAccount.address)).to.equal(0);
});

it("returns the full pool capacity less totalAvailableAssets", async () => {
const { pool, poolAdmin, otherAccount, liquidityAsset } =
await loadFixture(loadPoolFixture);
Expand All @@ -126,6 +144,46 @@ describe("Pool", () => {
);
});

it("returns 0 if totalAvailableAssets exceeds pool max capacity", async () => {
const {
pool,
poolController,
loan,
borrower,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Fund loan
await depositToPool(
pool,
otherAccount,
liquidityAsset,
DEFAULT_POOL_SETTINGS.maxCapacity
);
await fundLoan(loan, poolController, poolAdmin);
await loan.connect(borrower).drawdown(await loan.principal());

// Pay back loan
const interestWithFLFee = 23747 + 1249;
await liquidityAsset
.connect(borrower)
.approve(loan.address, interestWithFLFee + 1_000_000); // With principal
await liquidityAsset.mint(borrower.address, interestWithFLFee);
await loan.connect(borrower).completeFullPayment();

// Check total available assets
expect(await pool.totalAvailableAssets()).to.be.greaterThan(
(await pool.settings()).maxCapacity
);

// Max Deposit should return 0
expect(await pool.maxDeposit(otherAccount.address)).to.equal(0);
});

it("returns 0 when pool is closed ", async () => {
const { pool, poolAdmin, otherAccount, liquidityAsset } =
await loadFixture(loadPoolFixture);
Expand Down Expand Up @@ -282,6 +340,24 @@ describe("Pool", () => {
);
});

it("returns 0 when the pool is paused", async () => {
const {
pool,
pauser,
serviceConfiguration,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Pause
await serviceConfiguration.connect(pauser).setPaused(true);

expect(await pool.maxMint(otherAccount.address)).to.equal(0);
});

it("returns the full pool capacity less totalAvailableAssets", async () => {
const { pool, poolAdmin, otherAccount, liquidityAsset } =
await loadFixture(loadPoolFixture);
Expand All @@ -295,6 +371,46 @@ describe("Pool", () => {
);
});

it("returns 0 if totalAvailableAssets exceeds pool max capacity", async () => {
const {
pool,
poolController,
loan,
borrower,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Fund loan
await depositToPool(
pool,
otherAccount,
liquidityAsset,
DEFAULT_POOL_SETTINGS.maxCapacity
);
await fundLoan(loan, poolController, poolAdmin);
await loan.connect(borrower).drawdown(await loan.principal());

// Pay back loan
const interestWithFLFee = 23747 + 1249;
await liquidityAsset
.connect(borrower)
.approve(loan.address, interestWithFLFee + 1_000_000); // With principal
await liquidityAsset.mint(borrower.address, interestWithFLFee);
await loan.connect(borrower).completeFullPayment();

// Check total available assets
expect(await pool.totalAvailableAssets()).to.be.greaterThan(
(await pool.settings()).maxCapacity
);

// Max Deposit should return 0
expect(await pool.maxMint(otherAccount.address)).to.equal(0);
});

it("returns 0 when pool is closed ", async () => {
const { pool, poolAdmin, otherAccount, liquidityAsset } =
await loadFixture(loadPoolFixture);
Expand Down Expand Up @@ -881,6 +997,44 @@ describe("Pool", () => {

expect(await pool.maxRedeem(otherAccount.address)).to.equal(9); // 10 - snapshot dust
});

it("returns 0 when the pool is paused", async () => {
const {
pool,
pauser,
serviceConfiguration,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Deposit and request withdraw
const depositAmount = 10;
const withdrawAmount = 5;
await depositToPool(pool, otherAccount, liquidityAsset, depositAmount);
await pool.connect(otherAccount).requestWithdraw(withdrawAmount);

// Advance to next period
await time.increase(
(
await pool.settings()
).withdrawRequestPeriodDuration
);
await pool.snapshot();

// Some should be withdrawable
expect(await pool.maxWithdraw(otherAccount.address)).to.be.greaterThan(
0
);

// Pause
await serviceConfiguration.connect(pauser).setPaused(true);

// Should be 0
expect(await pool.maxRedeem(otherAccount.address)).to.equal(0);
});
});

describe("maxWithdraw()", () => {
Expand All @@ -898,6 +1052,44 @@ describe("Pool", () => {

expect(await pool.maxWithdraw(otherAccount.address)).to.equal(9);
});

it("returns 0 when the pool is paused", async () => {
const {
pool,
pauser,
serviceConfiguration,
poolAdmin,
otherAccount,
liquidityAsset
} = await loadFixture(loadPoolFixture);

await activatePool(pool, poolAdmin, liquidityAsset);

// Deposit and request withdraw
const depositAmount = 10;
const withdrawAmount = 5;
await depositToPool(pool, otherAccount, liquidityAsset, depositAmount);
await pool.connect(otherAccount).requestWithdraw(withdrawAmount);

// Advance to next period
await time.increase(
(
await pool.settings()
).withdrawRequestPeriodDuration
);
await pool.snapshot();

// Some should be withdrawable
expect(await pool.maxWithdraw(otherAccount.address)).to.be.greaterThan(
0
);

// Pause
await serviceConfiguration.connect(pauser).setPaused(true);

// Should be zero
expect(await pool.maxWithdraw(otherAccount.address)).to.equal(0);
});
});
});

Expand Down
Loading