Skip to content

Commit

Permalink
Contract size mitigation (#979)
Browse files Browse the repository at this point in the history
* moved inflator state update logic to PoolHelper

* moved flashLoan impl into PoolCommons
  • Loading branch information
EdNoepel authored Nov 16, 2023
1 parent 182c55a commit f1ad5cb
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 41 deletions.
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
19 changes: 4 additions & 15 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,20 +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);
// 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){
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

0 comments on commit f1ad5cb

Please sign in to comment.