Source Code
Latest 12 from a total of 12 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Multicall | 23461367 | 151 days ago | IN | 0 ETH | 0.00001141 | ||||
| Multicall | 23239477 | 182 days ago | IN | 0 ETH | 0.00003252 | ||||
| Multicall | 23017513 | 213 days ago | IN | 0 ETH | 0.00002658 | ||||
| Multicall | 22802805 | 243 days ago | IN | 0 ETH | 0.00030402 | ||||
| Multicall | 22581123 | 274 days ago | IN | 0 ETH | 0.00194776 | ||||
| Multicall | 21944713 | 363 days ago | IN | 0 ETH | 0.00085372 | ||||
| Multicall | 21722893 | 394 days ago | IN | 0 ETH | 0.00157562 | ||||
| Multicall | 21500827 | 425 days ago | IN | 0 ETH | 0.00449868 | ||||
| Multicall | 21063991 | 486 days ago | IN | 0 ETH | 0.00346316 | ||||
| Multicall | 20849001 | 516 days ago | IN | 0 ETH | 0.0095576 | ||||
| Multicall | 20626947 | 547 days ago | IN | 0 ETH | 0.00102453 | ||||
| Multicall | 20404908 | 578 days ago | IN | 0 ETH | 0.00291919 |
Latest 17 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 22581123 | 274 days ago | 0.00085532 ETH | ||||
| Transfer | 22581123 | 274 days ago | 0.00085532 ETH | ||||
| Transfer | 21944713 | 363 days ago | 0.00158228 ETH | ||||
| Transfer | 21944713 | 363 days ago | 0.00158228 ETH | ||||
| Transfer | 21722893 | 394 days ago | 0.00448998 ETH | ||||
| Transfer | 21722893 | 394 days ago | 0.00448998 ETH | ||||
| Transfer | 21500827 | 425 days ago | 0.00347377 ETH | ||||
| Transfer | 21500827 | 425 days ago | 0.00347377 ETH | ||||
| Transfer | 21063991 | 486 days ago | 0.00954601 ETH | ||||
| Transfer | 21063991 | 486 days ago | 0.00954601 ETH | ||||
| Transfer | 20849001 | 516 days ago | 0.00160627 ETH | ||||
| Transfer | 20849001 | 516 days ago | 0.00160627 ETH | ||||
| Transfer | 20626947 | 547 days ago | 0.00293099 ETH | ||||
| Transfer | 20626947 | 547 days ago | 0.00293099 ETH | ||||
| Transfer | 20404908 | 578 days ago | 0.02275871 ETH | ||||
| Transfer | 20404908 | 578 days ago | 0.02275871 ETH | ||||
| 0x60806040 | 19484670 | 707 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DCAFeeManager
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 9999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.22;
import '@openzeppelin/contracts/access/AccessControl.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/Multicall.sol';
import '@mean-finance/call-simulation/contracts/SimulationAdapter.sol';
import '../interfaces/IDCAFeeManager.sol';
import '../utils/SwapAdapter.sol';
contract DCAFeeManager is SwapAdapter, AccessControl, Multicall, IDCAFeeManager, SimulationAdapter {
bytes32 public constant SUPER_ADMIN_ROLE = keccak256('SUPER_ADMIN_ROLE');
bytes32 public constant ADMIN_ROLE = keccak256('ADMIN_ROLE');
using SafeERC20 for IERC20;
using Address for address payable;
constructor(address _superAdmin, address[] memory _initialAdmins) SwapAdapter() {
if (_superAdmin == address(0)) revert ZeroAddress();
// We are setting the super admin role as its own admin so we can transfer it
_setRoleAdmin(SUPER_ADMIN_ROLE, SUPER_ADMIN_ROLE);
_setRoleAdmin(ADMIN_ROLE, SUPER_ADMIN_ROLE);
_grantRole(SUPER_ADMIN_ROLE, _superAdmin);
for (uint256 i; i < _initialAdmins.length; i++) {
_grantRole(ADMIN_ROLE, _initialAdmins[i]);
}
}
receive() external payable {}
/// @inheritdoc IDCAFeeManager
function runSwapsAndTransferMany(RunSwapsAndTransferManyParams calldata _parameters) public payable onlyRole(ADMIN_ROLE) {
// Approve whatever is necessary
for (uint256 i = 0; i < _parameters.allowanceTargets.length; ++i) {
AllowanceTarget memory _allowance = _parameters.allowanceTargets[i];
_maxApproveSpender(_allowance.token, _allowance.allowanceTarget);
}
// Execute swaps
for (uint256 i = 0; i < _parameters.swaps.length; ++i) {
SwapContext memory _context = _parameters.swapContext[i];
_executeSwap(_parameters.swappers[_context.swapperIndex], _parameters.swaps[i], _context.value);
}
// Transfer out whatever was left in the contract
for (uint256 i = 0; i < _parameters.transferOutBalance.length; ++i) {
TransferOutBalance memory _transferOutBalance = _parameters.transferOutBalance[i];
_sendBalanceOnContractToRecipient(_transferOutBalance.token, _transferOutBalance.recipient);
}
}
/// @inheritdoc IDCAFeeManager
function withdrawFromPlatformBalance(
IDCAHub _hub,
IDCAHub.AmountOfToken[] calldata _amountToWithdraw,
address _recipient
) external onlyRole(ADMIN_ROLE) {
_hub.withdrawFromPlatformBalance(_amountToWithdraw, _recipient);
}
/// @inheritdoc IDCAFeeManager
function withdrawFromBalance(IDCAHub.AmountOfToken[] calldata _amountToWithdraw, address _recipient) external onlyRole(ADMIN_ROLE) {
for (uint256 i = 0; i < _amountToWithdraw.length; ++i) {
IDCAHub.AmountOfToken memory _amountOfToken = _amountToWithdraw[i];
if (_amountOfToken.amount == type(uint256).max) {
_sendBalanceOnContractToRecipient(_amountOfToken.token, _recipient);
} else {
_sendToRecipient(_amountOfToken.token, _amountOfToken.amount, _recipient);
}
}
}
/// @inheritdoc IDCAFeeManager
function revokeAllowances(RevokeAction[] calldata _revokeActions) external onlyRole(ADMIN_ROLE) {
_revokeAllowances(_revokeActions);
}
/// @inheritdoc IDCAFeeManager
function availableBalances(IDCAHub _hub, address[] calldata _tokens) external view returns (AvailableBalance[] memory _balances) {
_balances = new AvailableBalance[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
address _token = _tokens[i];
_balances[i] = AvailableBalance({
token: _token,
platformBalance: _hub.platformBalance(_token),
feeManagerBalance: IERC20(_token).balanceOf(address(this))
});
}
}
function supportsInterface(bytes4 _interfaceId) public view virtual override(AccessControl, SimulationAdapter) returns (bool) {
return SimulationAdapter.supportsInterface(_interfaceId) || AccessControl.supportsInterface(_interfaceId);
}
function getPositionKey(address _from, address _to) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_from, _to));
}
/// @dev This version does not check the swapper registry at all
function _maxApproveSpender(IERC20 _token, address _spender) internal {
_token.forceApprove(_spender, type(uint256).max);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
import { IERC165 } from "./interfaces/external/IERC165.sol";
import { ISimulationAdapter } from "./interfaces/ISimulationAdapter.sol";
/**
* @title Simulation Adapter
* @author Sam Bugs
* @notice This contracts adds off-chain simulation capabilities to existing contracts. It works similarly to a
* multicall, but the state is not modified in each subcall.
*/
abstract contract SimulationAdapter is IERC165, ISimulationAdapter {
/// @notice An error that contains a simulation's result
error SimulatedCall(SimulationResult result);
/// @inheritdoc IERC165
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return _interfaceId == type(ISimulationAdapter).interfaceId || _interfaceId == type(IERC165).interfaceId;
}
/// @inheritdoc ISimulationAdapter
function simulate(bytes[] calldata _calls) external payable returns (SimulationResult[] memory _results) {
_results = new SimulationResult[](_calls.length);
for (uint256 i = 0; i < _calls.length; i++) {
_results[i] = _simulate(_calls[i]);
}
return _results;
}
/**
* @notice Executes a simulation and returns the result
* @param _call The call to simulate
* @return _simulationResult The simulation's result
*/
function _simulate(bytes calldata _call) internal returns (SimulationResult memory _simulationResult) {
(bool _success, bytes memory _result) =
// solhint-disable-next-line avoid-low-level-calls
address(this).delegatecall(abi.encodeWithSelector(this.simulateAndRevert.selector, _call));
require(!_success, "WTF? Should have failed!");
// Move pointer to ignore selector
// solhint-disable-next-line no-inline-assembly
assembly {
_result := add(_result, 0x04)
}
(_simulationResult) = abi.decode(_result, (SimulationResult));
}
/**
* @notice Executes a call agains this contract and reverts with the result
* @dev This is meant to be used internally, do not call!
* @param _call The call to simulate
*/
function simulateAndRevert(bytes calldata _call) external payable {
uint256 _gasAtStart = gasleft();
// solhint-disable-next-line avoid-low-level-calls
(bool _success, bytes memory _result) = address(this).delegatecall(_call);
uint256 _gasSpent = _gasAtStart - gasleft();
revert SimulatedCall(SimulationResult({ success: _success, result: _result, gasSpent: _gasSpent }));
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
interface ISimulationAdapter {
/// @notice A simulation's result
struct SimulationResult {
bool success;
bytes result;
uint256 gasSpent;
}
/**
* @notice Executes individual simulations against this contract but doesn't modify the state when doing so
* @dev This function is meant to be used for off-chain simulation and should not be called on-chain
* @param calls The calls to simulate
* @return results Each simulation result
*/
function simulate(bytes[] calldata calls) external payable returns (SimulationResult[] memory results);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.7 <0.9.0;
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import '@mean-finance/oracles/solidity/interfaces/ITokenPriceOracle.sol';
import './IDCAPermissionManager.sol';
/**
* @title The interface for all state related queries
* @notice These methods allow users to read the hubs's current values
*/
interface IDCAHubParameters {
/**
* @notice Returns how much will the amount to swap differ from the previous swap. f.e. if the returned value is -100, then the amount to swap will be 100 less than the swap just before it
* @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB)
* @param tokenA One of the pair's token
* @param tokenB The other of the pair's token
* @param swapIntervalMask The byte representation of the swap interval to check
* @param swapNumber The swap number to check
* @return swapDeltaAToB How much less of token A will the following swap require
* @return swapDeltaBToA How much less of token B will the following swap require
*/
function swapAmountDelta(
address tokenA,
address tokenB,
bytes1 swapIntervalMask,
uint32 swapNumber
) external view returns (uint128 swapDeltaAToB, uint128 swapDeltaBToA);
/**
* @notice Returns the sum of the ratios reported in all swaps executed until the given swap number
* @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB)
* @param tokenA One of the pair's token
* @param tokenB The other of the pair's token
* @param swapIntervalMask The byte representation of the swap interval to check
* @param swapNumber The swap number to check
* @return accumRatioAToB The sum of all ratios from A to B
* @return accumRatioBToA The sum of all ratios from B to A
*/
function accumRatio(
address tokenA,
address tokenB,
bytes1 swapIntervalMask,
uint32 swapNumber
) external view returns (uint256 accumRatioAToB, uint256 accumRatioBToA);
/**
* @notice Returns swapping information about a specific pair
* @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB)
* @param tokenA One of the pair's token
* @param tokenB The other of the pair's token
* @param swapIntervalMask The byte representation of the swap interval to check
* @return performedSwaps How many swaps have been executed
* @return nextAmountToSwapAToB How much of token A will be swapped on the next swap
* @return lastSwappedAt Timestamp of the last swap
* @return nextAmountToSwapBToA How much of token B will be swapped on the next swap
*/
function swapData(
address tokenA,
address tokenB,
bytes1 swapIntervalMask
)
external
view
returns (
uint32 performedSwaps,
uint224 nextAmountToSwapAToB,
uint32 lastSwappedAt,
uint224 nextAmountToSwapBToA
);
/**
* @notice Returns the byte representation of the set of actice swap intervals for the given pair
* @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB)
* @param tokenA The smaller of the pair's token
* @param tokenB The other of the pair's token
* @return The byte representation of the set of actice swap intervals
*/
function activeSwapIntervals(address tokenA, address tokenB) external view returns (bytes1);
/**
* @notice Returns how much of the hub's token balance belongs to the platform
* @param token The token to check
* @return The amount that belongs to the platform
*/
function platformBalance(address token) external view returns (uint256);
}
/**
* @title The interface for all position related matters
* @notice These methods allow users to create, modify and terminate their positions
*/
interface IDCAHubPositionHandler {
/// @notice The position of a certain user
struct UserPosition {
// The token that the user deposited and will be swapped in exchange for "to"
IERC20Metadata from;
// The token that the user will get in exchange for their "from" tokens in each swap
IERC20Metadata to;
// How frequently the position's swaps should be executed
uint32 swapInterval;
// How many swaps were executed since deposit, last modification, or last withdraw
uint32 swapsExecuted;
// How many "to" tokens can currently be withdrawn
uint256 swapped;
// How many swaps left the position has to execute
uint32 swapsLeft;
// How many "from" tokens there are left to swap
uint256 remaining;
// How many "from" tokens need to be traded in each swap
uint120 rate;
}
/// @notice A list of positions that all have the same `to` token
struct PositionSet {
// The `to` token
address token;
// The position ids
uint256[] positionIds;
}
/**
* @notice Emitted when a position is terminated
* @param user The address of the user that terminated the position
* @param recipientUnswapped The address of the user that will receive the unswapped tokens
* @param recipientSwapped The address of the user that will receive the swapped tokens
* @param positionId The id of the position that was terminated
* @param returnedUnswapped How many "from" tokens were returned to the caller
* @param returnedSwapped How many "to" tokens were returned to the caller
*/
event Terminated(
address indexed user,
address indexed recipientUnswapped,
address indexed recipientSwapped,
uint256 positionId,
uint256 returnedUnswapped,
uint256 returnedSwapped
);
/**
* @notice Emitted when a position is created
* @param depositor The address of the user that creates the position
* @param owner The address of the user that will own the position
* @param positionId The id of the position that was created
* @param fromToken The address of the "from" token
* @param toToken The address of the "to" token
* @param swapInterval How frequently the position's swaps should be executed
* @param rate How many "from" tokens need to be traded in each swap
* @param startingSwap The number of the swap when the position will be executed for the first time
* @param lastSwap The number of the swap when the position will be executed for the last time
* @param permissions The permissions defined for the position
*/
event Deposited(
address indexed depositor,
address indexed owner,
uint256 positionId,
address fromToken,
address toToken,
uint32 swapInterval,
uint120 rate,
uint32 startingSwap,
uint32 lastSwap,
IDCAPermissionManager.PermissionSet[] permissions
);
/**
* @notice Emitted when a position is created and extra data is provided
* @param positionId The id of the position that was created
* @param data The extra data that was provided
*/
event Miscellaneous(uint256 positionId, bytes data);
/**
* @notice Emitted when a user withdraws all swapped tokens from a position
* @param withdrawer The address of the user that executed the withdraw
* @param recipient The address of the user that will receive the withdrawn tokens
* @param positionId The id of the position that was affected
* @param token The address of the withdrawn tokens. It's the same as the position's "to" token
* @param amount The amount that was withdrawn
*/
event Withdrew(address indexed withdrawer, address indexed recipient, uint256 positionId, address token, uint256 amount);
/**
* @notice Emitted when a user withdraws all swapped tokens from many positions
* @param withdrawer The address of the user that executed the withdraws
* @param recipient The address of the user that will receive the withdrawn tokens
* @param positions The positions to withdraw from
* @param withdrew The total amount that was withdrawn from each token
*/
event WithdrewMany(address indexed withdrawer, address indexed recipient, PositionSet[] positions, uint256[] withdrew);
/**
* @notice Emitted when a position is modified
* @param user The address of the user that modified the position
* @param positionId The id of the position that was modified
* @param rate How many "from" tokens need to be traded in each swap
* @param startingSwap The number of the swap when the position will be executed for the first time
* @param lastSwap The number of the swap when the position will be executed for the last time
*/
event Modified(address indexed user, uint256 positionId, uint120 rate, uint32 startingSwap, uint32 lastSwap);
/// @notice Thrown when a user tries to create a position with the same `from` & `to`
error InvalidToken();
/// @notice Thrown when a user tries to create a position with a swap interval that is not allowed
error IntervalNotAllowed();
/// @notice Thrown when a user tries operate on a position that doesn't exist (it might have been already terminated)
error InvalidPosition();
/// @notice Thrown when a user tries operate on a position that they don't have access to
error UnauthorizedCaller();
/// @notice Thrown when a user tries to create a position with zero swaps
error ZeroSwaps();
/// @notice Thrown when a user tries to create a position with zero funds
error ZeroAmount();
/// @notice Thrown when a user tries to withdraw a position whose `to` token doesn't match the specified one
error PositionDoesNotMatchToken();
/// @notice Thrown when a user tries create or modify a position with an amount too big
error AmountTooBig();
/**
* @notice Returns the permission manager contract
* @return The contract itself
*/
function permissionManager() external view returns (IDCAPermissionManager);
/**
* @notice Returns total created positions
* @return The total created positions
*/
function totalCreatedPositions() external view returns (uint256);
/**
* @notice Returns a user position
* @param positionId The id of the position
* @return position The position itself
*/
function userPosition(uint256 positionId) external view returns (UserPosition memory position);
/**
* @notice Creates a new position
* @dev Will revert:
* - With ZeroAddress if from, to or owner are zero
* - With InvalidToken if from == to
* - With ZeroAmount if amount is zero
* - With AmountTooBig if amount is too big
* - With ZeroSwaps if amountOfSwaps is zero
* - With IntervalNotAllowed if swapInterval is not allowed
* @param from The address of the "from" token
* @param to The address of the "to" token
* @param amount How many "from" tokens will be swapped in total
* @param amountOfSwaps How many swaps to execute for this position
* @param swapInterval How frequently the position's swaps should be executed
* @param owner The address of the owner of the position being created
* @param permissions Extra permissions to add to the position. Can be empty
* @return positionId The id of the created position
*/
function deposit(
address from,
address to,
uint256 amount,
uint32 amountOfSwaps,
uint32 swapInterval,
address owner,
IDCAPermissionManager.PermissionSet[] calldata permissions
) external returns (uint256 positionId);
/**
* @notice Creates a new position
* @dev Will revert:
* - With ZeroAddress if from, to or owner are zero
* - With InvalidToken if from == to
* - With ZeroAmount if amount is zero
* - With AmountTooBig if amount is too big
* - With ZeroSwaps if amountOfSwaps is zero
* - With IntervalNotAllowed if swapInterval is not allowed
* @param from The address of the "from" token
* @param to The address of the "to" token
* @param amount How many "from" tokens will be swapped in total
* @param amountOfSwaps How many swaps to execute for this position
* @param swapInterval How frequently the position's swaps should be executed
* @param owner The address of the owner of the position being created
* @param permissions Extra permissions to add to the position. Can be empty
* @param miscellaneous Bytes that will be emitted, and associated with the position
* @return positionId The id of the created position
*/
function deposit(
address from,
address to,
uint256 amount,
uint32 amountOfSwaps,
uint32 swapInterval,
address owner,
IDCAPermissionManager.PermissionSet[] calldata permissions,
bytes calldata miscellaneous
) external returns (uint256 positionId);
/**
* @notice Withdraws all swapped tokens from a position to a recipient
* @dev Will revert:
* - With InvalidPosition if positionId is invalid
* - With UnauthorizedCaller if the caller doesn't have access to the position
* - With ZeroAddress if recipient is zero
* @param positionId The position's id
* @param recipient The address to withdraw swapped tokens to
* @return swapped How much was withdrawn
*/
function withdrawSwapped(uint256 positionId, address recipient) external returns (uint256 swapped);
/**
* @notice Withdraws all swapped tokens from multiple positions
* @dev Will revert:
* - With InvalidPosition if any of the position ids are invalid
* - With UnauthorizedCaller if the caller doesn't have access to the position to any of the given positions
* - With ZeroAddress if recipient is zero
* - With PositionDoesNotMatchToken if any of the positions do not match the token in their position set
* @param positions A list positions, grouped by `to` token
* @param recipient The address to withdraw swapped tokens to
* @return withdrawn How much was withdrawn for each token
*/
function withdrawSwappedMany(PositionSet[] calldata positions, address recipient) external returns (uint256[] memory withdrawn);
/**
* @notice Takes the unswapped balance, adds the new deposited funds and modifies the position so that
* it is executed in newSwaps swaps
* @dev Will revert:
* - With InvalidPosition if positionId is invalid
* - With UnauthorizedCaller if the caller doesn't have access to the position
* - With AmountTooBig if amount is too big
* @param positionId The position's id
* @param amount Amount of funds to add to the position
* @param newSwaps The new amount of swaps
*/
function increasePosition(
uint256 positionId,
uint256 amount,
uint32 newSwaps
) external;
/**
* @notice Withdraws the specified amount from the unswapped balance and modifies the position so that
* it is executed in newSwaps swaps
* @dev Will revert:
* - With InvalidPosition if positionId is invalid
* - With UnauthorizedCaller if the caller doesn't have access to the position
* - With ZeroSwaps if newSwaps is zero and amount is not the total unswapped balance
* @param positionId The position's id
* @param amount Amount of funds to withdraw from the position
* @param newSwaps The new amount of swaps
* @param recipient The address to send tokens to
*/
function reducePosition(
uint256 positionId,
uint256 amount,
uint32 newSwaps,
address recipient
) external;
/**
* @notice Terminates the position and sends all unswapped and swapped balance to the specified recipients
* @dev Will revert:
* - With InvalidPosition if positionId is invalid
* - With UnauthorizedCaller if the caller doesn't have access to the position
* - With ZeroAddress if recipientUnswapped or recipientSwapped is zero
* @param positionId The position's id
* @param recipientUnswapped The address to withdraw unswapped tokens to
* @param recipientSwapped The address to withdraw swapped tokens to
* @return unswapped The unswapped balance sent to `recipientUnswapped`
* @return swapped The swapped balance sent to `recipientSwapped`
*/
function terminate(
uint256 positionId,
address recipientUnswapped,
address recipientSwapped
) external returns (uint256 unswapped, uint256 swapped);
}
/**
* @title The interface for all swap related matters
* @notice These methods allow users to get information about the next swap, and how to execute it
*/
interface IDCAHubSwapHandler {
/// @notice Information about a swap
struct SwapInfo {
// The tokens involved in the swap
TokenInSwap[] tokens;
// The pairs involved in the swap
PairInSwap[] pairs;
}
/// @notice Information about a token's role in a swap
struct TokenInSwap {
// The token's address
address token;
// How much will be given of this token as a reward
uint256 reward;
// How much of this token needs to be provided by swapper
uint256 toProvide;
// How much of this token will be paid to the platform
uint256 platformFee;
}
/// @notice Information about a pair in a swap
struct PairInSwap {
// The address of one of the tokens
address tokenA;
// The address of the other token
address tokenB;
// The total amount of token A swapped in this pair
uint256 totalAmountToSwapTokenA;
// The total amount of token B swapped in this pair
uint256 totalAmountToSwapTokenB;
// How much is 1 unit of token A when converted to B
uint256 ratioAToB;
// How much is 1 unit of token B when converted to A
uint256 ratioBToA;
// The swap intervals involved in the swap, represented as a byte
bytes1 intervalsInSwap;
}
/// @notice A pair of tokens, represented by their indexes in an array
struct PairIndexes {
// The index of the token A
uint8 indexTokenA;
// The index of the token B
uint8 indexTokenB;
}
/**
* @notice Emitted when a swap is executed
* @param sender The address of the user that initiated the swap
* @param rewardRecipient The address that received the reward
* @param callbackHandler The address that executed the callback
* @param swapInformation All information related to the swap
* @param borrowed How much was borrowed
* @param fee The swap fee at the moment of the swap
*/
event Swapped(
address indexed sender,
address indexed rewardRecipient,
address indexed callbackHandler,
SwapInfo swapInformation,
uint256[] borrowed,
uint32 fee
);
/// @notice Thrown when pairs indexes are not sorted correctly
error InvalidPairs();
/// @notice Thrown when trying to execute a swap, but there is nothing to swap
error NoSwapsToExecute();
/**
* @notice Returns all information related to the next swap
* @dev Will revert with:
* - With InvalidTokens if tokens are not sorted, or if there are duplicates
* - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair
* @param tokens The tokens involved in the next swap
* @param pairs The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array
* @param calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides
* the possibility to calculate the next swap information for privileged and non-privileged accounts
* @param oracleData Bytes to send to the oracle when executing a quote
* @return swapInformation The information about the next swap
*/
function getNextSwapInfo(
address[] calldata tokens,
PairIndexes[] calldata pairs,
bool calculatePrivilegedAvailability,
bytes calldata oracleData
) external view returns (SwapInfo memory swapInformation);
/**
* @notice Executes a flash swap
* @dev Will revert with:
* - With InvalidTokens if tokens are not sorted, or if there are duplicates
* - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair
* - With Paused if swaps are paused by protocol
* - With NoSwapsToExecute if there are no swaps to execute for the given pairs
* - With LiquidityNotReturned if the required tokens were not back during the callback
* @param tokens The tokens involved in the next swap
* @param pairsToSwap The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array
* @param rewardRecipient The address to send the reward to
* @param callbackHandler Address to call for callback (and send the borrowed tokens to)
* @param borrow How much to borrow of each of the tokens in tokens. The amount must match the position of the token in the tokens array
* @param callbackData Bytes to send to the caller during the callback
* @param oracleData Bytes to send to the oracle when executing a quote
* @return Information about the executed swap
*/
function swap(
address[] calldata tokens,
PairIndexes[] calldata pairsToSwap,
address rewardRecipient,
address callbackHandler,
uint256[] calldata borrow,
bytes calldata callbackData,
bytes calldata oracleData
) external returns (SwapInfo memory);
}
/**
* @title The interface for handling all configuration
* @notice This contract will manage configuration that affects all pairs, swappers, etc
*/
interface IDCAHubConfigHandler {
/**
* @notice Emitted when a new oracle is set
* @param oracle The new oracle contract
*/
event OracleSet(ITokenPriceOracle oracle);
/**
* @notice Emitted when a new swap fee is set
* @param feeSet The new swap fee
*/
event SwapFeeSet(uint32 feeSet);
/**
* @notice Emitted when new swap intervals are allowed
* @param swapIntervals The new swap intervals
*/
event SwapIntervalsAllowed(uint32[] swapIntervals);
/**
* @notice Emitted when some swap intervals are no longer allowed
* @param swapIntervals The swap intervals that are no longer allowed
*/
event SwapIntervalsForbidden(uint32[] swapIntervals);
/**
* @notice Emitted when a new platform fee ratio is set
* @param platformFeeRatio The new platform fee ratio
*/
event PlatformFeeRatioSet(uint16 platformFeeRatio);
/**
* @notice Emitted when allowed states of tokens are updated
* @param tokens Array of updated tokens
* @param allowed Array of new allow state per token were allowed[i] is the updated state of tokens[i]
*/
event TokensAllowedUpdated(address[] tokens, bool[] allowed);
/// @notice Thrown when trying to interact with an unallowed token
error UnallowedToken();
/// @notice Thrown when set allowed tokens input is not valid
error InvalidAllowedTokensInput();
/// @notice Thrown when trying to set a fee higher than the maximum allowed
error HighFee();
/// @notice Thrown when trying to set a fee that is not multiple of 100
error InvalidFee();
/// @notice Thrown when trying to set a fee ratio that is higher that the maximum allowed
error HighPlatformFeeRatio();
/**
* @notice Returns the max fee ratio that can be set
* @dev Cannot be modified
* @return The maximum possible value
*/
// solhint-disable-next-line func-name-mixedcase
function MAX_PLATFORM_FEE_RATIO() external view returns (uint16);
/**
* @notice Returns the fee charged on swaps
* @return swapFee The fee itself
*/
function swapFee() external view returns (uint32 swapFee);
/**
* @notice Returns the price oracle contract
* @return oracle The contract itself
*/
function oracle() external view returns (ITokenPriceOracle oracle);
/**
* @notice Returns how much will the platform take from the fees collected in swaps
* @return The current ratio
*/
function platformFeeRatio() external view returns (uint16);
/**
* @notice Returns the max fee that can be set for swaps
* @dev Cannot be modified
* @return maxFee The maximum possible fee
*/
// solhint-disable-next-line func-name-mixedcase
function MAX_FEE() external view returns (uint32 maxFee);
/**
* @notice Returns a byte that represents allowed swap intervals
* @return allowedSwapIntervals The allowed swap intervals
*/
function allowedSwapIntervals() external view returns (bytes1 allowedSwapIntervals);
/**
* @notice Returns if a token is currently allowed or not
* @return Allowed state of token
*/
function allowedTokens(address token) external view returns (bool);
/**
* @notice Returns token's magnitude (10**decimals)
* @return Stored magnitude for token
*/
function tokenMagnitude(address token) external view returns (uint120);
/**
* @notice Returns whether swaps and deposits are currently paused
* @return isPaused Whether swaps and deposits are currently paused
*/
function paused() external view returns (bool isPaused);
/**
* @notice Sets a new swap fee
* @dev Will revert with HighFee if the fee is higher than the maximum
* @dev Will revert with InvalidFee if the fee is not multiple of 100
* @param fee The new swap fee
*/
function setSwapFee(uint32 fee) external;
/**
* @notice Sets a new price oracle
* @dev Will revert with ZeroAddress if the zero address is passed
* @param oracle The new oracle contract
*/
function setOracle(ITokenPriceOracle oracle) external;
/**
* @notice Sets a new platform fee ratio
* @dev Will revert with HighPlatformFeeRatio if given ratio is too high
* @param platformFeeRatio The new ratio
*/
function setPlatformFeeRatio(uint16 platformFeeRatio) external;
/**
* @notice Adds new swap intervals to the allowed list
* @param swapIntervals The new swap intervals
*/
function addSwapIntervalsToAllowedList(uint32[] calldata swapIntervals) external;
/**
* @notice Removes some swap intervals from the allowed list
* @param swapIntervals The swap intervals to remove
*/
function removeSwapIntervalsFromAllowedList(uint32[] calldata swapIntervals) external;
/// @notice Pauses all swaps and deposits
function pause() external;
/// @notice Unpauses all swaps and deposits
function unpause() external;
}
/**
* @title The interface for handling platform related actions
* @notice This contract will handle all actions that affect the platform in some way
*/
interface IDCAHubPlatformHandler {
/**
* @notice Emitted when someone withdraws from the paltform balance
* @param sender The address of the user that initiated the withdraw
* @param recipient The address that received the withdraw
* @param amounts The tokens (and the amount) that were withdrawn
*/
event WithdrewFromPlatform(address indexed sender, address indexed recipient, IDCAHub.AmountOfToken[] amounts);
/**
* @notice Withdraws tokens from the platform balance
* @param amounts The amounts to withdraw
* @param recipient The address that will receive the tokens
*/
function withdrawFromPlatformBalance(IDCAHub.AmountOfToken[] calldata amounts, address recipient) external;
}
interface IDCAHub is IDCAHubParameters, IDCAHubConfigHandler, IDCAHubSwapHandler, IDCAHubPositionHandler, IDCAHubPlatformHandler {
/// @notice Specifies an amount of a token. For example to determine how much to borrow from certain tokens
struct AmountOfToken {
// The tokens' address
address token;
// How much to borrow or withdraw of the specified token
uint256 amount;
}
/// @notice Thrown when one of the parameters is a zero address
error ZeroAddress();
/// @notice Thrown when the expected liquidity is not returned in flash swaps
error LiquidityNotReturned();
/// @notice Thrown when a list of token pairs is not sorted, or if there are duplicates
error InvalidTokens();
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.7 <0.9.0;
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@mean-finance/nft-descriptors/solidity/interfaces/IDCAHubPositionDescriptor.sol';
interface IERC721BasicEnumerable {
/**
* @notice Count NFTs tracked by this contract
* @return A count of valid NFTs tracked by this contract, where each one of
* them has an assigned and queryable owner not equal to the zero address
*/
function totalSupply() external view returns (uint256);
}
/**
* @title The interface for all permission related matters
* @notice These methods allow users to set and remove permissions to their positions
*/
interface IDCAPermissionManager is IERC721, IERC721BasicEnumerable {
/// @notice Set of possible permissions
enum Permission {
INCREASE,
REDUCE,
WITHDRAW,
TERMINATE
}
/// @notice A set of permissions for a specific operator
struct PermissionSet {
// The address of the operator
address operator;
// The permissions given to the overator
Permission[] permissions;
}
/// @notice A collection of permissions sets for a specific position
struct PositionPermissions {
// The id of the token
uint256 tokenId;
// The permissions to assign to the position
PermissionSet[] permissionSets;
}
/**
* @notice Emitted when permissions for a token are modified
* @param tokenId The id of the token
* @param permissions The set of permissions that were updated
*/
event Modified(uint256 tokenId, PermissionSet[] permissions);
/**
* @notice Emitted when the address for a new descritor is set
* @param descriptor The new descriptor contract
*/
event NFTDescriptorSet(IDCAHubPositionDescriptor descriptor);
/// @notice Thrown when a user tries to set the hub, once it was already set
error HubAlreadySet();
/// @notice Thrown when a user provides a zero address when they shouldn't
error ZeroAddress();
/// @notice Thrown when a user calls a method that can only be executed by the hub
error OnlyHubCanExecute();
/// @notice Thrown when a user tries to modify permissions for a token they do not own
error NotOwner();
/// @notice Thrown when a user tries to execute a permit with an expired deadline
error ExpiredDeadline();
/// @notice Thrown when a user tries to execute a permit with an invalid signature
error InvalidSignature();
/**
* @notice The permit typehash used in the permit signature
* @return The typehash for the permit
*/
// solhint-disable-next-line func-name-mixedcase
function PERMIT_TYPEHASH() external pure returns (bytes32);
/**
* @notice The permit typehash used in the permission permit signature
* @return The typehash for the permission permit
*/
// solhint-disable-next-line func-name-mixedcase
function PERMISSION_PERMIT_TYPEHASH() external pure returns (bytes32);
/**
* @notice The permit typehash used in the multi permission permit signature
* @return The typehash for the multi permission permit
*/
// solhint-disable-next-line func-name-mixedcase
function MULTI_PERMISSION_PERMIT_TYPEHASH() external pure returns (bytes32);
/**
* @notice The permit typehash used in the permission permit signature
* @return The typehash for the permission set
*/
// solhint-disable-next-line func-name-mixedcase
function PERMISSION_SET_TYPEHASH() external pure returns (bytes32);
/**
* @notice The permit typehash used in the multi permission permit signature
* @return The typehash for the position permissions
*/
// solhint-disable-next-line func-name-mixedcase
function POSITION_PERMISSIONS_TYPEHASH() external pure returns (bytes32);
/**
* @notice The domain separator used in the permit signature
* @return The domain seperator used in encoding of permit signature
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the NFT descriptor contract
* @return The contract for the NFT descriptor
*/
function nftDescriptor() external returns (IDCAHubPositionDescriptor);
/**
* @notice Returns the address of the DCA Hub
* @return The address of the DCA Hub
*/
function hub() external returns (address);
/**
* @notice Returns the next nonce to use for a given user
* @param user The address of the user
* @return nonce The next nonce to use
*/
function nonces(address user) external returns (uint256 nonce);
/**
* @notice Returns whether the given address has the permission for the given token
* @param id The id of the token to check
* @param account The address of the user to check
* @param permission The permission to check
* @return Whether the user has the permission or not
*/
function hasPermission(
uint256 id,
address account,
Permission permission
) external view returns (bool);
/**
* @notice Returns whether the given address has the permissions for the given token
* @param id The id of the token to check
* @param account The address of the user to check
* @param permissions The permissions to check
* @return hasPermissions Whether the user has each permission or not
*/
function hasPermissions(
uint256 id,
address account,
Permission[] calldata permissions
) external view returns (bool[] memory hasPermissions);
/**
* @notice Sets the address for the hub
* @dev Can only be successfully executed once. Once it's set, it can be modified again
* Will revert:
* - With ZeroAddress if address is zero
* - With HubAlreadySet if the hub has already been set
* @param hub The address to set for the hub
*/
function setHub(address hub) external;
/**
* @notice Mints a new NFT with the given id, and sets the permissions for it
* @dev Will revert with OnlyHubCanExecute if the caller is not the hub
* @param id The id of the new NFT
* @param owner The owner of the new NFT
* @param permissions Permissions to set for the new NFT
*/
function mint(
uint256 id,
address owner,
PermissionSet[] calldata permissions
) external;
/**
* @notice Burns the NFT with the given id, and clears all permissions
* @dev Will revert with OnlyHubCanExecute if the caller is not the hub
* @param id The token's id
*/
function burn(uint256 id) external;
/**
* @notice Sets new permissions for the given position
* @dev Will revert with NotOwner if the caller is not the token's owner.
* Operators that are not part of the given permission sets do not see their permissions modified.
* In order to remove permissions to an operator, provide an empty list of permissions for them
* @param id The token's id
* @param permissions A list of permission sets
*/
function modify(uint256 id, PermissionSet[] calldata permissions) external;
/**
* @notice Sets new permissions for the given positions
* @dev This is basically the same as executing multiple `modify`
* @param permissions A list of position permissions to set
*/
function modifyMany(PositionPermissions[] calldata permissions) external;
/**
* @notice Approves spending of a specific token ID by spender via signature
* @param spender The account that is being approved
* @param tokenId The ID of the token that is being approved for spending
* @param deadline The deadline timestamp by which the call must be mined for the approve to work
* @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
* @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
* @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
*/
function permit(
address spender,
uint256 tokenId,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Sets permissions via signature
* @dev This method works similarly to `modifyMany`, but instead of being executed by the owner, it can be set by signature
* @param permissions The permissions to set for the different positions
* @param deadline The deadline timestamp by which the call must be mined for the approve to work
* @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
* @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
* @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
*/
function multiPermissionPermit(
PositionPermissions[] calldata permissions,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Sets permissions via signature
* @dev This method works similarly to `modify`, but instead of being executed by the owner, it can be set my signature
* @param permissions The permissions to set
* @param tokenId The token's id
* @param deadline The deadline timestamp by which the call must be mined for the approve to work
* @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
* @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
* @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
*/
function permissionPermit(
PermissionSet[] calldata permissions,
uint256 tokenId,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Sets a new NFT descriptor
* @dev Will revert with ZeroAddress if address is zero
* @param descriptor The new NFT descriptor contract
*/
function setNFTDescriptor(IDCAHubPositionDescriptor descriptor) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.7;
import {IDCAHub, IERC20} from '@mean-finance/dca-v2-core/contracts/interfaces/IDCAHub.sol';
import {SwapAdapter} from '../utils/SwapAdapter.sol';
import {SwapContext} from '../utils/types/SwapContext.sol';
import {TransferOutBalance} from '../utils/types/TransferOutBalance.sol';
/**
* @title DCA Fee Manager
* @notice This contract will manage all platform fees. Since fees come in different tokens, this manager
* will be in charge of taking them and converting them to different tokens, for example ETH/MATIC
* or stablecoins. Allowed users will to withdraw fees as generated, or DCA them into tokens
* of their choosing
*/
interface IDCAFeeManager {
/// @notice The parameters to execute the call
struct RunSwapsAndTransferManyParams {
// The accounts that should be approved for spending
AllowanceTarget[] allowanceTargets;
// The different swappers involved in the swap
address[] swappers;
// The different swapps to execute
bytes[] swaps;
// Context necessary for the swap execution
SwapContext[] swapContext;
// Tokens to transfer after swaps have been executed
TransferOutBalance[] transferOutBalance;
}
/// @notice An allowance to provide for the swaps to work
struct AllowanceTarget {
// The token that should be approved
IERC20 token;
// The spender
address allowanceTarget;
}
/// @notice Represents how much is available for withdraw, for a specific token
struct AvailableBalance {
address token;
uint256 platformBalance;
uint256 feeManagerBalance;
}
/// @notice Thrown when one of the parameters is a zero address
error ZeroAddress();
/**
* @notice Executes multiple swaps
* @dev Can only be executed by admins
* @param parameters The parameters for the swap
*/
function runSwapsAndTransferMany(RunSwapsAndTransferManyParams calldata parameters) external payable;
/**
* @notice Withdraws tokens from the platform balance, and sends them to the given recipient
* @dev Can only be executed by admins
* @param hub The address of the DCA Hub
* @param amountToWithdraw The tokens to withdraw, and their amounts
* @param recipient The address of the recipient
*/
function withdrawFromPlatformBalance(
IDCAHub hub,
IDCAHub.AmountOfToken[] calldata amountToWithdraw,
address recipient
) external;
/**
* @notice Withdraws tokens from the contract's balance, and sends them to the given recipient
* @dev Can only be executed by admins
* @param amountToWithdraw The tokens to withdraw, and their amounts
* @param recipient The address of the recipient
*/
function withdrawFromBalance(IDCAHub.AmountOfToken[] calldata amountToWithdraw, address recipient) external;
/**
* @notice Revokes ERC20 allowances for the given spenders
* @dev Can only be executed by admins
* @param revokeActions The spenders and tokens to revoke
*/
function revokeAllowances(SwapAdapter.RevokeAction[] calldata revokeActions) external;
/**
* @notice Returns how much is available for withdraw, for the given tokens
* @dev This is meant for off-chan purposes
* @param hub The address of the DCA Hub
* @param tokens The tokens to check the balance for
* @return How much is available for withdraw, for the given tokens
*/
function availableBalances(IDCAHub hub, address[] calldata tokens) external view returns (AvailableBalance[] memory);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.7 <0.9.0;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/Address.sol';
abstract contract SwapAdapter {
using SafeERC20 for IERC20;
using Address for address;
using Address for address payable;
/// @notice Describes how the allowance should be revoked for the given spender
struct RevokeAction {
address spender;
IERC20[] tokens;
}
address public constant PROTOCOL_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @notice Takes the given amount of tokens from the caller
* @param _token The token to check
* @param _amount The amount to take
*/
function _takeFromMsgSender(IERC20 _token, uint256 _amount) internal virtual {
_token.safeTransferFrom(msg.sender, address(this), _amount);
}
/**
* @notice Executes a swap for the given swapper
* @param _swapper The actual swapper
* @param _swapData The swap execution data
*/
function _executeSwap(
address _swapper,
bytes calldata _swapData,
uint256 _value
) internal virtual {
_swapper.functionCallWithValue(_swapData, _value);
}
/**
* @notice Transfers the given amount of tokens from the contract to the recipient
* @param _token The token to check
* @param _amount The amount to send
* @param _recipient The recipient
*/
function _sendToRecipient(
address _token,
uint256 _amount,
address _recipient
) internal virtual {
if (_recipient == address(0)) _recipient = msg.sender;
if (_token == PROTOCOL_TOKEN) {
payable(_recipient).sendValue(_amount);
} else {
IERC20(_token).safeTransfer(_recipient, _amount);
}
}
/**
* @notice Checks if the contract has any balance of the given token, and if it does,
* it sends it to the given recipient
* @param _token The token to check
* @param _recipient The recipient of the token balance
*/
function _sendBalanceOnContractToRecipient(address _token, address _recipient) internal virtual {
uint256 _balance = _token == PROTOCOL_TOKEN ? address(this).balance : IERC20(_token).balanceOf(address(this));
if (_balance > 0) {
_sendToRecipient(_token, _balance, _recipient);
}
}
/**
* @notice Revokes ERC20 allowances for the given spenders
* @dev If exposed, then it should be permissioned
* @param _revokeActions The spenders and tokens to revoke
*/
function _revokeAllowances(RevokeAction[] calldata _revokeActions) internal virtual {
for (uint256 i = 0; i < _revokeActions.length; ) {
RevokeAction memory _action = _revokeActions[i];
for (uint256 j = 0; j < _action.tokens.length; ) {
_action.tokens[j].forceApprove(_action.spender, 0);
unchecked {
j++;
}
}
unchecked {
i++;
}
}
}
}/// @notice Context necessary for the swap execution
struct SwapContext {
// The index of the swapper that should execute each swap. This might look strange but it's way cheaper than alternatives
uint8 swapperIndex;
// The ETH/MATIC/BNB to send as part of the swap
uint256 value;
}/// @notice A token that was left on the contract and should be transferred out
struct TransferOutBalance {
// The token to transfer
address token;
// The recipient of those tokens
address recipient;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Multicall.sol)
pragma solidity ^0.8.20;
import {Address} from "./Address.sol";
import {Context} from "./Context.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
* careful about sending transactions invoking {multicall}. For example, a relay address that filters function
* selectors won't filter calls nested within a {multicall} operation.
*
* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
* {_msgSender} are not propagated to subcalls.
*/
abstract contract Multicall is Context {
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
bytes memory context = msg.sender == _msgSender()
? new bytes(0)
: msg.data[msg.data.length - _contextSuffixLength():];
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
}
return results;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.7 <0.9.0;
/**
* @title The interface for generating a description for a position in a DCA Hub
* @notice Contracts that implement this interface must return a base64 JSON with the entire description
*/
interface IDCAHubPositionDescriptor {
/**
* @notice Generates a positions's description, both the JSON and the image inside
* @param hub The address of the DCA Hub
* @param positionId The token/position id
* @return description The position's description
*/
function tokenURI(address hub, uint256 positionId) external view returns (string memory description);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @title The interface for an oracle that provides price quotes
* @notice These methods allow users to add support for pairs, and then ask for quotes
*/
interface ITokenPriceOracle {
/// @notice Thrown when trying to add support for a pair that cannot be supported
error PairCannotBeSupported(address tokenA, address tokenB);
/// @notice Thrown when trying to execute a quote with a pair that isn't supported yet
error PairNotSupportedYet(address tokenA, address tokenB);
/**
* @notice Returns whether this oracle can support the given pair of tokens
* @dev tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order
* @param tokenA One of the pair's tokens
* @param tokenB The other of the pair's tokens
* @return Whether the given pair of tokens can be supported by the oracle
*/
function canSupportPair(address tokenA, address tokenB) external view returns (bool);
/**
* @notice Returns whether this oracle is already supporting the given pair of tokens
* @dev tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order
* @param tokenA One of the pair's tokens
* @param tokenB The other of the pair's tokens
* @return Whether the given pair of tokens is already being supported by the oracle
*/
function isPairAlreadySupported(address tokenA, address tokenB) external view returns (bool);
/**
* @notice Returns a quote, based on the given tokens and amount
* @dev Will revert if pair isn't supported
* @param tokenIn The token that will be provided
* @param amountIn The amount that will be provided
* @param tokenOut The token we would like to quote
* @param data Custom data that the oracle might need to operate
* @return amountOut How much `tokenOut` will be returned in exchange for `amountIn` amount of `tokenIn`
*/
function quote(
address tokenIn,
uint256 amountIn,
address tokenOut,
bytes calldata data
) external view returns (uint256 amountOut);
/**
* @notice Add or reconfigures the support for a given pair. This function will let the oracle take some actions
* to configure the pair, in preparation for future quotes. Can be called many times in order to let the oracle
* re-configure for a new context
* @dev Will revert if pair cannot be supported. tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order
* @param tokenA One of the pair's tokens
* @param tokenB The other of the pair's tokens
* @param data Custom data that the oracle might need to operate
*/
function addOrModifySupportForPair(
address tokenA,
address tokenB,
bytes calldata data
) external;
/**
* @notice Adds support for a given pair if the oracle didn't support it already. If called for a pair that is already supported,
* then nothing will happen. This function will let the oracle take some actions to configure the pair, in preparation
* for future quotes
* @dev Will revert if pair cannot be supported. tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order
* @param tokenA One of the pair's tokens
* @param tokenB The other of the pair's tokens
* @param data Custom data that the oracle might need to operate
*/
function addSupportForPairIfNeeded(
address tokenA,
address tokenB,
bytes calldata data
) external;
}{
"viaIR": false,
"optimizer": {
"runs": 9999,
"enabled": true
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {},
"remappings": [
"@openzeppelin/contracts/=node_modules/@mean-finance/dca-v2-periphery/node_modules/@openzeppelin/contracts/",
"@mean-finance/oracles/=node_modules/@mean-finance/oracles/",
"@mean-finance/nft-descriptors/=node_modules/@mean-finance/nft-descriptors/",
"@mean-finance/call-simulation/contracts/=node_modules/@mean-finance/call-simulation/src/",
"@mean-finance/swappers/=node_modules/@mean-finance/swappers/",
"@mean-finance/dca-v2-core/=node_modules/@mean-finance/dca-v2-core/",
"@mean-finance/permit2-adapter/=node_modules/@mean-finance/permit2-adapter/src/",
"@mean-finance/transformers/=node_modules/@mean-finance/transformers/solidity/contracts/transformers/",
"@mean-finance/dca-v2-periphery/=node_modules/@mean-finance/dca-v2-periphery/",
"@mean-finance/uniswap-v3-oracle/=node_modules/@mean-finance/uniswap-v3-oracle/",
"@call-simulation/=node_modules/@mean-finance/call-simulation/src/",
"@chainlink/=node_modules/@chainlink/",
"@api3/=node_modules/@api3/",
"@uniswap/=node_modules/@uniswap/",
"keep3r-v2/=node_modules/keep3r-v2/",
"base64-sol/=node_modules/base64-sol/",
"@sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry/",
"forge-std/=lib/forge-std/src/",
"@rari-capital/solmate/=lib/solmate/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"solmate/=lib/solmate/src/",
"sphinx/=lib/sphinx/packages/contracts/contracts/forge-std/src/"
]
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_superAdmin","type":"address"},{"internalType":"address[]","name":"_initialAdmins","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult","name":"result","type":"tuple"}],"name":"SimulatedCall","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUPER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"availableBalances","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"platformBalance","type":"uint256"},{"internalType":"uint256","name":"feeManagerBalance","type":"uint256"}],"internalType":"struct IDCAFeeManager.AvailableBalance[]","name":"_balances","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"getPositionKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"internalType":"struct SwapAdapter.RevokeAction[]","name":"_revokeActions","type":"tuple[]"}],"name":"revokeAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"}],"internalType":"struct IDCAFeeManager.AllowanceTarget[]","name":"allowanceTargets","type":"tuple[]"},{"internalType":"address[]","name":"swappers","type":"address[]"},{"internalType":"bytes[]","name":"swaps","type":"bytes[]"},{"components":[{"internalType":"uint8","name":"swapperIndex","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct SwapContext[]","name":"swapContext","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOutBalance[]","name":"transferOutBalance","type":"tuple[]"}],"internalType":"struct IDCAFeeManager.RunSwapsAndTransferManyParams","name":"_parameters","type":"tuple"}],"name":"runSwapsAndTransferMany","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_calls","type":"bytes[]"}],"name":"simulate","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult[]","name":"_results","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_call","type":"bytes"}],"name":"simulateAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IDCAHub.AmountOfToken[]","name":"_amountToWithdraw","type":"tuple[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawFromBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IDCAHub.AmountOfToken[]","name":"_amountToWithdraw","type":"tuple[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawFromPlatformBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162002a6938038062002a69833981016040819052620000349162000247565b6001600160a01b0382166200005c5760405163d92e233d60e01b815260040160405180910390fd5b6200007760008051602062002a29833981519152806200011a565b620000a160008051602062002a4983398151915260008051602062002a298339815191526200011a565b620000bc60008051602062002a298339815191528362000165565b5060005b815181101562000111576200010760008051602062002a49833981519152838381518110620000f357620000f362000330565b60200260200101516200016560201b60201c565b50600101620000c0565b50505062000346565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200020a576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001c13390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200020e565b5060005b92915050565b80516001600160a01b03811681146200022c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200025b57600080fd5b620002668362000214565b602084810151919350906001600160401b03808211156200028657600080fd5b818601915086601f8301126200029b57600080fd5b815181811115620002b057620002b062000231565b8060051b604051601f19603f83011681018181108582111715620002d857620002d862000231565b604052918252848201925083810185019189831115620002f757600080fd5b938501935b828510156200032057620003108562000214565b84529385019392850192620002fc565b8096505050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b6126d380620003566000396000f3fe6080604052600436106101485760003560e01c80636c06005a116100c0578063bcbef20611610074578063e9c0407111610059578063e9c040711461045c578063fb0cb6a51461047c578063fb5235d8146104a957600080fd5b8063bcbef20614610429578063d547741f1461043c57600080fd5b806391d14854116100a557806391d1485414610396578063a217fddf146103e7578063ac9650d8146103fc57600080fd5b80636c06005a1461034257806375b238fc1461036257600080fd5b806336568abe116101175780634460bdd6116100fc5780634460bdd6146102a157806351f63ebc146102d5578063585cc6a5146102f557600080fd5b806336568abe146102615780633ed242b41461028157600080fd5b806301ffc9a714610154578063248a9ca3146101895780632f2ff15d146101c757806336351365146101e957600080fd5b3661014f57005b600080fd5b34801561016057600080fd5b5061017461016f366004611b32565b6104bc565b60405190151581526020015b60405180910390f35b34801561019557600080fd5b506101b96101a4366004611b74565b60009081526020819052604090206001015490565b604051908152602001610180565b3480156101d357600080fd5b506101e76101e2366004611baf565b6104dc565b005b3480156101f557600080fd5b506101b9610204366004611bdf565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b34801561026d57600080fd5b506101e761027c366004611baf565b610507565b61029461028f366004611c59565b610565565b6040516101809190611d20565b3480156102ad57600080fd5b506101b97f7613a25ecc738585a232ad50a301178f12b3ba8887d13e138b523c4269c4768981565b3480156102e157600080fd5b506101e76102f0366004611de7565b61063d565b34801561030157600080fd5b5061031d73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610180565b34801561034e57600080fd5b506101e761035d366004611e3e565b6106fd565b34801561036e57600080fd5b506101b97fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b3480156103a257600080fd5b506101746103b1366004611baf565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156103f357600080fd5b506101b9600081565b34801561040857600080fd5b5061041c610417366004611c59565b6107b6565b6040516101809190611ea6565b6101e7610437366004611f1b565b61089e565b34801561044857600080fd5b506101e7610457366004611baf565b61097a565b34801561046857600080fd5b506101e7610477366004611c59565b61099f565b34801561048857600080fd5b5061049c610497366004611f8d565b6109d3565b6040516101809190611fe2565b6101e76104b7366004612051565b610c00565b60006104c782610dc7565b806104d657506104d682610e5f565b92915050565b6000828152602081905260409020600101546104f781610ef6565b6105018383610f03565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610556576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105608282610fff565b505050565b60608167ffffffffffffffff8111156105805761058061208c565b6040519080825280602002602001820160405280156105d757816020015b6105c4604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161059e5790505b50905060005b82811015610636576106118484838181106105fa576105fa6120bb565b905060200281019061060c91906120ea565b6110ba565b828281518110610623576106236120bb565b60209081029190910101526001016105dd565b5092915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561066781610ef6565b60005b838110156106f6576000858583818110610686576106866120bb565b90506040020180360381019061069c91906121cc565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200151036106da5780516106d59085611250565b6106ed565b6106ed8160000151826020015186611327565b5060010161066a565b5050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561072781610ef6565b6040517f560c649900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169063560c64999061077d90879087908790600401612206565b600060405180830381600087803b15801561079757600080fd5b505af11580156107ab573d6000803e3d6000fd5b505050505050505050565b6040805160008152602081019091526060908267ffffffffffffffff8111156107e1576107e161208c565b60405190808252806020026020018201604052801561081457816020015b60608152602001906001900390816107ff5790505b50915060005b838110156108965761087130868684818110610838576108386120bb565b905060200281019061084a91906120ea565b8560405160200161085d939291906122c5565b6040516020818303038152906040526113c3565b838281518110610883576108836120bb565b602090810291909101015260010161081a565b505092915050565b60005a90506000803073ffffffffffffffffffffffffffffffffffffffff1685856040516108cd9291906122ec565b600060405180830381855af49150503d8060008114610908576040519150601f19603f3d011682016040523d82523d6000602084013e61090d565b606091505b509150915060005a61091f908561228b565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161097191906122fc565b60405180910390fd5b60008281526020819052604090206001015461099581610ef6565b6105018383610fff565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109c981610ef6565b610560838361143d565b60608167ffffffffffffffff8111156109ee576109ee61208c565b604051908082528060200260200182016040528015610a5957816020015b610a466040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b815260200190600190039081610a0c5790505b50905060005b82811015610bf8576000848483818110610a7b57610a7b6120bb565b9050602002016020810190610a90919061230f565b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff80841680835292517fc67e32e900000000000000000000000000000000000000000000000000000000815260048101939093529293509160208301919089169063c67e32e990602401602060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b39919061232c565b81526040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260209091019073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610bab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcf919061232c565b815250838381518110610be457610be46120bb565b602090810291909101015250600101610a5f565b509392505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610c2a81610ef6565b60005b610c378380612345565b9050811015610c8f576000610c4c8480612345565b83818110610c5c57610c5c6120bb565b905060400201803603810190610c7291906123ad565b9050610c86816000015182602001516114e8565b50600101610c2d565b5060005b610ca060408401846123ee565b9050811015610d5b576000610cb86060850185612345565b83818110610cc857610cc86120bb565b905060400201803603810190610cde9190612456565b9050610d52610cf060208601866123ee565b835160ff16818110610d0457610d046120bb565b9050602002016020810190610d19919061230f565b610d2660408701876123ee565b85818110610d3657610d366120bb565b9050602002810190610d4891906120ea565b846020015161152d565b50600101610c93565b5060005b610d6c6080840184612345565b9050811015610560576000610d846080850185612345565b83818110610d9457610d946120bb565b905060400201803603810190610daa91906123ad565b9050610dbe81600001518260200151611250565b50600101610d5f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806104d657507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104d657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104d6565b610f008133611585565b50565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ff75760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610f953390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104d6565b5060006104d6565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ff75760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104d6565b6110e0604051806060016040528060001515815260200160608152602001600081525090565b6000803073ffffffffffffffffffffffffffffffffffffffff1663bcbef20660e01b8686604051602401611115929190612481565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161118091906124b0565b600060405180830381855af49150503d80600081146111bb576040519150601f19603f3d011682016040523d82523d6000602084013e6111c0565b606091505b5091509150811561122d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c65642100000000000000006044820152606401610971565b6004810190508080602001905181019061124791906124e1565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611316576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156112ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611311919061232c565b611318565b475b90508015610560576105608382845b73ffffffffffffffffffffffffffffffffffffffff81166113455750335b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016113a25761056073ffffffffffffffffffffffffffffffffffffffff82168361160b565b61056073ffffffffffffffffffffffffffffffffffffffff841682846116e1565b60606000808473ffffffffffffffffffffffffffffffffffffffff16846040516113ed91906124b0565b600060405180830381855af49150503d8060008114611428576040519150601f19603f3d011682016040523d82523d6000602084013e61142d565b606091505b5091509150611247858383611762565b60005b8181101561056057600083838381811061145c5761145c6120bb565b905060200281019061146e91906125b5565b611477906125e9565b905060005b8160200151518110156114de576114d682600001516000846020015184815181106114a9576114a96120bb565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166117f49092919063ffffffff16565b60010161147c565b5050600101611440565b61152973ffffffffffffffffffffffffffffffffffffffff8316827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6117f4565b5050565b6106f683838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505073ffffffffffffffffffffffffffffffffffffffff8716919050836118cc565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611529576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610971565b80471015611647576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610971565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146116a1576040519150601f19603f3d011682016040523d82523d6000602084013e6116a6565b606091505b5050905080610560576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261056091859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061198f565b6060826117775761177282611a25565b6117ed565b815115801561179b575073ffffffffffffffffffffffffffffffffffffffff84163b155b156117ea576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610971565b50805b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526118808482611a67565b6105015760405173ffffffffffffffffffffffffffffffffffffffff8481166024830152600060448301526118c291869182169063095ea7b39060640161171b565b610501848261198f565b60608147101561190a576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610971565b6000808573ffffffffffffffffffffffffffffffffffffffff16848660405161193391906124b0565b60006040518083038185875af1925050503d8060008114611970576040519150601f19603f3d011682016040523d82523d6000602084013e611975565b606091505b5091509150611985868383611762565b9695505050505050565b60006119b173ffffffffffffffffffffffffffffffffffffffff841683611b24565b905080516000141580156119d65750808060200190518101906119d491906126b8565b155b15610560576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610971565b805115611a355780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1684604051611a9191906124b0565b6000604051808303816000865af19150503d8060008114611ace576040519150601f19603f3d011682016040523d82523d6000602084013e611ad3565b606091505b5091509150818015611afd575080511580611afd575080806020019051810190611afd91906126b8565b801561124757505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b60606117ed838360006118cc565b600060208284031215611b4457600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146117ed57600080fd5b600060208284031215611b8657600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f0057600080fd5b60008060408385031215611bc257600080fd5b823591506020830135611bd481611b8d565b809150509250929050565b60008060408385031215611bf257600080fd5b8235611bfd81611b8d565b91506020830135611bd481611b8d565b60008083601f840112611c1f57600080fd5b50813567ffffffffffffffff811115611c3757600080fd5b6020830191508360208260051b8501011115611c5257600080fd5b9250929050565b60008060208385031215611c6c57600080fd5b823567ffffffffffffffff811115611c8357600080fd5b611c8f85828601611c0d565b90969095509350505050565b60005b83811015611cb6578181015183820152602001611c9e565b50506000910152565b60008151808452611cd7816020860160208601611c9b565b601f01601f19169290920160200192915050565b8051151582526000602082015160606020850152611d0c6060850182611cbf565b604093840151949093019390935250919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611d95577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611d83858351611ceb565b94509285019290850190600101611d49565b5092979650505050505050565b60008083601f840112611db457600080fd5b50813567ffffffffffffffff811115611dcc57600080fd5b6020830191508360208260061b8501011115611c5257600080fd5b600080600060408486031215611dfc57600080fd5b833567ffffffffffffffff811115611e1357600080fd5b611e1f86828701611da2565b9094509250506020840135611e3381611b8d565b809150509250925092565b60008060008060608587031215611e5457600080fd5b8435611e5f81611b8d565b9350602085013567ffffffffffffffff811115611e7b57600080fd5b611e8787828801611da2565b9094509250506040850135611e9b81611b8d565b939692955090935050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611d95577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611f09858351611cbf565b94509285019290850190600101611ecf565b60008060208385031215611f2e57600080fd5b823567ffffffffffffffff80821115611f4657600080fd5b818501915085601f830112611f5a57600080fd5b813581811115611f6957600080fd5b866020828501011115611f7b57600080fd5b60209290920196919550909350505050565b600080600060408486031215611fa257600080fd5b8335611fad81611b8d565b9250602084013567ffffffffffffffff811115611fc957600080fd5b611fd586828701611c0d565b9497909650939450505050565b602080825282518282018190526000919060409081850190868401855b82811015612044578151805173ffffffffffffffffffffffffffffffffffffffff16855286810151878601528501518585015260609093019290850190600101611fff565b5091979650505050505050565b60006020828403121561206357600080fd5b813567ffffffffffffffff81111561207a57600080fd5b820160a081850312156117ed57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261211f57600080fd5b83018035915067ffffffffffffffff82111561213a57600080fd5b602001915036819003821315611c5257600080fd5b6040805190810167ffffffffffffffff811182821017156121725761217261208c565b60405290565b6040516060810167ffffffffffffffff811182821017156121725761217261208c565b604051601f8201601f1916810167ffffffffffffffff811182821017156121c4576121c461208c565b604052919050565b6000604082840312156121de57600080fd5b6121e661214f565b82356121f181611b8d565b81526020928301359281019290925250919050565b60408082528181018490526000908560608401835b8781101561226057823561222e81611b8d565b73ffffffffffffffffffffffffffffffffffffffff16825260208381013590830152918301919083019060010161221b565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818103818111156104d6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8284823760008382016000815283516122e2818360208801611c9b565b0195945050505050565b8183823760009101908152919050565b6020815260006117ed6020830184611ceb565b60006020828403121561232157600080fd5b81356117ed81611b8d565b60006020828403121561233e57600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261237a57600080fd5b83018035915067ffffffffffffffff82111561239557600080fd5b6020019150600681901b3603821315611c5257600080fd5b6000604082840312156123bf57600080fd5b6123c761214f565b82356123d281611b8d565b815260208301356123e281611b8d565b60208201529392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261242357600080fd5b83018035915067ffffffffffffffff82111561243e57600080fd5b6020019150600581901b3603821315611c5257600080fd5b60006040828403121561246857600080fd5b61247061214f565b823560ff811681146121f157600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082516124c2818460208701611c9b565b9190910192915050565b805180151581146124dc57600080fd5b919050565b600060208083850312156124f457600080fd5b825167ffffffffffffffff8082111561250c57600080fd5b908401906060828703121561252057600080fd5b612528612178565b612531836124cc565b8152838301518281111561254457600080fd5b8301601f8101881361255557600080fd5b8051838111156125675761256761208c565b61257986601f19601f8401160161219b565b9350808452888682840101111561258f57600080fd5b61259e81878601888501611c9b565b505092830152604090810151908201529392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126124c257600080fd5b6000604082360312156125fb57600080fd5b61260361214f565b823561260e81611b8d565b815260208381013567ffffffffffffffff8082111561262c57600080fd5b9085019036601f83011261263f57600080fd5b8135818111156126515761265161208c565b8060051b915061266284830161219b565b818152918301840191848101903684111561267c57600080fd5b938501935b838510156126a6578435925061269683611b8d565b8282529385019390850190612681565b94860194909452509295945050505050565b6000602082840312156126ca57600080fd5b6117ed826124cc567613a25ecc738585a232ad50a301178f12b3ba8887d13e138b523c4269c47689a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Deployed Bytecode
0x6080604052600436106101485760003560e01c80636c06005a116100c0578063bcbef20611610074578063e9c0407111610059578063e9c040711461045c578063fb0cb6a51461047c578063fb5235d8146104a957600080fd5b8063bcbef20614610429578063d547741f1461043c57600080fd5b806391d14854116100a557806391d1485414610396578063a217fddf146103e7578063ac9650d8146103fc57600080fd5b80636c06005a1461034257806375b238fc1461036257600080fd5b806336568abe116101175780634460bdd6116100fc5780634460bdd6146102a157806351f63ebc146102d5578063585cc6a5146102f557600080fd5b806336568abe146102615780633ed242b41461028157600080fd5b806301ffc9a714610154578063248a9ca3146101895780632f2ff15d146101c757806336351365146101e957600080fd5b3661014f57005b600080fd5b34801561016057600080fd5b5061017461016f366004611b32565b6104bc565b60405190151581526020015b60405180910390f35b34801561019557600080fd5b506101b96101a4366004611b74565b60009081526020819052604090206001015490565b604051908152602001610180565b3480156101d357600080fd5b506101e76101e2366004611baf565b6104dc565b005b3480156101f557600080fd5b506101b9610204366004611bdf565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b34801561026d57600080fd5b506101e761027c366004611baf565b610507565b61029461028f366004611c59565b610565565b6040516101809190611d20565b3480156102ad57600080fd5b506101b97f7613a25ecc738585a232ad50a301178f12b3ba8887d13e138b523c4269c4768981565b3480156102e157600080fd5b506101e76102f0366004611de7565b61063d565b34801561030157600080fd5b5061031d73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610180565b34801561034e57600080fd5b506101e761035d366004611e3e565b6106fd565b34801561036e57600080fd5b506101b97fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b3480156103a257600080fd5b506101746103b1366004611baf565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156103f357600080fd5b506101b9600081565b34801561040857600080fd5b5061041c610417366004611c59565b6107b6565b6040516101809190611ea6565b6101e7610437366004611f1b565b61089e565b34801561044857600080fd5b506101e7610457366004611baf565b61097a565b34801561046857600080fd5b506101e7610477366004611c59565b61099f565b34801561048857600080fd5b5061049c610497366004611f8d565b6109d3565b6040516101809190611fe2565b6101e76104b7366004612051565b610c00565b60006104c782610dc7565b806104d657506104d682610e5f565b92915050565b6000828152602081905260409020600101546104f781610ef6565b6105018383610f03565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610556576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105608282610fff565b505050565b60608167ffffffffffffffff8111156105805761058061208c565b6040519080825280602002602001820160405280156105d757816020015b6105c4604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161059e5790505b50905060005b82811015610636576106118484838181106105fa576105fa6120bb565b905060200281019061060c91906120ea565b6110ba565b828281518110610623576106236120bb565b60209081029190910101526001016105dd565b5092915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561066781610ef6565b60005b838110156106f6576000858583818110610686576106866120bb565b90506040020180360381019061069c91906121cc565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200151036106da5780516106d59085611250565b6106ed565b6106ed8160000151826020015186611327565b5060010161066a565b5050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561072781610ef6565b6040517f560c649900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169063560c64999061077d90879087908790600401612206565b600060405180830381600087803b15801561079757600080fd5b505af11580156107ab573d6000803e3d6000fd5b505050505050505050565b6040805160008152602081019091526060908267ffffffffffffffff8111156107e1576107e161208c565b60405190808252806020026020018201604052801561081457816020015b60608152602001906001900390816107ff5790505b50915060005b838110156108965761087130868684818110610838576108386120bb565b905060200281019061084a91906120ea565b8560405160200161085d939291906122c5565b6040516020818303038152906040526113c3565b838281518110610883576108836120bb565b602090810291909101015260010161081a565b505092915050565b60005a90506000803073ffffffffffffffffffffffffffffffffffffffff1685856040516108cd9291906122ec565b600060405180830381855af49150503d8060008114610908576040519150601f19603f3d011682016040523d82523d6000602084013e61090d565b606091505b509150915060005a61091f908561228b565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161097191906122fc565b60405180910390fd5b60008281526020819052604090206001015461099581610ef6565b6105018383610fff565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109c981610ef6565b610560838361143d565b60608167ffffffffffffffff8111156109ee576109ee61208c565b604051908082528060200260200182016040528015610a5957816020015b610a466040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b815260200190600190039081610a0c5790505b50905060005b82811015610bf8576000848483818110610a7b57610a7b6120bb565b9050602002016020810190610a90919061230f565b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff80841680835292517fc67e32e900000000000000000000000000000000000000000000000000000000815260048101939093529293509160208301919089169063c67e32e990602401602060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b39919061232c565b81526040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260209091019073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610bab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcf919061232c565b815250838381518110610be457610be46120bb565b602090810291909101015250600101610a5f565b509392505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610c2a81610ef6565b60005b610c378380612345565b9050811015610c8f576000610c4c8480612345565b83818110610c5c57610c5c6120bb565b905060400201803603810190610c7291906123ad565b9050610c86816000015182602001516114e8565b50600101610c2d565b5060005b610ca060408401846123ee565b9050811015610d5b576000610cb86060850185612345565b83818110610cc857610cc86120bb565b905060400201803603810190610cde9190612456565b9050610d52610cf060208601866123ee565b835160ff16818110610d0457610d046120bb565b9050602002016020810190610d19919061230f565b610d2660408701876123ee565b85818110610d3657610d366120bb565b9050602002810190610d4891906120ea565b846020015161152d565b50600101610c93565b5060005b610d6c6080840184612345565b9050811015610560576000610d846080850185612345565b83818110610d9457610d946120bb565b905060400201803603810190610daa91906123ad565b9050610dbe81600001518260200151611250565b50600101610d5f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806104d657507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104d657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104d6565b610f008133611585565b50565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ff75760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610f953390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104d6565b5060006104d6565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ff75760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104d6565b6110e0604051806060016040528060001515815260200160608152602001600081525090565b6000803073ffffffffffffffffffffffffffffffffffffffff1663bcbef20660e01b8686604051602401611115929190612481565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161118091906124b0565b600060405180830381855af49150503d80600081146111bb576040519150601f19603f3d011682016040523d82523d6000602084013e6111c0565b606091505b5091509150811561122d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c65642100000000000000006044820152606401610971565b6004810190508080602001905181019061124791906124e1565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611316576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156112ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611311919061232c565b611318565b475b90508015610560576105608382845b73ffffffffffffffffffffffffffffffffffffffff81166113455750335b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016113a25761056073ffffffffffffffffffffffffffffffffffffffff82168361160b565b61056073ffffffffffffffffffffffffffffffffffffffff841682846116e1565b60606000808473ffffffffffffffffffffffffffffffffffffffff16846040516113ed91906124b0565b600060405180830381855af49150503d8060008114611428576040519150601f19603f3d011682016040523d82523d6000602084013e61142d565b606091505b5091509150611247858383611762565b60005b8181101561056057600083838381811061145c5761145c6120bb565b905060200281019061146e91906125b5565b611477906125e9565b905060005b8160200151518110156114de576114d682600001516000846020015184815181106114a9576114a96120bb565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166117f49092919063ffffffff16565b60010161147c565b5050600101611440565b61152973ffffffffffffffffffffffffffffffffffffffff8316827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6117f4565b5050565b6106f683838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505073ffffffffffffffffffffffffffffffffffffffff8716919050836118cc565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611529576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610971565b80471015611647576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610971565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146116a1576040519150601f19603f3d011682016040523d82523d6000602084013e6116a6565b606091505b5050905080610560576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261056091859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061198f565b6060826117775761177282611a25565b6117ed565b815115801561179b575073ffffffffffffffffffffffffffffffffffffffff84163b155b156117ea576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610971565b50805b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526118808482611a67565b6105015760405173ffffffffffffffffffffffffffffffffffffffff8481166024830152600060448301526118c291869182169063095ea7b39060640161171b565b610501848261198f565b60608147101561190a576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610971565b6000808573ffffffffffffffffffffffffffffffffffffffff16848660405161193391906124b0565b60006040518083038185875af1925050503d8060008114611970576040519150601f19603f3d011682016040523d82523d6000602084013e611975565b606091505b5091509150611985868383611762565b9695505050505050565b60006119b173ffffffffffffffffffffffffffffffffffffffff841683611b24565b905080516000141580156119d65750808060200190518101906119d491906126b8565b155b15610560576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610971565b805115611a355780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008473ffffffffffffffffffffffffffffffffffffffff1684604051611a9191906124b0565b6000604051808303816000865af19150503d8060008114611ace576040519150601f19603f3d011682016040523d82523d6000602084013e611ad3565b606091505b5091509150818015611afd575080511580611afd575080806020019051810190611afd91906126b8565b801561124757505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b60606117ed838360006118cc565b600060208284031215611b4457600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146117ed57600080fd5b600060208284031215611b8657600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f0057600080fd5b60008060408385031215611bc257600080fd5b823591506020830135611bd481611b8d565b809150509250929050565b60008060408385031215611bf257600080fd5b8235611bfd81611b8d565b91506020830135611bd481611b8d565b60008083601f840112611c1f57600080fd5b50813567ffffffffffffffff811115611c3757600080fd5b6020830191508360208260051b8501011115611c5257600080fd5b9250929050565b60008060208385031215611c6c57600080fd5b823567ffffffffffffffff811115611c8357600080fd5b611c8f85828601611c0d565b90969095509350505050565b60005b83811015611cb6578181015183820152602001611c9e565b50506000910152565b60008151808452611cd7816020860160208601611c9b565b601f01601f19169290920160200192915050565b8051151582526000602082015160606020850152611d0c6060850182611cbf565b604093840151949093019390935250919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611d95577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611d83858351611ceb565b94509285019290850190600101611d49565b5092979650505050505050565b60008083601f840112611db457600080fd5b50813567ffffffffffffffff811115611dcc57600080fd5b6020830191508360208260061b8501011115611c5257600080fd5b600080600060408486031215611dfc57600080fd5b833567ffffffffffffffff811115611e1357600080fd5b611e1f86828701611da2565b9094509250506020840135611e3381611b8d565b809150509250925092565b60008060008060608587031215611e5457600080fd5b8435611e5f81611b8d565b9350602085013567ffffffffffffffff811115611e7b57600080fd5b611e8787828801611da2565b9094509250506040850135611e9b81611b8d565b939692955090935050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015611d95577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611f09858351611cbf565b94509285019290850190600101611ecf565b60008060208385031215611f2e57600080fd5b823567ffffffffffffffff80821115611f4657600080fd5b818501915085601f830112611f5a57600080fd5b813581811115611f6957600080fd5b866020828501011115611f7b57600080fd5b60209290920196919550909350505050565b600080600060408486031215611fa257600080fd5b8335611fad81611b8d565b9250602084013567ffffffffffffffff811115611fc957600080fd5b611fd586828701611c0d565b9497909650939450505050565b602080825282518282018190526000919060409081850190868401855b82811015612044578151805173ffffffffffffffffffffffffffffffffffffffff16855286810151878601528501518585015260609093019290850190600101611fff565b5091979650505050505050565b60006020828403121561206357600080fd5b813567ffffffffffffffff81111561207a57600080fd5b820160a081850312156117ed57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261211f57600080fd5b83018035915067ffffffffffffffff82111561213a57600080fd5b602001915036819003821315611c5257600080fd5b6040805190810167ffffffffffffffff811182821017156121725761217261208c565b60405290565b6040516060810167ffffffffffffffff811182821017156121725761217261208c565b604051601f8201601f1916810167ffffffffffffffff811182821017156121c4576121c461208c565b604052919050565b6000604082840312156121de57600080fd5b6121e661214f565b82356121f181611b8d565b81526020928301359281019290925250919050565b60408082528181018490526000908560608401835b8781101561226057823561222e81611b8d565b73ffffffffffffffffffffffffffffffffffffffff16825260208381013590830152918301919083019060010161221b565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818103818111156104d6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8284823760008382016000815283516122e2818360208801611c9b565b0195945050505050565b8183823760009101908152919050565b6020815260006117ed6020830184611ceb565b60006020828403121561232157600080fd5b81356117ed81611b8d565b60006020828403121561233e57600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261237a57600080fd5b83018035915067ffffffffffffffff82111561239557600080fd5b6020019150600681901b3603821315611c5257600080fd5b6000604082840312156123bf57600080fd5b6123c761214f565b82356123d281611b8d565b815260208301356123e281611b8d565b60208201529392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261242357600080fd5b83018035915067ffffffffffffffff82111561243e57600080fd5b6020019150600581901b3603821315611c5257600080fd5b60006040828403121561246857600080fd5b61247061214f565b823560ff811681146121f157600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082516124c2818460208701611c9b565b9190910192915050565b805180151581146124dc57600080fd5b919050565b600060208083850312156124f457600080fd5b825167ffffffffffffffff8082111561250c57600080fd5b908401906060828703121561252057600080fd5b612528612178565b612531836124cc565b8152838301518281111561254457600080fd5b8301601f8101881361255557600080fd5b8051838111156125675761256761208c565b61257986601f19601f8401160161219b565b9350808452888682840101111561258f57600080fd5b61259e81878601888501611c9b565b505092830152604090810151908201529392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126124c257600080fd5b6000604082360312156125fb57600080fd5b61260361214f565b823561260e81611b8d565b815260208381013567ffffffffffffffff8082111561262c57600080fd5b9085019036601f83011261263f57600080fd5b8135818111156126515761265161208c565b8060051b915061266284830161219b565b818152918301840191848101903684111561267c57600080fd5b938501935b838510156126a6578435925061269683611b8d565b8282529385019390850190612681565b94860194909452509295945050505050565b6000602082840312156126ca57600080fd5b6117ed826124cc56
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
-----Decoded View---------------
Arg [0] : _superAdmin (address): 0xEC864BE26084ba3bbF3cAAcF8F6961A9263319C4
Arg [1] : _initialAdmins (address[]): 0xEC864BE26084ba3bbF3cAAcF8F6961A9263319C4
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Loading...
Loading
Loading...
Loading
Net Worth in USD
$278.89
Net Worth in ETH
0.137207
Token Allocations
LUSD
35.81%
MIMATIC
16.34%
SUSD
13.38%
Others
34.47%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ARB | 17.91% | $1.02 | 49.077 | $49.96 | |
| ARB | 11.41% | $2.4 | 13.2594 | $31.82 | |
| ARB | 10.70% | $0.937082 | 31.8398 | $29.84 | |
| ARB | 3.85% | $1 | 10.7182 | $10.74 | |
| ARB | 0.84% | $0.994846 | 2.355 | $2.34 | |
| ARB | 0.29% | $1.89 | 0.4286 | $0.8099 | |
| ARB | 0.26% | $0.046603 | 15.334 | $0.7146 | |
| ARB | 0.13% | $0.001767 | 210.771 | $0.3723 | |
| ARB | 0.05% | $2.59 | 0.0488 | $0.1263 | |
| OP | 17.89% | $1.02 | 49.0711 | $49.91 | |
| OP | 13.38% | $0.814253 | 45.8399 | $37.33 | |
| OP | 0.06% | $0.136438 | 1.3037 | $0.1778 | |
| POL | 16.34% | $1 | 45.467 | $45.56 | |
| POL | 6.15% | $1.18 | 14.5331 | $17.15 | |
| POL | 0.09% | $0.025882 | 9.4677 | $0.245 | |
| BSC | 0.49% | $1 | 1.3744 | $1.38 | |
| BASE | 0.15% | $0.000001 | 740,000 | $0.4299 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.