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

First borrower #968

Merged
merged 8 commits into from
Nov 16, 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
1 change: 0 additions & 1 deletion src/ERC721Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,6 @@ contract ERC721Pool is FlashloanablePool, IERC721Pool {
// Total collateral in buckets meets the requested removal amount, noOfNFTsToRemove_
_transferFromPoolToAddress(msg.sender, bucketTokenIds, noOfNFTsToRemove_);
}

}

/**
Expand Down
26 changes: 2 additions & 24 deletions src/base/FlashloanablePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { Pool } from './Pool.sol';
import { PoolCommons } from '../libraries/external/PoolCommons.sol';
import { IERC3156FlashBorrower } from '../interfaces/pool/IERC3156FlashBorrower.sol';

/**
Expand All @@ -32,30 +33,7 @@ abstract contract FlashloanablePool is Pool {
bytes calldata data_
) external virtual override nonReentrant returns (bool success_) {
if (!_isFlashloanSupported(token_)) revert FlashloanUnavailableForToken();

IERC20 tokenContract = IERC20(token_);

uint256 initialBalance = tokenContract.balanceOf(address(this));

tokenContract.safeTransfer(
address(receiver_),
amount_
);

if (receiver_.onFlashLoan(msg.sender, token_, amount_, 0, data_) !=
keccak256("ERC3156FlashBorrower.onFlashLoan")) revert FlashloanCallbackFailed();

tokenContract.safeTransferFrom(
address(receiver_),
address(this),
amount_
);

if (tokenContract.balanceOf(address(this)) != initialBalance) revert FlashloanIncorrectBalance();

success_ = true;

emit Flashloan(address(receiver_), token_, amount_);
success_ = PoolCommons.flashLoan(receiver_, token_, amount_, data_);
}

/**
Expand Down
15 changes: 4 additions & 11 deletions src/base/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pragma solidity 0.8.18;
import { Clone } from '@clones/Clone.sol';
import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { Multicall } from '@openzeppelin/contracts/utils/Multicall.sol';
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

Expand Down Expand Up @@ -51,6 +50,7 @@ import {
} from '../interfaces/pool/commons/IPoolInternals.sol';

import {
_determineInflatorState,
_priceAt,
_roundToScale
} from '../libraries/helpers/PoolHelper.sol';
Expand Down Expand Up @@ -688,16 +688,9 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool {
emit InterestUpdateFailure();
}

// update pool inflator
if (poolState_.isNewInterestAccrued) {
inflatorState.inflator = SafeCast.toUint208(poolState_.inflator);
inflatorState.inflatorUpdate = SafeCast.toUint48(block.timestamp);
// if the debt in the current pool state is 0, also update the inflator and inflatorUpdate fields in inflatorState
// slither-disable-next-line incorrect-equality
} else if (poolState_.debt == 0) {
inflatorState.inflator = SafeCast.toUint208(Maths.WAD);
inflatorState.inflatorUpdate = SafeCast.toUint48(block.timestamp);
}
(uint208 newInflator, bool updateTimestamp) = _determineInflatorState(poolState_, inflatorState);
inflatorState.inflator = newInflator;
if (updateTimestamp) inflatorState.inflatorUpdate = uint48(block.timestamp);
}

/**
Expand Down
47 changes: 47 additions & 0 deletions src/libraries/external/PoolCommons.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ pragma solidity 0.8.18;
import { PRBMathSD59x18 } from "@prb-math/contracts/PRBMathSD59x18.sol";
import { PRBMathUD60x18 } from "@prb-math/contracts/PRBMathUD60x18.sol";

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";


import { InterestState, EmaState, PoolState, DepositsState } from '../../interfaces/pool/commons/IPoolState.sol';
import { IERC3156FlashBorrower } from '../../interfaces/pool/IERC3156FlashBorrower.sol';

import { _dwatp, _indexOf, MAX_FENWICK_INDEX, MIN_PRICE, MAX_PRICE } from '../helpers/PoolHelper.sol';


import { Deposits } from '../internal/Deposits.sol';
import { Buckets } from '../internal/Buckets.sol';
import { Loans } from '../internal/Loans.sol';
Expand All @@ -21,6 +27,8 @@ import { Maths } from '../internal/Maths.sol';
- pool utilization
*/
library PoolCommons {
using SafeERC20 for IERC20;


/*****************/
/*** Constants ***/
Expand All @@ -40,9 +48,18 @@ library PoolCommons {
/**************/

// See `IPoolEvents` for descriptions
event Flashloan(address indexed receiver, address indexed token, uint256 amount);
event ResetInterestRate(uint256 oldRate, uint256 newRate);
event UpdateInterestRate(uint256 oldRate, uint256 newRate);

/**************/
/*** Errors ***/
/**************/

// See `IPoolErrors` for descriptions
error FlashloanCallbackFailed();
error FlashloanIncorrectBalance();

/*************************/
/*** Local Var Structs ***/
/*************************/
Expand Down Expand Up @@ -259,6 +276,36 @@ library PoolCommons {
}
}

function flashLoan(
IERC3156FlashBorrower receiver_,
address token_,
uint256 amount_,
bytes calldata data_
) external returns (bool success_) {
IERC20 tokenContract = IERC20(token_);

uint256 initialBalance = tokenContract.balanceOf(address(this));

tokenContract.safeTransfer(
address(receiver_),
amount_
);

if (receiver_.onFlashLoan(msg.sender, token_, amount_, 0, data_) !=
keccak256("ERC3156FlashBorrower.onFlashLoan")) revert FlashloanCallbackFailed();

tokenContract.safeTransferFrom(
address(receiver_),
address(this),
amount_
);

if (tokenContract.balanceOf(address(this)) != initialBalance) revert FlashloanIncorrectBalance();

success_ = true;
emit Flashloan(address(receiver_), token_, amount_);
}

/**************************/
/*** Internal Functions ***/
/**************************/
Expand Down
33 changes: 32 additions & 1 deletion src/libraries/helpers/PoolHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ pragma solidity 0.8.18;

import { PRBMathSD59x18 } from "@prb-math/contracts/PRBMathSD59x18.sol";
import { Math } from '@openzeppelin/contracts/utils/math/Math.sol';
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import { PoolType } from '../../interfaces/pool/IPool.sol';
import { PoolType } from '../../interfaces/pool/IPool.sol';
import { InflatorState, PoolState } from '../../interfaces/pool/commons/IPoolState.sol';

import { Buckets } from '../internal/Buckets.sol';
import { Maths } from '../internal/Maths.sol';
Expand Down Expand Up @@ -133,6 +135,35 @@ import { Maths } from '../internal/Maths.sol';
return Maths.min(Maths.wdiv(interestRate_, 365 * 1e18), 0.1 * 1e18);
}

/**
* @notice Determines how the inflator state should be updated
* @param poolState_ State of the pool after updateInterestState was called.
* @param inflatorState_ Old inflator state.
* @return newInflator_ New inflator value.
* @return updateTimestamp_ `True` if timestamp of last update should be updated.
*/
function _determineInflatorState(
PoolState memory poolState_,
InflatorState memory inflatorState_
) view returns (uint208 newInflator_, bool updateTimestamp_) {
newInflator_ = inflatorState_.inflator;

// update pool inflator
if (poolState_.isNewInterestAccrued) {
newInflator_ = SafeCast.toUint208(poolState_.inflator);
updateTimestamp_ = true;
// if the debt in the current pool state is 0, also update the inflator and inflatorUpdate fields in inflatorState
// slither-disable-next-line incorrect-equality
} else if (poolState_.debt == 0) {
newInflator_ = SafeCast.toUint208(Maths.WAD);
updateTimestamp_ = true;
// if the first loan has just been drawn, update the inflator timestamp
// slither-disable-next-line incorrect-equality
} else if (inflatorState_.inflator == Maths.WAD && inflatorState_.inflatorUpdate != block.timestamp){
updateTimestamp_ = true;
}
}

/**
* @notice Calculates debt-weighted average threshold price.
* @param t0Debt_ Pool debt owed by borrowers in `t0` terms.
Expand Down
Loading
Loading