ERC functionality split into internal/external
This commit is contained in:
123
src/ERC20External.sol
Normal file
123
src/ERC20External.sol
Normal file
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
import {IERC20Errors} from "../lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol";
|
||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {Context} from "../lib/openzeppelin-contracts/contracts/utils/Context.sol";
|
||||
import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
||||
import {ERC20Internal} from "./ERC20Internal.sol";
|
||||
|
||||
// Copied from OpenZeppelin's ERC20 implementation, but split into internal and external parts
|
||||
|
||||
contract ERC20External is ERC20Internal, IERC20Metadata {
|
||||
/**
|
||||
* @dev Sets the values for {name} and {symbol}.
|
||||
*
|
||||
* Both values are immutable: they can only be set once during construction.
|
||||
*/
|
||||
constructor(string memory name_, string memory symbol_) {
|
||||
_name = name_;
|
||||
_symbol = symbol_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev Returns the name of the token.
|
||||
*/
|
||||
function name() public view virtual returns (string memory) {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the symbol of the token, usually a shorter version of the
|
||||
* name.
|
||||
*/
|
||||
function symbol() public view virtual returns (string memory) {
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the number of decimals used to get its user representation.
|
||||
* For example, if `decimals` equals `2`, a balance of `505` tokens should
|
||||
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
|
||||
*
|
||||
* Tokens usually opt for a value of 18, imitating the relationship between
|
||||
* Ether and Wei. This is the default value returned by this function, unless
|
||||
* it's overridden.
|
||||
*
|
||||
* NOTE: This information is only used for _display_ purposes: it in
|
||||
* no way affects any of the arithmetic of the contract, including
|
||||
* {IERC20-balanceOf} and {IERC20-transfer}.
|
||||
*/
|
||||
function decimals() public view virtual returns (uint8) {
|
||||
return 18;
|
||||
}
|
||||
|
||||
/// @inheritdoc IERC20
|
||||
function totalSupply() public view virtual returns (uint256) {
|
||||
return _totalSupply;
|
||||
}
|
||||
|
||||
/// @inheritdoc IERC20
|
||||
function balanceOf(address account) public view virtual returns (uint256) {
|
||||
return _balances[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC20-transfer}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - the caller must have a balance of at least `value`.
|
||||
*/
|
||||
function transfer(address to, uint256 value) public virtual returns (bool) {
|
||||
address owner = _msgSender();
|
||||
_transfer(owner, to, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @inheritdoc IERC20
|
||||
function allowance(address owner, address spender) public view virtual returns (uint256) {
|
||||
return _allowances[owner][spender];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC20-approve}.
|
||||
*
|
||||
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
|
||||
* `transferFrom`. This is semantically equivalent to an infinite approval.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `spender` cannot be the zero address.
|
||||
*/
|
||||
function approve(address spender, uint256 value) public virtual returns (bool) {
|
||||
address owner = _msgSender();
|
||||
_approve(owner, spender, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC20-transferFrom}.
|
||||
*
|
||||
* Skips emitting an {Approval} event indicating an allowance update. This is not
|
||||
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
|
||||
*
|
||||
* NOTE: Does not update the allowance if the current allowance
|
||||
* is the maximum `uint256`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` and `to` cannot be the zero address.
|
||||
* - `from` must have a balance of at least `value`.
|
||||
* - the caller must have allowance for ``from``'s tokens of at least
|
||||
* `value`.
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
|
||||
address spender = _msgSender();
|
||||
_spendAllowance(from, spender, value);
|
||||
_transfer(from, to, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
175
src/ERC20Internal.sol
Normal file
175
src/ERC20Internal.sol
Normal file
@@ -0,0 +1,175 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
import {IERC20Errors} from "../lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol";
|
||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {Context} from "../lib/openzeppelin-contracts/contracts/utils/Context.sol";
|
||||
|
||||
// Copied from OpenZeppelin's ERC20 implementation, but split into internal and external parts
|
||||
|
||||
abstract contract ERC20Internal is Context, IERC20Errors {
|
||||
mapping(address account => uint256) internal _balances;
|
||||
mapping(address account => mapping(address spender => uint256)) internal _allowances;
|
||||
uint256 internal _totalSupply;
|
||||
string internal _name;
|
||||
string internal _symbol;
|
||||
|
||||
|
||||
/**
|
||||
* @dev Moves a `value` amount of tokens from `from` to `to`.
|
||||
*
|
||||
* This internal function is equivalent to {transfer}, and can be used to
|
||||
* e.g. implement automatic token fees, slashing mechanisms, etc.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead.
|
||||
*/
|
||||
function _transfer(address from, address to, uint256 value) internal {
|
||||
if (from == address(0)) {
|
||||
revert ERC20InvalidSender(address(0));
|
||||
}
|
||||
if (to == address(0)) {
|
||||
revert ERC20InvalidReceiver(address(0));
|
||||
}
|
||||
_update(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
|
||||
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
|
||||
* this function.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _update(address from, address to, uint256 value) internal virtual {
|
||||
if (from == address(0)) {
|
||||
// Overflow check required: The rest of the code assumes that totalSupply never overflows
|
||||
_totalSupply += value;
|
||||
} else {
|
||||
uint256 fromBalance = _balances[from];
|
||||
if (fromBalance < value) {
|
||||
revert ERC20InsufficientBalance(from, fromBalance, value);
|
||||
}
|
||||
unchecked {
|
||||
// Overflow not possible: value <= fromBalance <= totalSupply.
|
||||
_balances[from] = fromBalance - value;
|
||||
}
|
||||
}
|
||||
|
||||
if (to == address(0)) {
|
||||
unchecked {
|
||||
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
|
||||
_totalSupply -= value;
|
||||
}
|
||||
} else {
|
||||
unchecked {
|
||||
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
|
||||
_balances[to] += value;
|
||||
}
|
||||
}
|
||||
|
||||
emit IERC20.Transfer(from, to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
|
||||
* Relies on the `_update` mechanism
|
||||
*
|
||||
* Emits a {Transfer} event with `from` set to the zero address.
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead.
|
||||
*/
|
||||
function _mint(address account, uint256 value) internal {
|
||||
if (account == address(0)) {
|
||||
revert ERC20InvalidReceiver(address(0));
|
||||
}
|
||||
_update(address(0), account, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
|
||||
* Relies on the `_update` mechanism.
|
||||
*
|
||||
* Emits a {Transfer} event with `to` set to the zero address.
|
||||
*
|
||||
* NOTE: This function is not virtual, {_update} should be overridden instead
|
||||
*/
|
||||
function _burn(address account, uint256 value) internal {
|
||||
if (account == address(0)) {
|
||||
revert ERC20InvalidSender(address(0));
|
||||
}
|
||||
_update(account, address(0), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
|
||||
*
|
||||
* This internal function is equivalent to `approve`, and can be used to
|
||||
* e.g. set automatic allowances for certain subsystems, etc.
|
||||
*
|
||||
* Emits an {Approval} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `owner` cannot be the zero address.
|
||||
* - `spender` cannot be the zero address.
|
||||
*
|
||||
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
|
||||
*/
|
||||
function _approve(address owner, address spender, uint256 value) internal {
|
||||
_approve(owner, spender, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
|
||||
*
|
||||
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
|
||||
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
|
||||
* `Approval` event during `transferFrom` operations.
|
||||
*
|
||||
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
|
||||
* true using the following override:
|
||||
*
|
||||
* ```solidity
|
||||
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
|
||||
* super._approve(owner, spender, value, true);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Requirements are the same as {_approve}.
|
||||
*/
|
||||
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
|
||||
if (owner == address(0)) {
|
||||
revert ERC20InvalidApprover(address(0));
|
||||
}
|
||||
if (spender == address(0)) {
|
||||
revert ERC20InvalidSpender(address(0));
|
||||
}
|
||||
_allowances[owner][spender] = value;
|
||||
if (emitEvent) {
|
||||
emit IERC20.Approval(owner, spender, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Updates `owner`'s allowance for `spender` based on spent `value`.
|
||||
*
|
||||
* Does not update the allowance value in case of infinite allowance.
|
||||
* Revert if not enough allowance is available.
|
||||
*
|
||||
* Does not emit an {Approval} event.
|
||||
*/
|
||||
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
|
||||
uint256 currentAllowance = _allowances[owner][spender];
|
||||
if (currentAllowance < type(uint256).max) {
|
||||
if (currentAllowance < value) {
|
||||
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
|
||||
}
|
||||
unchecked {
|
||||
_approve(owner, spender, currentAllowance - value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,8 +82,12 @@ interface IPartyPool is IERC20Metadata {
|
||||
/// @notice Address that will receive collected protocol tokens when collectProtocolFees() is called.
|
||||
function protocolFeeAddress() external view returns (address);
|
||||
|
||||
/// @notice Per-token protocol fee ledger accessor. Returns tokens owed (raw uint token units) for token index i.
|
||||
function protocolFeesOwed(uint256) external view returns (uint256);
|
||||
/// @notice Protocol fee ledger accessor. Returns tokens owed (raw uint token units) from this pool as protocol fees
|
||||
/// that have not yet been transferred out.
|
||||
function allProtocolFeesOwed() external view returns (uint256[] memory);
|
||||
|
||||
/// @notice Callable by anyone, sends any owed protocol fees to the protocol fee address.
|
||||
function collectProtocolFees() external;
|
||||
|
||||
/// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q)
|
||||
/// @dev Pools are constructed with a κ value; this getter exposes the κ used by the pool.
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
import "forge-std/console2.sol";
|
||||
import "@abdk/ABDKMath64x64.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
import "./LMSRStabilized.sol";
|
||||
import "./LMSRStabilizedBalancedPair.sol";
|
||||
import "./IPartyPool.sol";
|
||||
import "./IPartyFlashCallback.sol";
|
||||
import "./PartyPoolBase.sol";
|
||||
import {PartyPoolSwapMintImpl} from "./PartyPoolSwapMintImpl.sol";
|
||||
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {Address} from "../lib/openzeppelin-contracts/contracts/utils/Address.sol";
|
||||
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
|
||||
import {IPartyFlashCallback} from "./IPartyFlashCallback.sol";
|
||||
import {IPartyPool} from "./IPartyPool.sol";
|
||||
import {LMSRStabilized} from "./LMSRStabilized.sol";
|
||||
import {LMSRStabilizedBalancedPair} from "./LMSRStabilizedBalancedPair.sol";
|
||||
import {PartyPoolBase} from "./PartyPoolBase.sol";
|
||||
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
|
||||
import {PartyPoolSwapMintImpl} from "./PartyPoolSwapMintImpl.sol";
|
||||
import {ERC20External} from "./ERC20External.sol";
|
||||
|
||||
/// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token
|
||||
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
|
||||
@@ -27,7 +28,7 @@ import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
|
||||
/// representation used by the LMSR library. Cached on-chain uint balances are kept to reduce balanceOf calls.
|
||||
/// The contract uses ceiling/floor rules described in function comments to bias rounding in favor of the pool
|
||||
/// (i.e., floor outputs to users, ceil inputs/fees where appropriate).
|
||||
contract PartyPool is PartyPoolBase, IPartyPool {
|
||||
contract PartyPool is PartyPoolBase, ERC20External, IPartyPool {
|
||||
using ABDKMath64x64 for int128;
|
||||
using LMSRStabilized for LMSRStabilized.State;
|
||||
using SafeERC20 for IERC20;
|
||||
@@ -54,6 +55,9 @@ contract PartyPool is PartyPoolBase, IPartyPool {
|
||||
address private immutable PROTOCOL_FEE_ADDRESS;
|
||||
function protocolFeeAddress() external view returns (address) { return PROTOCOL_FEE_ADDRESS; }
|
||||
|
||||
// @inheritdoc IPartyPool
|
||||
function allProtocolFeesOwed() external view returns (uint256[] memory) { return protocolFeesOwed; }
|
||||
|
||||
/// @notice If true and there are exactly two assets, an optimized 2-asset stable-pair path is used for some computations.
|
||||
bool immutable private IS_STABLE_PAIR; // if true, the optimized LMSRStabilizedBalancedPair optimization path is enabled
|
||||
|
||||
@@ -101,7 +105,7 @@ contract PartyPool is PartyPoolBase, IPartyPool {
|
||||
bool stable_,
|
||||
PartyPoolSwapMintImpl swapMintImpl_,
|
||||
PartyPoolMintImpl mintImpl_
|
||||
) PartyPoolBase(name_, symbol_) {
|
||||
) ERC20External(name_, symbol_) {
|
||||
require(tokens_.length > 1, "Pool: need >1 asset");
|
||||
require(tokens_.length == bases_.length, "Pool: lengths mismatch");
|
||||
tokens = tokens_;
|
||||
@@ -226,9 +230,6 @@ contract PartyPool is PartyPoolBase, IPartyPool {
|
||||
}
|
||||
|
||||
|
||||
// Per-token owed protocol fees (raw token units). Public getter autogenerated.
|
||||
uint256[] public protocolFeesOwed;
|
||||
|
||||
/// @notice Transfer all protocol fees to the configured protocolFeeAddress and zero the ledger.
|
||||
/// @dev Anyone can call; must have protocolFeeAddress != address(0) to be operational.
|
||||
function collectProtocolFees() external nonReentrant {
|
||||
@@ -411,7 +412,6 @@ contract PartyPool is PartyPoolBase, IPartyPool {
|
||||
|
||||
// Compute internal amounts using LMSR (exact-input with price limit)
|
||||
// if _stablePair is true, use the optimized path
|
||||
console2.log('stablepair optimization?', IS_STABLE_PAIR);
|
||||
(amountInInternalUsed, amountOutInternal) =
|
||||
IS_STABLE_PAIR ? LMSRStabilizedBalancedPair.swapAmountsForExactInput(lmsr, inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice)
|
||||
: lmsr.swapAmountsForExactInput(inputTokenIndex, outputTokenIndex, deltaInternalI, limitPrice);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
import "@abdk/ABDKMath64x64.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
||||
import "./LMSRStabilized.sol";
|
||||
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
|
||||
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
|
||||
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
|
||||
import {ERC20Internal} from "./ERC20Internal.sol";
|
||||
import {LMSRStabilized} from "./LMSRStabilized.sol";
|
||||
|
||||
/// @notice Abstract base contract that contains storage and internal helpers only.
|
||||
/// No external/public functions or constructor here — derived implementations own immutables and constructors.
|
||||
abstract contract PartyPoolBase is ERC20, ReentrancyGuard {
|
||||
abstract contract PartyPoolBase is ERC20Internal, ReentrancyGuard {
|
||||
using ABDKMath64x64 for int128;
|
||||
using LMSRStabilized for LMSRStabilized.State;
|
||||
|
||||
@@ -28,6 +28,10 @@ abstract contract PartyPoolBase is ERC20, ReentrancyGuard {
|
||||
/// @dev tokens[i] corresponds to the i-th asset and maps to index i in the internal LMSR arrays.
|
||||
IERC20[] internal tokens; // effectively immutable since there is no interface to change the tokens
|
||||
|
||||
/// @notice Amounts of token owed as protocol fees but not yet collected. Subtract this amount from the pool's token
|
||||
/// balances to compute the tokens owned by LP's.
|
||||
uint256[] internal protocolFeesOwed;
|
||||
|
||||
/// @notice Per-token uint base denominators used to convert uint token amounts <-> internal Q64.64 representation.
|
||||
/// @dev denominators()[i] is the base for tokens[i]. These bases are chosen by deployer and must match token decimals.
|
||||
uint256[] internal bases; // per-token uint base used to scale token amounts <-> internal
|
||||
@@ -41,9 +45,6 @@ abstract contract PartyPoolBase is ERC20, ReentrancyGuard {
|
||||
uint256[] internal cachedUintBalances;
|
||||
|
||||
|
||||
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}
|
||||
|
||||
|
||||
/* ----------------------
|
||||
Conversion & fee helpers (internal)
|
||||
---------------------- */
|
||||
|
||||
@@ -20,14 +20,12 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
event Mint(address indexed payer, address indexed receiver, uint256[] depositAmounts, uint256 lpMinted);
|
||||
event Burn(address indexed payer, address indexed receiver, uint256[] withdrawAmounts, uint256 lpBurned);
|
||||
|
||||
constructor() PartyPoolBase('','') {}
|
||||
|
||||
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external
|
||||
returns (uint256 lpMinted) {
|
||||
uint256 n = tokens.length;
|
||||
|
||||
// Check if this is initial deposit - revert if not
|
||||
bool isInitialDeposit = totalSupply() == 0 || lmsr.nAssets == 0;
|
||||
bool isInitialDeposit = _totalSupply == 0 || lmsr.nAssets == 0;
|
||||
require(isInitialDeposit, "initialMint: pool already initialized");
|
||||
|
||||
// Update cached balances for all assets
|
||||
@@ -62,7 +60,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
uint256 n = tokens.length;
|
||||
|
||||
// Check if this is NOT initial deposit - revert if it is
|
||||
bool isInitialDeposit = totalSupply() == 0 || lmsr.nAssets == 0;
|
||||
bool isInitialDeposit = _totalSupply == 0 || lmsr.nAssets == 0;
|
||||
require(!isInitialDeposit, "mint: use initialMint for pool initialization");
|
||||
require(lpTokenAmount > 0, "mint: zero LP amount");
|
||||
|
||||
@@ -71,7 +69,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
|
||||
|
||||
// Calculate required deposit amounts for the desired LP tokens
|
||||
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, lmsr.nAssets, totalSupply(), cachedUintBalances);
|
||||
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, lmsr.nAssets, _totalSupply, cachedUintBalances);
|
||||
|
||||
// Transfer in all token amounts
|
||||
for (uint i = 0; i < n; ) {
|
||||
@@ -104,7 +102,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
// Proportional issuance: totalSupply * delta / oldScaled
|
||||
if (delta > 0) {
|
||||
// floor truncation rounds in favor of the pool
|
||||
actualLpToMint = (totalSupply() * delta) / oldScaled;
|
||||
actualLpToMint = (_totalSupply * delta) / oldScaled;
|
||||
} else {
|
||||
actualLpToMint = 0;
|
||||
}
|
||||
@@ -135,10 +133,10 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
uint256 n = tokens.length;
|
||||
require(lpAmount > 0, "burn: zero lp");
|
||||
|
||||
uint256 supply = totalSupply();
|
||||
uint256 supply = _totalSupply;
|
||||
require(supply > 0, "burn: empty supply");
|
||||
require(lmsr.nAssets > 0, "burn: uninit pool");
|
||||
require(balanceOf(payer) >= lpAmount, "burn: insufficient LP");
|
||||
require(_balances[payer] >= lpAmount, "burn: insufficient LP");
|
||||
|
||||
// Refresh cached balances to reflect current on-chain balances before computing withdrawal amounts
|
||||
for (uint i = 0; i < n; ) {
|
||||
@@ -148,7 +146,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
}
|
||||
|
||||
// Compute proportional withdrawal amounts for the requested LP amount (rounded down)
|
||||
withdrawAmounts = burnAmounts(lpAmount, lmsr.nAssets, totalSupply(), cachedUintBalances);
|
||||
withdrawAmounts = burnAmounts(lpAmount, lmsr.nAssets, _totalSupply, cachedUintBalances);
|
||||
|
||||
// Transfer underlying tokens out to receiver according to computed proportions
|
||||
for (uint i = 0; i < n; ) {
|
||||
@@ -185,7 +183,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
|
||||
|
||||
// Burn exactly the requested LP amount from payer (authorization via allowance)
|
||||
if (msg.sender != payer) {
|
||||
uint256 allowed = allowance(payer, msg.sender);
|
||||
uint256 allowed = _allowances[payer][msg.sender];
|
||||
require(allowed >= lpAmount, "burn: allowance insufficient");
|
||||
_approve(payer, msg.sender, allowed - lpAmount);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ contract PartyPoolSwapMintImpl is PartyPoolBase {
|
||||
event Mint(address indexed payer, address indexed receiver, uint256[] depositAmounts, uint256 lpMinted);
|
||||
event Burn(address indexed payer, address indexed receiver, uint256[] withdrawAmounts, uint256 lpBurned);
|
||||
|
||||
constructor() PartyPoolBase('','') {}
|
||||
|
||||
/// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP.
|
||||
/// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal.
|
||||
@@ -85,7 +84,7 @@ contract PartyPoolSwapMintImpl is PartyPoolBase {
|
||||
|
||||
uint256 actualLpToMint;
|
||||
// Use natural ERC20 function since base contract inherits from ERC20
|
||||
uint256 currentSupply = totalSupply();
|
||||
uint256 currentSupply = _totalSupply;
|
||||
if (currentSupply == 0) {
|
||||
// If somehow supply zero (shouldn't happen as lmsr.nAssets>0), mint newScaled
|
||||
actualLpToMint = newScaled;
|
||||
@@ -259,9 +258,9 @@ contract PartyPoolSwapMintImpl is PartyPoolBase {
|
||||
require(lpAmount > 0, "burnSwap: zero lp");
|
||||
require(deadline == 0 || block.timestamp <= deadline, "burnSwap: deadline");
|
||||
|
||||
uint256 supply = totalSupply();
|
||||
uint256 supply = _totalSupply;
|
||||
require(supply > 0, "burnSwap: empty supply");
|
||||
require(balanceOf(payer) >= lpAmount, "burnSwap: insufficient LP");
|
||||
require(_balances[payer] >= lpAmount, "burnSwap: insufficient LP");
|
||||
|
||||
// alpha = lpAmount / supply as Q64.64 (adjusted for fee)
|
||||
int128 alpha = ABDKMath64x64.divu(lpAmount, supply) // fraction of total supply to burn
|
||||
@@ -285,7 +284,7 @@ contract PartyPoolSwapMintImpl is PartyPoolBase {
|
||||
|
||||
// Burn LP tokens from payer (authorization via allowance)
|
||||
if (msg.sender != payer) {
|
||||
uint256 allowed = allowance(payer, msg.sender);
|
||||
uint256 allowed = _allowances[payer][msg.sender];
|
||||
require(allowed >= lpAmount, "burnSwap: allowance insufficient");
|
||||
_approve(payer, msg.sender, allowed - lpAmount);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user