编译器
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;
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 = 1000000;
文件 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;
}
文件 8 的 38:FractionLibrary.sol
pragma solidity 0.8.13;
import { Fraction, Fraction112 } 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 isPositive(Fraction memory fraction) internal pure returns (bool) {
return isValid(fraction) && fraction.n != 0;
}
function isValid(Fraction112 memory fraction) internal pure returns (bool) {
return fraction.d != 0;
}
function isPositive(Fraction112 memory fraction) internal pure returns (bool) {
return isValid(fraction) && fraction.n != 0;
}
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
) 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 latestPoolCollection(uint16 poolType) external view returns (IPoolCollection);
function liquidityPools() external view returns (Token[] memory);
function collectionByPool(Token pool) external view returns (IPoolCollection);
function isPoolValid(Token pool) external view returns (bool);
function createPool(uint16 poolType, Token token) external;
function createPools(uint16 poolType, Token[] calldata tokens) external;
function migratePools(Token[] calldata pools) external;
function depositFor(
address provider,
Token pool,
uint256 tokenAmount
) external payable returns (uint256);
function deposit(Token pool, uint256 tokenAmount) external payable returns (uint256);
function depositForPermitted(
address provider,
Token pool,
uint256 tokenAmount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256);
function depositPermitted(
Token pool,
uint256 tokenAmount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256);
function initWithdrawal(IPoolToken poolToken, uint256 poolTokenAmount) external returns (uint256);
function initWithdrawalPermitted(
IPoolToken poolToken,
uint256 poolTokenAmount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256);
function cancelWithdrawal(uint256 id) external;
function withdraw(uint256 id) external returns (uint256);
function tradeBySourceAmount(
Token sourceToken,
Token targetToken,
uint256 sourceAmount,
uint256 minReturnAmount,
uint256 deadline,
address beneficiary
) external payable;
function tradeBySourceAmountPermitted(
Token sourceToken,
Token targetToken,
uint256 sourceAmount,
uint256 minReturnAmount,
uint256 deadline,
address beneficiary,
uint8 v,
bytes32 r,
bytes32 s
) external;
function tradeByTargetAmount(
Token sourceToken,
Token targetToken,
uint256 targetAmount,
uint256 maxSourceAmount,
uint256 deadline,
address beneficiary
) external payable;
function tradeByTargetAmountPermitted(
Token sourceToken,
Token targetToken,
uint256 targetAmount,
uint256 maxSourceAmount,
uint256 deadline,
address beneficiary,
uint8 v,
bytes32 r,
bytes32 s
) external;
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;
}
文件 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 networkFeePPM() external view returns (uint32);
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 AverageRate {
uint32 blockNumber;
Fraction112 rate;
}
struct Pool {
IPoolToken poolToken;
uint32 tradingFeePPM;
bool tradingEnabled;
bool depositingEnabled;
AverageRate averageRate;
uint256 depositLimit;
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;
struct TradeAmountAndFee {
uint256 amount;
uint256 tradingFeeAmount;
uint256 networkFeeAmount;
}
interface IPoolCollection is IVersioned {
function poolType() external pure returns (uint16);
function defaultTradingFeePPM() 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 poolData(Token pool) external view returns (Pool memory);
function poolLiquidity(Token pool) external view returns (PoolLiquidity memory);
function poolToken(Token pool) external view returns (IPoolToken);
function poolTokenToUnderlying(Token pool, uint256 poolTokenAmount) external view returns (uint256);
function underlyingToPoolToken(Token pool, uint256 tokenAmount) external view returns (uint256);
function poolTokenAmountToBurn(
Token pool,
uint256 tokenAmountToDistribute,
uint256 protocolPoolTokenAmount
) external view returns (uint256);
function createPool(Token token) external;
function depositFor(
bytes32 contextId,
address provider,
Token pool,
uint256 tokenAmount
) external returns (uint256);
function withdraw(
bytes32 contextId,
address provider,
Token pool,
uint256 poolTokenAmount
) 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) external returns (IPoolCollection);
}
文件 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 } 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);
return Fraction({ n: fraction.n / scale, d: fraction.d / scale });
}
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() {
_transferOwnership(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();
}
_transferOwnership(_newOwner);
}
function newOwner() external view returns (address) {
return _newOwner;
}
function _transferOwnership(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,
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 {
AverageRate,
IPoolCollection,
PoolLiquidity,
Pool,
TRADING_STATUS_UPDATE_DEFAULT,
TRADING_STATUS_UPDATE_ADMIN,
TRADING_STATUS_UPDATE_MIN_LIQUIDITY,
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 poolTokenTotalSupply;
uint256 newBaseTokenTradingLiquidity;
uint256 newBNTTradingLiquidity;
}
struct TradingLiquidityAction {
bool update;
uint256 newAmount;
}
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;
error AlreadyEnabled();
error DepositLimitExceeded();
error DepositingDisabled();
error InsufficientLiquidity();
error InsufficientSourceAmount();
error InsufficientTargetAmount();
error InvalidRate();
error RateUnstable();
error TradingDisabled();
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 = 2000;
uint32 private constant RATE_MAX_DEVIATION_PPM = 10000;
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;
mapping(Token => Pool) internal _poolData;
EnumerableSet.AddressSet private _pools;
uint32 private _defaultTradingFeePPM;
event PoolCreated(IPoolToken indexed poolToken, Token indexed token);
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 DepositLimitUpdated(Token indexed pool, uint256 prevDepositLimit, uint256 newDepositLimit);
event TokensDeposited(
bytes32 indexed contextId,
address indexed provider,
Token indexed token,
uint256 tokenAmount,
uint256 poolTokenAmount
);
event TokensWithdrawn(
bytes32 indexed contextId,
address indexed provider,
Token indexed token,
uint256 tokenAmount,
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
)
validAddress(address(initNetwork))
validAddress(address(initBNT))
validAddress(address(initNetworkSettings))
validAddress(address(initMasterVault))
validAddress(address(initBNTPool))
validAddress(address(initExternalProtectionVault))
validAddress(address(initPoolTokenFactory))
validAddress(address(initPoolMigrator))
{
_network = initNetwork;
_bnt = initBNT;
_networkSettings = initNetworkSettings;
_masterVault = initMasterVault;
_bntPool = initBNTPool;
_externalProtectionVault = initExternalProtectionVault;
_poolTokenFactory = initPoolTokenFactory;
_poolMigrator = initPoolMigrator;
_setDefaultTradingFeePPM(DEFAULT_TRADING_FEE_PPM);
}
function version() external view virtual returns (uint16) {
return 2;
}
function poolType() external pure returns (uint16) {
return POOL_TYPE;
}
function defaultTradingFeePPM() external view returns (uint32) {
return _defaultTradingFeePPM;
}
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 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,
averageRate: AverageRate({ blockNumber: 0, rate: zeroFraction112() }),
depositLimit: 0,
liquidity: PoolLiquidity({ bntTradingLiquidity: 0, baseTokenTradingLiquidity: 0, stakedBalance: 0 })
});
_addPool(token, newPool);
emit PoolCreated({ poolToken: newPoolToken, token: token });
emit TradingEnabled({ pool: token, newStatus: false, reason: TRADING_STATUS_UPDATE_DEFAULT });
emit TradingFeePPMUpdated({ pool: token, prevFeePPM: 0, newFeePPM: newPool.tradingFeePPM });
emit DepositingEnabled({ pool: token, newStatus: newPool.depositingEnabled });
emit DepositLimitUpdated({ pool: token, prevDepositLimit: 0, newDepositLimit: newPool.depositLimit });
}
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 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 tokenAmount) external view returns (uint256) {
Pool storage data = _poolData[pool];
return _underlyingToPoolToken(tokenAmount, data.poolToken.totalSupply(), data.liquidity.stakedBalance);
}
function poolTokenAmountToBurn(
Token pool,
uint256 tokenAmountToDistribute,
uint256 protocolPoolTokenAmount
) external view returns (uint256) {
if (tokenAmountToDistribute == 0) {
return 0;
}
Pool storage data = _poolData[pool];
uint256 poolTokenSupply = data.poolToken.totalSupply();
uint256 val = tokenAmountToDistribute * poolTokenSupply;
return
MathEx.mulDivF(
val,
poolTokenSupply,
val + data.liquidity.stakedBalance * (poolTokenSupply - protocolPoolTokenAmount)
);
}
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();
}
uint256 minLiquidityForTrading = _networkSettings.minLiquidityForTrading();
_updateTradingLiquidity(bytes32(0), pool, data, data.liquidity, fundingRate, minLiquidityForTrading);
if (data.liquidity.bntTradingLiquidity < minLiquidityForTrading) {
revert InsufficientLiquidity();
}
data.averageRate = AverageRate({ blockNumber: _blockNumber(), rate: fundingRate.toFraction112() });
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 setDepositLimit(Token pool, uint256 newDepositLimit) external onlyOwner {
Pool storage data = _poolStorage(pool);
uint256 prevDepositLimit = data.depositLimit;
if (prevDepositLimit == newDepositLimit) {
return;
}
data.depositLimit = newDepositLimit;
emit DepositLimitUpdated({ pool: pool, prevDepositLimit: prevDepositLimit, newDepositLimit: newDepositLimit });
}
function depositFor(
bytes32 contextId,
address provider,
Token pool,
uint256 tokenAmount
) external only(address(_network)) validAddress(provider) greaterThanZero(tokenAmount) returns (uint256) {
Pool storage data = _poolStorage(pool);
if (!data.depositingEnabled) {
revert DepositingDisabled();
}
uint256 currentStakedBalance = data.liquidity.stakedBalance;
uint256 prevPoolTokenTotalSupply = data.poolToken.totalSupply();
uint256 poolTokenAmount = _underlyingToPoolToken(tokenAmount, prevPoolTokenTotalSupply, currentStakedBalance);
uint256 newStakedBalance = currentStakedBalance + tokenAmount;
if (newStakedBalance > data.depositLimit) {
revert DepositLimitExceeded();
}
PoolLiquidity memory prevLiquidity = data.liquidity;
data.liquidity.stakedBalance = newStakedBalance;
data.poolToken.mint(provider, poolTokenAmount);
_updateTradingLiquidity(
contextId,
pool,
data,
data.liquidity,
data.averageRate.rate.fromFraction112(),
_networkSettings.minLiquidityForTrading()
);
emit TokensDeposited({
contextId: contextId,
provider: provider,
token: pool,
tokenAmount: tokenAmount,
poolTokenAmount: poolTokenAmount
});
_dispatchTradingLiquidityEvents(
contextId,
pool,
prevPoolTokenTotalSupply + poolTokenAmount,
prevLiquidity,
data.liquidity
);
return poolTokenAmount;
}
function withdraw(
bytes32 contextId,
address provider,
Token pool,
uint256 poolTokenAmount
) external only(address(_network)) validAddress(provider) greaterThanZero(poolTokenAmount) returns (uint256) {
Pool storage data = _poolStorage(pool);
InternalWithdrawalAmounts memory amounts = _poolWithdrawalAmounts(pool, data, poolTokenAmount);
_executeWithdrawal(contextId, provider, pool, data, poolTokenAmount, amounts);
return amounts.baseTokensToTransferFromMasterVault;
}
function withdrawalAmounts(Token pool, uint256 poolTokenAmount)
external
view
validAddress(address(pool))
greaterThanZero(poolTokenAmount)
returns (WithdrawalAmounts memory)
{
InternalWithdrawalAmounts memory amounts = _poolWithdrawalAmounts(pool, _poolStorage(pool), poolTokenAmount);
return
WithdrawalAmounts({
totalAmount: amounts.baseTokensWithdrawalAmount - amounts.baseTokensWithdrawalFee,
baseTokenAmount: amounts.baseTokensToTransferFromMasterVault + amounts.baseTokensToTransferFromEPV,
bntAmount: amounts.bntToMintForProvider
});
}
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))
{
if (_network.latestPoolCollection(POOL_TYPE) != targetPoolCollection) {
revert InvalidPoolCollection();
}
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,
Pool memory data,
uint256 poolTokenAmount
) internal view returns (InternalWithdrawalAmounts memory) {
uint256 baseTokenExcessAmount = pool.balanceOf(address(_masterVault)) -
data.liquidity.baseTokenTradingLiquidity;
uint256 poolTokenTotalSupply = data.poolToken.totalSupply();
uint256 baseTokensWithdrawalAmount = _poolTokenToUnderlying(
poolTokenAmount,
poolTokenTotalSupply,
data.liquidity.stakedBalance
);
PoolCollectionWithdrawal.Output memory output = PoolCollectionWithdrawal.calculateWithdrawalAmounts(
data.liquidity.bntTradingLiquidity,
data.liquidity.baseTokenTradingLiquidity,
baseTokenExcessAmount,
data.liquidity.stakedBalance,
pool.balanceOf(address(_externalProtectionVault)),
data.tradingFeePPM,
_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,
poolTokenTotalSupply: poolTokenTotalSupply,
newBaseTokenTradingLiquidity: output.r.isNeg
? data.liquidity.baseTokenTradingLiquidity - output.r.value
: data.liquidity.baseTokenTradingLiquidity + output.r.value,
newBNTTradingLiquidity: output.p.isNeg
? data.liquidity.bntTradingLiquidity - output.p.value
: data.liquidity.bntTradingLiquidity + output.p.value
});
}
function _executeWithdrawal(
bytes32 contextId,
address provider,
Token pool,
Pool storage data,
uint256 poolTokenAmount,
InternalWithdrawalAmounts memory amounts
) private {
PoolLiquidity storage liquidity = data.liquidity;
PoolLiquidity memory prevLiquidity = liquidity;
AverageRate memory averageRate = data.averageRate;
if (_poolRateState(prevLiquidity, averageRate) == PoolRateState.Unstable) {
revert RateUnstable();
}
data.poolToken.burnFrom(address(_network), poolTokenAmount);
uint256 newPoolTokenTotalSupply = amounts.poolTokenTotalSupply - poolTokenAmount;
liquidity.stakedBalance = MathEx.mulDivF(
liquidity.stakedBalance,
newPoolTokenTotalSupply,
amounts.poolTokenTotalSupply
);
liquidity.baseTokenTradingLiquidity = SafeCast.toUint128(amounts.newBaseTokenTradingLiquidity);
liquidity.bntTradingLiquidity = SafeCast.toUint128(amounts.newBNTTradingLiquidity);
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);
}
}
if (amounts.bntToMintForProvider > 0) {
_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.averageRate.rate = 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,
tokenAmount: amounts.baseTokensToTransferFromMasterVault,
poolTokenAmount: poolTokenAmount,
externalProtectionBaseTokenAmount: amounts.baseTokensToTransferFromEPV,
bntAmount: amounts.bntToMintForProvider,
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 tokenAmount,
uint256 poolTokenSupply,
uint256 stakedBalance
) private pure returns (uint256) {
if (poolTokenSupply == 0) {
if (stakedBalance > 0) {
revert InvalidStakedBalance();
}
return tokenAmount;
}
return MathEx.mulDivC(tokenAmount, poolTokenSupply, stakedBalance);
}
function _calcTargetBNTTradingLiquidity(
uint256 tokenReserveAmount,
uint256 availableFunding,
PoolLiquidity memory liquidity,
Fraction memory fundingRate,
uint256 minLiquidityForTrading
) private pure returns (TradingLiquidityAction memory) {
uint256 targetBNTTradingLiquidity = Math.min(
MathEx.mulDivF(tokenReserveAmount, fundingRate.n, fundingRate.d),
liquidity.bntTradingLiquidity + availableFunding
);
if (targetBNTTradingLiquidity < minLiquidityForTrading) {
return TradingLiquidityAction({ update: true, newAmount: 0 });
}
if (liquidity.bntTradingLiquidity == 0) {
uint256 newTargetBNTTradingLiquidity = minLiquidityForTrading * BOOTSTRAPPING_LIQUIDITY_BUFFER_FACTOR;
if (newTargetBNTTradingLiquidity > targetBNTTradingLiquidity) {
return TradingLiquidityAction({ update: false, newAmount: 0 });
}
targetBNTTradingLiquidity = newTargetBNTTradingLiquidity;
} else if (targetBNTTradingLiquidity >= liquidity.bntTradingLiquidity) {
targetBNTTradingLiquidity = Math.min(
targetBNTTradingLiquidity,
liquidity.bntTradingLiquidity * LIQUIDITY_GROWTH_FACTOR
);
}
return TradingLiquidityAction({ update: true, newAmount: targetBNTTradingLiquidity });
}
function _updateTradingLiquidity(
bytes32 contextId,
Token pool,
Pool storage data,
PoolLiquidity memory liquidity,
Fraction memory fundingRate,
uint256 minLiquidityForTrading
) private {
uint256 tokenReserveAmount = pool.balanceOf(address(_masterVault));
if (tokenReserveAmount == 0) {
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_MIN_LIQUIDITY);
return;
}
if (_poolRateState(liquidity, data.averageRate) == PoolRateState.Unstable) {
return;
}
if (!fundingRate.isPositive()) {
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_MIN_LIQUIDITY);
return;
}
TradingLiquidityAction memory action = _calcTargetBNTTradingLiquidity(
tokenReserveAmount,
_bntPool.availableFunding(pool),
liquidity,
fundingRate,
minLiquidityForTrading
);
if (!action.update) {
return;
}
if (action.newAmount == 0) {
_resetTradingLiquidity(contextId, pool, data, TRADING_STATUS_UPDATE_MIN_LIQUIDITY);
return;
}
if (action.newAmount > liquidity.bntTradingLiquidity) {
_bntPool.requestFunding(contextId, pool, action.newAmount - liquidity.bntTradingLiquidity);
} else if (action.newAmount < liquidity.bntTradingLiquidity) {
_bntPool.renounceFunding(contextId, pool, liquidity.bntTradingLiquidity - action.newAmount);
}
uint256 baseTokenTradingLiquidity = MathEx.mulDivF(action.newAmount, fundingRate.d, fundingRate.n);
PoolLiquidity memory newLiquidity = PoolLiquidity({
bntTradingLiquidity: SafeCast.toUint128(action.newAmount),
baseTokenTradingLiquidity: SafeCast.toUint128(baseTokenTradingLiquidity),
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.averageRate = AverageRate({ blockNumber: 0, rate: 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 tradingFeePPM,
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, tradingFeePPM, PPM_RESOLUTION);
return
TradeAmountAndTradingFee({ amount: targetAmount - tradingFeeAmount, tradingFeeAmount: tradingFeeAmount });
}
function _tradeAmountAndFeeByTargetAmount(
uint256 sourceBalance,
uint256 targetBalance,
uint32 tradingFeePPM,
uint256 targetAmount
) private pure returns (TradeAmountAndTradingFee memory) {
if (sourceBalance == 0) {
revert InsufficientLiquidity();
}
uint256 tradingFeeAmount = MathEx.mulDivF(targetAmount, tradingFeePPM, PPM_RESOLUTION - tradingFeePPM);
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 > 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 {
uint32 networkFeePPM = _networkSettings.networkFeePPM();
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;
_updateAverageRate(
data,
Fraction({ n: prevLiquidity.bntTradingLiquidity, d: prevLiquidity.baseTokenTradingLiquidity })
);
_processTrade(result);
PoolLiquidity memory newLiquidity = PoolLiquidity({
bntTradingLiquidity: SafeCast.toUint128(result.isSourceBNT ? result.sourceBalance : result.targetBalance),
baseTokenTradingLiquidity: SafeCast.toUint128(
result.isSourceBNT ? result.targetBalance : result.sourceBalance
),
stakedBalance: result.stakedBalance
});
_dispatchTradingLiquidityEvents(result.contextId, result.pool, prevLiquidity, newLiquidity);
data.liquidity = newLiquidity;
}
function _poolRateState(PoolLiquidity memory liquidity, AverageRate memory averageRateInfo)
internal
view
returns (PoolRateState)
{
Fraction memory spotRate = Fraction({
n: liquidity.bntTradingLiquidity,
d: liquidity.baseTokenTradingLiquidity
});
Fraction112 memory averageRate = averageRateInfo.rate;
if (!spotRate.isPositive() || !averageRate.isPositive()) {
return PoolRateState.Uninitialized;
}
if (averageRateInfo.blockNumber != _blockNumber()) {
averageRate = _calcAverageRate(averageRate, spotRate);
}
if (MathEx.isInRange(averageRate.fromFraction112(), spotRate, RATE_MAX_DEVIATION_PPM)) {
return PoolRateState.Stable;
}
return PoolRateState.Unstable;
}
function _updateAverageRate(Pool storage data, Fraction memory spotRate) private {
uint32 blockNumber = _blockNumber();
if (data.averageRate.blockNumber != blockNumber) {
data.averageRate = AverageRate({
blockNumber: blockNumber,
rate: _calcAverageRate(data.averageRate.rate, spotRate)
});
}
}
function _calcAverageRate(Fraction112 memory averageRate, Fraction memory spotRate)
private
pure
returns (Fraction112 memory)
{
return
MathEx
.weightedAverage(averageRate.fromFraction112(), spotRate, 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";
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
library TokenLibrary {
using SafeERC20 for IERC20;
using SafeERC20Ex for IERC20;
error PermitUnsupported();
address public constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
string private constant NATIVE_TOKEN_SYMBOL = "ETH";
uint8 private constant NATIVE_TOKEN_DECIMALS = 18;
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 permit(
Token token,
address owner,
address spender,
uint256 tokenAmount,
uint256 deadline,
Signature memory signature
) internal {
if (isNative(token)) {
revert PermitUnsupported();
}
IERC20Permit(address(token)).permit(
owner,
spender,
tokenAmount,
deadline,
signature.v,
signature.r,
signature.s
);
}
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 InvalidType();
error InvalidParam();
error NotEmpty();
error NotPayable();
error ZeroValue();
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"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AlreadyEnabled","type":"error"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DepositLimitExceeded","type":"error"},{"inputs":[],"name":"DepositingDisabled","type":"error"},{"inputs":[],"name":"DoesNotExist","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":"InvalidPoolCollection","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":false,"internalType":"uint256","name":"prevDepositLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDepositLimit","type":"uint256"}],"name":"DepositLimitUpdated","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":"contract IPoolToken","name":"poolToken","type":"address"},{"indexed":true,"internalType":"contract Token","name":"token","type":"address"}],"name":"PoolCreated","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":"tokenAmount","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":"tokenAmount","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":"tokenAmount","type":"uint256"}],"name":"depositFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","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":"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":"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"}],"internalType":"struct AverageRate","name":"averageRate","type":"tuple"},{"internalType":"uint256","name":"depositLimit","type":"uint256"},{"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":"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"}],"internalType":"struct AverageRate","name":"averageRate","type":"tuple"},{"internalType":"uint256","name":"depositLimit","type":"uint256"},{"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":"tokenAmountToDistribute","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":"pure","type":"function"},{"inputs":[],"name":"pools","outputs":[{"internalType":"contract Token[]","name":"","type":"address[]"}],"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":"uint256","name":"newDepositLimit","type":"uint256"}],"name":"setDepositLimit","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":"address","name":"ownerCandidate","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Token","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenAmount","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"}],"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"}]