编译器
0.8.13+commit.abaa5c0e
文件 1 的 38:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 38:BlockNumber.sol
pragma solidity 0.8.13;
abstract contract BlockNumber {
function _blockNumber() internal view virtual returns (uint32) {
return uint32(block.number);
}
}
文件 3 的 38:Constants.sol
pragma solidity 0.8.13;
uint32 constant PPM_RESOLUTION = 1_000_000;
文件 4 的 38:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 38:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 6 的 38:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 7 的 38:Fraction.sol
pragma solidity 0.8.13;
struct Fraction {
uint256 n;
uint256 d;
}
struct Fraction112 {
uint112 n;
uint112 d;
}
error InvalidFraction();
文件 8 的 38:FractionLibrary.sol
pragma solidity 0.8.13;
import { Fraction, Fraction112, InvalidFraction } from "./Fraction.sol";
import { MathEx } from "./MathEx.sol";
function zeroFraction() pure returns (Fraction memory) {
return Fraction({ n: 0, d: 1 });
}
function zeroFraction112() pure returns (Fraction112 memory) {
return Fraction112({ n: 0, d: 1 });
}
library FractionLibrary {
function isValid(Fraction memory fraction) internal pure returns (bool) {
return fraction.d != 0;
}
function isValid(Fraction112 memory fraction) internal pure returns (bool) {
return fraction.d != 0;
}
function isPositive(Fraction memory fraction) internal pure returns (bool) {
return isValid(fraction) && fraction.n != 0;
}
function isPositive(Fraction112 memory fraction) internal pure returns (bool) {
return isValid(fraction) && fraction.n != 0;
}
function inverse(Fraction memory fraction) internal pure returns (Fraction memory) {
Fraction memory invFraction = Fraction({ n: fraction.d, d: fraction.n });
if (!isValid(invFraction)) {
revert InvalidFraction();
}
return invFraction;
}
function inverse(Fraction112 memory fraction) internal pure returns (Fraction112 memory) {
Fraction112 memory invFraction = Fraction112({ n: fraction.d, d: fraction.n });
if (!isValid(invFraction)) {
revert InvalidFraction();
}
return invFraction;
}
function toFraction112(Fraction memory fraction) internal pure returns (Fraction112 memory) {
Fraction memory reducedFraction = MathEx.reducedFraction(fraction, type(uint112).max);
return Fraction112({ n: uint112(reducedFraction.n), d: uint112(reducedFraction.d) });
}
function fromFraction112(Fraction112 memory fraction) internal pure returns (Fraction memory) {
return Fraction({ n: fraction.n, d: fraction.d });
}
}
文件 9 的 38:IAccessControlEnumerableUpgradeable.sol
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
文件 10 的 38:IAccessControlUpgradeable.sol
pragma solidity ^0.8.0;
interface IAccessControlUpgradeable {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 11 的 38:IBNTPool.sol
pragma solidity 0.8.13;
import { IPoolToken } from "./IPoolToken.sol";
import { Token } from "../../token/Token.sol";
import { IVault } from "../../vaults/interfaces/IVault.sol";
bytes32 constant ROLE_BNT_POOL_TOKEN_MANAGER = keccak256("ROLE_BNT_POOL_TOKEN_MANAGER");
bytes32 constant ROLE_BNT_MANAGER = keccak256("ROLE_BNT_MANAGER");
bytes32 constant ROLE_VAULT_MANAGER = keccak256("ROLE_VAULT_MANAGER");
bytes32 constant ROLE_FUNDING_MANAGER = keccak256("ROLE_FUNDING_MANAGER");
interface IBNTPool is IVault {
function poolToken() external view returns (IPoolToken);
function stakedBalance() external view returns (uint256);
function currentPoolFunding(Token pool) external view returns (uint256);
function availableFunding(Token pool) external view returns (uint256);
function poolTokenToUnderlying(uint256 poolTokenAmount) external view returns (uint256);
function underlyingToPoolToken(uint256 bntAmount) external view returns (uint256);
function poolTokenAmountToBurn(uint256 bntAmountToDistribute) external view returns (uint256);
function mint(address recipient, uint256 bntAmount) external;
function burnFromVault(uint256 bntAmount) external;
function depositFor(
bytes32 contextId,
address provider,
uint256 bntAmount,
bool isMigrating,
uint256 originalVBNTAmount
) external returns (uint256);
function withdraw(
bytes32 contextId,
address provider,
uint256 poolTokenAmount,
uint256 bntAmount
) external returns (uint256);
function withdrawalAmount(uint256 poolTokenAmount) external view returns (uint256);
function requestFunding(
bytes32 contextId,
Token pool,
uint256 bntAmount
) external;
function renounceFunding(
bytes32 contextId,
Token pool,
uint256 bntAmount
) external;
function onFeesCollected(
Token pool,
uint256 feeAmount,
bool isTradeFee
) external;
}
文件 12 的 38:IBancorNetwork.sol
pragma solidity 0.8.13;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IUpgradeable } from "../../utility/interfaces/IUpgradeable.sol";
import { Token } from "../../token/Token.sol";
import { IPoolCollection } from "../../pools/interfaces/IPoolCollection.sol";
import { IPoolToken } from "../../pools/interfaces/IPoolToken.sol";
interface IFlashLoanRecipient {
function onFlashLoan(
address caller,
IERC20 erc20Token,
uint256 amount,
uint256 feeAmount,
bytes memory data
) external;
}
interface IBancorNetwork is IUpgradeable {
function poolCollections() external view returns (IPoolCollection[] memory);
function liquidityPools() external view returns (Token[] memory);
function collectionByPool(Token pool) external view returns (IPoolCollection);
function createPools(Token[] calldata tokens, IPoolCollection poolCollection) external;
function migratePools(Token[] calldata pools, IPoolCollection newPoolCollection) external;
function depositFor(
address provider,
Token pool,
uint256 tokenAmount
) external payable returns (uint256);
function deposit(Token pool, uint256 tokenAmount) external payable returns (uint256);
function initWithdrawal(IPoolToken poolToken, uint256 poolTokenAmount) external returns (uint256);
function cancelWithdrawal(uint256 id) external returns (uint256);
function withdraw(uint256 id) external returns (uint256);
function tradeBySourceAmount(
Token sourceToken,
Token targetToken,
uint256 sourceAmount,
uint256 minReturnAmount,
uint256 deadline,
address beneficiary
) external payable returns (uint256);
function tradeByTargetAmount(
Token sourceToken,
Token targetToken,
uint256 targetAmount,
uint256 maxSourceAmount,
uint256 deadline,
address beneficiary
) external payable returns (uint256);
function flashLoan(
Token token,
uint256 amount,
IFlashLoanRecipient recipient,
bytes calldata data
) external;
function migrateLiquidity(
Token token,
address provider,
uint256 amount,
uint256 availableAmount,
uint256 originalAmount
) external payable;
function withdrawNetworkFees(address recipient) external returns (uint256);
}
文件 13 的 38:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 14 的 38:IERC20Burnable.sol
pragma solidity 0.8.13;
interface IERC20Burnable {
function burn(uint256 amount) external;
function burnFrom(address recipient, uint256 amount) external;
}
文件 15 的 38:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 16 的 38:IExternalProtectionVault.sol
pragma solidity 0.8.13;
import { IVault } from "./IVault.sol";
interface IExternalProtectionVault is IVault {}
文件 17 的 38:IMasterVault.sol
pragma solidity 0.8.13;
import { IVault } from "./IVault.sol";
interface IMasterVault is IVault {}
文件 18 的 38:INetworkSettings.sol
pragma solidity 0.8.13;
import { IUpgradeable } from "../../utility/interfaces/IUpgradeable.sol";
import { Token } from "../../token/Token.sol";
error NotWhitelisted();
struct VortexRewards {
uint32 burnRewardPPM;
uint256 burnRewardMaxAmount;
}
interface INetworkSettings is IUpgradeable {
function protectedTokenWhitelist() external view returns (Token[] memory);
function isTokenWhitelisted(Token pool) external view returns (bool);
function poolFundingLimit(Token pool) external view returns (uint256);
function minLiquidityForTrading() external view returns (uint256);
function withdrawalFeePPM() external view returns (uint32);
function defaultFlashLoanFeePPM() external view returns (uint32);
function flashLoanFeePPM(Token pool) external view returns (uint32);
function vortexRewards() external view returns (VortexRewards memory);
}
文件 19 的 38:IOwned.sol
pragma solidity 0.8.13;
interface IOwned {
function owner() external view returns (address);
function transferOwnership(address ownerCandidate) external;
function acceptOwnership() external;
}
文件 20 的 38:IPoolCollection.sol
pragma solidity 0.8.13;
import { IVersioned } from "../../utility/interfaces/IVersioned.sol";
import { Fraction112 } from "../../utility/FractionLibrary.sol";
import { Token } from "../../token/Token.sol";
import { IPoolToken } from "./IPoolToken.sol";
struct PoolLiquidity {
uint128 bntTradingLiquidity;
uint128 baseTokenTradingLiquidity;
uint256 stakedBalance;
}
struct AverageRates {
uint32 blockNumber;
Fraction112 rate;
Fraction112 invRate;
}
struct Pool {
IPoolToken poolToken;
uint32 tradingFeePPM;
bool tradingEnabled;
bool depositingEnabled;
AverageRates averageRates;
PoolLiquidity liquidity;
}
struct WithdrawalAmounts {
uint256 totalAmount;
uint256 baseTokenAmount;
uint256 bntAmount;
}
uint8 constant TRADING_STATUS_UPDATE_DEFAULT = 0;
uint8 constant TRADING_STATUS_UPDATE_ADMIN = 1;
uint8 constant TRADING_STATUS_UPDATE_MIN_LIQUIDITY = 2;
uint8 constant TRADING_STATUS_UPDATE_INVALID_STATE = 3;
struct TradeAmountAndFee {
uint256 amount;
uint256 tradingFeeAmount;
uint256 networkFeeAmount;
}
interface IPoolCollection is IVersioned {
function poolType() external view returns (uint16);
function defaultTradingFeePPM() external view returns (uint32);
function networkFeePPM() external view returns (uint32);
function pools() external view returns (Token[] memory);
function poolCount() external view returns (uint256);
function isPoolValid(Token pool) external view returns (bool);
function poolLiquidity(Token pool) external view returns (PoolLiquidity memory);
function poolToken(Token pool) external view returns (IPoolToken);
function tradingFeePPM(Token pool) external view returns (uint32);
function tradingEnabled(Token pool) external view returns (bool);
function depositingEnabled(Token pool) external view returns (bool);
function isPoolStable(Token pool) external view returns (bool);
function poolTokenToUnderlying(Token pool, uint256 poolTokenAmount) external view returns (uint256);
function underlyingToPoolToken(Token pool, uint256 baseTokenAmount) external view returns (uint256);
function poolTokenAmountToBurn(
Token pool,
uint256 baseTokenAmountToDistribute,
uint256 protocolPoolTokenAmount
) external view returns (uint256);
function createPool(Token token) external;
function depositFor(
bytes32 contextId,
address provider,
Token pool,
uint256 baseTokenAmount
) external returns (uint256);
function withdraw(
bytes32 contextId,
address provider,
Token pool,
uint256 poolTokenAmount,
uint256 baseTokenAmount
) external returns (uint256);
function withdrawalAmounts(Token pool, uint256 poolTokenAmount) external view returns (WithdrawalAmounts memory);
function tradeBySourceAmount(
bytes32 contextId,
Token sourceToken,
Token targetToken,
uint256 sourceAmount,
uint256 minReturnAmount
) external returns (TradeAmountAndFee memory);
function tradeByTargetAmount(
bytes32 contextId,
Token sourceToken,
Token targetToken,
uint256 targetAmount,
uint256 maxSourceAmount
) external returns (TradeAmountAndFee memory);
function tradeOutputAndFeeBySourceAmount(
Token sourceToken,
Token targetToken,
uint256 sourceAmount
) external view returns (TradeAmountAndFee memory);
function tradeInputAndFeeByTargetAmount(
Token sourceToken,
Token targetToken,
uint256 targetAmount
) external view returns (TradeAmountAndFee memory);
function onFeesCollected(Token pool, uint256 feeAmount) external;
function migratePoolIn(Token pool, Pool calldata data) external;
function migratePoolOut(Token pool, IPoolCollection targetPoolCollection) external;
}
文件 21 的 38:IPoolMigrator.sol
pragma solidity 0.8.13;
import { Token } from "../../token/Token.sol";
import { IVersioned } from "../../utility/interfaces/IVersioned.sol";
import { IPoolCollection } from "./IPoolCollection.sol";
interface IPoolMigrator is IVersioned {
function migratePool(Token pool, IPoolCollection newPoolCollection) external;
}
文件 22 的 38:IPoolToken.sol
pragma solidity 0.8.13;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import { IERC20Burnable } from "../../token/interfaces/IERC20Burnable.sol";
import { Token } from "../../token/Token.sol";
import { IVersioned } from "../../utility/interfaces/IVersioned.sol";
import { IOwned } from "../../utility/interfaces/IOwned.sol";
interface IPoolToken is IVersioned, IOwned, IERC20, IERC20Permit, IERC20Burnable {
function reserveToken() external view returns (Token);
function mint(address recipient, uint256 amount) external;
}
文件 23 的 38:IPoolTokenFactory.sol
pragma solidity 0.8.13;
import { Token } from "../../token/Token.sol";
import { IUpgradeable } from "../../utility/interfaces/IUpgradeable.sol";
import { IPoolToken } from "./IPoolToken.sol";
interface IPoolTokenFactory is IUpgradeable {
function tokenSymbolOverride(Token token) external view returns (string memory);
function tokenDecimalsOverride(Token token) external view returns (uint8);
function createPoolToken(Token token) external returns (IPoolToken);
}
文件 24 的 38:IUpgradeable.sol
pragma solidity 0.8.13;
import { IVersioned } from "./IVersioned.sol";
import { IAccessControlEnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/IAccessControlEnumerableUpgradeable.sol";
interface IUpgradeable is IAccessControlEnumerableUpgradeable, IVersioned {
}
文件 25 的 38:IVault.sol
pragma solidity 0.8.13;
import { IUpgradeable } from "../../utility/interfaces/IUpgradeable.sol";
import { Token } from "../../token/Token.sol";
bytes32 constant ROLE_ASSET_MANAGER = keccak256("ROLE_ASSET_MANAGER");
interface IVault is IUpgradeable {
event FundsWithdrawn(Token indexed token, address indexed caller, address indexed target, uint256 amount);
event FundsBurned(Token indexed token, address indexed caller, uint256 amount);
function isPayable() external view returns (bool);
function withdrawFunds(
Token token,
address payable target,
uint256 amount
) external;
function burn(Token token, uint256 amount) external;
}
文件 26 的 38:IVersioned.sol
pragma solidity 0.8.13;
interface IVersioned {
function version() external view returns (uint16);
}
文件 27 的 38:Math.sol
pragma solidity ^0.8.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b + (a % b == 0 ? 0 : 1);
}
}
文件 28 的 38:MathEx.sol
pragma solidity 0.8.13;
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { Fraction, InvalidFraction } from "./Fraction.sol";
import { PPM_RESOLUTION } from "./Constants.sol";
uint256 constant ONE = 0x80000000000000000000000000000000;
uint256 constant LN2 = 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57;
struct Uint512 {
uint256 hi;
uint256 lo;
}
struct Sint256 {
uint256 value;
bool isNeg;
}
library MathEx {
error Overflow();
function exp2(Fraction memory f) internal pure returns (Fraction memory) {
uint256 x = MathEx.mulDivF(LN2, f.n, f.d);
uint256 y;
uint256 z;
uint256 n;
if (x >= (ONE << 4)) {
revert Overflow();
}
unchecked {
z = y = x % (ONE >> 3);
z = (z * y) / ONE;
n += z * 0x10e1b3be415a0000;
z = (z * y) / ONE;
n += z * 0x05a0913f6b1e0000;
z = (z * y) / ONE;
n += z * 0x0168244fdac78000;
z = (z * y) / ONE;
n += z * 0x004807432bc18000;
z = (z * y) / ONE;
n += z * 0x000c0135dca04000;
z = (z * y) / ONE;
n += z * 0x0001b707b1cdc000;
z = (z * y) / ONE;
n += z * 0x000036e0f639b800;
z = (z * y) / ONE;
n += z * 0x00000618fee9f800;
z = (z * y) / ONE;
n += z * 0x0000009c197dcc00;
z = (z * y) / ONE;
n += z * 0x0000000e30dce400;
z = (z * y) / ONE;
n += z * 0x000000012ebd1300;
z = (z * y) / ONE;
n += z * 0x0000000017499f00;
z = (z * y) / ONE;
n += z * 0x0000000001a9d480;
z = (z * y) / ONE;
n += z * 0x00000000001c6380;
z = (z * y) / ONE;
n += z * 0x000000000001c638;
z = (z * y) / ONE;
n += z * 0x0000000000001ab8;
z = (z * y) / ONE;
n += z * 0x000000000000017c;
z = (z * y) / ONE;
n += z * 0x0000000000000014;
z = (z * y) / ONE;
n += z * 0x0000000000000001;
n = n / 0x21c3677c82b40000 + y + ONE;
if ((x & (ONE >> 3)) != 0)
n = (n * 0x1c3d6a24ed82218787d624d3e5eba95f9) / 0x18ebef9eac820ae8682b9793ac6d1e776;
if ((x & (ONE >> 2)) != 0)
n = (n * 0x18ebef9eac820ae8682b9793ac6d1e778) / 0x1368b2fc6f9609fe7aceb46aa619baed4;
if ((x & (ONE >> 1)) != 0)
n = (n * 0x1368b2fc6f9609fe7aceb46aa619baed5) / 0x0bc5ab1b16779be3575bd8f0520a9f21f;
if ((x & (ONE << 0)) != 0)
n = (n * 0x0bc5ab1b16779be3575bd8f0520a9f21e) / 0x0454aaa8efe072e7f6ddbab84b40a55c9;
if ((x & (ONE << 1)) != 0)
n = (n * 0x0454aaa8efe072e7f6ddbab84b40a55c5) / 0x00960aadc109e7a3bf4578099615711ea;
if ((x & (ONE << 2)) != 0)
n = (n * 0x00960aadc109e7a3bf4578099615711d7) / 0x0002bf84208204f5977f9a8cf01fdce3d;
if ((x & (ONE << 3)) != 0)
n = (n * 0x0002bf84208204f5977f9a8cf01fdc307) / 0x0000003c6ab775dd0b95b4cbee7e65d11;
}
return Fraction({ n: n, d: ONE });
}
function reducedFraction(Fraction memory fraction, uint256 max) internal pure returns (Fraction memory) {
uint256 scale = Math.ceilDiv(Math.max(fraction.n, fraction.d), max);
Fraction memory reduced = Fraction({ n: fraction.n / scale, d: fraction.d / scale });
if (reduced.d == 0) {
revert InvalidFraction();
}
return reduced;
}
function weightedAverage(
Fraction memory fraction1,
Fraction memory fraction2,
uint256 weight1,
uint256 weight2
) internal pure returns (Fraction memory) {
return
Fraction({
n: fraction1.n * fraction2.d * weight1 + fraction1.d * fraction2.n * weight2,
d: fraction1.d * fraction2.d * (weight1 + weight2)
});
}
function isInRange(
Fraction memory baseSample,
Fraction memory offsetSample,
uint32 maxDeviationPPM
) internal pure returns (bool) {
Uint512 memory min = mul512(baseSample.n, offsetSample.d * (PPM_RESOLUTION - maxDeviationPPM));
Uint512 memory mid = mul512(baseSample.d, offsetSample.n * PPM_RESOLUTION);
Uint512 memory max = mul512(baseSample.n, offsetSample.d * (PPM_RESOLUTION + maxDeviationPPM));
return lte512(min, mid) && lte512(mid, max);
}
function toPos256(uint256 n) internal pure returns (Sint256 memory) {
return Sint256({ value: n, isNeg: false });
}
function toNeg256(uint256 n) internal pure returns (Sint256 memory) {
return Sint256({ value: n, isNeg: true });
}
function mulDivF(
uint256 x,
uint256 y,
uint256 z
) internal pure returns (uint256) {
Uint512 memory xy = mul512(x, y);
if (xy.hi == 0) {
return xy.lo / z;
}
if (xy.hi >= z) {
revert Overflow();
}
uint256 m = _mulMod(x, y, z);
Uint512 memory n = _sub512(xy, m);
if (n.hi == 0) {
return n.lo / z;
}
uint256 p = _unsafeSub(0, z) & z;
uint256 q = _div512(n, p);
uint256 r = _inv256(z / p);
return _unsafeMul(q, r);
}
function mulDivC(
uint256 x,
uint256 y,
uint256 z
) internal pure returns (uint256) {
uint256 w = mulDivF(x, y, z);
if (_mulMod(x, y, z) > 0) {
if (w >= type(uint256).max) {
revert Overflow();
}
return w + 1;
}
return w;
}
function subMax0(uint256 n1, uint256 n2) internal pure returns (uint256) {
return n1 > n2 ? n1 - n2 : 0;
}
function gt512(Uint512 memory x, Uint512 memory y) internal pure returns (bool) {
return x.hi > y.hi || (x.hi == y.hi && x.lo > y.lo);
}
function lt512(Uint512 memory x, Uint512 memory y) internal pure returns (bool) {
return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo);
}
function gte512(Uint512 memory x, Uint512 memory y) internal pure returns (bool) {
return !lt512(x, y);
}
function lte512(Uint512 memory x, Uint512 memory y) internal pure returns (bool) {
return !gt512(x, y);
}
function mul512(uint256 x, uint256 y) internal pure returns (Uint512 memory) {
uint256 p = _mulModMax(x, y);
uint256 q = _unsafeMul(x, y);
if (p >= q) {
return Uint512({ hi: p - q, lo: q });
}
return Uint512({ hi: _unsafeSub(p, q) - 1, lo: q });
}
function _sub512(Uint512 memory x, uint256 y) private pure returns (Uint512 memory) {
if (x.lo >= y) {
return Uint512({ hi: x.hi, lo: x.lo - y });
}
return Uint512({ hi: x.hi - 1, lo: _unsafeSub(x.lo, y) });
}
function _div512(Uint512 memory x, uint256 pow2n) private pure returns (uint256) {
uint256 pow2nInv = _unsafeAdd(_unsafeSub(0, pow2n) / pow2n, 1);
return _unsafeMul(x.hi, pow2nInv) | (x.lo / pow2n);
}
function _inv256(uint256 d) private pure returns (uint256) {
uint256 x = 1;
for (uint256 i = 0; i < 8; i++) {
x = _unsafeMul(x, _unsafeSub(2, _unsafeMul(x, d)));
}
return x;
}
function _unsafeAdd(uint256 x, uint256 y) private pure returns (uint256) {
unchecked {
return x + y;
}
}
function _unsafeSub(uint256 x, uint256 y) private pure returns (uint256) {
unchecked {
return x - y;
}
}
function _unsafeMul(uint256 x, uint256 y) private pure returns (uint256) {
unchecked {
return x * y;
}
}
function _mulModMax(uint256 x, uint256 y) private pure returns (uint256) {
return mulmod(x, y, type(uint256).max);
}
function _mulMod(
uint256 x,
uint256 y,
uint256 z
) private pure returns (uint256) {
return mulmod(x, y, z);
}
}
文件 29 的 38:Owned.sol
pragma solidity 0.8.13;
import { IOwned } from "./interfaces/IOwned.sol";
import { AccessDenied } from "./Utils.sol";
abstract contract Owned is IOwned {
error SameOwner();
address private _owner;
address private _newOwner;
event OwnerUpdate(address indexed prevOwner, address indexed newOwner);
constructor() {
_setOwnership(msg.sender);
}
modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() private view {
if (msg.sender != _owner) {
revert AccessDenied();
}
}
function owner() public view virtual returns (address) {
return _owner;
}
function transferOwnership(address ownerCandidate) public virtual onlyOwner {
if (ownerCandidate == _owner) {
revert SameOwner();
}
_newOwner = ownerCandidate;
}
function acceptOwnership() public virtual {
if (msg.sender != _newOwner) {
revert AccessDenied();
}
_setOwnership(_newOwner);
}
function newOwner() external view returns (address) {
return _newOwner;
}
function _setOwnership(address ownerCandidate) private {
address prevOwner = _owner;
_owner = ownerCandidate;
_newOwner = address(0);
emit OwnerUpdate({ prevOwner: prevOwner, newOwner: ownerCandidate });
}
}
文件 30 的 38:PoolCollection.sol
pragma solidity 0.8.13;
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { Token } from "../token/Token.sol";
import { TokenLibrary } from "../token/TokenLibrary.sol";
import { IMasterVault } from "../vaults/interfaces/IMasterVault.sol";
import { IExternalProtectionVault } from "../vaults/interfaces/IExternalProtectionVault.sol";
import { IVersioned } from "../utility/interfaces/IVersioned.sol";
import { PPM_RESOLUTION } from "../utility/Constants.sol";
import { Owned } from "../utility/Owned.sol";
import { BlockNumber } from "../utility/BlockNumber.sol";
import { Fraction, Fraction112, FractionLibrary, zeroFraction, zeroFraction112 } from "../utility/FractionLibrary.sol";
import { Sint256, MathEx } from "../utility/MathEx.sol";
import {
Utils,
AlreadyExists,
DoesNotExist,
InvalidParam,
InvalidPoolCollection,
InvalidStakedBalance
} from "../utility/Utils.sol";
import { INetworkSettings, NotWhitelisted } from "../network/interfaces/INetworkSettings.sol";
import { IBancorNetwork } from "../network/interfaces/IBancorNetwork.sol";
import { IPoolToken } from "./interfaces/IPoolToken.sol";
import { IPoolTokenFactory } from "./interfaces/IPoolTokenFactory.sol";
import { IPoolMigrator } from "./interfaces/IPoolMigrator.sol";
import {
AverageRates,
IPoolCollection,
PoolLiquidity,
Pool,
TRADING_STATUS_UPDATE_DEFAULT,
TRADING_STATUS_UPDATE_ADMIN,
TRADING_STATUS_UPDATE_MIN_LIQUIDITY,
TRADING_STATUS_UPDATE_INVALID_STATE,
TradeAmountAndFee,
WithdrawalAmounts
} from "./interfaces/IPoolCollection.sol";
import { IBNTPool } from "./interfaces/IBNTPool.sol";
import { PoolCollectionWithdrawal } from "./PoolCollectionWithdrawal.sol";
struct InternalWithdrawalAmounts {
uint256 baseTokensToTransferFromMasterVault;
uint256 bntToMintForProvider;
uint256 baseTokensToTransferFromEPV;
Sint256 baseTokensTradingLiquidityDelta;
Sint256 bntTradingLiquidityDelta;
Sint256 bntProtocolHoldingsDelta;
uint256 baseTokensWithdrawalFee;
uint256 baseTokensWithdrawalAmount;
uint256 poolTokenAmount;
uint256 poolTokenTotalSupply;
uint256 newBaseTokenTradingLiquidity;
uint256 newBNTTradingLiquidity;
}
struct TradingLiquidityAction {
bool update;
uint256 newBNTTradingLiquidity;
uint256 newBaseTokenTradingLiquidity;
}
enum PoolRateState {
Uninitialized,
Unstable,
Stable
}
contract PoolCollection is IPoolCollection, Owned, BlockNumber, Utils {
using TokenLibrary for Token;
using FractionLibrary for Fraction;
using FractionLibrary for Fraction112;
using EnumerableSet for EnumerableSet.AddressSet;
using SafeCast for uint256;
error AlreadyEnabled();
error DepositingDisabled();
error InsufficientLiquidity();
error InsufficientSourceAmount();
error InsufficientTargetAmount();
error InvalidRate();
error RateUnstable();
error TradingDisabled();
error FundingLimitTooHigh();
uint16 private constant POOL_TYPE = 1;
uint256 private constant LIQUIDITY_GROWTH_FACTOR = 2;
uint256 private constant BOOTSTRAPPING_LIQUIDITY_BUFFER_FACTOR = 2;
uint32 private constant DEFAULT_TRADING_FEE_PPM = 2_000;
uint32 private constant RATE_MAX_DEVIATION_PPM = 10_000;
uint256 private constant EMA_AVERAGE_RATE_WEIGHT = 4;
uint256 private constant EMA_SPOT_RATE_WEIGHT = 1;
struct TradeIntermediateResult {
uint256 sourceAmount;
uint256 targetAmount;
uint256 limit;
uint256 tradingFeeAmount;
uint256 networkFeeAmount;
uint256 sourceBalance;
uint256 targetBalance;
uint256 stakedBalance;
Token pool;
bool isSourceBNT;
bool bySourceAmount;
uint32 tradingFeePPM;
bytes32 contextId;
}
struct TradeAmountAndTradingFee {
uint256 amount;
uint256 tradingFeeAmount;
}
IBancorNetwork private immutable _network;
IERC20 private immutable _bnt;
INetworkSettings private immutable _networkSettings;
IMasterVault private immutable _masterVault;
IBNTPool internal immutable _bntPool;
IExternalProtectionVault private immutable _externalProtectionVault;
IPoolTokenFactory private immutable _poolTokenFactory;
IPoolMigrator private immutable _poolMigrator;
uint32 private immutable _networkFeePPM;
mapping(Token => Pool) internal _poolData;
EnumerableSet.AddressSet private _pools;
uint32 private _defaultTradingFeePPM;
bool private _protectionEnabled = true;
event DefaultTradingFeePPMUpdated(uint32 prevFeePPM, uint32 newFeePPM);
event TradingFeePPMUpdated(Token indexed pool, uint32 prevFeePPM, uint32 newFeePPM);
event TradingEnabled(Token indexed pool, bool indexed newStatus, uint8 indexed reason);
event DepositingEnabled(Token indexed pool, bool indexed newStatus);
event TokensDeposited(
bytes32 indexed contextId,
address indexed provider,
Token indexed token,
uint256 baseTokenAmount,
uint256 poolTokenAmount
);
event TokensWithdrawn(
bytes32 indexed contextId,
address indexed provider,
Token indexed token,
uint256 baseTokenAmount,
uint256 poolTokenAmount,
uint256 externalProtectionBaseTokenAmount,
uint256 bntAmount,
uint256 withdrawalFeeAmount
);
event TradingLiquidityUpdated(
bytes32 indexed contextId,
Token indexed pool,
Token indexed token,
uint256 prevLiquidity,
uint256 newLiquidity
);
event TotalLiquidityUpdated(
bytes32 indexed contextId,
Token indexed pool,
uint256 liquidity,
uint256 stakedBalance,
uint256 poolTokenSupply
);
constructor(
IBancorNetwork initNetwork,
IERC20 initBNT,
INetworkSettings initNetworkSettings,
IMasterVault initMasterVault,
IBNTPool initBNTPool,
IExternalProtectionVault initExternalProtectionVault,
IPoolTokenFactory initPoolTokenFactory,
IPoolMigrator initPoolMigrator,
uint32 initNetworkFeePPM
) {
_validAddress(address(initNetwork));
_validAddress(address(initBNT));
_validAddress(address(initNetworkSettings));
_validAddress(address(initMasterVault));
_validAddress(address(initBNTPool));
_validAddress(address(initExternalProtectionVault));
_validAddress(address(initPoolTokenFactory));
_validAddress(address(initPoolMigrator));
_validFee(initNetworkFeePPM);
_network = initNetwork;
_bnt = initBNT;
_networkSettings = initNetworkSettings;
_masterVault = initMasterVault;
_bntPool = initBNTPool;
_externalProtectionVault = initExternalProtectionVault;
_poolTokenFactory = initPoolTokenFactory;
_poolMigrator = initPoolMigrator;
_networkFeePPM = initNetworkFeePPM;
_setDefaultTradingFeePPM(DEFAULT_TRADING_FEE_PPM);
}
function version() external view virtual returns (uint16) {
return 6;
}
function poolType() external view virtual returns (uint16) {
return POOL_TYPE;
}
function defaultTradingFeePPM() external view returns (uint32) {
return _defaultTradingFeePPM;
}
function networkFeePPM() external view returns (uint32) {
return _networkFeePPM;
}
function pools() external view returns (Token[] memory) {
uint256 length = _pools.length();
Token[] memory list = new Token[](length);
for (uint256 i = 0; i < length; i++) {
list[i] = Token(_pools.at(i));
}
return list;
}
function poolCount() external view returns (uint256) {
return _pools.length();
}
function setDefaultTradingFeePPM(uint32 newDefaultTradingFeePPM)
external
onlyOwner
validFee(newDefaultTradingFeePPM)
{
_setDefaultTradingFeePPM(newDefaultTradingFeePPM);
}
function enableProtection(bool status) external onlyOwner {
if (_protectionEnabled == status) {
return;
}
_protectionEnabled = status;
}
function protectionEnabled() external view returns (bool) {
return _protectionEnabled;
}
function createPool(Token token) external only(address(_network)) {
if (!_networkSettings.isTokenWhitelisted(token)) {
revert NotWhitelisted();
}
IPoolToken newPoolToken = IPoolToken(_poolTokenFactory.createPoolToken(token));
newPoolToken.acceptOwnership();
Pool memory newPool = Pool({
poolToken: newPoolToken,
tradingFeePPM: _defaultTradingFeePPM,
tradingEnabled: false,
depositingEnabled: true,
averageRates: AverageRates({ blockNumber: 0, rate: zeroFraction112(), invRate: zeroFraction112() }),
liquidity: PoolLiquidity({ bntTradingLiquidity: 0, baseTokenTradingLiquidity: 0, stakedBalance: 0 })
});
_addPool(token, newPool);
emit TradingEnabled({ pool: token, newStatus: newPool.tradingEnabled, reason: TRADING_STATUS_UPDATE_DEFAULT });
emit TradingFeePPMUpdated({ pool: token, prevFeePPM: 0, newFeePPM: newPool.tradingFeePPM });
emit DepositingEnabled({ pool: token, newStatus: newPool.depositingEnabled });
}
function isPoolValid(Token pool) external view returns (bool) {
return address(_poolData[pool].poolToken) != address(0);
}
function poolData(Token pool) external view returns (Pool memory) {
return _poolData[pool];
}
function poolLiquidity(Token pool) external view returns (PoolLiquidity memory) {
return _poolData[pool].liquidity;
}
function poolToken(Token pool) external view returns (IPoolToken) {
return _poolData[pool].poolToken;
}
function tradingFeePPM(Token pool) external view returns (uint32) {
return _poolData[pool].tradingFeePPM;
}
function tradingEnabled(Token pool) external view returns (bool) {
return _poolData[pool].tradingEnabled;
}
function depositingEnabled(Token pool) external view returns (bool) {
return _poolData[pool].depositingEnabled;
}
function poolTokenToUnderlying(Token pool, uint256 poolTokenAmount) external view returns (uint256) {
Pool storage data = _poolData[pool];
return _poolTokenToUnderlying(poolTokenAmount, data.poolToken.totalSupply(), data.liquidity.stakedBalance);
}
function underlyingToPoolToken(Token pool, uint256 baseTokenAmount) external view returns (uint256) {
Pool storage data = _poolData[pool];
return _underlyingToPoolToken(baseTokenAmount, data.poolToken.totalSupply(), data.liquidity.stakedBalance);
}
function poolTokenAmountToBurn(
Token pool,
uint256 baseTokenAmountToDistribute,
uint256 protocolPoolTokenAmount
) external view returns (uint256) {
if (baseTokenAmountToDistribute == 0) {
return 0;
}
Pool storage data = _poolData[pool];
uint256 poolTokenSupply = data.poolToken.totalSupply();
uint256 val = baseTokenAmountToDistribute * poolTokenSupply;
return
MathEx.mulDivF(
val,
poolTokenSupply,
val + data.liquidity.stakedBalance * (poolTokenSupply - protocolPoolTokenAmount)
);
}
function isPoolStable(Token pool) external view returns (bool) {
Pool storage data = _poolData[pool];
return _poolRateState(data.liquidity, data.averageRates) == PoolRateState.Stable;
}
function setTradingFeePPM(Token pool, uint32 newTradingFeePPM) external onlyOwner validFee(newTradingFeePPM) {
Pool storage data = _poolStorage(pool);
uint32 prevTradingFeePPM = data.tradingFeePPM;
if (prevTradingFeePPM == newTradingFeePPM) {
return;
}
data.tradingFeePPM = newTradingFeePPM;
emit TradingFeePPMUpdated({ pool: pool, prevFeePPM: prevTradingFeePPM, newFeePPM: newTradingFeePPM });
}
function enableTrading(
Token pool,
uint256 bntVirtualBalance,
uint256 baseTokenVirtualBalance
) external onlyOwner {
Fraction memory fundingRate = Fraction({ n: bntVirtualBalance, d: baseTokenVirtualBalance });
_validRate(fundingRate);
Pool storage data = _poolStorage(pool);
if (data.tradingEnabled) {
revert AlreadyEnabled();
}
bytes32 contextId = keccak256(abi.encodePacked(msg.sender, pool, bntVirtualBalance, baseTokenVirtualBalance));
uint256 minLiquidityForTrading = _networkSettings.minLiquidityForTrading();
_updateTradingLiquidity(contextId, pool, data, fundingRate, minLiquidityForTrading);
if (data.liquidity.bntTradingLiquidity < minLiquidityForTrading) {
revert InsufficientLiquidity();
}
Fraction112 memory fundingRate112 = fundingRate.toFraction112();
data.averageRates = AverageRates({
blockNumber: _blockNumber(),
rate: fundingRate112,
invRate: fundingRate112.inverse()
});
data.tradingEnabled = true;
emit TradingEnabled({ pool: pool, newStatus: true, reason: TRADING_STATUS_UPDATE_ADMIN });
}
function disableTrading(Token pool) external onlyOwner {
Pool storage data = _poolStorage(pool);
_resetTradingLiquidity(bytes32(0), pool, data, TRADING_STATUS_UPDATE_ADMIN);
}
function enableDepositing(Token pool, bool status) external onlyOwner {
Pool storage data = _poolStorage(pool);
if (data.depositingEnabled == status) {
return;
}
data.depositingEnabled = status;
emit DepositingEnabled({ pool: pool, newStatus: status });
}
function depositFor(
bytes32 contextId,
address provider,
Token pool,
uint256 baseTokenAmount
) external only(address(_network)) validAddress(provider) greaterThanZero(baseTokenAmount) returns (uint256) {
Pool storage data = _poolStorage(pool);
if (!data.depositingEnabled) {
revert DepositingDisabled();
}
PoolLiquidity memory prevLiquidity = data.liquidity;
uint256 currentStakedBalance = prevLiquidity.stakedBalance;
uint256 prevPoolTokenTotalSupply = data.poolToken.totalSupply();
if (prevPoolTokenTotalSupply == 0 && currentStakedBalance != 0) {
currentStakedBalance = 0;
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_INVALID_STATE);
}
uint256 poolTokenAmount = _underlyingToPoolToken(
baseTokenAmount,
prevPoolTokenTotalSupply,
currentStakedBalance
);
data.liquidity.stakedBalance = currentStakedBalance + baseTokenAmount;
data.poolToken.mint(provider, poolTokenAmount);
_updateTradingLiquidity(
contextId,
pool,
data,
data.averageRates.rate.fromFraction112(),
_networkSettings.minLiquidityForTrading()
);
if (data.tradingEnabled) {
_updateAverageRates(
data,
Fraction({ n: data.liquidity.bntTradingLiquidity, d: data.liquidity.baseTokenTradingLiquidity })
);
}
emit TokensDeposited({
contextId: contextId,
provider: provider,
token: pool,
baseTokenAmount: baseTokenAmount,
poolTokenAmount: poolTokenAmount
});
_dispatchTradingLiquidityEvents(
contextId,
pool,
prevPoolTokenTotalSupply + poolTokenAmount,
prevLiquidity,
data.liquidity
);
return poolTokenAmount;
}
function withdraw(
bytes32 contextId,
address provider,
Token pool,
uint256 poolTokenAmount,
uint256 baseTokenAmount
)
external
only(address(_network))
validAddress(provider)
greaterThanZero(poolTokenAmount)
greaterThanZero(baseTokenAmount)
returns (uint256)
{
Pool storage data = _poolStorage(pool);
PoolLiquidity memory liquidity = data.liquidity;
uint256 poolTokenTotalSupply = data.poolToken.totalSupply();
uint256 underlyingAmount = _poolTokenToUnderlying(
poolTokenAmount,
poolTokenTotalSupply,
liquidity.stakedBalance
);
if (baseTokenAmount > underlyingAmount) {
revert InvalidParam();
}
InternalWithdrawalAmounts memory amounts = _poolWithdrawalAmounts(
pool,
poolTokenAmount,
baseTokenAmount,
liquidity,
data.tradingFeePPM,
poolTokenTotalSupply
);
_executeWithdrawal(contextId, provider, pool, data, amounts);
if (data.tradingEnabled) {
_updateAverageRates(
data,
Fraction({ n: data.liquidity.bntTradingLiquidity, d: data.liquidity.baseTokenTradingLiquidity })
);
}
return amounts.baseTokensToTransferFromMasterVault;
}
function withdrawalAmounts(Token pool, uint256 poolTokenAmount)
external
view
validAddress(address(pool))
greaterThanZero(poolTokenAmount)
returns (WithdrawalAmounts memory)
{
Pool storage data = _poolData[pool];
PoolLiquidity memory liquidity = data.liquidity;
uint256 poolTokenTotalSupply = data.poolToken.totalSupply();
uint256 underlyingAmount = _poolTokenToUnderlying(
poolTokenAmount,
poolTokenTotalSupply,
liquidity.stakedBalance
);
InternalWithdrawalAmounts memory amounts = _poolWithdrawalAmounts(
pool,
poolTokenAmount,
underlyingAmount,
liquidity,
data.tradingFeePPM,
poolTokenTotalSupply
);
return
WithdrawalAmounts({
totalAmount: amounts.baseTokensWithdrawalAmount - amounts.baseTokensWithdrawalFee,
baseTokenAmount: amounts.baseTokensToTransferFromMasterVault + amounts.baseTokensToTransferFromEPV,
bntAmount: _protectionEnabled ? amounts.bntToMintForProvider : 0
});
}
function tradeBySourceAmount(
bytes32 contextId,
Token sourceToken,
Token targetToken,
uint256 sourceAmount,
uint256 minReturnAmount
)
external
only(address(_network))
greaterThanZero(sourceAmount)
greaterThanZero(minReturnAmount)
returns (TradeAmountAndFee memory)
{
TradeIntermediateResult memory result = _initTrade(
contextId,
sourceToken,
targetToken,
sourceAmount,
minReturnAmount,
true
);
_performTrade(result);
return
TradeAmountAndFee({
amount: result.targetAmount,
tradingFeeAmount: result.tradingFeeAmount,
networkFeeAmount: result.networkFeeAmount
});
}
function tradeByTargetAmount(
bytes32 contextId,
Token sourceToken,
Token targetToken,
uint256 targetAmount,
uint256 maxSourceAmount
)
external
only(address(_network))
greaterThanZero(targetAmount)
greaterThanZero(maxSourceAmount)
returns (TradeAmountAndFee memory)
{
TradeIntermediateResult memory result = _initTrade(
contextId,
sourceToken,
targetToken,
targetAmount,
maxSourceAmount,
false
);
_performTrade(result);
return
TradeAmountAndFee({
amount: result.sourceAmount,
tradingFeeAmount: result.tradingFeeAmount,
networkFeeAmount: result.networkFeeAmount
});
}
function tradeOutputAndFeeBySourceAmount(
Token sourceToken,
Token targetToken,
uint256 sourceAmount
) external view greaterThanZero(sourceAmount) returns (TradeAmountAndFee memory) {
TradeIntermediateResult memory result = _initTrade(bytes32(0), sourceToken, targetToken, sourceAmount, 1, true);
_processTrade(result);
return
TradeAmountAndFee({
amount: result.targetAmount,
tradingFeeAmount: result.tradingFeeAmount,
networkFeeAmount: result.networkFeeAmount
});
}
function tradeInputAndFeeByTargetAmount(
Token sourceToken,
Token targetToken,
uint256 targetAmount
) external view greaterThanZero(targetAmount) returns (TradeAmountAndFee memory) {
TradeIntermediateResult memory result = _initTrade(
bytes32(0),
sourceToken,
targetToken,
targetAmount,
type(uint256).max,
false
);
_processTrade(result);
return
TradeAmountAndFee({
amount: result.sourceAmount,
tradingFeeAmount: result.tradingFeeAmount,
networkFeeAmount: result.networkFeeAmount
});
}
function onFeesCollected(Token pool, uint256 feeAmount) external only(address(_network)) {
if (feeAmount == 0) {
return;
}
Pool storage data = _poolStorage(pool);
data.liquidity.stakedBalance += feeAmount;
}
function migratePoolIn(Token pool, Pool calldata data)
external
validAddress(address(pool))
only(address(_poolMigrator))
{
_addPool(pool, data);
data.poolToken.acceptOwnership();
}
function migratePoolOut(Token pool, IPoolCollection targetPoolCollection)
external
validAddress(address(targetPoolCollection))
only(address(_poolMigrator))
{
IPoolToken cachedPoolToken = _poolData[pool].poolToken;
_removePool(pool);
cachedPoolToken.transferOwnership(address(targetPoolCollection));
}
function _addPool(Token pool, Pool memory data) private {
if (!_pools.add(address(pool))) {
revert AlreadyExists();
}
_poolData[pool] = data;
}
function _removePool(Token pool) private {
if (!_pools.remove(address(pool))) {
revert DoesNotExist();
}
delete _poolData[pool];
}
function _poolWithdrawalAmounts(
Token pool,
uint256 poolTokenAmount,
uint256 baseTokensWithdrawalAmount,
PoolLiquidity memory liquidity,
uint32 poolTradingFeePPM,
uint256 poolTokenTotalSupply
) internal view returns (InternalWithdrawalAmounts memory) {
uint256 baseTokenExcessAmount = pool.balanceOf(address(_masterVault)) - liquidity.baseTokenTradingLiquidity;
PoolCollectionWithdrawal.Output memory output = PoolCollectionWithdrawal.calculateWithdrawalAmounts(
liquidity.bntTradingLiquidity,
liquidity.baseTokenTradingLiquidity,
baseTokenExcessAmount,
liquidity.stakedBalance,
pool.balanceOf(address(_externalProtectionVault)),
poolTradingFeePPM,
_networkSettings.withdrawalFeePPM(),
baseTokensWithdrawalAmount
);
return
InternalWithdrawalAmounts({
baseTokensToTransferFromMasterVault: output.s,
bntToMintForProvider: output.t,
baseTokensToTransferFromEPV: output.u,
baseTokensTradingLiquidityDelta: output.r,
bntTradingLiquidityDelta: output.p,
bntProtocolHoldingsDelta: output.q,
baseTokensWithdrawalFee: output.v,
baseTokensWithdrawalAmount: baseTokensWithdrawalAmount,
poolTokenAmount: poolTokenAmount,
poolTokenTotalSupply: poolTokenTotalSupply,
newBaseTokenTradingLiquidity: output.r.isNeg
? liquidity.baseTokenTradingLiquidity - output.r.value
: liquidity.baseTokenTradingLiquidity + output.r.value,
newBNTTradingLiquidity: output.p.isNeg
? liquidity.bntTradingLiquidity - output.p.value
: liquidity.bntTradingLiquidity + output.p.value
});
}
function _executeWithdrawal(
bytes32 contextId,
address provider,
Token pool,
Pool storage data,
InternalWithdrawalAmounts memory amounts
) private {
PoolLiquidity storage liquidity = data.liquidity;
PoolLiquidity memory prevLiquidity = liquidity;
AverageRates memory averageRates = data.averageRates;
if (_poolRateState(prevLiquidity, averageRates) == PoolRateState.Unstable) {
revert RateUnstable();
}
data.poolToken.burn(amounts.poolTokenAmount);
uint256 newPoolTokenTotalSupply = amounts.poolTokenTotalSupply - amounts.poolTokenAmount;
liquidity.stakedBalance = MathEx.mulDivF(
liquidity.stakedBalance,
newPoolTokenTotalSupply,
amounts.poolTokenTotalSupply
);
liquidity.baseTokenTradingLiquidity = amounts.newBaseTokenTradingLiquidity.toUint128();
liquidity.bntTradingLiquidity = amounts.newBNTTradingLiquidity.toUint128();
if (amounts.bntProtocolHoldingsDelta.value > 0) {
assert(amounts.bntProtocolHoldingsDelta.isNeg);
_bntPool.renounceFunding(contextId, pool, amounts.bntProtocolHoldingsDelta.value);
} else if (amounts.bntTradingLiquidityDelta.value > 0) {
if (amounts.bntTradingLiquidityDelta.isNeg) {
_bntPool.burnFromVault(amounts.bntTradingLiquidityDelta.value);
} else {
_bntPool.mint(address(_masterVault), amounts.bntTradingLiquidityDelta.value);
}
}
bool isProtectionEnabled = _protectionEnabled;
if (amounts.bntToMintForProvider > 0 && isProtectionEnabled) {
_bntPool.mint(address(provider), amounts.bntToMintForProvider);
}
if (amounts.baseTokensToTransferFromEPV > 0) {
_externalProtectionVault.withdrawFunds(
pool,
payable(address(_masterVault)),
amounts.baseTokensToTransferFromEPV
);
amounts.baseTokensToTransferFromMasterVault += amounts.baseTokensToTransferFromEPV;
}
if (amounts.baseTokensToTransferFromMasterVault > 0) {
_masterVault.withdrawFunds(pool, payable(provider), amounts.baseTokensToTransferFromMasterVault);
}
if (amounts.newBaseTokenTradingLiquidity == 0) {
data.averageRates.rate = zeroFraction112();
data.averageRates.invRate = zeroFraction112();
}
if (amounts.newBNTTradingLiquidity < _networkSettings.minLiquidityForTrading()) {
_resetTradingLiquidity(
contextId,
pool,
data,
amounts.newBNTTradingLiquidity,
TRADING_STATUS_UPDATE_MIN_LIQUIDITY
);
}
emit TokensWithdrawn({
contextId: contextId,
provider: provider,
token: pool,
baseTokenAmount: amounts.baseTokensToTransferFromMasterVault,
poolTokenAmount: amounts.poolTokenAmount,
externalProtectionBaseTokenAmount: amounts.baseTokensToTransferFromEPV,
bntAmount: isProtectionEnabled ? amounts.bntToMintForProvider : 0,
withdrawalFeeAmount: amounts.baseTokensWithdrawalFee
});
_dispatchTradingLiquidityEvents(contextId, pool, newPoolTokenTotalSupply, prevLiquidity, data.liquidity);
}
function _setDefaultTradingFeePPM(uint32 newDefaultTradingFeePPM) private {
uint32 prevDefaultTradingFeePPM = _defaultTradingFeePPM;
if (prevDefaultTradingFeePPM == newDefaultTradingFeePPM) {
return;
}
_defaultTradingFeePPM = newDefaultTradingFeePPM;
emit DefaultTradingFeePPMUpdated({ prevFeePPM: prevDefaultTradingFeePPM, newFeePPM: newDefaultTradingFeePPM });
}
function _poolStorage(Token pool) private view returns (Pool storage) {
Pool storage data = _poolData[pool];
if (address(data.poolToken) == address(0)) {
revert DoesNotExist();
}
return data;
}
function _poolTokenToUnderlying(
uint256 poolTokenAmount,
uint256 poolTokenSupply,
uint256 stakedBalance
) private pure returns (uint256) {
if (poolTokenSupply == 0) {
if (stakedBalance > 0) {
revert InvalidStakedBalance();
}
return poolTokenAmount;
}
return MathEx.mulDivF(poolTokenAmount, stakedBalance, poolTokenSupply);
}
function _underlyingToPoolToken(
uint256 baseTokenAmount,
uint256 poolTokenSupply,
uint256 stakedBalance
) private pure returns (uint256) {
if (poolTokenSupply == 0) {
if (stakedBalance > 0) {
revert InvalidStakedBalance();
}
return baseTokenAmount;
}
return MathEx.mulDivC(baseTokenAmount, poolTokenSupply, stakedBalance);
}
function _calcTargetTradingLiquidity(
uint256 totalBaseTokenReserveAmount,
uint256 availableFunding,
PoolLiquidity memory liquidity,
Fraction memory fundingRate,
uint256 minLiquidityForTrading
) private pure returns (TradingLiquidityAction memory) {
uint256 totalTokenDeltaAmount = totalBaseTokenReserveAmount - liquidity.baseTokenTradingLiquidity;
uint256 targetBNTTradingLiquidityDelta = Math.min(
MathEx.mulDivF(totalTokenDeltaAmount, fundingRate.n, fundingRate.d),
availableFunding
);
uint256 targetBNTTradingLiquidity = liquidity.bntTradingLiquidity + targetBNTTradingLiquidityDelta;
if (targetBNTTradingLiquidity < minLiquidityForTrading) {
return TradingLiquidityAction({ update: true, newBNTTradingLiquidity: 0, newBaseTokenTradingLiquidity: 0 });
}
if (liquidity.bntTradingLiquidity == 0) {
uint256 newTargetBNTTradingLiquidity = minLiquidityForTrading * BOOTSTRAPPING_LIQUIDITY_BUFFER_FACTOR;
if (newTargetBNTTradingLiquidity > targetBNTTradingLiquidity) {
return
TradingLiquidityAction({
update: false,
newBNTTradingLiquidity: 0,
newBaseTokenTradingLiquidity: 0
});
}
targetBNTTradingLiquidity = newTargetBNTTradingLiquidity;
} else if (targetBNTTradingLiquidity >= liquidity.bntTradingLiquidity) {
targetBNTTradingLiquidity = Math.min(
targetBNTTradingLiquidity,
liquidity.bntTradingLiquidity * LIQUIDITY_GROWTH_FACTOR
);
}
uint256 bntTradingLiquidityDelta = targetBNTTradingLiquidity - liquidity.bntTradingLiquidity;
uint256 baseTokenTradingLiquidityDelta = bntTradingLiquidityDelta == 0
? 0
: MathEx.mulDivF(bntTradingLiquidityDelta, fundingRate.d, fundingRate.n);
return
TradingLiquidityAction({
update: true,
newBNTTradingLiquidity: targetBNTTradingLiquidity,
newBaseTokenTradingLiquidity: liquidity.baseTokenTradingLiquidity + baseTokenTradingLiquidityDelta
});
}
function _updateTradingLiquidity(
bytes32 contextId,
Token pool,
Pool storage data,
Fraction memory fundingRate,
uint256 minLiquidityForTrading
) private {
uint256 totalBaseTokenReserveAmount = pool.balanceOf(address(_masterVault));
if (totalBaseTokenReserveAmount == 0) {
revert InsufficientLiquidity();
}
PoolLiquidity memory liquidity = data.liquidity;
if (_poolRateState(liquidity, data.averageRates) == PoolRateState.Unstable) {
return;
}
if (!fundingRate.isPositive()) {
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_MIN_LIQUIDITY);
return;
}
TradingLiquidityAction memory action = _calcTargetTradingLiquidity(
totalBaseTokenReserveAmount,
_bntPool.availableFunding(pool),
liquidity,
fundingRate,
minLiquidityForTrading
);
if (!action.update) {
return;
}
if (action.newBNTTradingLiquidity == 0 || action.newBaseTokenTradingLiquidity == 0) {
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_MIN_LIQUIDITY);
return;
}
if (action.newBNTTradingLiquidity > liquidity.bntTradingLiquidity) {
_bntPool.requestFunding(contextId, pool, action.newBNTTradingLiquidity - liquidity.bntTradingLiquidity);
} else if (action.newBNTTradingLiquidity < liquidity.bntTradingLiquidity) {
_bntPool.renounceFunding(contextId, pool, liquidity.bntTradingLiquidity - action.newBNTTradingLiquidity);
}
PoolLiquidity memory newLiquidity = PoolLiquidity({
bntTradingLiquidity: action.newBNTTradingLiquidity.toUint128(),
baseTokenTradingLiquidity: action.newBaseTokenTradingLiquidity.toUint128(),
stakedBalance: liquidity.stakedBalance
});
data.liquidity = newLiquidity;
_dispatchTradingLiquidityEvents(contextId, pool, data.poolToken.totalSupply(), liquidity, newLiquidity);
}
function _dispatchTradingLiquidityEvents(
bytes32 contextId,
Token pool,
PoolLiquidity memory prevLiquidity,
PoolLiquidity memory newLiquidity
) private {
if (newLiquidity.bntTradingLiquidity != prevLiquidity.bntTradingLiquidity) {
emit TradingLiquidityUpdated({
contextId: contextId,
pool: pool,
token: Token(address(_bnt)),
prevLiquidity: prevLiquidity.bntTradingLiquidity,
newLiquidity: newLiquidity.bntTradingLiquidity
});
}
if (newLiquidity.baseTokenTradingLiquidity != prevLiquidity.baseTokenTradingLiquidity) {
emit TradingLiquidityUpdated({
contextId: contextId,
pool: pool,
token: pool,
prevLiquidity: prevLiquidity.baseTokenTradingLiquidity,
newLiquidity: newLiquidity.baseTokenTradingLiquidity
});
}
}
function _dispatchTradingLiquidityEvents(
bytes32 contextId,
Token pool,
uint256 poolTokenTotalSupply,
PoolLiquidity memory prevLiquidity,
PoolLiquidity memory newLiquidity
) private {
_dispatchTradingLiquidityEvents(contextId, pool, prevLiquidity, newLiquidity);
if (newLiquidity.stakedBalance != prevLiquidity.stakedBalance) {
emit TotalLiquidityUpdated({
contextId: contextId,
pool: pool,
liquidity: pool.balanceOf(address(_masterVault)),
stakedBalance: newLiquidity.stakedBalance,
poolTokenSupply: poolTokenTotalSupply
});
}
}
function _resetTradingLiquidity(
bytes32 contextId,
Token pool,
Pool storage data,
uint8 reason
) private {
_resetTradingLiquidity(contextId, pool, data, data.liquidity.bntTradingLiquidity, reason);
}
function _resetTradingLiquidity(
bytes32 contextId,
Token pool,
Pool storage data,
uint256 currentBNTTradingLiquidity,
uint8 reason
) private {
data.liquidity.bntTradingLiquidity = 0;
data.liquidity.baseTokenTradingLiquidity = 0;
data.averageRates = AverageRates({ blockNumber: 0, rate: zeroFraction112(), invRate: zeroFraction112() });
if (data.tradingEnabled) {
data.tradingEnabled = false;
emit TradingEnabled({ pool: pool, newStatus: false, reason: reason });
}
if (currentBNTTradingLiquidity > 0) {
_bntPool.renounceFunding(contextId, pool, currentBNTTradingLiquidity);
}
}
function _initTrade(
bytes32 contextId,
Token sourceToken,
Token targetToken,
uint256 amount,
uint256 limit,
bool bySourceAmount
) private view returns (TradeIntermediateResult memory result) {
bool isSourceBNT = sourceToken.isEqual(_bnt);
bool isTargetBNT = targetToken.isEqual(_bnt);
if (isSourceBNT && !isTargetBNT) {
result.isSourceBNT = true;
result.pool = targetToken;
} else if (!isSourceBNT && isTargetBNT) {
result.isSourceBNT = false;
result.pool = sourceToken;
} else {
revert DoesNotExist();
}
Pool storage data = _poolStorage(result.pool);
if (!data.tradingEnabled) {
revert TradingDisabled();
}
result.contextId = contextId;
result.bySourceAmount = bySourceAmount;
if (result.bySourceAmount) {
result.sourceAmount = amount;
} else {
result.targetAmount = amount;
}
result.limit = limit;
result.tradingFeePPM = data.tradingFeePPM;
PoolLiquidity memory liquidity = data.liquidity;
if (result.isSourceBNT) {
result.sourceBalance = liquidity.bntTradingLiquidity;
result.targetBalance = liquidity.baseTokenTradingLiquidity;
} else {
result.sourceBalance = liquidity.baseTokenTradingLiquidity;
result.targetBalance = liquidity.bntTradingLiquidity;
}
result.stakedBalance = liquidity.stakedBalance;
}
function _tradeAmountAndFeeBySourceAmount(
uint256 sourceBalance,
uint256 targetBalance,
uint32 feePPM,
uint256 sourceAmount
) private pure returns (TradeAmountAndTradingFee memory) {
if (sourceBalance == 0 || targetBalance == 0) {
revert InsufficientLiquidity();
}
uint256 targetAmount = MathEx.mulDivF(targetBalance, sourceAmount, sourceBalance + sourceAmount);
uint256 tradingFeeAmount = MathEx.mulDivF(targetAmount, feePPM, PPM_RESOLUTION);
return
TradeAmountAndTradingFee({ amount: targetAmount - tradingFeeAmount, tradingFeeAmount: tradingFeeAmount });
}
function _tradeAmountAndFeeByTargetAmount(
uint256 sourceBalance,
uint256 targetBalance,
uint32 feePPM,
uint256 targetAmount
) private pure returns (TradeAmountAndTradingFee memory) {
if (sourceBalance == 0) {
revert InsufficientLiquidity();
}
uint256 tradingFeeAmount = MathEx.mulDivF(targetAmount, feePPM, PPM_RESOLUTION - feePPM);
uint256 fullTargetAmount = targetAmount + tradingFeeAmount;
uint256 sourceAmount = MathEx.mulDivF(sourceBalance, fullTargetAmount, targetBalance - fullTargetAmount);
return TradeAmountAndTradingFee({ amount: sourceAmount, tradingFeeAmount: tradingFeeAmount });
}
function _processTrade(TradeIntermediateResult memory result) private view {
TradeAmountAndTradingFee memory tradeAmountAndFee;
if (result.bySourceAmount) {
tradeAmountAndFee = _tradeAmountAndFeeBySourceAmount(
result.sourceBalance,
result.targetBalance,
result.tradingFeePPM,
result.sourceAmount
);
result.targetAmount = tradeAmountAndFee.amount;
if (result.targetAmount < result.limit) {
revert InsufficientTargetAmount();
}
} else {
tradeAmountAndFee = _tradeAmountAndFeeByTargetAmount(
result.sourceBalance,
result.targetBalance,
result.tradingFeePPM,
result.targetAmount
);
result.sourceAmount = tradeAmountAndFee.amount;
if (result.sourceAmount == 0 || result.sourceAmount > result.limit) {
revert InsufficientSourceAmount();
}
}
result.tradingFeeAmount = tradeAmountAndFee.tradingFeeAmount;
result.sourceBalance += result.sourceAmount;
result.targetBalance -= result.targetAmount;
if (result.isSourceBNT) {
result.stakedBalance += result.tradingFeeAmount;
}
_processNetworkFee(result);
}
function _processNetworkFee(TradeIntermediateResult memory result) private view {
if (_networkFeePPM == 0) {
return;
}
uint256 targetNetworkFeeAmount = MathEx.mulDivF(result.tradingFeeAmount, _networkFeePPM, PPM_RESOLUTION);
result.targetBalance -= targetNetworkFeeAmount;
if (!result.isSourceBNT) {
result.networkFeeAmount = targetNetworkFeeAmount;
return;
}
result.networkFeeAmount = _tradeAmountAndFeeBySourceAmount(
result.targetBalance,
result.sourceBalance,
0,
targetNetworkFeeAmount
).amount;
result.targetBalance += targetNetworkFeeAmount;
result.sourceBalance -= result.networkFeeAmount;
result.stakedBalance -= targetNetworkFeeAmount;
}
function _performTrade(TradeIntermediateResult memory result) private {
Pool storage data = _poolData[result.pool];
PoolLiquidity memory prevLiquidity = data.liquidity;
_updateAverageRates(
data,
Fraction({ n: prevLiquidity.bntTradingLiquidity, d: prevLiquidity.baseTokenTradingLiquidity })
);
_processTrade(result);
PoolLiquidity memory newLiquidity = PoolLiquidity({
bntTradingLiquidity: (result.isSourceBNT ? result.sourceBalance : result.targetBalance).toUint128(),
baseTokenTradingLiquidity: (result.isSourceBNT ? result.targetBalance : result.sourceBalance).toUint128(),
stakedBalance: result.stakedBalance
});
_dispatchTradingLiquidityEvents(result.contextId, result.pool, prevLiquidity, newLiquidity);
data.liquidity = newLiquidity;
}
function _poolRateState(PoolLiquidity memory liquidity, AverageRates memory averageRates)
internal
view
returns (PoolRateState)
{
Fraction memory spotRate = Fraction({
n: liquidity.bntTradingLiquidity,
d: liquidity.baseTokenTradingLiquidity
});
Fraction112 memory rate = averageRates.rate;
if (!spotRate.isPositive() || !rate.isPositive()) {
return PoolRateState.Uninitialized;
}
Fraction memory invSpotRate = spotRate.inverse();
Fraction112 memory invRate = averageRates.invRate;
if (!invSpotRate.isPositive() || !invRate.isPositive()) {
return PoolRateState.Uninitialized;
}
if (averageRates.blockNumber != _blockNumber()) {
rate = _calcAverageRate(rate, spotRate);
invRate = _calcAverageRate(invRate, invSpotRate);
}
if (
MathEx.isInRange(rate.fromFraction112(), spotRate, RATE_MAX_DEVIATION_PPM) &&
MathEx.isInRange(invRate.fromFraction112(), invSpotRate, RATE_MAX_DEVIATION_PPM)
) {
return PoolRateState.Stable;
}
return PoolRateState.Unstable;
}
function _updateAverageRates(Pool storage data, Fraction memory spotRate) private {
uint32 blockNumber = _blockNumber();
if (data.averageRates.blockNumber != blockNumber) {
data.averageRates = AverageRates({
blockNumber: blockNumber,
rate: _calcAverageRate(data.averageRates.rate, spotRate),
invRate: _calcAverageRate(data.averageRates.invRate, spotRate.inverse())
});
}
}
function _calcAverageRate(Fraction112 memory averageRate, Fraction memory rate)
private
pure
returns (Fraction112 memory)
{
if (rate.n * averageRate.d == rate.d * averageRate.n) {
return averageRate;
}
return
MathEx
.weightedAverage(averageRate.fromFraction112(), rate, EMA_AVERAGE_RATE_WEIGHT, EMA_SPOT_RATE_WEIGHT)
.toFraction112();
}
function _validRate(Fraction memory rate) internal pure {
if (!rate.isPositive()) {
revert InvalidRate();
}
}
}
文件 31 的 38:PoolCollectionWithdrawal.sol
pragma solidity 0.8.13;
import { PPM_RESOLUTION as M } from "../utility/Constants.sol";
import { Sint256, Uint512, MathEx } from "../utility/MathEx.sol";
error PoolCollectionWithdrawalInputInvalid();
library PoolCollectionWithdrawal {
using MathEx for uint256;
struct Output {
Sint256 p;
Sint256 q;
Sint256 r;
uint256 s;
uint256 t;
uint256 u;
uint256 v;
}
function calculateWithdrawalAmounts(
uint256 a,
uint256 b,
uint256 c,
uint256 e,
uint256 w,
uint256 m,
uint256 n,
uint256 x
) internal pure returns (Output memory output) {
if (
a > type(uint128).max ||
b > type(uint128).max ||
c > type(uint128).max ||
e > type(uint128).max ||
w > type(uint128).max ||
m > M ||
n > M ||
x > e
) {
revert PoolCollectionWithdrawalInputInvalid();
}
uint256 y = (x * (M - n)) / M;
if ((e * (M - n)) / M > b + c) {
uint256 f = (e * (M - n)) / M - (b + c);
uint256 g = e - (b + c);
if (isStable(b, c, e, x) && affordableDeficit(b, e, f, g, m, n, x)) {
output = arbitrageDeficit(a, b, e, f, m, x, y);
} else if (a > 0) {
output = defaultDeficit(a, b, c, e, y);
(output.t, output.u) = externalProtection(a, b, e, g, y, w);
} else {
output.s = (y * c) / e;
(output.t, output.u) = externalProtection(a, b, e, g, y, w);
}
} else {
uint256 f = MathEx.subMax0(b + c, e);
if (f > 0 && isStable(b, c, e, x) && affordableSurplus(b, e, f, m, n, x)) {
output = arbitrageSurplus(a, b, e, f, m, n, x, y);
} else if (a > 0) {
output = defaultSurplus(a, b, c, y);
} else {
output.s = y;
}
}
output.v = x - y;
}
function isStable(
uint256 b,
uint256 c,
uint256 e,
uint256 x
) private pure returns (bool) {
return b * x < c * (e - x);
}
function affordableDeficit(
uint256 b,
uint256 e,
uint256 f,
uint256 g,
uint256 m,
uint256 n,
uint256 x
) private pure returns (bool) {
Uint512 memory lhs = MathEx.mul512(b * e, f * m + e * n);
Uint512 memory rhs = MathEx.mul512(f * x, g * (M - m));
return MathEx.gt512(lhs, rhs);
}
function affordableSurplus(
uint256 b,
uint256 e,
uint256 f,
uint256 m,
uint256 n,
uint256 x
) private pure returns (bool) {
Uint512 memory lhs = MathEx.mul512(b * e, (f * m + e * n) * M);
Uint512 memory rhs = MathEx.mul512(f * x, (f * M + e * n) * (M - m));
return MathEx.gt512(lhs, rhs);
}
function arbitrageDeficit(
uint256 a,
uint256 b,
uint256 e,
uint256 f,
uint256 m,
uint256 x,
uint256 y
) private pure returns (Output memory output) {
uint256 i = f * (M - m);
uint256 j = mulSubMulDivF(b, e * M, x, i, 1);
output.p = MathEx.mulDivF(a * x, i, j).toPos256();
output.r = MathEx.mulDivF(x, f, e).toNeg256();
output.s = y;
}
function arbitrageSurplus(
uint256 a,
uint256 b,
uint256 e,
uint256 f,
uint256 m,
uint256 n,
uint256 x,
uint256 y
) private pure returns (Output memory output) {
uint256 i = f * M + e * n;
uint256 j = mulAddMulDivF(b, e * (M - m), x, i * (M - m), M);
output.p = MathEx.mulDivF(a * x, i, j).toNeg256();
output.r = MathEx.mulDivF(x, i, e * M).toPos256();
output.s = y;
}
function defaultDeficit(
uint256 a,
uint256 b,
uint256 c,
uint256 e,
uint256 y
) private pure returns (Output memory output) {
uint256 z = MathEx.subMax0(y * b, c * (e - y));
output.p = MathEx.mulDivF(a, z, b * e).toNeg256();
output.q = output.p;
output.r = (z / e).toNeg256();
output.s = MathEx.mulDivF(y, b + c, e);
}
function defaultSurplus(
uint256 a,
uint256 b,
uint256 c,
uint256 y
) private pure returns (Output memory output) {
uint256 z = MathEx.subMax0(y, c);
output.p = MathEx.mulDivF(a, z, b).toNeg256();
output.q = output.p;
output.r = z.toNeg256();
output.s = y;
}
function externalProtection(
uint256 a,
uint256 b,
uint256 e,
uint256 g,
uint256 y,
uint256 w
) private pure returns (uint256 t, uint256 u) {
uint256 yg = y * g;
uint256 we = w * e;
if (yg > we) {
t = a > 0 ? MathEx.mulDivF(a, yg - we, b * e) : 0;
u = w;
} else {
t = 0;
u = yg / e;
}
}
function mulAddMulDivF(
uint256 a,
uint256 b,
uint256 x,
uint256 y,
uint256 z
) private pure returns (uint256) {
return a * b + MathEx.mulDivF(x, y, z);
}
function mulSubMulDivF(
uint256 a,
uint256 b,
uint256 x,
uint256 y,
uint256 z
) private pure returns (uint256) {
return a * b - MathEx.mulDivF(x, y, z);
}
}
文件 32 的 38:SafeCast.sol
pragma solidity ^0.8.0;
library SafeCast {
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
function toInt256(uint256 value) internal pure returns (int256) {
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
文件 33 的 38:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 34 的 38:SafeERC20Ex.sol
pragma solidity 0.8.13;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
library SafeERC20Ex {
using SafeERC20 for IERC20;
function ensureApprove(
IERC20 token,
address spender,
uint256 amount
) internal {
if (amount == 0) {
return;
}
uint256 allowance = token.allowance(address(this), spender);
if (allowance >= amount) {
return;
}
if (allowance > 0) {
token.safeApprove(spender, 0);
}
token.safeApprove(spender, amount);
}
}
文件 35 的 38:Token.sol
pragma solidity 0.8.13;
interface Token {
}
文件 36 的 38:TokenLibrary.sol
pragma solidity 0.8.13;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import { SafeERC20Ex } from "./SafeERC20Ex.sol";
import { Token } from "./Token.sol";
library TokenLibrary {
using SafeERC20 for IERC20;
using SafeERC20Ex for IERC20;
error PermitUnsupported();
address private constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
string private constant NATIVE_TOKEN_SYMBOL = "ETH";
uint8 private constant NATIVE_TOKEN_DECIMALS = 18;
Token public constant NATIVE_TOKEN = Token(NATIVE_TOKEN_ADDRESS);
function isNative(Token token) internal pure returns (bool) {
return address(token) == NATIVE_TOKEN_ADDRESS;
}
function symbol(Token token) internal view returns (string memory) {
if (isNative(token)) {
return NATIVE_TOKEN_SYMBOL;
}
return toERC20(token).symbol();
}
function decimals(Token token) internal view returns (uint8) {
if (isNative(token)) {
return NATIVE_TOKEN_DECIMALS;
}
return toERC20(token).decimals();
}
function balanceOf(Token token, address account) internal view returns (uint256) {
if (isNative(token)) {
return account.balance;
}
return toIERC20(token).balanceOf(account);
}
function safeTransfer(
Token token,
address to,
uint256 amount
) internal {
if (amount == 0) {
return;
}
if (isNative(token)) {
payable(to).transfer(amount);
} else {
toIERC20(token).safeTransfer(to, amount);
}
}
function safeTransferFrom(
Token token,
address from,
address to,
uint256 amount
) internal {
if (amount == 0 || isNative(token)) {
return;
}
toIERC20(token).safeTransferFrom(from, to, amount);
}
function safeApprove(
Token token,
address spender,
uint256 amount
) internal {
if (isNative(token)) {
return;
}
toIERC20(token).safeApprove(spender, amount);
}
function ensureApprove(
Token token,
address spender,
uint256 amount
) internal {
if (isNative(token)) {
return;
}
toIERC20(token).ensureApprove(spender, amount);
}
function isEqual(Token token, IERC20 erc20Token) internal pure returns (bool) {
return toIERC20(token) == erc20Token;
}
function toIERC20(Token token) internal pure returns (IERC20) {
return IERC20(address(token));
}
function toERC20(Token token) internal pure returns (ERC20) {
return ERC20(address(token));
}
}
文件 37 的 38:Utils.sol
pragma solidity 0.8.13;
import { PPM_RESOLUTION } from "./Constants.sol";
error AccessDenied();
error AlreadyExists();
error DoesNotExist();
error InvalidAddress();
error InvalidExternalAddress();
error InvalidFee();
error InvalidPool();
error InvalidPoolCollection();
error InvalidStakedBalance();
error InvalidToken();
error InvalidParam();
error NotEmpty();
error NotPayable();
error ZeroValue();
abstract contract Utils {
modifier only(address caller) {
_only(caller);
_;
}
function _only(address caller) internal view {
if (msg.sender != caller) {
revert AccessDenied();
}
}
modifier greaterThanZero(uint256 value) {
_greaterThanZero(value);
_;
}
function _greaterThanZero(uint256 value) internal pure {
if (value == 0) {
revert ZeroValue();
}
}
modifier validAddress(address addr) {
_validAddress(addr);
_;
}
function _validAddress(address addr) internal pure {
if (addr == address(0)) {
revert InvalidAddress();
}
}
modifier validExternalAddress(address addr) {
_validExternalAddress(addr);
_;
}
function _validExternalAddress(address addr) internal view {
if (addr == address(0) || addr == address(this)) {
revert InvalidExternalAddress();
}
}
modifier validFee(uint32 fee) {
_validFee(fee);
_;
}
function _validFee(uint32 fee) internal pure {
if (fee > PPM_RESOLUTION) {
revert InvalidFee();
}
}
}
文件 38 的 38:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/pools/PoolCollection.sol": "PoolCollection"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IBancorNetwork","name":"initNetwork","type":"address"},{"internalType":"contract IERC20","name":"initBNT","type":"address"},{"internalType":"contract INetworkSettings","name":"initNetworkSettings","type":"address"},{"internalType":"contract IMasterVault","name":"initMasterVault","type":"address"},{"internalType":"contract IBNTPool","name":"initBNTPool","type":"address"},{"internalType":"contract IExternalProtectionVault","name":"initExternalProtectionVault","type":"address"},{"internalType":"contract IPoolTokenFactory","name":"initPoolTokenFactory","type":"address"},{"internalType":"contract IPoolMigrator","name":"initPoolMigrator","type":"address"},{"internalType":"uint32","name":"initNetworkFeePPM","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AlreadyEnabled","type":"error"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DepositingDisabled","type":"error"},{"inputs":[],"name":"DoesNotExist","type":"error"},{"inputs":[],"name":"FundingLimitTooHigh","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientSourceAmount","type":"error"},{"inputs":[],"name":"InsufficientTargetAmount","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidFraction","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[],"name":"InvalidRate","type":"error"},{"inputs":[],"name":"InvalidStakedBalance","type":"error"},{"inputs":[],"name":"NotWhitelisted","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"PoolCollectionWithdrawalInputInvalid","type":"error"},{"inputs":[],"name":"RateUnstable","type":"error"},{"inputs":[],"name":"SameOwner","type":"error"},{"inputs":[],"name":"TradingDisabled","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"prevFeePPM","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"newFeePPM","type":"uint32"}],"name":"DefaultTradingFeePPMUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Token","name":"pool","type":"address"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"DepositingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contextId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"contract Token","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolTokenAmount","type":"uint256"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contextId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"contract Token","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"externalProtectionBaseTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bntAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawalFeeAmount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contextId","type":"bytes32"},{"indexed":true,"internalType":"contract Token","name":"pool","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakedBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolTokenSupply","type":"uint256"}],"name":"TotalLiquidityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Token","name":"pool","type":"address"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"},{"indexed":true,"internalType":"uint8","name":"reason","type":"uint8"}],"name":"TradingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Token","name":"pool","type":"address"},{"indexed":false,"internalType":"uint32","name":"prevFeePPM","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"newFeePPM","type":"uint32"}],"name":"TradingFeePPMUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"contextId","type":"bytes32"},{"indexed":true,"internalType":"contract Token","name":"pool","type":"address"},{"indexed":true,"internalType":"contract Token","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"prevLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidity","type":"uint256"}],"name":"TradingLiquidityUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"token","type":"address"}],"name":"createPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultTradingFeePPM","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"contextId","type":"bytes32"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"baseTokenAmount","type":"uint256"}],"name":"depositFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"depositingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"disableTrading","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"enableDepositing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"enableProtection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"bntVirtualBalance","type":"uint256"},{"internalType":"uint256","name":"baseTokenVirtualBalance","type":"uint256"}],"name":"enableTrading","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"isPoolStable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"isPoolValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"components":[{"internalType":"contract IPoolToken","name":"poolToken","type":"address"},{"internalType":"uint32","name":"tradingFeePPM","type":"uint32"},{"internalType":"bool","name":"tradingEnabled","type":"bool"},{"internalType":"bool","name":"depositingEnabled","type":"bool"},{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"components":[{"internalType":"uint112","name":"n","type":"uint112"},{"internalType":"uint112","name":"d","type":"uint112"}],"internalType":"struct Fraction112","name":"rate","type":"tuple"},{"components":[{"internalType":"uint112","name":"n","type":"uint112"},{"internalType":"uint112","name":"d","type":"uint112"}],"internalType":"struct Fraction112","name":"invRate","type":"tuple"}],"internalType":"struct AverageRates","name":"averageRates","type":"tuple"},{"components":[{"internalType":"uint128","name":"bntTradingLiquidity","type":"uint128"},{"internalType":"uint128","name":"baseTokenTradingLiquidity","type":"uint128"},{"internalType":"uint256","name":"stakedBalance","type":"uint256"}],"internalType":"struct PoolLiquidity","name":"liquidity","type":"tuple"}],"internalType":"struct Pool","name":"data","type":"tuple"}],"name":"migratePoolIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"contract IPoolCollection","name":"targetPoolCollection","type":"address"}],"name":"migratePoolOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"networkFeePPM","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"onFeesCollected","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"poolData","outputs":[{"components":[{"internalType":"contract IPoolToken","name":"poolToken","type":"address"},{"internalType":"uint32","name":"tradingFeePPM","type":"uint32"},{"internalType":"bool","name":"tradingEnabled","type":"bool"},{"internalType":"bool","name":"depositingEnabled","type":"bool"},{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"components":[{"internalType":"uint112","name":"n","type":"uint112"},{"internalType":"uint112","name":"d","type":"uint112"}],"internalType":"struct Fraction112","name":"rate","type":"tuple"},{"components":[{"internalType":"uint112","name":"n","type":"uint112"},{"internalType":"uint112","name":"d","type":"uint112"}],"internalType":"struct Fraction112","name":"invRate","type":"tuple"}],"internalType":"struct AverageRates","name":"averageRates","type":"tuple"},{"components":[{"internalType":"uint128","name":"bntTradingLiquidity","type":"uint128"},{"internalType":"uint128","name":"baseTokenTradingLiquidity","type":"uint128"},{"internalType":"uint256","name":"stakedBalance","type":"uint256"}],"internalType":"struct PoolLiquidity","name":"liquidity","type":"tuple"}],"internalType":"struct Pool","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"poolLiquidity","outputs":[{"components":[{"internalType":"uint128","name":"bntTradingLiquidity","type":"uint128"},{"internalType":"uint128","name":"baseTokenTradingLiquidity","type":"uint128"},{"internalType":"uint256","name":"stakedBalance","type":"uint256"}],"internalType":"struct PoolLiquidity","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"poolToken","outputs":[{"internalType":"contract IPoolToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"baseTokenAmountToDistribute","type":"uint256"},{"internalType":"uint256","name":"protocolPoolTokenAmount","type":"uint256"}],"name":"poolTokenAmountToBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"poolTokenAmount","type":"uint256"}],"name":"poolTokenToUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolType","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pools","outputs":[{"internalType":"contract Token[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protectionEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"newDefaultTradingFeePPM","type":"uint32"}],"name":"setDefaultTradingFeePPM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint32","name":"newTradingFeePPM","type":"uint32"}],"name":"setTradingFeePPM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"contextId","type":"bytes32"},{"internalType":"contract Token","name":"sourceToken","type":"address"},{"internalType":"contract Token","name":"targetToken","type":"address"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"}],"name":"tradeBySourceAmount","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tradingFeeAmount","type":"uint256"},{"internalType":"uint256","name":"networkFeeAmount","type":"uint256"}],"internalType":"struct TradeAmountAndFee","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"contextId","type":"bytes32"},{"internalType":"contract Token","name":"sourceToken","type":"address"},{"internalType":"contract Token","name":"targetToken","type":"address"},{"internalType":"uint256","name":"targetAmount","type":"uint256"},{"internalType":"uint256","name":"maxSourceAmount","type":"uint256"}],"name":"tradeByTargetAmount","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tradingFeeAmount","type":"uint256"},{"internalType":"uint256","name":"networkFeeAmount","type":"uint256"}],"internalType":"struct TradeAmountAndFee","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"sourceToken","type":"address"},{"internalType":"contract Token","name":"targetToken","type":"address"},{"internalType":"uint256","name":"targetAmount","type":"uint256"}],"name":"tradeInputAndFeeByTargetAmount","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tradingFeeAmount","type":"uint256"},{"internalType":"uint256","name":"networkFeeAmount","type":"uint256"}],"internalType":"struct TradeAmountAndFee","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"sourceToken","type":"address"},{"internalType":"contract Token","name":"targetToken","type":"address"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"}],"name":"tradeOutputAndFeeBySourceAmount","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tradingFeeAmount","type":"uint256"},{"internalType":"uint256","name":"networkFeeAmount","type":"uint256"}],"internalType":"struct TradeAmountAndFee","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"tradingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"}],"name":"tradingFeePPM","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ownerCandidate","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"baseTokenAmount","type":"uint256"}],"name":"underlyingToPoolToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"contextId","type":"bytes32"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"poolTokenAmount","type":"uint256"},{"internalType":"uint256","name":"baseTokenAmount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"poolTokenAmount","type":"uint256"}],"name":"withdrawalAmounts","outputs":[{"components":[{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"baseTokenAmount","type":"uint256"},{"internalType":"uint256","name":"bntAmount","type":"uint256"}],"internalType":"struct WithdrawalAmounts","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}]