Skip to content

Commit

Permalink
fix-division-before-multiplication
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyewwww committed Jan 5, 2024
1 parent ad9d148 commit a6d2d6f
Show file tree
Hide file tree
Showing 5 changed files with 5 additions and 63 deletions.
13 changes: 0 additions & 13 deletions contracts/GasSavingPool/impl/GSP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 ====================================
Expand Down
22 changes: 2 additions & 20 deletions contracts/GasSavingPool/impl/GSPFunding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,36 @@ 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) {
// case 2. normal case
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]);
Expand All @@ -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);
Expand Down
19 changes: 0 additions & 19 deletions contracts/GasSavingPool/impl/GSPStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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_;

Expand All @@ -65,19 +50,15 @@ 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_;
// _PRICE_LIMIT_ is 1/1000 by default, which is used to limit the setting range of I
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 ============
Expand Down
8 changes: 0 additions & 8 deletions contracts/GasSavingPool/impl/GSPTrader.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand All @@ -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(
Expand All @@ -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
Expand All @@ -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(
Expand Down
6 changes: 3 additions & 3 deletions contracts/lib/DODOMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit a6d2d6f

Please sign in to comment.