From a6d2d6f2566c8dac09e670bd3ce78bed493c5777 Mon Sep 17 00:00:00 2001 From: Skye Date: Fri, 5 Jan 2024 16:07:47 +0800 Subject: [PATCH] fix-division-before-multiplication --- contracts/GasSavingPool/impl/GSP.sol | 13 ------------ contracts/GasSavingPool/impl/GSPFunding.sol | 22 ++------------------- contracts/GasSavingPool/impl/GSPStorage.sol | 19 ------------------ contracts/GasSavingPool/impl/GSPTrader.sol | 8 -------- contracts/lib/DODOMath.sol | 6 +++--- 5 files changed, 5 insertions(+), 63 deletions(-) diff --git a/contracts/GasSavingPool/impl/GSP.sol b/contracts/GasSavingPool/impl/GSP.sol index ea5afd9..5765fc2 100644 --- a/contracts/GasSavingPool/impl/GSP.sol +++ b/contracts/GasSavingPool/impl/GSP.sol @@ -41,40 +41,27 @@ contract GSP is GSPTrader, GSPFunding { uint256 k, bool isOpenTWAP ) external { - // GSP can only be initialized once require(!_GSP_INITIALIZED_, "GSP_INITIALIZED"); - // _GSP_INITIALIZED_ is set to true after initialization _GSP_INITIALIZED_ = true; - // baseTokenAddress and quoteTokenAddress should not be the same require(baseTokenAddress != quoteTokenAddress, "BASE_QUOTE_CAN_NOT_BE_SAME"); - // _BASE_TOKEN_ and _QUOTE_TOKEN_ should be valid ERC20 tokens _BASE_TOKEN_ = IERC20(baseTokenAddress); _QUOTE_TOKEN_ = IERC20(quoteTokenAddress); - // i should be greater than 0 and less than 10**36 require(i > 0 && i <= 10**36); _I_ = i; - // k should be greater than 0 and less than 10**18 require(k <= 10**18); _K_ = k; - // _LP_FEE_RATE_ is set when initialization _LP_FEE_RATE_ = lpFeeRate; - // _MT_FEE_RATE_ is set when initialization _MT_FEE_RATE_ = mtFeeRate; - // _MAINTAINER_ is set when initialization, the address receives the fee _MAINTAINER_ = maintainer; _IS_OPEN_TWAP_ = isOpenTWAP; - // if _IS_OPEN_TWAP_ is true, _BLOCK_TIMESTAMP_LAST_ is set to the current block timestamp if (isOpenTWAP) _BLOCK_TIMESTAMP_LAST_ = uint32(block.timestamp % 2**32); string memory connect = "_"; string memory suffix = "GSP"; - // name of the shares is the combination of suffix, connect and string of the GSP name = string(abi.encodePacked(suffix, connect, addressToShortString(address(this)))); - // symbol of the shares is GLP symbol = "GLP"; - // decimals of the shares is the same as the base token decimals decimals = IERC20Metadata(baseTokenAddress).decimals(); // ============================== Permit ==================================== diff --git a/contracts/GasSavingPool/impl/GSPFunding.sol b/contracts/GasSavingPool/impl/GSPFunding.sol index 894ad2f..36a454a 100644 --- a/contracts/GasSavingPool/impl/GSPFunding.sol +++ b/contracts/GasSavingPool/impl/GSPFunding.sol @@ -37,29 +37,23 @@ contract GSPFunding is GSPVault { uint256 quoteInput ) { - // The balance of baseToken and quoteToken should be the balance minus the fee uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)) - _MT_FEE_BASE_; uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)) - _MT_FEE_QUOTE_; - // The reserve of baseToken and quoteToken uint256 baseReserve = _BASE_RESERVE_; uint256 quoteReserve = _QUOTE_RESERVE_; - // The amount of baseToken and quoteToken user transfer to GSP baseInput = baseBalance - baseReserve; quoteInput = quoteBalance - quoteReserve; - // BaseToken should be transferred to GSP before calling buyShares require(baseInput > 0, "NO_BASE_INPUT"); // Round down when withdrawing. Therefore, never be a situation occuring balance is 0 but totalsupply is not 0 // But May Happen,reserve >0 But totalSupply = 0 if (totalSupply == 0) { // case 1. initial supply - // The shares will be minted to user shares = quoteBalance < DecimalMath.mulFloor(baseBalance, _I_) ? DecimalMath.divFloor(quoteBalance, _I_) : baseBalance; - // The target will be updated _BASE_TARGET_ = uint112(shares); _QUOTE_TARGET_ = uint112(DecimalMath.mulFloor(shares, _I_)); } else if (baseReserve > 0 && quoteReserve > 0) { @@ -67,15 +61,12 @@ contract GSPFunding is GSPVault { uint256 baseInputRatio = DecimalMath.divFloor(baseInput, baseReserve); uint256 quoteInputRatio = DecimalMath.divFloor(quoteInput, quoteReserve); uint256 mintRatio = quoteInputRatio < baseInputRatio ? quoteInputRatio : baseInputRatio; - // The shares will be minted to user shares = DecimalMath.mulFloor(totalSupply, mintRatio); - // The target will be updated _BASE_TARGET_ = uint112(uint256(_BASE_TARGET_) + (DecimalMath.mulFloor(uint256(_BASE_TARGET_), mintRatio))); _QUOTE_TARGET_ = uint112(uint256(_QUOTE_TARGET_) + (DecimalMath.mulFloor(uint256(_QUOTE_TARGET_), mintRatio))); } - // The shares will be minted to user - // The reserve will be updated + _mint(to, shares); _setReserve(baseBalance, quoteBalance); emit BuyShares(to, shares, _SHARES_[to]); @@ -97,34 +88,25 @@ contract GSPFunding is GSPVault { bytes calldata data, uint256 deadline ) external nonReentrant returns (uint256 baseAmount, uint256 quoteAmount) { - // The deadline should be greater than current timestamp require(deadline >= block.timestamp, "TIME_EXPIRED"); - // The amount of shares user want to sell should be less than user's balance require(shareAmount <= _SHARES_[msg.sender], "GLP_NOT_ENOUGH"); - // The balance of baseToken and quoteToken should be the balance minus the fee uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)) - _MT_FEE_BASE_; uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)) - _MT_FEE_QUOTE_; - // The total shares of GSP uint256 totalShares = totalSupply; - // The amount of baseToken and quoteToken user will receive is calculated by the ratio of user's shares to total shares baseAmount = baseBalance * shareAmount / totalShares; quoteAmount = quoteBalance * shareAmount / totalShares; - // The target will be updated _BASE_TARGET_ = uint112(uint256(_BASE_TARGET_) - DecimalMath._divCeil((uint256(_BASE_TARGET_) * (shareAmount)), totalShares)); _QUOTE_TARGET_ = uint112(uint256(_QUOTE_TARGET_) - DecimalMath._divCeil((uint256(_QUOTE_TARGET_) * (shareAmount)), totalShares)); - // The calculated baseToken and quoteToken amount should geater than minBaseToken and minQuoteToken require( baseAmount >= baseMinAmount && quoteAmount >= quoteMinAmount, "WITHDRAW_NOT_ENOUGH" ); - // The shares will be burned from user - // The baseToken and quoteToken will be transferred to user - // The reserve will be synced + _burn(msg.sender, shareAmount); _transferBaseOut(to, baseAmount); _transferQuoteOut(to, quoteAmount); diff --git a/contracts/GasSavingPool/impl/GSPStorage.sol b/contracts/GasSavingPool/impl/GSPStorage.sol index 421993c..0942b13 100644 --- a/contracts/GasSavingPool/impl/GSPStorage.sol +++ b/contracts/GasSavingPool/impl/GSPStorage.sol @@ -17,42 +17,27 @@ import {PMMPricing} from "../../lib/PMMPricing.sol"; contract GSPStorage is ReentrancyGuard { // ============ Storage for Setup ============ - // _GSP_INITIALIZED_ will be set to true when the init function is called bool internal _GSP_INITIALIZED_; - // GSP does not open TWAP by default - // _IS_OPEN_TWAP_ can be set to true when the init function is called bool public _IS_OPEN_TWAP_ = false; // ============ Core Address ============ - // _MAINTAINER_ is the maintainer of GSP address public _MAINTAINER_; - // _BASE_TOKEN_ and _QUOTE_TOKEN_ should be ERC20 token IERC20 public _BASE_TOKEN_; IERC20 public _QUOTE_TOKEN_; - // _BASE_RESERVE_ and _QUOTE_RESERVE_ are the current reserves of the GSP uint112 public _BASE_RESERVE_; uint112 public _QUOTE_RESERVE_; - // _BLOCK_TIMESTAMP_LAST_ is used when calculating TWAP uint32 public _BLOCK_TIMESTAMP_LAST_; - // _BASE_PRICE_CUMULATIVE_LAST_ is used when calculating TWAP uint256 public _BASE_PRICE_CUMULATIVE_LAST_; - // _BASE_TARGET_ and _QUOTE_TARGET_ are recalculated when the pool state changes uint112 public _BASE_TARGET_; uint112 public _QUOTE_TARGET_; - // _RState_ is the current R state of the GSP uint32 public _RState_; // ============ Shares (ERC20) ============ - // symbol is the symbol of the shares string public symbol; - // decimals is the decimals of the shares uint8 public decimals; - // name is the name of the shares string public name; - // totalSupply is the total supply of the shares uint256 public totalSupply; - // _SHARES_ is the mapping from account to share balance, record the share balance of each account mapping(address => uint256) internal _SHARES_; mapping(address => mapping(address => uint256)) internal _ALLOWED_; @@ -65,9 +50,7 @@ contract GSPStorage is ReentrancyGuard { mapping(address => uint256) public nonces; // ============ Variables for Pricing ============ - // _MT_FEE_RATE_ is the fee rate of mt fee uint256 public _MT_FEE_RATE_; - // _LP_FEE_RATE_ is the fee rate of lp fee uint256 public _LP_FEE_RATE_; uint256 public _K_; uint256 public _I_; @@ -75,9 +58,7 @@ contract GSPStorage is ReentrancyGuard { uint256 public _PRICE_LIMIT_ = 1e3; // ============ Mt Fee ============ - // _MT_FEE_BASE_ represents the mt fee in base token uint256 public _MT_FEE_BASE_; - // _MT_FEE_QUOTE_ represents the mt fee in quote token uint256 public _MT_FEE_QUOTE_; // ============ Helper Functions ============ diff --git a/contracts/GasSavingPool/impl/GSPTrader.sol b/contracts/GasSavingPool/impl/GSPTrader.sol index 97c3f3b..1cb8c65 100644 --- a/contracts/GasSavingPool/impl/GSPTrader.sol +++ b/contracts/GasSavingPool/impl/GSPTrader.sol @@ -43,11 +43,8 @@ contract GSPTrader is GSPVault { uint256 mtFee; uint256 newBaseTarget; PMMPricing.RState newRState; - // calculate the amount of quote token to receive and mt fee (receiveQuoteAmount, mtFee, newRState, newBaseTarget) = querySellBase(tx.origin, baseInput); - // transfer quote token to recipient _transferQuoteOut(to, receiveQuoteAmount); - // update mt fee in quote token _MT_FEE_QUOTE_ = _MT_FEE_QUOTE_ + mtFee; @@ -58,7 +55,6 @@ contract GSPTrader is GSPVault { _RState_ = uint32(newRState); emit RChange(newRState); } - // update reserve _setReserve(baseBalance, _QUOTE_TOKEN_.balanceOf(address(this)) - _MT_FEE_QUOTE_); emit DODOSwap( @@ -82,14 +78,11 @@ contract GSPTrader is GSPVault { uint256 mtFee; uint256 newQuoteTarget; PMMPricing.RState newRState; - // calculate the amount of base token to receive and mt fee (receiveBaseAmount, mtFee, newRState, newQuoteTarget) = querySellQuote( tx.origin, quoteInput ); - // transfer base token to recipient _transferBaseOut(to, receiveBaseAmount); - // update mt fee in base token _MT_FEE_BASE_ = _MT_FEE_BASE_ + mtFee; // update TARGET @@ -99,7 +92,6 @@ contract GSPTrader is GSPVault { _RState_ = uint32(newRState); emit RChange(newRState); } - // update reserve _setReserve((_BASE_TOKEN_.balanceOf(address(this)) - _MT_FEE_BASE_), quoteBalance); emit DODOSwap( diff --git a/contracts/lib/DODOMath.sol b/contracts/lib/DODOMath.sol index ba228ad..1ccbc76 100644 --- a/contracts/lib/DODOMath.sol +++ b/contracts/lib/DODOMath.sol @@ -144,9 +144,9 @@ library DODOMath { } else if ((idelta * V1) / idelta == V1) { temp = (idelta * V1) / (V0 * V0); } else { - temp = delta * (V1) / (V0) * (i) / (V0); + temp = delta * V1 / V0 * i / V0; } - return V1 * (temp) / (temp + (DecimalMath.ONE)); + return V1 * temp / (temp + (DecimalMath.ONE)); } // calculate -b value and sig @@ -156,7 +156,7 @@ library DODOMath { // bAbs = abs(part1-part2) // if part1>part2 => b is negative => bSig is false // if part2>part1 => b is positive => bSig is true - uint256 part2 = k * (V0) / (V1) * (V0) + (i * (delta)); // kQ0^2/Q1-i*deltaB + uint256 part2 = k * V0 / (V1 * V0) + (i * (delta)); // kQ0^2/Q1-i*deltaB uint256 bAbs = (DecimalMath.ONE - k) * (V1); // (1-k)Q1 bool bSig;