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

Contract size improvements #1046

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
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
21 changes: 16 additions & 5 deletions src/ERC20Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

pragma solidity 0.8.18;

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

import {
IERC20Pool,
Expand Down Expand Up @@ -36,7 +37,6 @@ import { PoolState } from './interfaces/pool/commons/IPoolState.sol';
import { FlashloanablePool } from './base/FlashloanablePool.sol';

import {
_getCollateralDustPricePrecisionAdjustment,
_roundToScale,
_roundUpToScale
} from './libraries/helpers/PoolHelper.sol';
Expand Down Expand Up @@ -493,8 +493,19 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @return Amount of collateral dust amount of the bucket.
*/
function _bucketCollateralDust(uint256 bucketIndex_) internal pure returns (uint256) {
// price precision adjustment will always be 0 for encumbered collateral
uint256 pricePrecisionAdjustment = _getCollateralDustPricePrecisionAdjustment(bucketIndex_);
// Price precision adjustment used in calculating collateral dust for a bucket.
// To ensure the accuracy of the exchange rate calculation, buckets with smaller prices require
// larger minimum amounts of collateral. This formula imposes a lower bound independent of token scale.
uint256 pricePrecisionAdjustment;

// conditional is a gas optimization
if (bucketIndex_ > 3900) {
int256 bucketOffset = int256(bucketIndex_ - 3900);
int256 result = PRBMathSD59x18.sqrt(PRBMathSD59x18.div(bucketOffset * 1e18, int256(36 * 1e18)));
// price precision adjustment will always be 0 for encumbered collateral
pricePrecisionAdjustment = uint256(result / 1e18);
}

// difference between the normalized scale and the collateral token's scale
return Maths.max(_getArgUint256(COLLATERAL_SCALE), 10 ** pricePrecisionAdjustment);
}
Expand Down
20 changes: 16 additions & 4 deletions src/base/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuar
import { Multicall } from '@openzeppelin/contracts/utils/Multicall.sol';
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { Math } from '@openzeppelin/contracts/utils/math/Math.sol';

import {
IPool,
Expand Down Expand Up @@ -51,7 +53,6 @@ import {

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

(uint208 newInflator, bool updateTimestamp) = _determineInflatorState(poolState_, inflatorState);
inflatorState.inflator = newInflator;
if (updateTimestamp) inflatorState.inflatorUpdate = uint48(block.timestamp);
// update pool inflator
if (poolState_.isNewInterestAccrued) {
inflatorState.inflator = SafeCast.toUint208(poolState_.inflator);
inflatorState.inflatorUpdate = uint48(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 = uint48(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 = uint48(block.timestamp);
}
}

/**
Expand Down
51 changes: 1 addition & 50 deletions src/libraries/helpers/PoolHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ 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 { InflatorState, PoolState } from '../../interfaces/pool/commons/IPoolState.sol';
import { PoolType } from '../../interfaces/pool/IPool.sol';

import { Buckets } from '../internal/Buckets.sol';
import { Maths } from '../internal/Maths.sol';
Expand Down Expand Up @@ -138,35 +136,6 @@ import { Maths } from '../internal/Maths.sol';
return Maths.wdiv(interestRate_, 365 * 3e18);
}

/**
* @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 `HTP` price.
* @param maxT0DebtToCollateral_ Max t0 debt to collateral in pool.
Expand Down Expand Up @@ -228,24 +197,6 @@ import { Maths } from '../internal/Maths.sol';
return Maths.wmul(collateral_, price_) >= Maths.wmul(COLLATERALIZATION_FACTOR, debt_);
}

/**
* @notice Price precision adjustment used in calculating collateral dust for a bucket.
* To ensure the accuracy of the exchange rate calculation, buckets with smaller prices require
* larger minimum amounts of collateral. This formula imposes a lower bound independent of token scale.
* @param bucketIndex_ Index of the bucket, or `0` for encumbered collateral with no bucket affinity.
* @return pricePrecisionAdjustment_ Unscaled integer of the minimum number of decimal places the dust limit requires.
*/
function _getCollateralDustPricePrecisionAdjustment(
uint256 bucketIndex_
) pure returns (uint256 pricePrecisionAdjustment_) {
// conditional is a gas optimization
if (bucketIndex_ > 3900) {
int256 bucketOffset = int256(bucketIndex_ - 3900);
int256 result = PRBMathSD59x18.sqrt(PRBMathSD59x18.div(bucketOffset * 1e18, int256(36 * 1e18)));
pricePrecisionAdjustment_ = uint256(result / 1e18);
}
}

/**
* @notice Returns the amount of collateral calculated for the given amount of `LP`.
* @dev The value returned is capped at collateral amount available in bucket.
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/internal/Buckets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ library Buckets {
uint256 bucketLP_,
uint256 bucketDeposit_,
uint256 bucketPrice_
) internal pure returns (uint256) {
) external pure returns (uint256) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating getExchangeRate method visibility to external created inconsistency in Buckets Library but is only called in view method in Pool contract.

return lpToQuoteTokens(
bucketCollateral_,
bucketLP_,
Expand Down
2 changes: 1 addition & 1 deletion tests/forge/unit/ERC20Pool/ERC20PoolFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { IPoolErrors } from 'src/interfaces/pool/commons/IPoolErrors.sol';
import { IPoolFactory } from 'src/interfaces/pool/IPoolFactory.sol';

contract ERC20PoolFactoryTest is ERC20HelperContract {
address immutable poolAddress = 0x9Fd7552Da37D2D296CB4a84d507c35Dcc926220a;
address immutable poolAddress = 0x22e52d5C273D99547F9Fa44B8034C16d93773B13;
bytes32 constant ERC20_NON_SUBSET_HASH = keccak256("ERC20_NON_SUBSET_HASH");

function setUp() external {
Expand Down
9 changes: 0 additions & 9 deletions tests/forge/unit/ERC20Pool/ERC20PoolPrecision.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -761,15 +761,6 @@ contract ERC20PoolPrecisionTest is ERC20DSTestPlus {
}

function testCollateralDustPricePrecisionAdjustment() external tearDown {
// test the bucket price adjustment used for determining dust amount
assertEq(_getCollateralDustPricePrecisionAdjustment(0), 0);
assertEq(_getCollateralDustPricePrecisionAdjustment(1), 0);
assertEq(_getCollateralDustPricePrecisionAdjustment(4156), 2);
assertEq(_getCollateralDustPricePrecisionAdjustment(4310), 3);
assertEq(_getCollateralDustPricePrecisionAdjustment(5260), 6);
assertEq(_getCollateralDustPricePrecisionAdjustment(6466), 8);
assertEq(_getCollateralDustPricePrecisionAdjustment(6647), 8);
assertEq(_getCollateralDustPricePrecisionAdjustment(7388), 9);

// check dust limits for 18-decimal collateral
init(18, 18);
Expand Down
8 changes: 4 additions & 4 deletions tests/forge/unit/ERC721Pool/ERC721PoolFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract ERC721PoolFactoryTest is ERC721HelperContract {

// deploy NFT collection pool
vm.expectEmit(true, true, false, true);
emit PoolCreated(0x8a2be84c82956B6DdA0c4D647Ae9357d845a086B, _factory.getNFTSubsetHash(tokenIds));
emit PoolCreated(0xCF7E26A9FE732063F431b91478E27092AD911162, _factory.getNFTSubsetHash(tokenIds));
_NFTCollectionPoolAddress = _factory.deployPool(address(_collateral), address(_quote), tokenIds, 0.05 * 10**18);
_NFTCollectionPool = ERC721Pool(_NFTCollectionPoolAddress);

Expand All @@ -46,7 +46,7 @@ contract ERC721PoolFactoryTest is ERC721HelperContract {
_tokenIdsSubsetOne[3] = 61;

vm.expectEmit(true, true, false, true);
emit PoolCreated(0x18D11C8Cf8dc292E647F0b324d10637a3A63F678, _factory.getNFTSubsetHash(_tokenIdsSubsetOne));
emit PoolCreated(0x4693faE904804C89B14b1C13d2a53f10D2c4e5E3, _factory.getNFTSubsetHash(_tokenIdsSubsetOne));
_NFTSubsetOnePoolAddress = _factory.deployPool(address(_collateral), address(_quote), _tokenIdsSubsetOne, 0.05 * 10**18);
_NFTSubsetOnePool = ERC721Pool(_NFTSubsetOnePoolAddress);

Expand All @@ -61,7 +61,7 @@ contract ERC721PoolFactoryTest is ERC721HelperContract {
_tokenIdsSubsetTwo[6] = 180;

vm.expectEmit(true, true, false, true);
emit PoolCreated(0xf80F47F84F20d8aF58cC8e93634348491357323c, _factory.getNFTSubsetHash(_tokenIdsSubsetTwo));
emit PoolCreated(0x0782c1757679ea21E7eFc4af5C7374dFD2388b58, _factory.getNFTSubsetHash(_tokenIdsSubsetTwo));
_NFTSubsetTwoPoolAddress = _factory.deployPool(address(_collateral), address(_quote), _tokenIdsSubsetTwo, 0.05 * 10**18);
_NFTSubsetTwoPool = ERC721Pool(_NFTSubsetTwoPoolAddress);

Expand Down Expand Up @@ -311,7 +311,7 @@ contract ERC721PoolFactoryTest is ERC721HelperContract {
tokenIdsTestSubset[2] = 3;

vm.expectEmit(true, true, false, true);
emit PoolCreated(0xA8FBA534d7ebefEBB270cDC4814A1A25916A94d3, _factory.getNFTSubsetHash(tokenIdsTestSubset));
emit PoolCreated(0x993df58454B37994dA5C81F98c33e3857a42dFc2, _factory.getNFTSubsetHash(tokenIdsTestSubset));
address poolAddress = _factory.deployPool(address(_collateral), address(_quote), tokenIdsTestSubset, 0.05 * 10**18);

// check tracking of deployed pools
Expand Down
2 changes: 1 addition & 1 deletion tests/forge/unit/PositionManager/PositionManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,7 @@ contract PositionManagerERC20PoolTest is PositionManagerERC20PoolHelperContract
_positionManager.nonces(5);

// check domain separator matches expectations for the test chain
assertEq(_positionManager.DOMAIN_SEPARATOR(), 0x255893ac72554d931c70a8c246ff1216c7122c81a4d4f7f2a2eb5377f2481f12);
assertEq(_positionManager.DOMAIN_SEPARATOR(), 0x433817320eb965ca857baacaaaffc14f306708454d94514994a825a8a91200f6);
}

function testPermitReverts() external {
Expand Down
Loading