编译器
0.8.16+commit.07a7930e
文件 1 的 26: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 的 26: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;
}
}
文件 3 的 26:DCAConfigHandler.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import "./DCAParameters.sol";
import "./../utils/Governable.sol";
import "./../libraries/Intervals.sol";
import "../interfaces/IDCAConfigHandler.sol";
import "./../interfaces/IWNative.sol";
import { ZeroAddress, InvalidInterval, HighFee, HighPlatformFeeRatio, InvalidToken, InvalidNoOfSwaps, InvalidLength } from "./../common/Error.sol";
abstract contract DCAConfigHandler is DCAParameters, Governable, Pausable, IDCAConfigHandler {
bytes1 public allowedSwapIntervals;
mapping(address => bool) public allowedTokens;
mapping(address => uint256) public tokenMagnitude;
mapping(address => bool) public admins;
mapping(address => bool) public swapExecutors;
mapping(bytes1 => uint256) internal _swapFeeMap;
IWNative public immutable wNative;
address public feeVault;
address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 public maxNoOfSwap;
uint256 public nextToNextTimeThreshold = 10 minutes;
uint256 public platformFeeRatio;
uint256 public constant MAX_FEE = 1000;
uint256 public constant MAX_PLATFORM_FEE_RATIO = 10000;
uint256 public constant BPS_DENOMINATOR = 10000;
constructor(address governor_, address wNative_, address feeVault_, uint256 maxNoOfSwap_) Governable(governor_) {
if (feeVault_ == address(0) || wNative_ == address(0)) revert ZeroAddress();
if (maxNoOfSwap_ < 2) revert InvalidNoOfSwaps();
wNative = IWNative(wNative_);
feeVault = feeVault_;
maxNoOfSwap = maxNoOfSwap_;
}
modifier onlyAdminOrGovernor() {
if (!admins[_msgSender()] && _msgSender() != governance()) revert UnauthorizedCaller();
_;
}
modifier onlySwapper() {
if (!swapExecutors[_msgSender()]) revert UnauthorizedCaller();
_;
}
function getSwapFee(uint32 interval_) external view returns (uint256) {
return _swapFeeMap[Intervals.intervalToMask(interval_)];
}
function pause() external onlyGovernance {
_pause();
}
function unpause() external onlyGovernance {
_unpause();
}
function addAdmins(address[] calldata accounts_) external onlyGovernance {
_setAdmin(accounts_, true);
emit AdminAdded(accounts_);
}
function removeAdmins(address[] calldata accounts_) external onlyGovernance {
_setAdmin(accounts_, false);
emit AdminRemoved(accounts_);
}
function addSwapExecutors(address[] calldata executor_) external onlyGovernance {
_setSwapExecutor(executor_, true);
emit SwapExecutorAdded(executor_);
}
function removeSwapExecutors(address[] calldata executor_) external onlyGovernance {
_setSwapExecutor(executor_, false);
emit SwapExecutorRemoved(executor_);
}
function addAllowedTokens(address[] calldata tokens_) external onlyAdminOrGovernor {
_setAllowedTokens(tokens_, true);
emit TokensAdded(tokens_);
}
function removeAllowedTokens(address[] calldata tokens_) external onlyAdminOrGovernor {
_setAllowedTokens(tokens_, false);
emit TokensRemoved(tokens_);
}
function addSwapIntervalsToAllowedList(uint32[] calldata swapIntervals_) external onlyAdminOrGovernor {
for (uint256 i; i < swapIntervals_.length; ++i) {
allowedSwapIntervals |= Intervals.intervalToMask(swapIntervals_[i]);
}
emit SwapIntervalsAdded(swapIntervals_);
}
function removeSwapIntervalsFromAllowedList(uint32[] calldata swapIntervals_) external onlyAdminOrGovernor {
for (uint256 i; i < swapIntervals_.length; ++i) {
allowedSwapIntervals &= ~Intervals.intervalToMask(swapIntervals_[i]);
}
emit SwapIntervalsRemoved(swapIntervals_);
}
function updateMaxSwapLimit(uint256 maxNoOfSwap_) external onlyAdminOrGovernor {
if (maxNoOfSwap_ < 2) revert InvalidNoOfSwaps();
maxNoOfSwap = maxNoOfSwap_;
emit SwapLimitUpdated(maxNoOfSwap_);
}
function updateSwapTimeThreshold(uint256 nextToNextTimeThreshold_) external onlyAdminOrGovernor {
nextToNextTimeThreshold = nextToNextTimeThreshold_;
emit SwapThresholdUpdated(nextToNextTimeThreshold_);
}
function setFeeVault(address newVault_) external onlyGovernance {
if (newVault_ == address(0)) revert ZeroAddress();
feeVault = newVault_;
emit FeeVaultUpdated(newVault_);
}
function setSwapFee(uint32[] calldata intervals_, uint256[] calldata swapFee_) external onlyGovernance {
if (intervals_.length != swapFee_.length) revert InvalidLength();
for (uint256 i; i < intervals_.length; i++) {
if (swapFee_[i] > MAX_FEE) revert HighFee();
_swapFeeMap[Intervals.intervalToMask(intervals_[i])] = swapFee_[i];
}
emit SwapFeeUpdated(intervals_, swapFee_);
}
function setPlatformFeeRatio(uint256 platformFeeRatio_) external onlyGovernance {
if (platformFeeRatio_ > MAX_PLATFORM_FEE_RATIO) revert HighPlatformFeeRatio();
platformFeeRatio = platformFeeRatio_;
emit PlatformFeeRatioUpdated(platformFeeRatio_);
}
function _setAllowedTokens(address[] calldata tokens_, bool allowed_) private {
for (uint256 i; i < tokens_.length; ++i) {
address token = tokens_[i];
if (token == address(0) || token == NATIVE_TOKEN) revert InvalidToken();
allowedTokens[token] = allowed_;
if (tokenMagnitude[token] == 0) {
tokenMagnitude[token] = 10**IERC20Metadata(token).decimals();
}
}
}
function _setAdmin(address[] calldata accounts_, bool state_) private {
for (uint256 i; i < accounts_.length; i++) {
if (accounts_[i] == address(0)) revert ZeroAddress();
admins[accounts_[i]] = state_;
}
}
function _setSwapExecutor(address[] calldata accounts_, bool state_) private {
for (uint256 i; i < accounts_.length; i++) {
if (accounts_[i] == address(0)) revert ZeroAddress();
swapExecutors[accounts_[i]] = state_;
}
}
}
文件 4 的 26:DCAParameters.sol
pragma solidity 0.8.16;
import "./../interfaces/IDCAParameters.sol";
import { SwapData } from "./../common/Types.sol";
abstract contract DCAParameters is IDCAParameters {
mapping(address => mapping(address => bytes1)) public activeSwapIntervals;
mapping(address => mapping(address => mapping(bytes1 => SwapData))) public swapData;
mapping(address => mapping(address => mapping(bytes1 => mapping(uint256 => uint256)))) public swapAmountDelta;
mapping(address => mapping(address => mapping(bytes1 => mapping(uint256 => uint256)))) public accumRatio;
}
文件 5 的 26:DCAPositionHandler.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./../interfaces/IDCAPositionHandler.sol";
import "./../utils/Permitable.sol";
import "./DCAConfigHandler.sol";
import { UserPosition, PositionInfo, CreatePositionDetails, PermitType } from "./../common/Types.sol";
import { ZeroAddress, NotWNative, NativeTransferFailed, UnauthorizedTokens, InvalidAmount, InvalidNoOfSwaps, UnauthorizedInterval, InvalidRate, NoChanges, ZeroSwappedTokens, InvalidAmountTransferred, InvalidNativeAmount, InvalidPosition } from "./../common/Error.sol";
abstract contract DCAPositionHandler is Permitable, DCAConfigHandler, IDCAPositionHandler {
using SafeERC20 for IERC20;
mapping(uint256 => UserPosition) public userPositions;
mapping(uint256 => uint256) internal _swappedBeforeModified;
uint256 public totalCreatedPositions;
constructor(address permit2_) Permitable(permit2_) {}
function getPositionDetails(uint256 positionId_) external view returns (PositionInfo memory positionInfo) {
UserPosition memory userPosition = userPositions[positionId_];
uint256 performedSwaps = swapData[userPosition.from][userPosition.to][userPosition.swapIntervalMask].performedSwaps;
positionInfo.owner = userPosition.owner;
positionInfo.from = userPosition.from;
positionInfo.to = userPosition.to;
positionInfo.rate = userPosition.rate;
positionInfo.swapsLeft = _remainingNoOfSwaps(userPosition.startingSwap, userPosition.finalSwap, performedSwaps);
positionInfo.swapsExecuted = userPosition.finalSwap - userPosition.startingSwap - positionInfo.swapsLeft;
positionInfo.unswapped = _calculateUnswapped(userPosition, performedSwaps);
if (userPosition.swapIntervalMask > 0) {
positionInfo.swapInterval = Intervals.maskToInterval(userPosition.swapIntervalMask);
positionInfo.swapped = _calculateSwapped(positionId_, userPosition, performedSwaps);
}
}
function createPosition(CreatePositionDetails calldata details_) external payable whenNotPaused {
if (details_.from == NATIVE_TOKEN && msg.value != details_.amount) revert InvalidNativeAmount();
(uint256 positionId, bool isNative) = _create(details_);
emit Created(_msgSender(), positionId, isNative);
}
function createBatchPositions(CreatePositionDetails[] calldata details_) external payable whenNotPaused {
uint256 value = msg.value;
bool[] memory isNative = new bool[](details_.length);
for (uint256 i; i < details_.length; ++i) {
if (details_[i].from == NATIVE_TOKEN) {
if (details_[i].amount > value) revert InvalidNativeAmount();
value -= details_[i].amount;
}
(, isNative[i]) = _create(details_[i]);
}
if (value != 0) revert InvalidNativeAmount();
emit CreatedBatched(_msgSender(), totalCreatedPositions, details_.length, isNative);
}
function modifyPosition(uint256 positionId_, uint256 amount_, uint256 noOfSwaps_, bool isIncrease_, bool isNative_, bytes calldata permit_) external payable whenNotPaused {
UserPosition memory userPosition = userPositions[positionId_];
_assertPositionExistsAndCallerIsOwner(userPosition);
if (amount_ == 0) {
_assertTokensAreAllowed(userPosition.from, userPosition.to);
if (msg.value != 0) revert InvalidNativeAmount();
} else if (isIncrease_) {
_assertTokensAreAllowed(userPosition.from, userPosition.to);
_deposit(isNative_, userPosition.from, amount_, permit_);
}
(uint256 rate, uint256 startingSwap, uint256 finalSwap) = _modify(userPosition, positionId_, amount_, noOfSwaps_, isIncrease_);
if (!isIncrease_ && amount_ > 0) _pay(isNative_, userPosition.from, _msgSender(), amount_);
emit Modified(_msgSender(), positionId_, rate, startingSwap, finalSwap, isNative_);
}
function terminatePosition(uint256 positionId_, address recipient_, bool isNative_) external {
if (recipient_ == address(0)) revert ZeroAddress();
UserPosition memory userPosition = userPositions[positionId_];
_assertPositionExistsAndCallerIsOwner(userPosition);
(uint256 unswapped, uint256 swapped) = _terminate(userPosition, positionId_);
if (isNative_) {
if (userPosition.from == address(wNative)) {
_unwrapAndTransfer(recipient_, unswapped);
IERC20(userPosition.to).safeTransfer(recipient_, swapped);
} else if ((userPosition.to == address(wNative))) {
IERC20(userPosition.from).safeTransfer(recipient_, unswapped);
_unwrapAndTransfer(recipient_, swapped);
} else revert NotWNative();
} else {
IERC20(userPosition.from).safeTransfer(recipient_, unswapped);
IERC20(userPosition.to).safeTransfer(recipient_, swapped);
}
emit Terminated(_msgSender(), recipient_, positionId_, swapped, unswapped, isNative_);
}
function withdrawPosition(uint256 positionId_, address recipient_, bool isNative_) external {
if (recipient_ == address(0)) revert ZeroAddress();
UserPosition memory userPosition = userPositions[positionId_];
_assertPositionExistsAndCallerIsOwner(userPosition);
uint256 swapped = _withdraw(userPosition, positionId_);
if (swapped == 0) revert ZeroSwappedTokens();
_pay(isNative_, userPosition.to, recipient_, swapped);
emit Withdrawn(_msgSender(), recipient_, positionId_, swapped, isNative_);
}
function transferPositionOwnership(uint256 positionId_, address newOwner_) external whenNotPaused {
if (newOwner_ == address(0)) revert ZeroAddress();
UserPosition memory userPosition = userPositions[positionId_];
_assertPositionExistsAndCallerIsOwner(userPosition);
userPositions[positionId_].owner = newOwner_;
emit PositionOwnerUpdated(userPosition.owner, newOwner_, positionId_);
}
function _deposit(bool isNative_, address token_, uint256 amount_, bytes calldata permit_) private {
if (isNative_) {
if (msg.value != amount_) revert InvalidNativeAmount();
if (token_ != address(wNative)) revert NotWNative();
_wrap(amount_);
} else {
_permitAndTransferFrom(token_, permit_, amount_);
}
}
function _pay(bool isNative_, address token_, address recipient_, uint256 amount_) private {
if (isNative_) {
if (token_ != address(wNative)) revert NotWNative();
_unwrapAndTransfer(recipient_, amount_);
} else {
IERC20(token_).safeTransfer(recipient_, amount_);
}
}
function _safeNativeTransfer(address recipient_, uint256 amount_) internal {
(bool sent, ) = recipient_.call{ value: amount_ }(new bytes(0));
if (!sent) revert NativeTransferFailed();
}
function _permitAndTransferFrom(address token_, bytes calldata permit_, uint256 amount_) internal {
(PermitType permitType, bytes memory data) = abi.decode(permit_, (PermitType, bytes));
if(permitType == PermitType.PERMIT2_APPROVE) {
_permit2Approve(token_, data);
IPermit2(PERMIT2).transferFrom(
_msgSender(),
address(this),
uint160(amount_),
token_
);
} else if (permitType == PermitType.PERMIT2_TRANSFER_FROM) {
_permit2TransferFrom(token_, data, amount_);
} else {
_permit(token_, data);
IERC20(token_).safeTransferFrom(_msgSender(), address(this), amount_);
}
}
function _wrap(uint256 amount_) internal {
if (amount_ > 0) wNative.deposit{ value: amount_ }();
}
function _unwrapAndTransfer(address recipient_, uint256 amount_) internal {
if (amount_ > 0) {
wNative.withdraw(amount_);
_safeNativeTransfer(recipient_, amount_);
}
}
function _create(CreatePositionDetails calldata details_) private returns (uint256 positionId, bool isNative) {
if (details_.from == address(0) || details_.to == address(0)) revert ZeroAddress();
if (details_.amount == 0) revert InvalidAmount();
if (details_.noOfSwaps == 0 || details_.noOfSwaps > maxNoOfSwap) revert InvalidNoOfSwaps();
bool isFromNative = details_.from == NATIVE_TOKEN;
bool isToNative = details_.to == NATIVE_TOKEN;
isNative = isFromNative || isToNative;
address from = isFromNative ? address(wNative) : details_.from;
address to = isToNative ? address(wNative) : details_.to;
if (from == to) revert InvalidToken();
_assertTokensAreAllowed(from, to);
bytes1 swapIntervalMask = Intervals.intervalToMask(details_.swapInterval);
if (allowedSwapIntervals & swapIntervalMask == 0) revert InvalidInterval();
uint256 rate = _calculateRate(details_.amount, details_.noOfSwaps);
if (rate == 0) revert InvalidRate();
if (isFromNative) _wrap(details_.amount);
else _permitAndTransferFrom(from, details_.permit, details_.amount);
positionId = ++totalCreatedPositions;
uint256 performedSwaps = swapData[from][to][swapIntervalMask].performedSwaps;
if (activeSwapIntervals[from][to] & swapIntervalMask == 0) activeSwapIntervals[from][to] |= swapIntervalMask;
(uint256 startingSwap, uint256 finalSwap) = _addToDelta(from, to, swapIntervalMask, rate, performedSwaps, performedSwaps + details_.noOfSwaps
);
userPositions[positionId] = UserPosition({
owner: _msgSender(), from: from, to: to, swapIntervalMask: swapIntervalMask, rate: rate,
swapWhereLastUpdated: performedSwaps, startingSwap: startingSwap, finalSwap: finalSwap
});
}
function _modify(UserPosition memory userPosition_, uint256 positionId_, uint256 amount_, uint256 noOfSwaps_, bool isIncrease_)
internal returns (uint256 newRate,uint256 newStartingSwap,uint256 newFinalSwap)
{
uint256 performedSwaps = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask].performedSwaps;
uint256 remainingNoOfSwaps = _remainingNoOfSwaps(userPosition_.startingSwap, userPosition_.finalSwap, performedSwaps);
uint256 unswapped = remainingNoOfSwaps * userPosition_.rate;
uint256 tempUnswapped = unswapped;
if (isIncrease_) tempUnswapped += amount_;
else {
if (amount_ > unswapped) revert InvalidAmount();
tempUnswapped -= amount_;
}
if (tempUnswapped == unswapped && noOfSwaps_ == remainingNoOfSwaps) revert NoChanges();
if (
(tempUnswapped > 0 && (noOfSwaps_ == 0 || noOfSwaps_ > maxNoOfSwap)) ||
(tempUnswapped == 0 && noOfSwaps_ > 0)
) revert InvalidNoOfSwaps();
if (noOfSwaps_ > 0) newRate = _calculateRate(tempUnswapped, noOfSwaps_);
if (newRate > 0) {
newStartingSwap = performedSwaps;
newFinalSwap = performedSwaps + noOfSwaps_;
}
_swappedBeforeModified[positionId_] = _calculateSwapped(positionId_, userPosition_, performedSwaps);
_removeFromDelta(userPosition_, performedSwaps);
if(newRate > 0) {
(newStartingSwap, newFinalSwap) = _addToDelta(userPosition_.from, userPosition_.to, userPosition_.swapIntervalMask, newRate, newStartingSwap, newFinalSwap);
if((activeSwapIntervals[userPosition_.from][userPosition_.to] & userPosition_.swapIntervalMask == 0)) {
activeSwapIntervals[userPosition_.from][userPosition_.to] |= userPosition_.swapIntervalMask;
}
} else {
SwapData memory data = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask];
if (data.nextAmountToSwap == 0 && data.nextToNextAmountToSwap == 0)
activeSwapIntervals[userPosition_.from][userPosition_.to] &= ~userPosition_.swapIntervalMask;
}
userPositions[positionId_].rate = newRate;
userPositions[positionId_].swapWhereLastUpdated = performedSwaps;
userPositions[positionId_].startingSwap = newStartingSwap;
userPositions[positionId_].finalSwap = newFinalSwap;
}
function _terminate(UserPosition memory userPosition_, uint256 positionId_) private returns (uint256 unswapped, uint256 swapped){
uint256 performedSwaps = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask].performedSwaps;
swapped = _calculateSwapped(positionId_, userPosition_, performedSwaps);
unswapped = _calculateUnswapped(userPosition_, performedSwaps);
_removeFromDelta(userPosition_, performedSwaps);
SwapData memory data = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask];
if (data.nextAmountToSwap == 0 && data.nextToNextAmountToSwap == 0)
activeSwapIntervals[userPosition_.from][userPosition_.to] &= ~userPosition_.swapIntervalMask;
delete userPositions[positionId_];
_swappedBeforeModified[positionId_] = 0;
}
function _withdraw(UserPosition memory userPosition_, uint256 positionId_) internal returns (uint256 swapped) {
uint256 performedSwaps = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask].performedSwaps;
swapped = _calculateSwapped(positionId_, userPosition_, performedSwaps);
userPositions[positionId_].swapWhereLastUpdated = performedSwaps;
_swappedBeforeModified[positionId_] = 0;
}
function _addToDelta(address from_, address to_, bytes1 swapIntervalMask_, uint256 rate_, uint256 startingSwap_, uint256 finalSwap_) internal returns (uint256, uint256) {
(bool isPartOfNextSwap, uint256 timeUntilThreshold) = _getTimeUntilThreshold(from_, to_, swapIntervalMask_);
SwapData storage data = swapData[from_][to_][swapIntervalMask_];
if (isPartOfNextSwap && block.timestamp > timeUntilThreshold) {
startingSwap_ += 1;
finalSwap_ += 1;
data.nextToNextAmountToSwap += rate_;
} else {
data.nextAmountToSwap += rate_;
}
swapAmountDelta[from_][to_][swapIntervalMask_][finalSwap_ + 1] += rate_;
return (startingSwap_, finalSwap_);
}
function _removeFromDelta(UserPosition memory userPosition_, uint256 performedSwaps_) internal {
if (userPosition_.finalSwap > performedSwaps_) {
SwapData storage data = swapData[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask];
if (userPosition_.startingSwap > performedSwaps_) {
data.nextToNextAmountToSwap -= userPosition_.rate;
} else {
data.nextAmountToSwap -= userPosition_.rate;
}
swapAmountDelta[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask][
userPosition_.finalSwap + 1
] -= userPosition_.rate;
}
}
function _calculateSwapped( uint256 positionId_, UserPosition memory userPosition_, uint256 performedSwaps_) internal view returns (uint256) {
uint256 finalNo = Math.min(performedSwaps_, userPosition_.finalSwap);
if (userPosition_.swapWhereLastUpdated > finalNo) return 0;
else if (userPosition_.swapWhereLastUpdated == finalNo) return _swappedBeforeModified[positionId_];
uint256 startingNo= Math.max(userPosition_.swapWhereLastUpdated, userPosition_.startingSwap);
uint256 avgAccumulationPrice = accumRatio[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask][finalNo] -
accumRatio[userPosition_.from][userPosition_.to][userPosition_.swapIntervalMask][startingNo];
return ((avgAccumulationPrice * userPosition_.rate) / tokenMagnitude[userPosition_.from]) + _swappedBeforeModified[positionId_];
}
function _remainingNoOfSwaps(uint256 startingSwap_, uint256 finalSwap_, uint256 performedSwaps_) private pure returns (uint256 remainingNoOfSwap) {
uint256 noOfSwaps = finalSwap_ - startingSwap_;
uint256 totalSwapExecutedFromStart = _subtractIfPossible(performedSwaps_, startingSwap_);
remainingNoOfSwap = totalSwapExecutedFromStart > noOfSwaps ? 0 : noOfSwaps - totalSwapExecutedFromStart;
}
function _calculateUnswapped(UserPosition memory userPosition_, uint256 performedSwaps_) internal pure returns (uint256){
return _remainingNoOfSwaps(userPosition_.startingSwap, userPosition_.finalSwap, performedSwaps_) * userPosition_.rate;
}
function _calculateRate(uint256 amount_, uint256 noOfSwaps_) internal pure returns (uint256) {
return amount_ / noOfSwaps_;
}
function _assertTokensAreAllowed(address tokenA_, address tokenB_) internal view {
if (!allowedTokens[tokenA_] || !allowedTokens[tokenB_]) revert UnauthorizedTokens();
}
function _assertPositionExistsAndCallerIsOwner(UserPosition memory userPosition_) internal view {
if (userPosition_.swapIntervalMask == 0) revert InvalidPosition();
if (_msgSender() != userPosition_.owner) revert UnauthorizedCaller();
}
function _subtractIfPossible(uint256 a_, uint256 b_) internal pure returns (uint256) {
return a_ > b_ ? a_ - b_ : 0;
}
function _getTimeUntilThreshold(address from_, address to_, bytes1 interval_) private view returns (bool, uint256) {
bytes1 activeIntervals = activeSwapIntervals[from_][to_];
bytes1 mask = 0x01;
bytes1 intervalsInSwap;
uint256 nextSwapTimeEnd = type(uint256).max;
while (activeIntervals >= mask && mask > 0) {
if (activeIntervals & mask == mask || interval_ == mask) {
SwapData memory swapDataMem = swapData[from_][to_][mask];
uint32 swapInterval = Intervals.maskToInterval(mask);
uint256 currSwapTime = (block.timestamp / swapInterval) * swapInterval;
uint256 nextSwapTime = swapDataMem.lastSwappedAt == 0
? currSwapTime
: ((swapDataMem.lastSwappedAt / swapInterval) + 1) * swapInterval;
if(currSwapTime > nextSwapTime) nextSwapTime = currSwapTime;
uint256 tempNextSwapTimeEnd = nextSwapTime + swapInterval;
if (
(block.timestamp > nextSwapTime && block.timestamp < tempNextSwapTimeEnd) &&
(swapDataMem.nextAmountToSwap > 0 || mask == interval_)
) {
intervalsInSwap |= mask;
if (tempNextSwapTimeEnd < nextSwapTimeEnd) {
nextSwapTimeEnd = tempNextSwapTimeEnd;
}
}
}
mask <<= 1;
}
return (intervalsInSwap & interval_ == interval_, nextSwapTimeEnd - nextToNextTimeThreshold);
}
}
文件 6 的 26:DCASwapHandler.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./../interfaces/IDCASwapHandler.sol";
import "./DCAConfigHandler.sol";
import { SwapInfo, Pair, SwapDetails } from "./../common/Types.sol";
import { InvalidLength, NoAvailableSwap, InvalidSwapAmount, InvalidReturnAmount, SwapCallFailed, InvalidBlankSwap } from "./../common/Error.sol";
abstract contract DCASwapHandler is DCAConfigHandler, IDCASwapHandler {
using SafeERC20 for IERC20;
function secondsUntilNextSwap(Pair[] calldata pairs_) external view returns (uint256[] memory) {
uint256[] memory secondsArr = new uint256[](pairs_.length);
for (uint256 i; i < pairs_.length; i++) secondsArr[i] = _secondsUntilNextSwap(pairs_[i].from, pairs_[i].to);
return secondsArr;
}
function getNextSwapInfo(Pair[] calldata pairs_) external view returns (SwapInfo[] memory) {
SwapInfo[] memory swapInformation = new SwapInfo[](pairs_.length);
for (uint256 i; i < pairs_.length; ++i) {
Pair memory pair = pairs_[i];
(uint256 amountToSwap, bytes1 intervalsInSwap, uint256 swapperReward, uint256 platformFee) = _getTotalAmountsToSwap(pair.from, pair.to);
swapInformation[i] = SwapInfo(pair.from, pair.to, amountToSwap, 0, swapperReward, platformFee, intervalsInSwap);
}
return swapInformation;
}
function swap(SwapDetails[] calldata data_, address rewardRecipient_) external onlySwapper whenNotPaused {
if (data_.length == 0) revert InvalidLength();
SwapInfo[] memory swapInfo = new SwapInfo[](data_.length);
for (uint256 i; i < data_.length; ++i) {
SwapDetails memory data = data_[i];
(uint256 amountToSwap, bytes1 intervalsInSwap, uint256 swapperReward, uint256 platformFee) = _getTotalAmountsToSwap(data.from, data.to);
if (amountToSwap == 0 || intervalsInSwap == 0) revert NoAvailableSwap();
if (data.amount != amountToSwap) revert InvalidSwapAmount();
uint256 returnAmount = _executeSwap(data);
if (returnAmount < data.minReturnAmount) revert InvalidReturnAmount();
_registerSwap(data.from, data.to, amountToSwap, returnAmount, intervalsInSwap);
swapInfo[i] = SwapInfo(data.from, data.to, amountToSwap, returnAmount, swapperReward, platformFee, intervalsInSwap);
if (platformFee > 0) IERC20(data.from).safeTransfer(feeVault, platformFee);
if (swapperReward > 0) IERC20(data.from).safeTransfer(rewardRecipient_, swapperReward);
}
emit Swapped(_msgSender(), rewardRecipient_, swapInfo);
}
function blankSwap(address from_, address to_, bytes1 maskedInterval_) external onlySwapper whenNotPaused {
SwapData storage data = swapData[from_][to_][maskedInterval_];
if (data.nextAmountToSwap > 0 || data.nextToNextAmountToSwap == 0) revert InvalidBlankSwap();
accumRatio[from_][to_][maskedInterval_][data.performedSwaps + 1] = accumRatio[from_][to_][maskedInterval_][data.performedSwaps];
data.nextAmountToSwap += data.nextToNextAmountToSwap;
data.nextToNextAmountToSwap = 0;
data.performedSwaps += 1;
emit BlankSwapped(_msgSender(), from_, to_, maskedInterval_);
}
function _executeSwap(SwapDetails memory data_) private returns (uint256 returnAmount) {
uint256 balanceBefore = IERC20(data_.to).balanceOf(address(this));
IERC20(data_.from).approve(data_.tokenProxy, data_.amount);
(bool success, ) = data_.executor.call(data_.swapCallData);
if (!success) revert SwapCallFailed();
returnAmount = IERC20(data_.to).balanceOf(address(this)) - balanceBefore;
}
function _getSwapAmountAndFee(uint256 amount_, uint256 fee_) private pure returns (uint256, uint256) {
uint256 feeAmount = (amount_ * fee_) / BPS_DENOMINATOR;
return (amount_ - feeAmount, feeAmount);
}
function _getTotalAmountsToSwap(address from_, address to_) private view
returns (uint256 amountToSwap, bytes1 intervalsInSwap, uint256 swapperReward, uint256 platformFee)
{
bytes1 activeIntervalsMem = activeSwapIntervals[from_][to_];
bytes1 mask = 0x01;
while (activeIntervalsMem >= mask && mask > 0) {
if (activeIntervalsMem & mask != 0) {
SwapData memory swapDataMem = swapData[from_][to_][mask];
uint32 swapInterval = Intervals.maskToInterval(mask);
if (((swapDataMem.lastSwappedAt / swapInterval) + 1) * swapInterval > block.timestamp) break;
if (swapDataMem.nextAmountToSwap > 0) {
intervalsInSwap |= mask;
(uint256 amountToSwapForInterval, uint256 feeAmount) = _getSwapAmountAndFee(swapDataMem.nextAmountToSwap, _swapFeeMap[mask]);
(uint256 reward, uint256 fee) = _getSwapAmountAndFee(feeAmount, platformFeeRatio);
amountToSwap += amountToSwapForInterval;
swapperReward += reward;
platformFee += fee;
}
}
mask <<= 1;
}
if (amountToSwap == 0) intervalsInSwap = 0;
}
function _registerSwap(address tokenA_, address tokenB_,uint256 amountToSwap_, uint256 totalReturnAmount_, bytes1 intervalsInSwap_) private {
bytes1 mask = 0x01;
bytes1 activeIntervals = activeSwapIntervals[tokenA_][tokenB_];
while (activeIntervals >= mask && mask != 0) {
SwapData memory swapDataMem = swapData[tokenA_][tokenB_][mask];
if (intervalsInSwap_ & mask != 0 && swapDataMem.nextAmountToSwap > 0) {
(uint256 amountToSwapForIntervalWithoutFee, ) = _getSwapAmountAndFee(swapDataMem.nextAmountToSwap, _swapFeeMap[mask]);
uint256 returnAmountForInterval = totalReturnAmount_ * amountToSwapForIntervalWithoutFee * tokenMagnitude[tokenA_] / amountToSwap_;
uint256 swapPrice = returnAmountForInterval / swapDataMem.nextAmountToSwap;
accumRatio[tokenA_][tokenB_][mask][swapDataMem.performedSwaps + 1] = accumRatio[tokenA_][tokenB_][mask][swapDataMem.performedSwaps] + swapPrice;
swapData[tokenA_][tokenB_][mask] = SwapData(
swapDataMem.performedSwaps + 1,
swapDataMem.nextAmountToSwap +
swapDataMem.nextToNextAmountToSwap -
swapAmountDelta[tokenA_][tokenB_][mask][swapDataMem.performedSwaps + 2],
0,
block.timestamp
);
if (swapData[tokenA_][tokenB_][mask].nextAmountToSwap == 0) activeSwapIntervals[tokenA_][tokenB_] &= ~mask;
delete swapAmountDelta[tokenA_][tokenB_][mask][swapDataMem.performedSwaps + 2];
} else if (swapDataMem.nextAmountToSwap == 0 && swapDataMem.nextToNextAmountToSwap > 0) {
SwapData storage data = swapData[tokenA_][tokenB_][mask];
accumRatio[tokenA_][tokenB_][mask][swapDataMem.performedSwaps + 1] = accumRatio[tokenA_][tokenB_][mask][swapDataMem.performedSwaps];
data.nextAmountToSwap = swapDataMem.nextAmountToSwap + swapDataMem.nextToNextAmountToSwap;
data.nextToNextAmountToSwap = 0;
data.performedSwaps += 1;
}
mask <<= 1;
}
}
function _secondsUntilNextSwap(address from_, address to_) private view returns (uint256) {
bytes1 activeIntervals = activeSwapIntervals[from_][to_];
bytes1 mask = 0x01;
uint256 smallerIntervalBlocking;
while (activeIntervals >= mask && mask > 0) {
if (activeIntervals & mask == mask) {
SwapData memory swapDataMem = swapData[from_][to_][mask];
uint32 swapInterval = Intervals.maskToInterval(mask);
uint256 nextAvailable = ((swapDataMem.lastSwappedAt / swapInterval) + 1) * swapInterval;
if (swapDataMem.nextAmountToSwap > 0) {
if (nextAvailable <= block.timestamp) return smallerIntervalBlocking;
else return nextAvailable - block.timestamp;
} else if (nextAvailable > block.timestamp) {
smallerIntervalBlocking = smallerIntervalBlocking == 0 ? nextAvailable - block.timestamp : smallerIntervalBlocking;
}
}
mask <<= 1;
}
return type(uint256).max;
}
}
文件 7 的 26:DZapDCA.sol
pragma solidity 0.8.16;
import "./../interfaces/IDZapDCA.sol";
import "./DCAParameters.sol";
import "./DCAConfigHandler.sol";
import "./DCAPositionHandler.sol";
import "./DCASwapHandler.sol";
import { ZeroAddress } from "./../common/Error.sol";
contract DZapDCA is DCAParameters, DCAConfigHandler, DCASwapHandler, DCAPositionHandler, IDZapDCA {
using SafeERC20 for IERC20;
constructor(address governor_, address wNative_, address feeVault_, address permit2_, uint256 maxNoOfSwap_) DCAConfigHandler(governor_, wNative_, feeVault_, maxNoOfSwap_) DCAPositionHandler(permit2_) {}
function batchCall(bytes[] calldata data_) external returns (bytes[] memory results) {
results = new bytes[](data_.length);
for (uint256 i; i < data_.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data_[i]);
}
return results;
}
receive() external payable {}
}
文件 8 的 26:Error.sol
pragma solidity 0.8.16;
error InvalidInterval();
error InvalidMask();
error UnauthorizedCaller();
error ZeroAddress();
error HighPlatformFeeRatio();
error HighFee();
error InvalidToken();
error InvalidNoOfSwaps();
error InvalidPermitSender();
error InvalidPermitData();
error InvalidPermit();
error InvalidAmountTransferred();
error InvalidLength();
error NoAvailableSwap();
error InvalidSwapAmount();
error InvalidReturnAmount();
error SwapCallFailed();
error InvalidBlankSwap();
error InvalidPosition();
error InvalidNativeAmount();
error NotWNative();
error NativeTransferFailed();
error UnauthorizedTokens();
error InvalidTokens();
error InvalidAmount();
error UnauthorizedInterval();
error InvalidRate();
error NoChanges();
error ZeroSwappedTokens();
文件 9 的 26:Governable.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/utils/Context.sol";
import { UnauthorizedCaller, ZeroAddress } from "../common/Error.sol";
abstract contract Governable is Context {
address private _governance;
event GovernanceChanged(address indexed formerGov, address indexed newGov);
modifier onlyGovernance() {
if (governance() != _msgSender()) revert UnauthorizedCaller();
_;
}
constructor(address governance_) {
if (governance_ == address(0)) revert ZeroAddress();
_governance = governance_;
emit GovernanceChanged(address(0), governance_);
}
function governance() public view virtual returns (address) {
return _governance;
}
function changeGovernance(address newGov) external virtual onlyGovernance {
if (newGov == address(0)) revert ZeroAddress();
emit GovernanceChanged(_governance, newGov);
_governance = newGov;
}
}
文件 10 的 26:IDAIPermit.sol
pragma solidity 0.8.16;
interface IDAIPermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 11 的 26:IDCAConfigHandler.sol
pragma solidity 0.8.16;
import "./IWNative.sol";
interface IDCAConfigHandler {
event AdminAdded(address[] accounts);
event AdminRemoved(address[] accounts);
event SwapExecutorAdded(address[] accounts);
event SwapExecutorRemoved(address[] accounts);
event SwapLimitUpdated(uint256 noOfSwaps);
event SwapThresholdUpdated(uint256 threshold);
event TokensAdded(address[] tokens);
event TokensRemoved(address[] tokens);
event SwapIntervalsAdded(uint32[] swapIntervals);
event SwapIntervalsRemoved(uint32[] swapIntervals);
event FeeVaultUpdated(address feeVault);
event SwapFeeUpdated(uint32[] intervals, uint256[] swapFee);
event PlatformFeeRatioUpdated(uint256 platformFeeRatio);
function allowedSwapIntervals() external view returns (bytes1);
function allowedTokens(address token_) external view returns (bool);
function tokenMagnitude(address token_) external view returns (uint256);
function admins(address account_) external view returns (bool);
function swapExecutors(address account_) external view returns (bool);
function wNative() external view returns (IWNative);
function feeVault() external view returns (address);
function NATIVE_TOKEN() external view returns (address);
function getSwapFee(uint32 interval_) external view returns (uint256);
function platformFeeRatio() external view returns (uint256);
function MAX_FEE() external view returns (uint256);
function MAX_PLATFORM_FEE_RATIO() external view returns (uint256);
function BPS_DENOMINATOR() external view returns (uint256);
function pause() external;
function unpause() external;
function addAdmins(address[] calldata accounts_) external;
function removeAdmins(address[] calldata accounts_) external;
function addSwapExecutors(address[] calldata executor_) external;
function removeSwapExecutors(address[] calldata executor_) external;
function addAllowedTokens(address[] calldata tokens_) external;
function removeAllowedTokens(address[] calldata tokens_) external;
function addSwapIntervalsToAllowedList(uint32[] calldata swapIntervals_) external;
function removeSwapIntervalsFromAllowedList(uint32[] calldata swapIntervals_) external;
function setFeeVault(address newVault_) external;
function setSwapFee(uint32[] calldata intervals_, uint256[] calldata swapFee_) external;
function setPlatformFeeRatio(uint256 platformFeeRatio_) external;
}
文件 12 的 26:IDCAParameters.sol
pragma solidity 0.8.16;
interface IDCAParameters {
function activeSwapIntervals(address from_, address to_) external view returns (bytes1);
function swapData(address from_, address to_, bytes1 swapInterval_) external view
returns (uint256 performedSwaps, uint256 nextAmountToSwap, uint256 nextToNextSwap, uint256 lastSwappedAt);
function swapAmountDelta(address from_, address to_, bytes1 swapInterval_, uint256 swapNo_) external view returns (uint256);
function accumRatio(address from_, address to_, bytes1 swapInterval_, uint256 swapNo_) external view returns (uint256);
}
文件 13 的 26:IDCAPositionHandler.sol
pragma solidity 0.8.16;
import { PositionInfo, CreatePositionDetails } from "./../common/Types.sol";
interface IDCAPositionHandler {
event Created(address indexed user, uint256 positionId, bool isNative);
event CreatedBatched(address indexed user, uint256 finalIndex, uint256 noOfPositions, bool[] isNative);
event Modified(address indexed user, uint256 positionId, uint256 rate, uint256 startingSwap, uint256 finalSwap, bool isNative);
event Terminated(address indexed user, address indexed recipient, uint256 positionId, uint256 unswapped, uint256 swapped, bool isNative);
event Withdrawn(address indexed user, address indexed recipient, uint256 positionId, uint256 swapped, bool isNative);
event PositionOwnerUpdated(address indexed oldOwner, address indexed newOwner, uint256 positionId);
function userPositions(uint256 positionId_) external view returns (address owner, address from, address to, bytes1 swapIntervalMask, uint256 rate, uint256 swapWhereLastUpdated, uint256 startingSwap, uint256 finalSwap);
function totalCreatedPositions() external view returns (uint256);
function getPositionDetails(uint256 positionId_) external view returns (PositionInfo memory positionInfo);
function createPosition(CreatePositionDetails calldata details_) external payable;
function createBatchPositions(CreatePositionDetails[] calldata details_) external payable;
function modifyPosition(uint256 positionId_, uint256 amount_, uint256 noOfSwaps_, bool isIncrease_, bool isNative_, bytes calldata permit_) external payable;
function terminatePosition(uint256 positionId_, address recipient_, bool isNative_) external;
function withdrawPosition(uint256 positionId_, address recipient_, bool isNative_) external;
function transferPositionOwnership(uint256 positionId_, address newOwner_) external;
}
文件 14 的 26:IDCASwapHandler.sol
pragma solidity 0.8.16;
import { SwapInfo, SwapDetails, Pair } from "./../common/Types.sol";
interface IDCASwapHandler {
event Swapped(address indexed sender, address indexed rewardRecipient, SwapInfo[] swapInformation);
event BlankSwapped(address indexed sender, address from, address to, bytes1 interval);
function secondsUntilNextSwap(Pair[] calldata pairs_) external view returns (uint256[] memory);
function getNextSwapInfo(Pair[] calldata pairs_) external view returns (SwapInfo[] memory);
function swap(SwapDetails[] calldata data_, address rewardRecipient_) external;
}
文件 15 的 26:IDZapDCA.sol
pragma solidity 0.8.16;
import "./IDCAConfigHandler.sol";
import "./IDCAPositionHandler.sol";
import "./IDCASwapHandler.sol";
import "./IDCAParameters.sol";
interface IDZapDCA is IDCAParameters, IDCAConfigHandler, IDCAPositionHandler, IDCASwapHandler {
event TokensRescued(address indexed to, address indexed token, uint256 amount);
function batchCall(bytes[] calldata data_) external returns (bytes[] memory results);
}
文件 16 的 26:IERC20.sol
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
文件 17 的 26:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../token/ERC20/extensions/IERC20Metadata.sol";
文件 18 的 26:IPermit2.sol
pragma solidity 0.8.16;
interface IPermit2 {
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
function permit(
address owner,
PermitSingle memory permitSingle,
bytes calldata signature
) external;
function transferFrom(
address from,
address to,
uint160 amount,
address token
) external;
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
}
文件 19 的 26:IWNative.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
interface IWNative is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 20 的 26:Intervals.sol
pragma solidity 0.8.16;
import { InvalidInterval, InvalidMask } from "./../common/Error.sol";
library Intervals {
function intervalToMask(uint32 swapInterval_) internal pure returns (bytes1) {
if (swapInterval_ == 1 hours) return 0x01;
if (swapInterval_ == 4 hours) return 0x02;
if (swapInterval_ == 12 hours) return 0x04;
if (swapInterval_ == 1 days) return 0x08;
if (swapInterval_ == 3 days) return 0x10;
if (swapInterval_ == 1 weeks) return 0x20;
if (swapInterval_ == 2 weeks) return 0x40;
if (swapInterval_ == 30 days) return 0x80;
revert InvalidInterval();
}
function maskToInterval(bytes1 mask_) internal pure returns (uint32) {
if (mask_ == 0x01) return 1 hours;
if (mask_ == 0x02) return 4 hours;
if (mask_ == 0x04) return 12 hours;
if (mask_ == 0x08) return 1 days;
if (mask_ == 0x10) return 3 days;
if (mask_ == 0x20) return 1 weeks;
if (mask_ == 0x40) return 2 weeks;
if (mask_ == 0x80) return 30 days;
revert InvalidMask();
}
function intervalsInByte(bytes1 byte_) internal pure returns (uint32[] memory intervals) {
intervals = new uint32[](8);
uint8 _index;
bytes1 mask_ = 0x01;
while (byte_ >= mask_ && mask_ > 0) {
if (byte_ & mask_ != 0) intervals[_index++] = maskToInterval(mask_);
mask_ <<= 1;
}
}
}
文件 21 的 26: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);
}
}
}
文件 22 的 26:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 23 的 26:Permitable.sol
pragma solidity 0.8.16;
import { ZeroAddress, InvalidPermit, InvalidPermitData, InvalidPermitSender } from "./../common/Error.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "./../interfaces/IDAIPermit.sol";
import "./../interfaces/IPermit2.sol";
abstract contract Permitable {
address public immutable PERMIT2;
constructor(address permit2_) {
if (permit2_ == address(0)) revert ZeroAddress();
PERMIT2 = permit2_;
}
function _permit2Approve(address token_, bytes memory data_) internal {
if(data_.length > 0) {
(uint160 allowanceAmount, uint48 nonce, uint48 expiration, uint256 sigDeadline, bytes memory signature) = abi.decode(data_, (uint160, uint48, uint48, uint256, bytes));
IPermit2(PERMIT2).permit(
msg.sender,
IPermit2.PermitSingle(
IPermit2.PermitDetails(
token_,
allowanceAmount,
expiration,
nonce
),
address(this),
sigDeadline
),
signature
);
}
}
function _permit2TransferFrom(address token_, bytes memory data_, uint256 amount_) internal {
(uint256 nonce, uint256 deadline, bytes memory signature) = abi.decode(data_, (uint256, uint256, bytes));
IPermit2(PERMIT2).permitTransferFrom(
IPermit2.PermitTransferFrom(
IPermit2.TokenPermissions(token_, amount_),
nonce,
deadline
),
IPermit2.SignatureTransferDetails(address(this), amount_),
msg.sender,
signature
);
}
function _permit(address token_, bytes memory data_) internal {
if (data_.length > 0) {
bool success;
if (data_.length == 32 * 7) {
(success, ) = token_.call(abi.encodePacked(IERC20Permit.permit.selector, data_));
} else if (data_.length == 32 * 8) {
(success, ) = token_.call(abi.encodePacked(IDAIPermit.permit.selector, data_));
} else {
revert InvalidPermitData();
}
if (!success) revert InvalidPermit();
}
}
}
文件 24 的 26: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");
}
}
}
文件 25 的 26:Types.sol
pragma solidity 0.8.16;
struct UserPosition {
address owner;
address from;
address to;
bytes1 swapIntervalMask;
uint256 rate;
uint256 swapWhereLastUpdated;
uint256 startingSwap;
uint256 finalSwap;
}
struct PositionInfo {
address owner;
address from;
address to;
uint32 swapInterval;
uint256 rate;
uint256 swapsExecuted;
uint256 swapsLeft;
uint256 swapped;
uint256 unswapped;
}
struct CreatePositionDetails {
address from;
address to;
uint32 swapInterval;
uint256 amount;
uint256 noOfSwaps;
bytes permit;
}
struct SwapData {
uint256 performedSwaps;
uint256 nextAmountToSwap;
uint256 nextToNextAmountToSwap;
uint256 lastSwappedAt;
}
struct SwapInfo {
address from;
address to;
uint256 swappedAmount;
uint256 receivedAmount;
uint256 reward;
uint256 fee;
bytes1 intervalsInSwap;
}
struct SwapDetails {
address executor;
address tokenProxy;
address from;
address to;
uint256 amount;
uint256 minReturnAmount;
bytes swapCallData;
}
struct Pair {
address from;
address to;
}
enum PermitType {
PERMIT2_APPROVE,
PERMIT2_TRANSFER_FROM,
PERMIT
}
文件 26 的 26: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/core/DZapDCA.sol": "DZapDCA"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"governor_","type":"address"},{"internalType":"address","name":"wNative_","type":"address"},{"internalType":"address","name":"feeVault_","type":"address"},{"internalType":"address","name":"permit2_","type":"address"},{"internalType":"uint256","name":"maxNoOfSwap_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"HighFee","type":"error"},{"inputs":[],"name":"HighPlatformFeeRatio","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidBlankSwap","type":"error"},{"inputs":[],"name":"InvalidInterval","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidMask","type":"error"},{"inputs":[],"name":"InvalidNativeAmount","type":"error"},{"inputs":[],"name":"InvalidNoOfSwaps","type":"error"},{"inputs":[],"name":"InvalidPermit","type":"error"},{"inputs":[],"name":"InvalidPermitData","type":"error"},{"inputs":[],"name":"InvalidPosition","type":"error"},{"inputs":[],"name":"InvalidRate","type":"error"},{"inputs":[],"name":"InvalidReturnAmount","type":"error"},{"inputs":[],"name":"InvalidSwapAmount","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NoAvailableSwap","type":"error"},{"inputs":[],"name":"NoChanges","type":"error"},{"inputs":[],"name":"NotWNative","type":"error"},{"inputs":[],"name":"SwapCallFailed","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"UnauthorizedTokens","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroSwappedTokens","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"AdminRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bytes1","name":"interval","type":"bytes1"}],"name":"BlankSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isNative","type":"bool"}],"name":"Created","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"noOfPositions","type":"uint256"},{"indexed":false,"internalType":"bool[]","name":"isNative","type":"bool[]"}],"name":"CreatedBatched","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeVault","type":"address"}],"name":"FeeVaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"formerGov","type":"address"},{"indexed":true,"internalType":"address","name":"newGov","type":"address"}],"name":"GovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingSwap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalSwap","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isNative","type":"bool"}],"name":"Modified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"platformFeeRatio","type":"uint256"}],"name":"PlatformFeeRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"PositionOwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"SwapExecutorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"SwapExecutorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32[]","name":"intervals","type":"uint32[]"},{"indexed":false,"internalType":"uint256[]","name":"swapFee","type":"uint256[]"}],"name":"SwapFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32[]","name":"swapIntervals","type":"uint32[]"}],"name":"SwapIntervalsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32[]","name":"swapIntervals","type":"uint32[]"}],"name":"SwapIntervalsRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"noOfSwaps","type":"uint256"}],"name":"SwapLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"SwapThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"rewardRecipient","type":"address"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"swappedAmount","type":"uint256"},{"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes1","name":"intervalsInSwap","type":"bytes1"}],"indexed":false,"internalType":"struct SwapInfo[]","name":"swapInformation","type":"tuple[]"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unswapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapped","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isNative","type":"bool"}],"name":"Terminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"TokensAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"TokensRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensRescued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapped","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isNative","type":"bool"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PLATFORM_FEE_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes1","name":"","type":"bytes1"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accumRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"activeSwapIntervals","outputs":[{"internalType":"bytes1","name":"","type":"bytes1"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts_","type":"address[]"}],"name":"addAdmins","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"addAllowedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"executor_","type":"address[]"}],"name":"addSwapExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"swapIntervals_","type":"uint32[]"}],"name":"addSwapIntervalsToAllowedList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowedSwapIntervals","outputs":[{"internalType":"bytes1","name":"","type":"bytes1"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data_","type":"bytes[]"}],"name":"batchCall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"bytes1","name":"maskedInterval_","type":"bytes1"}],"name":"blankSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGov","type":"address"}],"name":"changeGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"swapInterval","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"noOfSwaps","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct CreatePositionDetails[]","name":"details_","type":"tuple[]"}],"name":"createBatchPositions","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"swapInterval","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"noOfSwaps","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct CreatePositionDetails","name":"details_","type":"tuple"}],"name":"createPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"internalType":"struct Pair[]","name":"pairs_","type":"tuple[]"}],"name":"getNextSwapInfo","outputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"swappedAmount","type":"uint256"},{"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes1","name":"intervalsInSwap","type":"bytes1"}],"internalType":"struct SwapInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"}],"name":"getPositionDetails","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"swapInterval","type":"uint32"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"swapsExecuted","type":"uint256"},{"internalType":"uint256","name":"swapsLeft","type":"uint256"},{"internalType":"uint256","name":"swapped","type":"uint256"},{"internalType":"uint256","name":"unswapped","type":"uint256"}],"internalType":"struct PositionInfo","name":"positionInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"interval_","type":"uint32"}],"name":"getSwapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxNoOfSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"noOfSwaps_","type":"uint256"},{"internalType":"bool","name":"isIncrease_","type":"bool"},{"internalType":"bool","name":"isNative_","type":"bool"},{"internalType":"bytes","name":"permit_","type":"bytes"}],"name":"modifyPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nextToNextTimeThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts_","type":"address[]"}],"name":"removeAdmins","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"removeAllowedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"executor_","type":"address[]"}],"name":"removeSwapExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"swapIntervals_","type":"uint32[]"}],"name":"removeSwapIntervalsFromAllowedList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"internalType":"struct Pair[]","name":"pairs_","type":"tuple[]"}],"name":"secondsUntilNextSwap","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newVault_","type":"address"}],"name":"setFeeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"platformFeeRatio_","type":"uint256"}],"name":"setPlatformFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"intervals_","type":"uint32[]"},{"internalType":"uint256[]","name":"swapFee_","type":"uint256[]"}],"name":"setSwapFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"executor","type":"address"},{"internalType":"address","name":"tokenProxy","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"bytes","name":"swapCallData","type":"bytes"}],"internalType":"struct SwapDetails[]","name":"data_","type":"tuple[]"},{"internalType":"address","name":"rewardRecipient_","type":"address"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes1","name":"","type":"bytes1"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"swapAmountDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes1","name":"","type":"bytes1"}],"name":"swapData","outputs":[{"internalType":"uint256","name":"performedSwaps","type":"uint256"},{"internalType":"uint256","name":"nextAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"nextToNextAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"lastSwappedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swapExecutors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"bool","name":"isNative_","type":"bool"}],"name":"terminatePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenMagnitude","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCreatedPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"},{"internalType":"address","name":"newOwner_","type":"address"}],"name":"transferPositionOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxNoOfSwap_","type":"uint256"}],"name":"updateMaxSwapLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nextToNextTimeThreshold_","type":"uint256"}],"name":"updateSwapTimeThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPositions","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes1","name":"swapIntervalMask","type":"bytes1"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"swapWhereLastUpdated","type":"uint256"},{"internalType":"uint256","name":"startingSwap","type":"uint256"},{"internalType":"uint256","name":"finalSwap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wNative","outputs":[{"internalType":"contract IWNative","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"bool","name":"isNative_","type":"bool"}],"name":"withdrawPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]