编译器
0.8.19+commit.7dd6d404
文件 1 的 13: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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 13:AttoDecimal.sol
pragma solidity 0.8.19;
library AttoDecimal {
struct Instance {
uint256 mantissa;
}
uint256 constant BASE = 10;
function ONE_MANTISSA(uint8 decimals) internal pure returns (uint256) {
return BASE ** decimals;
}
function SQUARED_ONE_MANTISSA(
uint8 decimals
) internal pure returns (uint256) {
return ONE_MANTISSA(decimals) * ONE_MANTISSA(decimals);
}
function MAX_INTEGER(uint8 decimals) internal pure returns (uint256) {
return type(uint256).max / ONE_MANTISSA(decimals);
}
function mul(
Instance memory a,
uint256 b
) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa * b});
}
function div(
Instance memory a,
uint256 b
) internal pure returns (Instance memory) {
return Instance({mantissa: a.mantissa / b});
}
function div(
uint256 a,
Instance memory b,
uint8 decimals
) internal pure returns (Instance memory) {
return
Instance({
mantissa: (a * SQUARED_ONE_MANTISSA(decimals)) / b.mantissa
});
}
function floor(
Instance memory a,
uint8 decimals
) internal pure returns (uint256) {
return a.mantissa / ONE_MANTISSA(decimals);
}
function ceil(
Instance memory a,
uint8 decimals
) internal pure returns (uint256) {
return
(a.mantissa / ONE_MANTISSA(decimals)) +
(a.mantissa % ONE_MANTISSA(decimals) > 0 ? 1 : 0);
}
function eq(
Instance memory a,
uint256 b,
uint8 decimals
) internal pure returns (bool) {
if (b > MAX_INTEGER(decimals)) return false;
return a.mantissa == b * ONE_MANTISSA(decimals);
}
function gt(
Instance memory a,
Instance memory b
) internal pure returns (bool) {
return a.mantissa > b.mantissa;
}
function lt(
Instance memory a,
uint256 b,
uint8 decimals
) internal pure returns (bool) {
if (b > MAX_INTEGER(decimals)) return true;
return a.mantissa < (b * (ONE_MANTISSA(decimals)));
}
function lt(
Instance memory a,
Instance memory b
) internal pure returns (bool) {
return a.mantissa < b.mantissa;
}
}
文件 3 的 13: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;
}
}
文件 4 的 13: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, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(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;
unchecked {
_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 {}
}
文件 5 的 13:FixedSwap.sol
pragma solidity 0.8.19;
import "whitelist/interfaces/IWhitelist.sol";
import "./libs/AttoDecimal.sol";
import "solowei/TwoStageOwnable.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import "openzeppelin-contracts/contracts/utils/math/Math.sol";
contract FixedSwap is ReentrancyGuard, TwoStageOwnable {
using SafeERC20 for IERC20;
using AttoDecimal for AttoDecimal.Instance;
IWhitelist public whitelist;
enum Type {
SIMPLE,
INTERVAL,
LINEAR
}
struct Props {
uint256 issuanceLimit;
uint256 startsAt;
uint256 endsAt;
IERC20 paymentToken;
IERC20 issuanceToken;
AttoDecimal.Instance fee;
AttoDecimal.Instance rate;
}
struct AccountState {
uint256 paymentSum;
}
struct ComplexAccountState {
uint256 issuanceAmount;
uint256 withdrawnIssuanceAmount;
}
struct Account {
AccountState state;
ComplexAccountState complex;
uint256 immediatelyUnlockedAmount;
uint256 unlockedIntervalsCount;
}
struct State {
uint256 available;
uint256 issuance;
uint256 lockedPayments;
uint256 unlockedPayments;
uint256 paymentLimit;
address nominatedOwner;
address owner;
}
struct Interval {
uint256 startsAt;
AttoDecimal.Instance unlockingPart;
}
struct LinearProps {
uint256 endsAt;
uint256 duration;
}
struct Pool {
Type type_;
uint256 index;
AttoDecimal.Instance immediatelyUnlockingPart;
Props props;
LinearProps linear;
State state;
Interval[] intervals;
mapping(address => Account) accounts;
}
Pool[] private _pools;
mapping(IERC20 => uint256) private _collectedFees;
function getTimestamp() internal view virtual returns (uint256) {
return block.timestamp;
}
function poolsCount() public view returns (uint256) {
return _pools.length;
}
function poolProps(uint256 poolIndex) public view returns (Type type_, Props memory props) {
Pool storage pool = _getPool(poolIndex);
return (pool.type_, pool.props);
}
function intervalPoolProps(uint256 poolIndex)
public
view
returns (Props memory props, AttoDecimal.Instance memory immediatelyUnlockingPart, Interval[] memory intervals)
{
Pool storage pool = _getPool(poolIndex);
_assertPoolIsInterval(pool);
return (pool.props, pool.immediatelyUnlockingPart, pool.intervals);
}
function linearPoolProps(uint256 poolIndex)
public
view
returns (Props memory props, AttoDecimal.Instance memory immediatelyUnlockingPart, LinearProps memory linear)
{
Pool storage pool = _getPool(poolIndex);
_assertPoolIsLinear(pool);
return (pool.props, pool.immediatelyUnlockingPart, pool.linear);
}
function poolState(uint256 poolIndex) public view returns (State memory state) {
return _getPool(poolIndex).state;
}
function poolAccount(
uint256 poolIndex,
address address_
)
public
view
returns (Type type_, AccountState memory state)
{
Pool storage pool = _getPool(poolIndex);
return (pool.type_, pool.accounts[address_].state);
}
function intervalPoolAccount(
uint256 poolIndex,
address address_
)
public
view
returns (AccountState memory state, ComplexAccountState memory complex, uint256 unlockedIntervalsCount)
{
Pool storage pool = _getPool(poolIndex);
_assertPoolIsInterval(pool);
Account storage account = pool.accounts[address_];
return (account.state, account.complex, account.unlockedIntervalsCount);
}
function linearPoolAccount(
uint256 poolIndex,
address address_
)
public
view
returns (AccountState memory state, ComplexAccountState memory complex, uint256 immediatelyUnlockedAmount)
{
Pool storage pool = _getPool(poolIndex);
_assertPoolIsLinear(pool);
Account storage account = pool.accounts[address_];
return (account.state, account.complex, account.immediatelyUnlockedAmount);
}
function collectedFees(IERC20 token) public view returns (uint256) {
return _collectedFees[token];
}
event AccountLimitChanged(uint256 indexed poolIndex, address indexed address_, uint256 indexed limitIndex);
event FeeWithdrawn(address indexed token, uint256 amount);
event ImmediatelyUnlockingPartUpdated(uint256 indexed poolIndex, uint256 mantissa);
event IntervalCreated(uint256 indexed poolIndex, uint256 startsAt, uint256 unlockingPart);
event IssuanceIncreased(uint256 indexed poolIndex, uint256 amount);
event LinearUnlockingEndingTimestampUpdated(uint256 indexed poolIndex, uint256 timestamp);
event LinearPoolUnlocking(uint256 indexed poolIndex, address indexed account, uint256 amount);
event PaymentLimitCreated(uint256 indexed poolIndex, uint256 indexed limitIndex, uint256 limit);
event PaymentLimitChanged(uint256 indexed poolIndex, uint256 indexed limitIndex, uint256 newLimit);
event PaymentUnlocked(uint256 indexed poolIndex, uint256 unlockedAmount, uint256 collectedFee);
event PaymentsWithdrawn(uint256 indexed poolIndex, uint256 amount);
event PoolOwnerChanged(uint256 indexed poolIndex, address indexed newOwner);
event PoolOwnerNominated(uint256 indexed poolIndex, address indexed nominatedOwner);
event UnsoldWithdrawn(uint256 indexed poolIndex, uint256 amount);
event WhitelistContractChanged(address oldAddress, address newAddress);
event PoolCreated(
Type type_,
IERC20 indexed paymentToken,
IERC20 indexed issuanceToken,
uint256 poolIndex,
uint256 issuanceLimit,
uint256 startsAt,
uint256 endsAt,
uint256 fee,
uint256 rate,
uint256 paymentLimit
);
event Swap(
uint256 indexed poolIndex,
address indexed caller,
uint256 requestedPaymentAmount,
uint256 paymentAmount,
uint256 issuanceAmount
);
constructor(address owner_, address whitelistContract_) public TwoStageOwnable(owner_) {
whitelist = IWhitelist(whitelistContract_);
}
function createSimplePool(
Props memory props,
uint256 paymentLimit,
address owner_
)
external
onlyOwner
returns (bool success, uint256 poolIndex)
{
return (true, _createSimplePool(props, paymentLimit, owner_, Type.SIMPLE).index);
}
function createIntervalPool(
Props memory props,
uint256 paymentLimit,
address owner_,
AttoDecimal.Instance memory immediatelyUnlockingPart,
Interval[] memory intervals
)
external
onlyOwner
returns (bool success, uint256 poolIndex)
{
Pool storage pool = _createSimplePool(props, paymentLimit, owner_, Type.INTERVAL);
_setImmediatelyUnlockingPart(pool, immediatelyUnlockingPart);
uint256 intervalsCount = intervals.length;
AttoDecimal.Instance memory lastUnlockingPart = immediatelyUnlockingPart;
uint256 lastIntervalStartingTimestamp = props.endsAt - 1;
for (uint256 i = 0; i < intervalsCount; i++) {
Interval memory interval = intervals[i];
require(interval.unlockingPart.gt(lastUnlockingPart), "Invalid interval unlocking part");
lastUnlockingPart = interval.unlockingPart;
uint256 startingTimestamp = interval.startsAt;
require(startingTimestamp > lastIntervalStartingTimestamp, "Invalid interval starting timestamp");
lastIntervalStartingTimestamp = startingTimestamp;
pool.intervals.push(interval);
emit IntervalCreated(poolIndex, interval.startsAt, interval.unlockingPart.mantissa);
}
require(
lastUnlockingPart.eq(1, ERC20(address(props.paymentToken)).decimals()), "Unlocking part not equal to one"
);
return (true, pool.index);
}
function createLinearPool(
Props memory props,
uint256 paymentLimit,
address owner_,
AttoDecimal.Instance memory immediatelyUnlockingPart,
uint256 linearUnlockingEndsAt
)
external
onlyOwner
returns (bool success, uint256 poolIndex)
{
require(linearUnlockingEndsAt > props.endsAt, "Linear unlocking less than or equal to pool ending timestamp");
Pool storage pool = _createSimplePool(props, paymentLimit, owner_, Type.LINEAR);
_setImmediatelyUnlockingPart(pool, immediatelyUnlockingPart);
pool.linear.endsAt = linearUnlockingEndsAt;
pool.linear.duration = linearUnlockingEndsAt - props.endsAt;
emit LinearUnlockingEndingTimestampUpdated(pool.index, linearUnlockingEndsAt);
return (true, pool.index);
}
function increaseIssuance(uint256 poolIndex, uint256 amount) external returns (bool success) {
require(amount > 0, "Amount is zero");
Pool storage pool = _getPool(poolIndex);
require(getTimestamp() < pool.props.endsAt, "Pool ended");
address caller = msg.sender;
_assertPoolOwnership(pool, caller);
pool.state.issuance = pool.state.issuance + amount;
require(pool.state.issuance <= pool.props.issuanceLimit, "Issuance limit exceeded");
pool.state.available = pool.state.available + amount;
emit IssuanceIncreased(poolIndex, amount);
pool.props.issuanceToken.safeTransferFrom(caller, address(this), amount);
return true;
}
function swap(
uint256 poolIndex,
uint256 requestedPaymentAmount
)
external
nonReentrant
returns (uint256 paymentAmount, uint256 issuanceAmount)
{
require(requestedPaymentAmount > 0, "Requested payment amount is zero");
address caller = msg.sender;
require(whitelist.isWhitelisted(caller), "FixedSwap::Caller Not Whitelisted");
Pool storage pool = _getPool(poolIndex);
uint256 timestamp = getTimestamp();
require(timestamp >= pool.props.startsAt, "Pool not started");
require(timestamp < pool.props.endsAt, "Pool ended");
require(pool.state.available > 0, "No available issuance");
(paymentAmount, issuanceAmount) = _calculateSwapAmounts(pool, requestedPaymentAmount, caller);
Account storage account = pool.accounts[caller];
if (paymentAmount > 0) {
pool.state.lockedPayments = pool.state.lockedPayments + paymentAmount;
account.state.paymentSum = account.state.paymentSum + paymentAmount;
uint256 contractBalanceBefore = pool.props.paymentToken.balanceOf(address(this));
pool.props.paymentToken.safeTransferFrom(caller, address(this), paymentAmount);
uint256 contractBalanceAfter = pool.props.paymentToken.balanceOf(address(this));
require(
contractBalanceBefore + paymentAmount == contractBalanceAfter,
"Failed to transfer correct amount"
);
}
if (issuanceAmount > 0) {
if (pool.type_ == Type.SIMPLE) {
pool.props.issuanceToken.safeTransfer(caller, issuanceAmount);
} else {
uint256 totalIssuanceAmount = account.complex.issuanceAmount + issuanceAmount;
account.complex.issuanceAmount = totalIssuanceAmount;
uint256 newWithdrawnIssuanceAmount = pool.immediatelyUnlockingPart.mul(totalIssuanceAmount).floor(
ERC20(address(pool.props.paymentToken)).decimals()
);
uint256 issuanceToWithdraw = newWithdrawnIssuanceAmount - account.complex.withdrawnIssuanceAmount;
account.complex.withdrawnIssuanceAmount = newWithdrawnIssuanceAmount;
if (pool.type_ == Type.LINEAR) {
account.immediatelyUnlockedAmount = newWithdrawnIssuanceAmount;
}
if (issuanceToWithdraw > 0) {
pool.props.issuanceToken.safeTransfer(caller, issuanceToWithdraw);
}
}
pool.state.available = pool.state.available - issuanceAmount;
}
emit Swap(poolIndex, caller, requestedPaymentAmount, paymentAmount, issuanceAmount);
}
function unlockInterval(
uint256 poolIndex,
uint256 intervalIndex
)
external
returns (uint256 withdrawnIssuanceAmount)
{
address caller = msg.sender;
Pool storage pool = _getPool(poolIndex);
_assertPoolIsInterval(pool);
require(intervalIndex < pool.intervals.length, "Invalid interval index");
Interval storage interval = pool.intervals[intervalIndex];
require(interval.startsAt <= getTimestamp(), "Interval not started");
Account storage account = pool.accounts[caller];
require(intervalIndex >= account.unlockedIntervalsCount, "Already unlocked");
uint256 newWithdrawnIssuanceAmount = interval.unlockingPart.mul(account.complex.issuanceAmount).floor(
ERC20(address(pool.props.paymentToken)).decimals()
);
uint256 issuanceToWithdraw = newWithdrawnIssuanceAmount - account.complex.withdrawnIssuanceAmount;
account.complex.withdrawnIssuanceAmount = newWithdrawnIssuanceAmount;
if (issuanceToWithdraw > 0) {
pool.props.issuanceToken.safeTransfer(caller, issuanceToWithdraw);
}
account.unlockedIntervalsCount = intervalIndex + 1;
return issuanceToWithdraw;
}
function unlockLinear(uint256 poolIndex) external returns (uint256 withdrawalAmount) {
address caller = msg.sender;
uint256 timestamp = getTimestamp();
Pool storage pool = _getPool(poolIndex);
_assertPoolIsLinear(pool);
require(pool.props.endsAt < timestamp, "Pool not ended");
Account storage account = pool.accounts[caller];
uint256 issuanceAmount = account.complex.issuanceAmount;
require(account.complex.withdrawnIssuanceAmount < issuanceAmount, "All funds already unlocked");
uint256 passedTime = timestamp - pool.props.endsAt;
uint256 freezedAmount = issuanceAmount - account.immediatelyUnlockedAmount;
uint256 unfreezedAmount = (passedTime * freezedAmount) / pool.linear.duration;
uint256 newWithdrawnIssuanceAmount = timestamp >= pool.linear.endsAt
? issuanceAmount
: Math.min(account.immediatelyUnlockedAmount + unfreezedAmount, issuanceAmount);
withdrawalAmount = newWithdrawnIssuanceAmount - account.complex.withdrawnIssuanceAmount;
if (withdrawalAmount > 0) {
account.complex.withdrawnIssuanceAmount = newWithdrawnIssuanceAmount;
emit LinearPoolUnlocking(pool.index, caller, withdrawalAmount);
pool.props.issuanceToken.safeTransfer(caller, withdrawalAmount);
}
}
function withdrawPayments(uint256 poolIndex) external returns (bool success) {
Pool storage pool = _getPool(poolIndex);
address caller = msg.sender;
_assertPoolOwnership(pool, caller);
_unlockPayments(pool);
uint256 collectedPayments = pool.state.unlockedPayments;
require(collectedPayments > 0, "No collected payments");
pool.state.unlockedPayments = 0;
emit PaymentsWithdrawn(poolIndex, collectedPayments);
pool.props.paymentToken.safeTransfer(caller, collectedPayments);
return true;
}
function withdrawUnsold(uint256 poolIndex) external returns (bool success) {
Pool storage pool = _getPool(poolIndex);
address caller = msg.sender;
_assertPoolOwnership(pool, caller);
require(getTimestamp() >= pool.props.endsAt, "Not ended");
uint256 amount = pool.state.available;
require(amount > 0, "No unsold");
pool.state.available = 0;
emit UnsoldWithdrawn(poolIndex, amount);
pool.props.issuanceToken.safeTransfer(caller, amount);
return true;
}
function collectFee(uint256 poolIndex) external onlyOwner returns (bool success) {
_unlockPayments(_getPool(poolIndex));
return true;
}
function withdrawFee(IERC20 token) external onlyOwner returns (bool success) {
uint256 collectedFee = _collectedFees[token];
require(collectedFee > 0, "No collected fees");
_collectedFees[token] = 0;
emit FeeWithdrawn(address(token), collectedFee);
token.safeTransfer(owner(), collectedFee);
return true;
}
function nominateNewPoolOwner(uint256 poolIndex, address nominatedOwner_) external returns (bool success) {
Pool storage pool = _getPool(poolIndex);
_assertPoolOwnership(pool, msg.sender);
require(nominatedOwner_ != pool.state.owner, "Already owner");
if (pool.state.nominatedOwner == nominatedOwner_) return true;
pool.state.nominatedOwner = nominatedOwner_;
emit PoolOwnerNominated(poolIndex, nominatedOwner_);
return true;
}
function acceptPoolOwnership(uint256 poolIndex) external returns (bool success) {
Pool storage pool = _getPool(poolIndex);
address caller = msg.sender;
require(pool.state.nominatedOwner == caller, "Not nominated to pool ownership");
pool.state.owner = caller;
pool.state.nominatedOwner = address(0);
emit PoolOwnerChanged(poolIndex, caller);
return true;
}
function _assertPoolIsInterval(Pool storage pool) private view {
require(pool.type_ == Type.INTERVAL, "Not interval pool");
}
function _assertPoolIsLinear(Pool storage pool) private view {
require(pool.type_ == Type.LINEAR, "Not linear pool");
}
function _assertPoolOwnership(Pool storage pool, address account) private view {
require(account == pool.state.owner, "Permission denied");
}
function _calculateSwapAmounts(
Pool storage pool,
uint256 requestedPaymentAmount,
address account
)
private
view
returns (uint256 paymentAmount, uint256 issuanceAmount)
{
paymentAmount = requestedPaymentAmount;
Account storage poolAccount_ = pool.accounts[account];
uint256 paymentLimit = pool.state.paymentLimit;
require(poolAccount_.state.paymentSum < paymentLimit, "Account payment limit exceeded");
if (poolAccount_.state.paymentSum + paymentAmount > paymentLimit) {
paymentAmount = paymentLimit - poolAccount_.state.paymentSum;
}
issuanceAmount = pool.props.rate.mul(paymentAmount).floor(ERC20(address(pool.props.paymentToken)).decimals());
if (issuanceAmount > pool.state.available) {
issuanceAmount = pool.state.available;
paymentAmount = AttoDecimal.div(
issuanceAmount, pool.props.rate, ERC20(address(pool.props.paymentToken)).decimals()
).ceil(ERC20(address(pool.props.paymentToken)).decimals());
}
}
function _getPool(uint256 index) private view returns (Pool storage) {
require(index < _pools.length, "Pool not found");
return _pools[index];
}
function _createSimplePool(
Props memory props,
uint256 paymentLimit,
address owner_,
Type type_
)
private
returns (Pool storage)
{
{
uint256 timestamp = getTimestamp();
uint8 decimals = ERC20(address(props.paymentToken)).decimals();
if (props.startsAt < timestamp) props.startsAt = timestamp;
require(decimals > 0, "PaymentTokenDecimals is 0");
require(props.fee.lt(1, decimals), "Fee gte 100%");
require(props.startsAt < props.endsAt, "Invalid ending timestamp");
}
uint256 poolIndex = _pools.length;
_pools.push();
Pool storage pool = _pools[poolIndex];
pool.index = poolIndex;
pool.type_ = type_;
pool.props = props;
pool.state.paymentLimit = paymentLimit;
pool.state.owner = owner_;
emit PoolCreated(
type_,
props.paymentToken,
props.issuanceToken,
poolIndex,
props.issuanceLimit,
props.startsAt,
props.endsAt,
props.fee.mantissa,
props.rate.mantissa,
paymentLimit
);
emit PoolOwnerChanged(poolIndex, owner_);
return pool;
}
function _setImmediatelyUnlockingPart(
Pool storage pool,
AttoDecimal.Instance memory immediatelyUnlockingPart
)
private
{
uint8 decimals = ERC20(address(pool.props.paymentToken)).decimals();
require(immediatelyUnlockingPart.lt(1, decimals), "Invalid immediately unlocking part value");
pool.immediatelyUnlockingPart = immediatelyUnlockingPart;
emit ImmediatelyUnlockingPartUpdated(pool.index, immediatelyUnlockingPart.mantissa);
}
function _unlockPayments(Pool storage pool) private {
if (pool.state.lockedPayments == 0) return;
uint256 fee =
pool.props.fee.mul(pool.state.lockedPayments).ceil(ERC20(address(pool.props.paymentToken)).decimals());
_collectedFees[pool.props.paymentToken] = _collectedFees[pool.props.paymentToken] + fee;
uint256 unlockedAmount = pool.state.lockedPayments - fee;
pool.state.unlockedPayments = pool.state.unlockedPayments + unlockedAmount;
pool.state.lockedPayments = 0;
emit PaymentUnlocked(pool.index, unlockedAmount, fee);
}
function changeWhitelistAddress(address _newWhitelistAddress) external onlyOwner {
require(_newWhitelistAddress != address(0), "FixedSwap: ZeroAddress");
emit WhitelistContractChanged(address(whitelist), _newWhitelistAddress);
whitelist = IWhitelist(_newWhitelistAddress);
}
}
文件 6 的 13:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
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);
}
文件 7 的 13: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);
}
文件 8 的 13:IWhitelist.sol
pragma solidity 0.8.19;
interface IWhitelist {
function addWallets(address[] calldata wallets) external;
function removeWallets(address[] calldata wallets) external;
function isWhitelisted(address wallet) external view returns (bool);
event AddressesWhitelisted(address caller);
event AddressesBlacklisted(address caller);
}
文件 9 的 13:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
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 == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 10 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 11 的 13:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.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 safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
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");
}
}
}
文件 12 的 13:TwoStageOwnable.sol
pragma solidity ^0.8.6;
abstract contract TwoStageOwnable {
address private _nominatedOwner;
address private _owner;
function nominatedOwner() public view returns (address) {
return _nominatedOwner;
}
function owner() public view returns (address) {
return _owner;
}
event OwnerChanged(address indexed newOwner);
event OwnerNominated(address indexed nominatedOwner);
constructor(address owner_) {
require(owner_ != address(0), "Owner is zero");
_setOwner(owner_);
}
function acceptOwnership() external returns (bool success) {
require(msg.sender == _nominatedOwner, "Not nominated to ownership");
_setOwner(_nominatedOwner);
return true;
}
function nominateNewOwner(address owner_) external onlyOwner returns (bool success) {
_nominateNewOwner(owner_);
return true;
}
modifier onlyOwner {
require(msg.sender == _owner, "Not owner");
_;
}
function _nominateNewOwner(address owner_) internal {
if (_nominatedOwner == owner_) return;
require(_owner != owner_, "Already owner");
_nominatedOwner = owner_;
emit OwnerNominated(owner_);
}
function _setOwner(address newOwner) internal {
if (_owner == newOwner) return;
_owner = newOwner;
_nominatedOwner = address(0);
emit OwnerChanged(newOwner);
}
}
文件 13 的 13: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": {
"FixedSwapEnhanced/src/FixedSwap.sol": "FixedSwap"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/",
":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solowei-06/=lib/solowei-06/contracts/",
":solowei/=lib/solowei/contracts/",
":whitelist/=Whitelist/src/"
]
}
[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"whitelistContract_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"address_","type":"address"},{"indexed":true,"internalType":"uint256","name":"limitIndex","type":"uint256"}],"name":"AccountLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mantissa","type":"uint256"}],"name":"ImmediatelyUnlockingPartUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startsAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockingPart","type":"uint256"}],"name":"IntervalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IssuanceIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LinearPoolUnlocking","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"LinearUnlockingEndingTimestampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nominatedOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"limitIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"PaymentLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"limitIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"PaymentLimitCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collectedFee","type":"uint256"}],"name":"PaymentUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PaymentsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum FixedSwap.Type","name":"type_","type":"uint8"},{"indexed":true,"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startsAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endsAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentLimit","type":"uint256"}],"name":"PoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"PoolOwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"nominatedOwner","type":"address"}],"name":"PoolOwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestedPaymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"issuanceAmount","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnsoldWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"WhitelistContractChanged","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"acceptPoolOwnership","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newWhitelistAddress","type":"address"}],"name":"changeWhitelistAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"collectFee","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"collectedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"},{"internalType":"uint256","name":"paymentLimit","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"immediatelyUnlockingPart","type":"tuple"},{"components":[{"internalType":"uint256","name":"startsAt","type":"uint256"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"unlockingPart","type":"tuple"}],"internalType":"struct FixedSwap.Interval[]","name":"intervals","type":"tuple[]"}],"name":"createIntervalPool","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"},{"internalType":"uint256","name":"paymentLimit","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"immediatelyUnlockingPart","type":"tuple"},{"internalType":"uint256","name":"linearUnlockingEndsAt","type":"uint256"}],"name":"createLinearPool","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"},{"internalType":"uint256","name":"paymentLimit","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"}],"name":"createSimplePool","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseIssuance","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"address","name":"address_","type":"address"}],"name":"intervalPoolAccount","outputs":[{"components":[{"internalType":"uint256","name":"paymentSum","type":"uint256"}],"internalType":"struct FixedSwap.AccountState","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"issuanceAmount","type":"uint256"},{"internalType":"uint256","name":"withdrawnIssuanceAmount","type":"uint256"}],"internalType":"struct FixedSwap.ComplexAccountState","name":"complex","type":"tuple"},{"internalType":"uint256","name":"unlockedIntervalsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"intervalPoolProps","outputs":[{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"immediatelyUnlockingPart","type":"tuple"},{"components":[{"internalType":"uint256","name":"startsAt","type":"uint256"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"unlockingPart","type":"tuple"}],"internalType":"struct FixedSwap.Interval[]","name":"intervals","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"address","name":"address_","type":"address"}],"name":"linearPoolAccount","outputs":[{"components":[{"internalType":"uint256","name":"paymentSum","type":"uint256"}],"internalType":"struct FixedSwap.AccountState","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"issuanceAmount","type":"uint256"},{"internalType":"uint256","name":"withdrawnIssuanceAmount","type":"uint256"}],"internalType":"struct FixedSwap.ComplexAccountState","name":"complex","type":"tuple"},{"internalType":"uint256","name":"immediatelyUnlockedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"linearPoolProps","outputs":[{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"immediatelyUnlockingPart","type":"tuple"},{"components":[{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"internalType":"struct FixedSwap.LinearProps","name":"linear","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"nominateNewOwner","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"address","name":"nominatedOwner_","type":"address"}],"name":"nominateNewPoolOwner","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"address","name":"address_","type":"address"}],"name":"poolAccount","outputs":[{"internalType":"enum FixedSwap.Type","name":"type_","type":"uint8"},{"components":[{"internalType":"uint256","name":"paymentSum","type":"uint256"}],"internalType":"struct FixedSwap.AccountState","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"poolProps","outputs":[{"internalType":"enum FixedSwap.Type","name":"type_","type":"uint8"},{"components":[{"internalType":"uint256","name":"issuanceLimit","type":"uint256"},{"internalType":"uint256","name":"startsAt","type":"uint256"},{"internalType":"uint256","name":"endsAt","type":"uint256"},{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"contract IERC20","name":"issuanceToken","type":"address"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"fee","type":"tuple"},{"components":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"internalType":"struct AttoDecimal.Instance","name":"rate","type":"tuple"}],"internalType":"struct FixedSwap.Props","name":"props","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"poolState","outputs":[{"components":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"issuance","type":"uint256"},{"internalType":"uint256","name":"lockedPayments","type":"uint256"},{"internalType":"uint256","name":"unlockedPayments","type":"uint256"},{"internalType":"uint256","name":"paymentLimit","type":"uint256"},{"internalType":"address","name":"nominatedOwner","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"internalType":"struct FixedSwap.State","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"uint256","name":"requestedPaymentAmount","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256","name":"issuanceAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"},{"internalType":"uint256","name":"intervalIndex","type":"uint256"}],"name":"unlockInterval","outputs":[{"internalType":"uint256","name":"withdrawnIssuanceAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"unlockLinear","outputs":[{"internalType":"uint256","name":"withdrawalAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelist","outputs":[{"internalType":"contract IWhitelist","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdrawFee","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"withdrawPayments","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"name":"withdrawUnsold","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]