More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set DNA Router A... | 10924550 | 48 days ago | IN | 0 ETH | 0 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
13039057 | 33 mins ago | 0 ETH | ||||
13039057 | 33 mins ago | 0 ETH | ||||
13038856 | 40 mins ago | 0.00003292 ETH | ||||
13038856 | 40 mins ago | 0.00003292 ETH | ||||
13037581 | 1 hr ago | 0 ETH | ||||
13037581 | 1 hr ago | 0 ETH | ||||
13035626 | 2 hrs ago | 0 ETH | ||||
13035626 | 2 hrs ago | 0 ETH | ||||
13032982 | 3 hrs ago | 0.00003125 ETH | ||||
13032982 | 3 hrs ago | 0.00003125 ETH | ||||
13032452 | 4 hrs ago | 0 ETH | ||||
13032452 | 4 hrs ago | 0 ETH | ||||
13031629 | 4 hrs ago | 0.00003308 ETH | ||||
13031629 | 4 hrs ago | 0.00003308 ETH | ||||
13030748 | 5 hrs ago | 0.00000024 ETH | ||||
13030748 | 5 hrs ago | 0.00000024 ETH | ||||
13027327 | 7 hrs ago | 0.00000019 ETH | ||||
13027327 | 7 hrs ago | 0.00000019 ETH | ||||
13027199 | 7 hrs ago | 0.00000002 ETH | ||||
13027199 | 7 hrs ago | 0.00000002 ETH | ||||
13025669 | 8 hrs ago | 0.00000006 ETH | ||||
13025669 | 8 hrs ago | 0.00000006 ETH | ||||
13025180 | 8 hrs ago | 0.00003362 ETH | ||||
13025180 | 8 hrs ago | 0.00003362 ETH | ||||
13024747 | 8 hrs ago | 0.00003027 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DNAController
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 65535 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity 0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "./DNARouter.sol"; import "./BaseAggregator.sol"; import { Permit2, Permit2Helper } from "./Permit2Helper.sol"; import "./lib/Common.sol"; contract DNAController is Ownable, Permit2Helper { DNARouter public dnaRouter; address public dnaTokenAddr; // Mapping to track taxable tokens mapping(address => bool) public isTaxable; // Errors error ZeroAddress(); error InvalidFeePercent(); error InvalidFeeToken(); error InvalidTokenAddresses(); error InvalidTaxableTokens(); error InvalidFeeAmount(); /// @dev Constructor to set the base aggregator contract address /// @param _dnaRouter Address of the BaseAggregator contract constructor(ISignatureTransfer permit2, DNARouter _dnaRouter, address _dnaTokenAddr) Ownable(_msgSender()) Permit2Helper(permit2) { dnaRouter = _dnaRouter; dnaTokenAddr = _dnaTokenAddr; isTaxable[_dnaTokenAddr] = true; } // Configure taxable tokens function setTaxableToken(address _tokenAddr, bool _taxable) external onlyOwner { if (_tokenAddr == address(0)) { revert ZeroAddress(); } isTaxable[_tokenAddr] = _taxable; } function isTaxableToken(address _tokenAddr) public view returns (bool) { return isTaxable[_tokenAddr]; } // set DNA Router Address function setDNARouterAddress(DNARouter _dnaRouter) external onlyOwner { require (address(_dnaRouter) != address(0), "ZeroAddress"); dnaRouter = _dnaRouter; } /// @notice Executes the respective swap function in the BaseAggregator based on input parameters function executeSwap( Common.ExecuteSwapParam memory executeSwapParam ) external payable { // validations // should be called only in taxable Tokens if (!isTaxable[executeSwapParam.sellTokenAddress] && !isTaxable[executeSwapParam.buyTokenAddress]) { revert InvalidTaxableTokens(); } if (executeSwapParam.sellTokenAddress == address(dnaTokenAddr) || executeSwapParam.buyTokenAddress == address(dnaTokenAddr)) { executeSwapParam.feeAmount = 0; } if (executeSwapParam.sellTokenAddress != address(0)) { address recipient = address(dnaRouter); uint256 sellTokenBalanceBefore; uint256 transferredSellAmount = executeSwapParam.sellAmount; if (isTaxable[executeSwapParam.sellTokenAddress]) { recipient = address(this); sellTokenBalanceBefore = ERC20(executeSwapParam.sellTokenAddress).balanceOf(address(this)); } // Use Permit2 for token approval and transfer permit2.permitTransferFrom( ISignatureTransfer.PermitTransferFrom({ permitted: ISignatureTransfer.TokenPermissions({ token: executeSwapParam.sellTokenAddress, amount: executeSwapParam.sellAmount }), nonce: executeSwapParam.permit.nonce, deadline: executeSwapParam.permit.deadline }), ISignatureTransfer.SignatureTransferDetails({ to: recipient, requestedAmount: executeSwapParam.sellAmount }), msg.sender, executeSwapParam.permit.signature ); // Todo: testnet // ERC20(executeSwapParam.sellTokenAddress).transferFrom(msg.sender, recipient, executeSwapParam.sellAmount); // If taxable, transfer remaining balance to dnaRouter if (isTaxable[executeSwapParam.sellTokenAddress]) { transferredSellAmount = ERC20(executeSwapParam.sellTokenAddress).balanceOf(address(this)) - sellTokenBalanceBefore; if (transferredSellAmount > 0) { SafeTransferLib.safeTransfer( ERC20(executeSwapParam.sellTokenAddress), address(dnaRouter), transferredSellAmount ); } } // If both sellToken and buyToken are specified, call token-to-token function if (executeSwapParam.buyTokenAddress != address(0)) { // Track buy token balance before the swap uint256 buyTokenBalanceBefore = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); executeSwapParam.sellAmount = transferredSellAmount; if (executeSwapParam.intermediateTokenAddress == address(0)) { dnaRouter.fillQuoteTokenToToken( executeSwapParam, msg.sender ); } else { dnaRouter.fillQuoteTokenToTokenViaToken( executeSwapParam, msg.sender ); } // If taxable, transfer remaining balance to dnaRouter if (isTaxable[executeSwapParam.buyTokenAddress] ) { // Calculate the actual tokens received from the swap and transfer swapped buytoken back to userAddress uint256 receivedBuyTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)) - buyTokenBalanceBefore; if (receivedBuyTokenAmount > 0) { SafeTransferLib.safeTransfer( ERC20(executeSwapParam.buyTokenAddress), address(msg.sender), receivedBuyTokenAmount ); } } } else { // If buyToken is address(0), call token-to-ETH function // feeToken will be 5e15 for 0.5% dnaRouter.fillQuoteTokenToEth( executeSwapParam.sellTokenAddress, executeSwapParam.target, executeSwapParam.swapCallData, transferredSellAmount, executeSwapParam.feeAmount, msg.sender, executeSwapParam.permit ); } } else { // Track buy token balance before the swap uint256 buyTokenBalanceBefore = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); // If sellToken is address(0), call ETH-to-token function dnaRouter.fillQuoteEthToToken{value: msg.value}( executeSwapParam.buyTokenAddress, executeSwapParam.target, executeSwapParam.swapCallData, executeSwapParam.feeAmount, msg.sender ); // Calculate the actual tokens received from the swap and transfer swapped buytoken back to userAddress uint256 receivedBuyTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)) - buyTokenBalanceBefore; if (receivedBuyTokenAmount > 0) { SafeTransferLib.safeTransfer( ERC20(executeSwapParam.buyTokenAddress), address(msg.sender), receivedBuyTokenAmount ); } } } receive() external payable {} /// @dev method to withdraw ERC20 tokens (from the fees) /// @param token address of the token to withdraw /// @param to address that's receiving the tokens /// @param amount amount of tokens to withdraw function withdrawToken(address token, address to, uint256 amount) external onlyOwner { require(to != address(0), "ZERO_ADDRESS"); SafeTransferLib.safeTransfer(ERC20(token), to, amount); } /// @dev method to withdraw ETH (from the fees) /// @param to address that's receiving the ETH /// @param amount amount of ETH to withdraw function withdrawEth(address to, uint256 amount) external onlyOwner { require(to != address(0), "ZERO_ADDRESS"); SafeTransferLib.safeTransferETH(to, amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// 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.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
//SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol"; import { ERC20 } from "solmate/src/tokens/ERC20.sol"; import { Permit2, Permit2Helper } from "./Permit2Helper.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import { ISignatureTransfer } from "./interfaces/ISignatureTransfer.sol"; import { IDNAController } from "./interfaces/IDNAController.sol"; import { IWETH } from "./interfaces/IWETH.sol"; import "./interfaces/IUniswapV2Router02.sol"; import "./interfaces/IUniswapV3Router02.sol"; import "./interfaces/IDNAStaking.sol"; import "./lib/Common.sol"; contract BaseAggregator is Permit2Helper, ReentrancyGuard { // Struct to store token data struct TokenData { bool isAllowed; uint256 balance; } // dnaController Address address public dnaController; // UniswapV2 Router Address address public uniswapV2RouterAddr; // UniswapV2 Router Address address public uniswapV3RouterAddr; // dna Staking contract address address public dnaStakingAddr; // company wallet address address public companyWalletAddr; // amount of weth as threshold for staking reward distribution (0.1 WETH) // Todo: // uint256 public stakingRewardThreshold = 10**6; uint256 public stakingRewardThreshold = 10**17; // e.g. for 0.2%, value should be 20. For 20%, value should be 2000 uint16 public companyFeePercentage; uint256 public fixedTokenAmount = 1000000; // Store the fee balances and isAllowed for the tracked assets to distribute as staking reward mapping(address => TokenData) public feeTokenData; event FillQuoteTokenToToken( address indexed sellToken, address indexed buyToken, address indexed user, address target, uint256 amountSold, uint256 amountBought, FeeToken feeToken, uint256 feeAmount ); event FillQuoteTokenToEth( address indexed sellToken, address indexed user, address target, uint256 amountSold, uint256 amountBought, uint256 feeAmount ); event FillQuoteEthToToken( address indexed buyToken, address indexed user, address target, uint256 amountSold, uint256 amountBought, uint256 feeAmount ); event FillQuoteTokenToTokenViaToken( address indexed sellToken, address indexed intermediateToken, address indexed buyToken, address user, address target, address nextTarget, uint256 amountSold, uint256 amountBought, FeeToken feeToken, uint256 feeAmount ); event StakeTriggered( address indexed feeToken, uint256 distributionAmount, uint256 companyFeeAmount ); /// @dev Set of allowed swapTargets. mapping(address => bool) public swapTargets; /// @dev modifier that ensures only approved targets can be called modifier onlyApprovedTarget(address target) { require(swapTargets[target], "TARGET_NOT_AUTH"); _; } constructor(ISignatureTransfer permit2) Permit2Helper(permit2) { } /// @param buyTokenAddress the address of token that the user should receive /// @param target the address of the aggregator contract that will exec the swap /// @param swapCallData the memory that will be passed to the aggregator contract /// @param feeAmount the amount of ETH that we will take as a fee /// @param userAddress the address in which at last swapped token need to transfer function fillQuoteEthToToken( address buyTokenAddress, address payable target, bytes memory swapCallData, uint256 feeAmount, address userAddress ) external payable nonReentrant onlyApprovedTarget(target) { // Validations if (msg.sender == dnaController) { require( ( IDNAController(dnaController).isTaxableToken(buyTokenAddress) ), "Unauthorized" ); } else { require( ( !IDNAController(dnaController).isTaxableToken(buyTokenAddress) ), "Unauthorized" ); } // 1 - Get the initial balances uint256 initialTokenBalance = ERC20(buyTokenAddress).balanceOf(address(this)); uint256 initialEthAmount = address(this).balance - msg.value; uint256 sellAmount = msg.value - feeAmount; // 2 - Call the encoded swap function call on the contract at `target`, // passing along any ETH attached to this function call to cover protocol fees // minus our fees, which are kept in this contract _performSwap(target, swapCallData, sellAmount); // 3 - Make sure we received the tokens uint256 finalTokenBalance = ERC20(buyTokenAddress).balanceOf(address(this)); require(initialTokenBalance < finalTokenBalance, "NO_TOKENS"); // 4 - Send the received tokens back to the user uint256 tokensToSend = finalTokenBalance - initialTokenBalance; address toAddr = IDNAController(dnaController).isTaxableToken(buyTokenAddress) ? dnaController : userAddress; SafeTransferLib.safeTransfer(ERC20(buyTokenAddress), toAddr, tokensToSend); // 5 - Return the remaining ETH to the user (if any) { uint256 finalEthAmount = address(this).balance - feeAmount; if (finalEthAmount > initialEthAmount) { uint256 ethDiff = finalEthAmount - initialEthAmount; SafeTransferLib.safeTransferETH(userAddress, ethDiff); sellAmount -= ethDiff; // We don't want to include refund amount in the sellAmount when emitting event } } emit FillQuoteEthToToken(buyTokenAddress, target, userAddress, sellAmount, tokensToSend, feeAmount); } function fillQuoteTokenToToken( Common.ExecuteSwapParam calldata executeSwapParam, address userAddress ) external payable nonReentrant onlyApprovedTarget(executeSwapParam.target) { require(executeSwapParam.intermediateTokenAddress == address(0), "INVALID_INTERMEDIATE_TOKEN"); // 1 - Get the initial output token balance uint256 initialOutputTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); // 2 - Move the tokens to this contract (which includes our fees) if (msg.sender == dnaController) { // Validations require( ( IDNAController(dnaController).isTaxableToken(executeSwapParam.sellTokenAddress) || IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress) ), "Unauthorized" ); } else { require( ( (!IDNAController(dnaController).isTaxableToken(executeSwapParam.sellTokenAddress) && !IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress)) ), "Unauthorized" ); executePermitTransfer(executeSwapParam.sellTokenAddress, executeSwapParam.sellAmount, executeSwapParam.permit); } // 3 - Approve the aggregator's contract to swap the tokens if needed uint256 tokensToSwap = executeSwapParam.feeToken == FeeToken.INPUT ? executeSwapParam.sellAmount - executeSwapParam.feeAmount : executeSwapParam.sellAmount; SafeTransferLib.safeApprove(ERC20(executeSwapParam.sellTokenAddress), executeSwapParam.target, tokensToSwap); // 4 - Call the encoded swap function call on the contract at `target`, _performSwap(executeSwapParam.target, executeSwapParam.swapCallData, msg.value); // 5 - Check that the tokens were fully spent during the swap uint256 allowance = ERC20(executeSwapParam.sellTokenAddress).allowance(address(this), executeSwapParam.target); require(allowance == 0, "ALLOWANCE_NOT_ZERO"); // 6 - Make sure we received the tokens uint256 finalOutputTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); require(initialOutputTokenAmount < finalOutputTokenAmount, "NO_TOKENS"); // 7 - Send tokens to the user uint256 tokensDiff = finalOutputTokenAmount - initialOutputTokenAmount; uint256 tokensToSend = executeSwapParam.feeToken == FeeToken.OUTPUT ? tokensDiff - executeSwapParam.feeAmount : tokensDiff; // Process collected fee as staking reward address feeTokenAddr = executeSwapParam.feeToken == FeeToken.INPUT ? executeSwapParam.sellTokenAddress : executeSwapParam.buyTokenAddress; if (executeSwapParam.feeAmount > 0 && feeTokenData[feeTokenAddr].isAllowed) { checkStakeForDistribution(feeTokenAddr, executeSwapParam.feeAmount); } address toAddr = IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress) ? dnaController : userAddress; SafeTransferLib.safeTransfer(ERC20(executeSwapParam.buyTokenAddress), toAddr, tokensToSend); emit FillQuoteTokenToToken( executeSwapParam.sellTokenAddress, executeSwapParam.buyTokenAddress, userAddress, executeSwapParam.target, tokensToSwap, tokensToSend, executeSwapParam.feeToken, executeSwapParam.feeAmount ); } /// @dev method that executes ERC20 to ETH token swaps with the ability to take a fee from the output /// @param sellTokenAddress the address of token that the user is selling /// @param target the address of the aggregator contract that will exec the swap /// @param swapCallData the memory that will be passed to the aggregator contract /// @param sellAmount the amount of tokens that the user is selling /// @param feePercentage the amount of ETH that we will take as a fee with 1e18 precision /// @param userAddress the address in which at last swapped token need to transfer /// @param permit struct containing the nonce, deadline, v, r and s values of the permit data function fillQuoteTokenToEth( address sellTokenAddress, address payable target, bytes memory swapCallData, uint256 sellAmount, uint256 feePercentage, address userAddress, Permit2 memory permit ) external payable nonReentrant onlyApprovedTarget(target) { // 1 - Get the initial ETH amount uint256 initialEthAmount = address(this).balance - msg.value; address wethAddr = IUniswapV2Router02(uniswapV2RouterAddr).WETH(); uint256 initialWethBalance = ERC20(wethAddr).balanceOf(address(this)); // 2 - Move the tokens to this contract if (msg.sender == dnaController) { // Validations require( ( IDNAController(dnaController).isTaxableToken(sellTokenAddress) ), "Unauthorized" ); } else { require( ( !IDNAController(dnaController).isTaxableToken(sellTokenAddress) ), "Unauthorized" ); executePermitTransfer(sellTokenAddress, sellAmount, permit); } // 3 - Approve the aggregator's contract to swap the tokens SafeTransferLib.safeApprove(ERC20(sellTokenAddress), target, sellAmount); // 4 - Call the encoded swap function call on the contract at `target`, _performSwap(target, swapCallData, msg.value); // 5 - Check that the tokens were fully spent during the swap uint256 allowance = ERC20(sellTokenAddress).allowance(address(this), target); require(allowance == 0, "ALLOWANCE_NOT_ZERO"); // 6 - Convert only the newly received WETH to ETH if (target == uniswapV3RouterAddr) { uint256 wethReceived = ERC20(wethAddr).balanceOf(address(this)) - initialWethBalance; if (wethReceived > 0) { IWETH(wethAddr).withdraw(wethReceived); // Unwrap only the received WETH to ETH } } // 7 - Subtract the fees and send the rest to the user // Fees will be held in this contract uint256 finalEthAmount = address(this).balance; uint256 ethDiff = finalEthAmount - initialEthAmount; require(ethDiff > 0, "NO_ETH_BACK"); uint256 fees; uint256 ethToSend; if (feePercentage > 0 && sellTokenAddress != IDNAController(dnaController).dnaTokenAddr()) { fees = (ethDiff * feePercentage) / 1e18; ethToSend = ethDiff - fees; SafeTransferLib.safeTransferETH(userAddress, ethToSend); // when there's no fee, 1inch sends the funds directly to the user // we check to prevent sending 0 ETH in that case } else if (ethDiff > 0) { ethToSend = ethDiff; SafeTransferLib.safeTransferETH(userAddress, ethToSend); } emit FillQuoteTokenToEth(sellTokenAddress, userAddress, target, sellAmount, ethToSend, fees); } function fillQuoteTokenToTokenViaToken( Common.ExecuteSwapParam calldata executeSwapParam, address userAddress ) external payable nonReentrant { require(executeSwapParam.intermediateTokenAddress != address(0), "INVALID_INTERMEDIATE_TOKEN"); require(!IDNAController(dnaController).isTaxableToken(executeSwapParam.intermediateTokenAddress),"Unauthorized"); // 1 - Get the initial output token balance uint256 initialOutputTokenAmount = ERC20(executeSwapParam.intermediateTokenAddress).balanceOf(address(this)); // 2 - Move the tokens to this contract (which includes our fees) if (msg.sender == dnaController) { // Validations require( ( IDNAController(dnaController).isTaxableToken(executeSwapParam.sellTokenAddress) || IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress) ), "Unauthorized" ); } else { require( ( (!IDNAController(dnaController).isTaxableToken(executeSwapParam.sellTokenAddress) && !IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress)) ), "Unauthorized" ); executePermitTransfer(executeSwapParam.sellTokenAddress, executeSwapParam.sellAmount, executeSwapParam.permit); } // 3 - Approve the aggregator's contract to swap the tokens if needed uint256 tokensToSwap = executeSwapParam.feeToken == FeeToken.INPUT ? executeSwapParam.sellAmount - executeSwapParam.feeAmount : executeSwapParam.sellAmount; SafeTransferLib.safeApprove(ERC20(executeSwapParam.sellTokenAddress), executeSwapParam.target, tokensToSwap); // 4 - Call the encoded swap function call on the contract at `target`, _performSwap(executeSwapParam.target, executeSwapParam.swapCallData, msg.value); // 5 - Check that the tokens were fully spent during the swap uint256 allowance = ERC20(executeSwapParam.sellTokenAddress).allowance(address(this), executeSwapParam.target); require(allowance == 0, "ALLOWANCE_NOT_ZERO"); // 6 - Make sure we received the tokens uint256 finalOutputTokenAmount = ERC20(executeSwapParam.intermediateTokenAddress).balanceOf(address(this)); require(initialOutputTokenAmount < finalOutputTokenAmount, "NO_TOKENS"); // 7 - Send tokens to the user uint256 tokensDiff = finalOutputTokenAmount - initialOutputTokenAmount; uint256 tokensToSend = executeSwapParam.feeToken == FeeToken.OUTPUT ? tokensDiff - executeSwapParam.feeAmount : tokensDiff; // Process collected fee as staking reward address feeTokenAddr = executeSwapParam.feeToken == FeeToken.INPUT ? executeSwapParam.sellTokenAddress : executeSwapParam.buyTokenAddress; if (executeSwapParam.feeAmount > 0 && feeTokenData[feeTokenAddr].isAllowed) { checkStakeForDistribution(feeTokenAddr, executeSwapParam.feeAmount); } // second swap // 8 - create SwapCallData for the next swap address routerAddress = executeSwapParam.target == uniswapV2RouterAddr ? uniswapV3RouterAddr : uniswapV2RouterAddr; bytes memory nextSwapCallData = createSwapCallData( routerAddress, executeSwapParam.pathV2, executeSwapParam.pathV3, tokensToSend ); // 9 - Get the initial output token balance initialOutputTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); // 10 - Approve the aggregator's contract to swap the tokens if needed address nextTarget = executeSwapParam.target == uniswapV2RouterAddr ? uniswapV3RouterAddr : uniswapV2RouterAddr; SafeTransferLib.safeApprove(ERC20(executeSwapParam.intermediateTokenAddress), nextTarget, tokensToSend); // 11 - Call the encoded swap function call on the contract at `target`, _performSwap(nextTarget, nextSwapCallData, msg.value); // 12 - Check that the tokens were fully spent during the swap allowance = ERC20(executeSwapParam.intermediateTokenAddress).allowance(address(this), nextTarget); require(allowance == 0, "ALLOWANCE_NOT_ZERO"); // 13 - Make sure we received the tokens finalOutputTokenAmount = ERC20(executeSwapParam.buyTokenAddress).balanceOf(address(this)); require(initialOutputTokenAmount < finalOutputTokenAmount, "NO_TOKENS"); tokensDiff = finalOutputTokenAmount - initialOutputTokenAmount; tokensToSend = tokensDiff; // 14 - Send tokens to the user address toAddr = IDNAController(dnaController).isTaxableToken(executeSwapParam.buyTokenAddress) ? dnaController : userAddress; SafeTransferLib.safeTransfer(ERC20(executeSwapParam.buyTokenAddress), toAddr, tokensToSend); emit FillQuoteTokenToTokenViaToken( executeSwapParam.sellTokenAddress, executeSwapParam.intermediateTokenAddress, executeSwapParam.buyTokenAddress, userAddress, executeSwapParam.target, nextTarget, tokensToSwap, tokensToSend, executeSwapParam.feeToken, executeSwapParam.feeAmount ); } function createSwapCallData( address routerAddress, address[] memory pathV2, bytes memory pathV3, uint256 amountIn ) public view returns (bytes memory) { if (routerAddress == uniswapV3RouterAddr) { // Create swapCallData for V3 router IUniswapV3Router02.ExactInputParams memory params = IUniswapV3Router02.ExactInputParams({ path: pathV3, recipient: address(this), amountIn: amountIn, amountOutMinimum: 0 }); return abi.encodeWithSelector( IUniswapV3Router02.exactInput.selector, params ); } else { // Create swapCallData for V2 router return abi.encodeWithSelector( IUniswapV2Router02.swapExactTokensForTokensSupportingFeeOnTransferTokens.selector, amountIn, 0, pathV2, address(this), block.timestamp + 5 minutes ); } } function executePermitTransfer( address token, uint256 amount, Permit2 memory permit ) internal { permit2.permitTransferFrom( ISignatureTransfer.PermitTransferFrom({ permitted: ISignatureTransfer.TokenPermissions({ token: token, amount: amount }), nonce: permit.nonce, deadline: permit.deadline }), ISignatureTransfer.SignatureTransferDetails({ to: address(this), requestedAmount: amount }), msg.sender, permit.signature ); // Todo: testnet // ERC20(token).transferFrom(msg.sender, address(this), amount); } // Function to trigger reward distribution in Staking contract function checkStakeForDistribution(address feeToken, uint256 feeAmount) internal { feeTokenData[feeToken].balance += feeAmount; uint256 companyFeeAmount = (feeTokenData[feeToken].balance * companyFeePercentage) / 10000; // 20% for company uint256 distributionAmount = feeTokenData[feeToken].balance - companyFeeAmount; // 80% for stake Reward // need to check buy calling getAmountsOut to get the output in weth uint256 feeInWETHToken = feeToken == IUniswapV2Router02(uniswapV2RouterAddr).WETH() ? distributionAmount : getFeesInWETHFromToken(feeToken, feeTokenData[feeToken].balance); // Check if buyback condition is met if (feeInWETHToken >= stakingRewardThreshold) { ERC20(feeToken).approve(dnaStakingAddr, distributionAmount); // distribute the reward in staking IDNAStaking(dnaStakingAddr).notifyRewardAmount(feeToken, distributionAmount); // Check that the tokens were fully distibuted in staking uint256 allowance = ERC20(feeToken).allowance(address(this), dnaStakingAddr); require(allowance == 0, "ALLOWANCE_NOT_ZERO"); feeTokenData[feeToken].balance = 0; SafeTransferLib.safeTransfer(ERC20(feeToken), companyWalletAddr, companyFeeAmount); emit StakeTriggered(feeToken, distributionAmount, companyFeeAmount); } } // Function to get the equivalent Weth value for a given fee token function getFeesInWETHFromToken(address tokenAddress, uint256 tokenAmount) internal view returns (uint256) { // Fetch the price of the fee token in WETH via fixed amount uint[] memory tokenPriceInWETH = IUniswapV2Router02(uniswapV2RouterAddr).getAmountsOut( fixedTokenAmount, getPathForTokenToWETH(tokenAddress) ); // The equivalent WETH value for the fee amount return (tokenPriceInWETH[1]*tokenAmount)/fixedTokenAmount; } function getPathForTokenToWETH(address tokenAddress) internal view returns (address[] memory) { address[] memory path = new address[](2); // If token is not WETH, path is Token -> WETH address path[0] = tokenAddress; path[1] = IUniswapV2Router02(uniswapV2RouterAddr).WETH(); return path; } function _performSwap(address target, bytes memory swapCallData, uint256 amount ) private { (bool success, bytes memory res) = target.call{ value: amount }(swapCallData); if (!success) { assembly { let returndata_size := mload(res) revert(add(32, res), returndata_size) } } } }
//SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol"; import { ERC20 } from "solmate/src/tokens/ERC20.sol"; import { BaseAggregator } from "./BaseAggregator.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ISignatureTransfer } from "./interfaces/ISignatureTransfer.sol"; contract DNARouter is BaseAggregator, Ownable { /// @dev Event emitted when a swap target gets added event SwapTargetAdded(address indexed target); /// @dev Event emitted when a swap target gets removed event SwapTargetRemoved(address indexed target); /// @dev Event emitted when token fees are withdrawn event TokenWithdrawn(address indexed token, address indexed target, uint256 amount); /// @dev Event emitted when ETH fees are withdrawn event EthWithdrawn(address indexed target, uint256 amount); constructor( address[] memory _swapTargets, ISignatureTransfer _permit2, address _uniswapV3routerAddr, address _companyWallet, address _uniswapV2RouterAddr ) Ownable(_msgSender()) BaseAggregator(_permit2) { for (uint256 i = 0; i < _swapTargets.length; i++) { swapTargets[_swapTargets[i]] = true; } uniswapV2RouterAddr = _uniswapV2RouterAddr; uniswapV3RouterAddr = _uniswapV3routerAddr; companyWalletAddr = _companyWallet; companyFeePercentage = 2000; // 20% } /// @dev We don't want to accept any ETH, except refunds from aggregators /// or the owner (for testing purposes), which can also withdraw /// This is done by evaluating the value of status, which is set to 2 /// only during swaps due to the "nonReentrant" modifier receive() external payable { require(_reentrancyGuardEntered() || msg.sender == owner(), "NO_RECEIVE"); } // set DNAController Address function setDnaController(address _dnaController) external onlyOwner { require (_dnaController != address(0), "ZeroAddress"); dnaController = _dnaController; } // set DNAStaking Address function setDNAStakingAddress(address _dnaStakingAddr) external onlyOwner { require (_dnaStakingAddr != address(0), "ZeroAddress"); dnaStakingAddr = _dnaStakingAddr; } // set company Fee Percentage function setCompanyFeePercentage(uint16 newValue) external onlyOwner { // newValue should not be greater then 10000(100%) require(newValue <= 10000, "InvalidFeeValue" ) ; companyFeePercentage = newValue; } // set Staking Reward Threshold function setStakingRewardThreshold(uint256 _stakingRewardThreshold) external onlyOwner { require (_stakingRewardThreshold > 0, "Invalid Value"); stakingRewardThreshold = _stakingRewardThreshold; } // Function to set the allowed status of a token (only callable by admin/owner) function setFeeTokenData(address tokenAddress, bool isAllowed) external onlyOwner { feeTokenData[tokenAddress].isAllowed = isAllowed; } // Function to set balance of the allowed token (only callable by admin/owner) function sponsorTokens(address tokenAddress, uint256 amount) external { require(feeTokenData[tokenAddress].isAllowed, "Invalid Fee Token"); ERC20(tokenAddress).transferFrom(msg.sender, address(this), amount); feeTokenData[tokenAddress].balance = amount; } // set Fixed Token Amount function setFixedTokenAmount(uint256 _fixedTokenAmount) external onlyOwner { require (_fixedTokenAmount > 0, "Invalid Value"); fixedTokenAmount = _fixedTokenAmount; } /// @dev method to add or remove swap targets from swapTargets /// This is required so we only approve "trusted" swap targets /// to transfer tokens out of this contract /// @param target address of the swap target to add /// @param add flag to add or remove the swap target function updateSwapTargets(address target, bool add) external onlyOwner { swapTargets[target] = add; if (add) { emit SwapTargetAdded(target); } else { emit SwapTargetRemoved(target); } } /// @dev method to withdraw ERC20 tokens (from the fees) /// @param token address of the token to withdraw /// @param to address that's receiving the tokens /// @param amount amount of tokens to withdraw function withdrawToken(address token, address to, uint256 amount) external onlyOwner { require(to != address(0), "ZERO_ADDRESS"); SafeTransferLib.safeTransfer(ERC20(token), to, amount); emit TokenWithdrawn(token, to, amount); } /// @dev method to withdraw ETH (from the fees) /// @param to address that's receiving the ETH /// @param amount amount of ETH to withdraw function withdrawEth(address to, uint256 amount) external onlyOwner { require(to != address(0), "ZERO_ADDRESS"); SafeTransferLib.safeTransferETH(to, amount); emit EthWithdrawn(to, amount); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IDNAController { function isTaxableToken(address _tokenAddr) external view returns (bool); function dnaTokenAddr() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IDNAStaking { function stakeEvolutionRewards( address _staker, uint256 amount ) external; function notifyRewardAmount( address _rewardsToken, uint256 reward ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IEIP712 { function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {IEIP712} from "./IEIP712.sol"; /// @title SignatureTransfer /// @notice Handles ERC20 token transfers through signature based actions /// @dev Requires user's token approval on the Permit2 contract interface ISignatureTransfer is IEIP712 { /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount /// @param maxAmount The maximum amount a spender can request to transfer error InvalidAmount(uint256 maxAmount); /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred error LengthMismatch(); /// @notice Emits an event when the owner successfully invalidates an unordered nonce. event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask); /// @notice The token and amount details for a transfer signed in the permit transfer signature struct TokenPermissions { // ERC20 token address address token; // the maximum amount that can be spent uint256 amount; } /// @notice The signed permit message for a single token transfer struct PermitTransferFrom { TokenPermissions permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Specifies the recipient address and amount for batched transfers. /// @dev Recipients and amounts correspond to the index of the signed token permissions array. /// @dev Reverts if the requested amount is greater than the permitted signed amount. struct SignatureTransferDetails { // recipient address address to; // spender requested amount uint256 requestedAmount; } /// @notice Used to reconstruct the signed permit message for multiple token transfers /// @dev Do not need to pass in spender address as it is required that it is msg.sender /// @dev Note that a user still signs over a spender address struct PermitBatchTransferFrom { // the tokens and corresponding amounts permitted for a transfer TokenPermissions[] permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce /// @dev It returns a uint256 bitmap /// @dev The index, or wordPosition is capped at type(uint248).max function nonceBitmap(address, uint256) external view returns (uint256); /// @notice Transfers a token using a signed permit message /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param signature The signature to verify function permitTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes calldata signature ) external; /// @notice Transfers a token using a signed permit message /// @notice Includes extra data provided by the caller to verify signature over /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; /// @notice Transfers multiple tokens using a signed permit message /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails Specifies the recipient and requested amount for the token transfer /// @param signature The signature to verify function permitTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes calldata signature ) external; /// @notice Transfers multiple tokens using a signed permit message /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition /// @notice Includes extra data provided by the caller to verify signature over /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails Specifies the recipient and requested amount for the token transfer /// @param witness Extra data to include when checking the user signature /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash /// @param signature The signature to verify function permitWitnessTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes32 witness, string calldata witnessTypeString, bytes calldata signature ) external; /// @notice Invalidates the bits specified in mask for the bitmap at the word position /// @dev The wordPos is maxed at type(uint248).max /// @param wordPos A number to index the nonceBitmap at /// @param mask A bitmap masked against msg.sender's current bitmap at the word position function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IUniswapV2Router02 { function swapExactETHForTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function getAmountsOut( uint amountIn, address[] calldata path ) external view returns (uint[] memory amounts); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IUniswapV3Router02 { struct ExactInputParams { bytes path; address recipient; uint256 amountIn; uint256 amountOutMinimum; } function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); }
//SPDX-License-Identifier: MIT pragma solidity 0.8.24; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { Permit2, Permit2Helper } from "../Permit2Helper.sol"; enum FeeToken { INPUT, OUTPUT } library Common { struct ExecuteSwapParam { address sellTokenAddress; // The token the user is selling (use address(0) for ETH) address intermediateTokenAddress; // The token the user is swapping in between address buyTokenAddress; // The token the user wants to buy (use address(0) for ETH) address payable target; // The target aggregator contract address for swap bytes swapCallData; // The calldata for the swap operation uint256 sellAmount; // The amount of tokens/ETH to sell FeeToken feeToken; // The token to be used for the fee (ignored for ETH-related functions) uint256 feeAmount; // The amount of the tokens to sell that we will take as a fee Permit2 permit; // The permit details for the sellToken (only for token-based swaps) address[] pathV2; // Path for the second swap via intermediate token bytes pathV3; // Bytes path with fee tier for V3 } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { ISignatureTransfer } from "./interfaces/ISignatureTransfer.sol"; struct Permit2 { uint256 nonce; uint256 deadline; bytes signature; } contract Permit2Helper { ISignatureTransfer public immutable permit2; constructor(ISignatureTransfer _permit2) { permit2 = _permit2; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "APPROVE_FAILED"); } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 65535 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISignatureTransfer","name":"permit2","type":"address"},{"internalType":"contract DNARouter","name":"_dnaRouter","type":"address"},{"internalType":"address","name":"_dnaTokenAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidFeeAmount","type":"error"},{"inputs":[],"name":"InvalidFeePercent","type":"error"},{"inputs":[],"name":"InvalidFeeToken","type":"error"},{"inputs":[],"name":"InvalidTaxableTokens","type":"error"},{"inputs":[],"name":"InvalidTokenAddresses","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"dnaRouter","outputs":[{"internalType":"contract DNARouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dnaTokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sellTokenAddress","type":"address"},{"internalType":"address","name":"intermediateTokenAddress","type":"address"},{"internalType":"address","name":"buyTokenAddress","type":"address"},{"internalType":"address payable","name":"target","type":"address"},{"internalType":"bytes","name":"swapCallData","type":"bytes"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"enum FeeToken","name":"feeToken","type":"uint8"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2","name":"permit","type":"tuple"},{"internalType":"address[]","name":"pathV2","type":"address[]"},{"internalType":"bytes","name":"pathV3","type":"bytes"}],"internalType":"struct Common.ExecuteSwapParam","name":"executeSwapParam","type":"tuple"}],"name":"executeSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTaxable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddr","type":"address"}],"name":"isTaxableToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract ISignatureTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract DNARouter","name":"_dnaRouter","type":"address"}],"name":"setDNARouterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"bool","name":"_taxable","type":"bool"}],"name":"setTaxableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a03461011657601f611b9a38819003918201601f19168301916001600160401b0383118484101761011b578084926060946040528339810103126101165780516001600160a01b039182821682036101165760208101519083821680920361011657604001518381168091036101165733156100fd578060409360009384549160018060a01b031992338482161787558751983391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08880a360805281600154161760015560025416176002558152600360205220600160ff19825416179055611a68908161013282396080518181816105f601526114640152f35b604051631e4fbdf760e01b815260006004820152602490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c806301e336671461148857806312261ee71461141957806316eebebd146110d15780631b9a91a41461134857806320cbe712146112f65780633729c5ca146112a457806368f47877146111d5578063715018a614611139578063819906fe146110d15780638da5cb5b14611080578063adc855b814610289578063d70f82021461019c5763f2fde38b146100b6575061000e565b346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610199576100ed611504565b6100f5611906565b73ffffffffffffffffffffffffffffffffffffffff80911690811561016857600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b602483604051907f1e4fbdf70000000000000000000000000000000000000000000000000000000082526004820152fd5b80fd5b50346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995760043573ffffffffffffffffffffffffffffffffffffffff8116809103610285576101f5611906565b8015610227577fffffffffffffffffffffffff0000000000000000000000000000000000000000600154161760015580f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f416464726573730000000000000000000000000000000000000000006044820152fd5b5080fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995767ffffffffffffffff6004351161019957610160807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc600435360301126102855760405190810181811067ffffffffffffffff8211176110535760405261031f600435600401611527565b815261032f602460043501611527565b6020820152610342604460043501611527565b60408201526064600435013573ffffffffffffffffffffffffffffffffffffffff8116810361104f5760608201526084600435013567ffffffffffffffff811161104f57610397906004369181350101611604565b608082015260043560a481013560a083015260c40135600281101561104f5760c082015260043560e481013560e0830152610104013567ffffffffffffffff811161104f576004350160607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc823603011261104f576040519061041982611548565b600481013582526024810135602083015260448101359067ffffffffffffffff8211610f4757600461044e9236920101611604565b6040820152610100820152610124600435013567ffffffffffffffff811161104f57366023826004350101121561104f5760048181350101359067ffffffffffffffff8211611022578160051b604051926104ac60208301856115c3565b8352602083019036602482856004350101011161101e57906024836004350101915b602481856004350101018310611002575050505061012082015267ffffffffffffffff6101446004350135116102855761051336600480356101448101350101611604565b61014082015273ffffffffffffffffffffffffffffffffffffffff8151168252600360205260ff6040832054161580610fd6575b610fac5773ffffffffffffffffffffffffffffffffffffffff81511673ffffffffffffffffffffffffffffffffffffffff60025416808214908115610f88575b50610f7d575b15610d5a5773ffffffffffffffffffffffffffffffffffffffff60015416828360a08401519273ffffffffffffffffffffffffffffffffffffffff8551168252600360205260ff604083205416610cbd575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8651169060a087015160405192610641846115a7565b835260208301526101008701519060208251920151936040519361066485611548565b8452602084019283526040840194855260a089015173ffffffffffffffffffffffffffffffffffffffff6040519261069b846115a7565b168252602082015260406101008a01510151823b15610cb9578694610767869261074e61071a956040519a8b998a9889977f30f28b7a0000000000000000000000000000000000000000000000000000000089526004890190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044870152516064860152805173ffffffffffffffffffffffffffffffffffffffff1660848601526020015160a4850152565b3360c484015261010060e48401526101048301906116de565b03925af180156109cd57610ca5575b505073ffffffffffffffffffffffffffffffffffffffff8351168452600360205260ff604085205416610bbe575b506040820151839073ffffffffffffffffffffffffffffffffffffffff1615610a9c575073ffffffffffffffffffffffffffffffffffffffff60408301511690604051906020826024817f70a0823100000000000000000000000000000000000000000000000000000000968782523060048301525afa918215610a91578592610a5d575b5060a0840152602083015173ffffffffffffffffffffffffffffffffffffffff166109d8578373ffffffffffffffffffffffffffffffffffffffff60015416803b15610285578160405180927fe06949b00000000000000000000000000000000000000000000000000000000082528183816108a9338c600484016117a2565b03925af180156109cd576109b5575b50505b73ffffffffffffffffffffffffffffffffffffffff6040840151168452600360205260ff6040852054166108f1575b5050505b80f35b602073ffffffffffffffffffffffffffffffffffffffff6040850151169260246040518095819382523060048301525afa80156109aa578490610971575b610939925061173c565b80610945575b806108ea565b61096a9173ffffffffffffffffffffffffffffffffffffffff60403392015116611957565b388061093f565b506020823d6020116109a2575b8161098b602093836115c3565b8101031261099d57610939915161092f565b600080fd5b3d915061097e565b6040513d86823e3d90fd5b6109be90611593565b6109c95783386108b8565b8380fd5b6040513d84823e3d90fd5b8373ffffffffffffffffffffffffffffffffffffffff60015416803b15610285578160405180927f01aa94bb000000000000000000000000000000000000000000000000000000008252818381610a33338c600484016117a2565b03925af180156109cd57610a49575b50506108bb565b610a5290611593565b6109c9578338610a42565b9091506020813d602011610a89575b81610a79602093836115c3565b8101031261099d57519038610829565b3d9150610a6c565b6040513d87823e3d90fd5b919073ffffffffffffffffffffffffffffffffffffffff6001541673ffffffffffffffffffffffffffffffffffffffff8351169073ffffffffffffffffffffffffffffffffffffffff60608501511660808501519261010060e087015196015190833b15610bba57610b9788968793610b57996040519a8b998a9889977f7c965eed0000000000000000000000000000000000000000000000000000000089526004890152602488015260e0604488015260e48701906116de565b92606486015260848501523360a48501527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8483030160c4850152611778565b03925af180156109cd57610baa57505080f35b610bb390611593565b6101995780f35b8780fd5b60249150602073ffffffffffffffffffffffffffffffffffffffff845116604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa80156109aa578490610c71575b610c25925061173c565b80610c31575b386107a4565b610c6c8173ffffffffffffffffffffffffffffffffffffffff84511673ffffffffffffffffffffffffffffffffffffffff6001541690611957565b610c2b565b506020823d602011610c9d575b81610c8b602093836115c3565b8101031261099d57610c259151610c1b565b3d9150610c7e565b610cae90611593565b6109c9578338610776565b8680fd5b50505030836024602073ffffffffffffffffffffffffffffffffffffffff865116604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156109cd578291610d25575b50916105df565b9150506020813d602011610d52575b81610d41602093836115c3565b8101031261099d5784905138610d1e565b3d9150610d34565b73ffffffffffffffffffffffffffffffffffffffff6040820151166040516020816024817f70a0823100000000000000000000000000000000000000000000000000000000958682523060048301525afa9081156109aa578491610f4b575b5073ffffffffffffffffffffffffffffffffffffffff600154168473ffffffffffffffffffffffffffffffffffffffff6040860151169173ffffffffffffffffffffffffffffffffffffffff6060870151169060808701519160e088015194823b15610f4757610e6b95604051968795869485947f64d9f7970000000000000000000000000000000000000000000000000000000086526004860152602485015260a0604485015260a48401906116de565b906064830152336084830152039134905af18015610a9157610f34575b50602073ffffffffffffffffffffffffffffffffffffffff6040850151169260246040518095819382523060048301525afa80156109aa578490610f00575b610ed1925061173c565b80610edb57505080f35b6108ee9173ffffffffffffffffffffffffffffffffffffffff60403392015116611957565b506020823d602011610f2c575b81610f1a602093836115c3565b8101031261099d57610ed19151610ec7565b3d9150610f0d565b610f4090949194611593565b9238610e88565b8480fd5b90506020813d602011610f75575b81610f66602093836115c3565b810103126109c9575138610db9565b3d9150610f59565b8260e083015261058d565b905073ffffffffffffffffffffffffffffffffffffffff6040840151161438610587565b60046040517f9f57533c000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff604082015116825260ff60408320541615610547565b60208060249361101186611527565b81520193019291506104ce565b8580fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8280fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b50346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995760ff604060209273ffffffffffffffffffffffffffffffffffffffff611125611504565b168152600384522054166040519015158152f35b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957611170611906565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101995760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995761120d611504565b6024359081151580920361104f5773ffffffffffffffffffffffffffffffffffffffff90611239611906565b16801561127a5782526003602052604082209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911617905580f35b60046040517fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b50346101995760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995780808080611384611504565b61138c611906565b6113ad73ffffffffffffffffffffffffffffffffffffffff82161515611679565b602435905af1156113bb5780f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346101995760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610199576114c0611504565b73ffffffffffffffffffffffffffffffffffffffff6024358181169291838203610f47576114fa6108ee946114f3611906565b1515611679565b6044359216611957565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361099d57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361099d57565b6060810190811067ffffffffffffffff82111761156457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161156457604052565b6040810190811067ffffffffffffffff82111761156457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761156457604052565b81601f8201121561099d5780359067ffffffffffffffff8211611564576040519261165760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601856115c3565b8284526020838301011161099d57816000926020809301838601378301015290565b1561168057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152fd5b919082519283825260005b8481106117285750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016116e9565b9190820391821161174957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906060604061179f93805184526020810151602085015201519181604082015201906116de565b90565b909291926040825273ffffffffffffffffffffffffffffffffffffffff80825116604084015260209181838201511660608501528160408201511660808501528160608201511660a085015260808101519061180c610160928360c08801526101a08701906116de565b9060a081015160e087015260c0810151906101009160028110156118d757828895949395015260e08101519361012094858901528101519061187b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09361014093858b830301858c0152611778565b948101519383898703019089015286808551968781520194019460005b888282106118c1575050506118ba9450015190868303016101808701526116de565b9416910152565b8751891687529687019690950194600101611898565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff60005416330361192757565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b91604460209260009273ffffffffffffffffffffffffffffffffffffffff604051927fa9059cbb000000000000000000000000000000000000000000000000000000008452166004830152602482015282855af19081601f3d11600160005114161516611a25575b50156119c757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b3b153d17159050386119bf56fea2646970667358221220eabc33b23eb09ec0a9dc5978f7d9e2ebdcaec0d02dec4cd4d4cdb3aab2f25e1664736f6c63430008180033000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000008274b0265c101027961e561e526acabb2c237113000000000000000000000000ed49fe44fd4249a09843c2ba4bba7e50beca7113
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c806301e336671461148857806312261ee71461141957806316eebebd146110d15780631b9a91a41461134857806320cbe712146112f65780633729c5ca146112a457806368f47877146111d5578063715018a614611139578063819906fe146110d15780638da5cb5b14611080578063adc855b814610289578063d70f82021461019c5763f2fde38b146100b6575061000e565b346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610199576100ed611504565b6100f5611906565b73ffffffffffffffffffffffffffffffffffffffff80911690811561016857600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b602483604051907f1e4fbdf70000000000000000000000000000000000000000000000000000000082526004820152fd5b80fd5b50346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995760043573ffffffffffffffffffffffffffffffffffffffff8116809103610285576101f5611906565b8015610227577fffffffffffffffffffffffff0000000000000000000000000000000000000000600154161760015580f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f416464726573730000000000000000000000000000000000000000006044820152fd5b5080fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995767ffffffffffffffff6004351161019957610160807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc600435360301126102855760405190810181811067ffffffffffffffff8211176110535760405261031f600435600401611527565b815261032f602460043501611527565b6020820152610342604460043501611527565b60408201526064600435013573ffffffffffffffffffffffffffffffffffffffff8116810361104f5760608201526084600435013567ffffffffffffffff811161104f57610397906004369181350101611604565b608082015260043560a481013560a083015260c40135600281101561104f5760c082015260043560e481013560e0830152610104013567ffffffffffffffff811161104f576004350160607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc823603011261104f576040519061041982611548565b600481013582526024810135602083015260448101359067ffffffffffffffff8211610f4757600461044e9236920101611604565b6040820152610100820152610124600435013567ffffffffffffffff811161104f57366023826004350101121561104f5760048181350101359067ffffffffffffffff8211611022578160051b604051926104ac60208301856115c3565b8352602083019036602482856004350101011161101e57906024836004350101915b602481856004350101018310611002575050505061012082015267ffffffffffffffff6101446004350135116102855761051336600480356101448101350101611604565b61014082015273ffffffffffffffffffffffffffffffffffffffff8151168252600360205260ff6040832054161580610fd6575b610fac5773ffffffffffffffffffffffffffffffffffffffff81511673ffffffffffffffffffffffffffffffffffffffff60025416808214908115610f88575b50610f7d575b15610d5a5773ffffffffffffffffffffffffffffffffffffffff60015416828360a08401519273ffffffffffffffffffffffffffffffffffffffff8551168252600360205260ff604083205416610cbd575b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31673ffffffffffffffffffffffffffffffffffffffff8651169060a087015160405192610641846115a7565b835260208301526101008701519060208251920151936040519361066485611548565b8452602084019283526040840194855260a089015173ffffffffffffffffffffffffffffffffffffffff6040519261069b846115a7565b168252602082015260406101008a01510151823b15610cb9578694610767869261074e61071a956040519a8b998a9889977f30f28b7a0000000000000000000000000000000000000000000000000000000089526004890190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044870152516064860152805173ffffffffffffffffffffffffffffffffffffffff1660848601526020015160a4850152565b3360c484015261010060e48401526101048301906116de565b03925af180156109cd57610ca5575b505073ffffffffffffffffffffffffffffffffffffffff8351168452600360205260ff604085205416610bbe575b506040820151839073ffffffffffffffffffffffffffffffffffffffff1615610a9c575073ffffffffffffffffffffffffffffffffffffffff60408301511690604051906020826024817f70a0823100000000000000000000000000000000000000000000000000000000968782523060048301525afa918215610a91578592610a5d575b5060a0840152602083015173ffffffffffffffffffffffffffffffffffffffff166109d8578373ffffffffffffffffffffffffffffffffffffffff60015416803b15610285578160405180927fe06949b00000000000000000000000000000000000000000000000000000000082528183816108a9338c600484016117a2565b03925af180156109cd576109b5575b50505b73ffffffffffffffffffffffffffffffffffffffff6040840151168452600360205260ff6040852054166108f1575b5050505b80f35b602073ffffffffffffffffffffffffffffffffffffffff6040850151169260246040518095819382523060048301525afa80156109aa578490610971575b610939925061173c565b80610945575b806108ea565b61096a9173ffffffffffffffffffffffffffffffffffffffff60403392015116611957565b388061093f565b506020823d6020116109a2575b8161098b602093836115c3565b8101031261099d57610939915161092f565b600080fd5b3d915061097e565b6040513d86823e3d90fd5b6109be90611593565b6109c95783386108b8565b8380fd5b6040513d84823e3d90fd5b8373ffffffffffffffffffffffffffffffffffffffff60015416803b15610285578160405180927f01aa94bb000000000000000000000000000000000000000000000000000000008252818381610a33338c600484016117a2565b03925af180156109cd57610a49575b50506108bb565b610a5290611593565b6109c9578338610a42565b9091506020813d602011610a89575b81610a79602093836115c3565b8101031261099d57519038610829565b3d9150610a6c565b6040513d87823e3d90fd5b919073ffffffffffffffffffffffffffffffffffffffff6001541673ffffffffffffffffffffffffffffffffffffffff8351169073ffffffffffffffffffffffffffffffffffffffff60608501511660808501519261010060e087015196015190833b15610bba57610b9788968793610b57996040519a8b998a9889977f7c965eed0000000000000000000000000000000000000000000000000000000089526004890152602488015260e0604488015260e48701906116de565b92606486015260848501523360a48501527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8483030160c4850152611778565b03925af180156109cd57610baa57505080f35b610bb390611593565b6101995780f35b8780fd5b60249150602073ffffffffffffffffffffffffffffffffffffffff845116604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa80156109aa578490610c71575b610c25925061173c565b80610c31575b386107a4565b610c6c8173ffffffffffffffffffffffffffffffffffffffff84511673ffffffffffffffffffffffffffffffffffffffff6001541690611957565b610c2b565b506020823d602011610c9d575b81610c8b602093836115c3565b8101031261099d57610c259151610c1b565b3d9150610c7e565b610cae90611593565b6109c9578338610776565b8680fd5b50505030836024602073ffffffffffffffffffffffffffffffffffffffff865116604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156109cd578291610d25575b50916105df565b9150506020813d602011610d52575b81610d41602093836115c3565b8101031261099d5784905138610d1e565b3d9150610d34565b73ffffffffffffffffffffffffffffffffffffffff6040820151166040516020816024817f70a0823100000000000000000000000000000000000000000000000000000000958682523060048301525afa9081156109aa578491610f4b575b5073ffffffffffffffffffffffffffffffffffffffff600154168473ffffffffffffffffffffffffffffffffffffffff6040860151169173ffffffffffffffffffffffffffffffffffffffff6060870151169060808701519160e088015194823b15610f4757610e6b95604051968795869485947f64d9f7970000000000000000000000000000000000000000000000000000000086526004860152602485015260a0604485015260a48401906116de565b906064830152336084830152039134905af18015610a9157610f34575b50602073ffffffffffffffffffffffffffffffffffffffff6040850151169260246040518095819382523060048301525afa80156109aa578490610f00575b610ed1925061173c565b80610edb57505080f35b6108ee9173ffffffffffffffffffffffffffffffffffffffff60403392015116611957565b506020823d602011610f2c575b81610f1a602093836115c3565b8101031261099d57610ed19151610ec7565b3d9150610f0d565b610f4090949194611593565b9238610e88565b8480fd5b90506020813d602011610f75575b81610f66602093836115c3565b810103126109c9575138610db9565b3d9150610f59565b8260e083015261058d565b905073ffffffffffffffffffffffffffffffffffffffff6040840151161438610587565b60046040517f9f57533c000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff604082015116825260ff60408320541615610547565b60208060249361101186611527565b81520193019291506104ce565b8580fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8280fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b50346101995760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995760ff604060209273ffffffffffffffffffffffffffffffffffffffff611125611504565b168152600384522054166040519015158152f35b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957611170611906565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101995760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995761120d611504565b6024359081151580920361104f5773ffffffffffffffffffffffffffffffffffffffff90611239611906565b16801561127a5782526003602052604082209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911617905580f35b60046040517fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b50346101995760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101995780808080611384611504565b61138c611906565b6113ad73ffffffffffffffffffffffffffffffffffffffff82161515611679565b602435905af1156113bb5780f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b503461019957807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019957602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3168152f35b50346101995760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610199576114c0611504565b73ffffffffffffffffffffffffffffffffffffffff6024358181169291838203610f47576114fa6108ee946114f3611906565b1515611679565b6044359216611957565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361099d57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361099d57565b6060810190811067ffffffffffffffff82111761156457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161156457604052565b6040810190811067ffffffffffffffff82111761156457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761156457604052565b81601f8201121561099d5780359067ffffffffffffffff8211611564576040519261165760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601856115c3565b8284526020838301011161099d57816000926020809301838601378301015290565b1561168057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152fd5b919082519283825260005b8481106117285750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b6020818301810151848301820152016116e9565b9190820391821161174957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b906060604061179f93805184526020810151602085015201519181604082015201906116de565b90565b909291926040825273ffffffffffffffffffffffffffffffffffffffff80825116604084015260209181838201511660608501528160408201511660808501528160608201511660a085015260808101519061180c610160928360c08801526101a08701906116de565b9060a081015160e087015260c0810151906101009160028110156118d757828895949395015260e08101519361012094858901528101519061187b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09361014093858b830301858c0152611778565b948101519383898703019089015286808551968781520194019460005b888282106118c1575050506118ba9450015190868303016101808701526116de565b9416910152565b8751891687529687019690950194600101611898565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff60005416330361192757565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b91604460209260009273ffffffffffffffffffffffffffffffffffffffff604051927fa9059cbb000000000000000000000000000000000000000000000000000000008452166004830152602482015282855af19081601f3d11600160005114161516611a25575b50156119c757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b3b153d17159050386119bf56fea2646970667358221220eabc33b23eb09ec0a9dc5978f7d9e2ebdcaec0d02dec4cd4d4cdb3aab2f25e1664736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000008274b0265c101027961e561e526acabb2c237113000000000000000000000000ed49fe44fd4249a09843c2ba4bba7e50beca7113
-----Decoded View---------------
Arg [0] : permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [1] : _dnaRouter (address): 0x8274b0265C101027961e561e526AcabB2c237113
Arg [2] : _dnaTokenAddr (address): 0xED49fE44fD4249A09843C2Ba4bba7e50BECa7113
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [1] : 0000000000000000000000008274b0265c101027961e561e526acabb2c237113
Arg [2] : 000000000000000000000000ed49fe44fd4249a09843c2ba4bba7e50beca7113
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.