ERC4626MerklAdapterFactory

Description:

Decentralized Finance (DeFi) protocol contract providing Mintable, Swap, Liquidity, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/adapters/ERC4626MerklAdapterFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
// The implementation of this contract was inspired by Morpho Vault V2, developed by the Morpho Association in 2025.
pragma solidity 0.8.28;

import {ERC4626MerklAdapter} from "./ERC4626MerklAdapter.sol";
import {IERC4626MerklAdapterFactory} from "./interfaces/IERC4626MerklAdapterFactory.sol";

contract ERC4626MerklAdapterFactory is IERC4626MerklAdapterFactory {
    /* STORAGE */

    mapping(address parentVault => mapping(address erc4626Vault => address)) public erc4626MerklAdapter;
    mapping(address account => bool) public isERC4626MerklAdapter;

    /* FUNCTIONS */

    /// @dev Returns the address of the deployed ERC4626MerklAdapter.
    function createERC4626MerklAdapter(address parentVault, address erc4626Vault) external returns (address) {
        address _erc4626Adapter = address(new ERC4626MerklAdapter{salt: bytes32(0)}(parentVault, erc4626Vault));
        erc4626MerklAdapter[parentVault][erc4626Vault] = _erc4626Adapter;
        isERC4626MerklAdapter[_erc4626Adapter] = true;
        emit CreateERC4626MerklAdapter(parentVault, erc4626Vault, _erc4626Adapter);
        return _erc4626Adapter;
    }
}
"
    },
    "src/adapters/ERC4626MerklAdapter.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
// The implementation of this contract was inspired by Morpho Vault V2, developed by the Morpho Association in 2025.
pragma solidity 0.8.28;

import {IVaultV2} from "../interfaces/IVaultV2.sol";
import {IERC4626} from "../interfaces/IERC4626.sol";
import {IERC20} from "../interfaces/IERC20.sol";
import {IERC4626MerklAdapter} from "./interfaces/IERC4626MerklAdapter.sol";
import {IMerklDistributor} from "../interfaces/IMerklDistributor.sol";
import {SafeERC20Lib} from "../libraries/SafeERC20Lib.sol";

/// @dev Generic ERC4626 adapter with Merkl rewards claiming functionality
/// @dev Designed for integration with ERC4626-compliant vaults like Stata (AAVE wrapper)
/// @dev This adapter must be used with ERC4626 vaults that are protected against inflation attacks
/// @dev Must not be used with an ERC4626 vault which can re-enter the parent vault
contract ERC4626MerklAdapter is IERC4626MerklAdapter {
    /* IMMUTABLES */

    address public immutable factory;
    address public immutable parentVault;
    address public immutable erc4626Vault;
    bytes32 public immutable adapterId;

    /* CONSTANTS */

    /// @dev Merkl distributor address on the vast majority of chains
    address public constant MERKL_DISTRIBUTOR = 0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae;

    /* STORAGE */

    address public skimRecipient;
    address public claimer;

    /* FUNCTIONS */

    constructor(address _parentVault, address _erc4626Vault) {
        factory = msg.sender;
        parentVault = _parentVault;
        erc4626Vault = _erc4626Vault;
        adapterId = keccak256(abi.encode("this", address(this)));
        address asset = IVaultV2(_parentVault).asset();
        require(asset == IERC4626(_erc4626Vault).asset(), AssetMismatch());
        SafeERC20Lib.safeApprove(asset, _parentVault, type(uint256).max);
        SafeERC20Lib.safeApprove(asset, _erc4626Vault, type(uint256).max);
    }

    function setClaimer(address newClaimer) external {
        if (msg.sender != IVaultV2(parentVault).curator()) revert NotAuthorized();
        claimer = newClaimer;
        emit SetClaimer(newClaimer);
    }

    function setSkimRecipient(address newSkimRecipient) external {
        require(msg.sender == IVaultV2(parentVault).owner(), NotAuthorized());
        skimRecipient = newSkimRecipient;
        emit SetSkimRecipient(newSkimRecipient);
    }

    /// @dev Skims the adapter's balance of `token` and sends it to `skimRecipient`.
    /// @dev This is useful to handle rewards that the adapter has earned.
    function skim(address token) external {
        require(msg.sender == skimRecipient, NotAuthorized());
        require(token != erc4626Vault, CannotSkimERC4626Shares());
        uint256 balance = IERC20(token).balanceOf(address(this));
        SafeERC20Lib.safeTransfer(token, skimRecipient, balance);
        emit Skim(token, balance);
    }

    /// @dev Does not log anything because the ids (logged in the parent vault) are enough.
    /// @dev Returns the ids of the allocation and the change in allocation.
    function allocate(bytes memory data, uint256 assets, bytes4, address) external returns (bytes32[] memory, int256) {
        require(data.length == 0, InvalidData());
        require(msg.sender == parentVault, NotAuthorized());

        if (assets > 0) IERC4626(erc4626Vault).deposit(assets, address(this));
        uint256 oldAllocation = allocation();
        uint256 newAllocation = IERC4626(erc4626Vault).previewRedeem(IERC4626(erc4626Vault).balanceOf(address(this)));

        // Safe casts because ERC4626 vaults bound the total supply, and allocation is less than the
        // max total assets of the vault.
        return (ids(), int256(newAllocation) - int256(oldAllocation));
    }

    /// @dev Does not log anything because the ids (logged in the parent vault) are enough.
    /// @dev Returns the ids of the deallocation and the change in allocation.
    function deallocate(bytes memory data, uint256 assets, bytes4, address)
        external
        returns (bytes32[] memory, int256)
    {
        require(data.length == 0, InvalidData());
        require(msg.sender == parentVault, NotAuthorized());

        if (assets > 0) IERC4626(erc4626Vault).withdraw(assets, address(this), address(this));
        uint256 oldAllocation = allocation();
        uint256 newAllocation = IERC4626(erc4626Vault).previewRedeem(IERC4626(erc4626Vault).balanceOf(address(this)));

        // Safe casts because ERC4626 vaults bound the total supply, and allocation is less than the
        // max total assets of the vault.
        return (ids(), int256(newAllocation) - int256(oldAllocation));
    }

    /// @dev Claims rewards from Merkl distributor contract and swap it to parent vault's asset
    /// @dev Only the claimer can call this function
    /// @param data Encoded ClaimParams struct containing merkl params and swap params
    function claim(bytes calldata data) external {
        require(msg.sender == claimer, NotAuthorized());

        // Decode the claim data
        (MerklParams memory merklParams, SwapParams[] memory swapParams) = abi.decode(data, (MerklParams, SwapParams[]));

        // Claim data checks
        require(swapParams.length == merklParams.tokens.length, InvalidData());

        // Call the Merkl distributor
        IMerklDistributor(MERKL_DISTRIBUTOR).claim(
            merklParams.users, merklParams.tokens, merklParams.amounts, merklParams.proofs
        );

        IERC20 parentVaultAsset = IERC20(IVaultV2(parentVault).asset());
        for (uint256 i; i < swapParams.length; ++i) {
            // Verify the swapping data
            require(
                swapParams[i].swapper != erc4626Vault && swapParams[i].swapper != parentVault
                    && swapParams[i].swapper != MERKL_DISTRIBUTOR,
                SwapperCannotBeTiedContract()
            );
            require(swapParams[i].minAmountOut > 0, InvalidData());

            // Snapshot for sanity check
            uint256 parentVaultBalanceBefore = parentVaultAsset.balanceOf(parentVault);
            uint256 rewardTokenBalanceBefore = IERC20(merklParams.tokens[i]).balanceOf(address(this));

            // Swap the rewards
            SafeERC20Lib.safeApprove(merklParams.tokens[i], swapParams[i].swapper, merklParams.amounts[i]);
            (bool success,) = swapParams[i].swapper.call(swapParams[i].swapData);
            require(success, SwapReverted());
            uint256 swappedAmount = rewardTokenBalanceBefore - IERC20(merklParams.tokens[i]).balanceOf(address(this));

            // Check if the parent vault received them
            uint256 parentVaultBalanceAfter = parentVaultAsset.balanceOf(parentVault);
            require(parentVaultBalanceAfter >= parentVaultBalanceBefore + swapParams[i].minAmountOut, SlippageTooHigh());

            emit ClaimRewards(merklParams.tokens[i], merklParams.amounts[i]);
            emit SwapRewards(swapParams[i].swapper, merklParams.tokens[i], swappedAmount, swapParams[i].swapData);
        }
    }

    /// @dev Returns adapter's ids.
    function ids() public view returns (bytes32[] memory) {
        bytes32[] memory ids_ = new bytes32[](1);
        ids_[0] = adapterId;
        return ids_;
    }

    function allocation() public view returns (uint256) {
        return IVaultV2(parentVault).allocation(adapterId);
    }

    function realAssets() external view returns (uint256) {
        return allocation() != 0
            ? IERC4626(erc4626Vault).previewRedeem(IERC4626(erc4626Vault).balanceOf(address(this)))
            : 0;
    }
}
"
    },
    "src/adapters/interfaces/IERC4626MerklAdapterFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
// The implementation of this contract was inspired by Morpho Vault V2, developed by the Morpho Association in 2025.
pragma solidity >=0.5.0;

interface IERC4626MerklAdapterFactory {
    /* EVENTS */

    event CreateERC4626MerklAdapter(
        address indexed parentVault, address indexed erc4626Vault, address indexed erc4626MerklAdapter
    );

    /* FUNCTIONS */

    function erc4626MerklAdapter(address parentVault, address erc4626Vault) external view returns (address);
    function isERC4626MerklAdapter(address account) external view returns (bool);
    function createERC4626MerklAdapter(address parentVault, address erc4626Vault)
        external
        returns (address erc4626Adapter);
}
"
    },
    "src/interfaces/IVaultV2.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

import {IERC20} from "./IERC20.sol";
import {IERC4626} from "./IERC4626.sol";
import {IERC2612} from "./IERC2612.sol";

struct Caps {
    uint256 allocation;
    uint128 absoluteCap;
    uint128 relativeCap;
}

interface IVaultV2 is IERC4626, IERC2612 {
    // State variables
    function virtualShares() external view returns (uint256);
    function owner() external view returns (address);
    function curator() external view returns (address);
    function receiveSharesGate() external view returns (address);
    function sendSharesGate() external view returns (address);
    function receiveAssetsGate() external view returns (address);
    function sendAssetsGate() external view returns (address);
    function adapterRegistry() external view returns (address);
    function isSentinel(address account) external view returns (bool);
    function isAllocator(address account) external view returns (bool);
    function firstTotalAssets() external view returns (uint256);
    function _totalAssets() external view returns (uint128);
    function lastUpdate() external view returns (uint64);
    function maxRate() external view returns (uint64);
    function adapters(uint256 index) external view returns (address);
    function adaptersLength() external view returns (uint256);
    function isAdapter(address account) external view returns (bool);
    function allocation(bytes32 id) external view returns (uint256);
    function absoluteCap(bytes32 id) external view returns (uint256);
    function relativeCap(bytes32 id) external view returns (uint256);
    function forceDeallocatePenalty(address adapter) external view returns (uint256);
    function liquidityAdapter() external view returns (address);
    function liquidityData() external view returns (bytes memory);
    function timelock(bytes4 selector) external view returns (uint256);
    function abdicated(bytes4 selector) external view returns (bool);
    function executableAt(bytes memory data) external view returns (uint256);
    function performanceFee() external view returns (uint96);
    function performanceFeeRecipient() external view returns (address);
    function managementFee() external view returns (uint96);
    function managementFeeRecipient() external view returns (address);

    // Gating
    function canSendShares(address account) external view returns (bool);
    function canReceiveShares(address account) external view returns (bool);
    function canSendAssets(address account) external view returns (bool);
    function canReceiveAssets(address account) external view returns (bool);

    // Multicall
    function multicall(bytes[] memory data) external;

    // Owner functions
    function setOwner(address newOwner) external;
    function setCurator(address newCurator) external;
    function setIsSentinel(address account, bool isSentinel) external;
    function setName(string memory newName) external;
    function setSymbol(string memory newSymbol) external;

    // Timelocks for curator functions
    function submit(bytes memory data) external;
    function revoke(bytes memory data) external;

    // Curator functions
    function setIsAllocator(address account, bool newIsAllocator) external;
    function setReceiveSharesGate(address newReceiveSharesGate) external;
    function setSendSharesGate(address newSendSharesGate) external;
    function setReceiveAssetsGate(address newReceiveAssetsGate) external;
    function setSendAssetsGate(address newSendAssetsGate) external;
    function setAdapterRegistry(address newAdapterRegistry) external;
    function addAdapter(address account) external;
    function removeAdapter(address account) external;
    function increaseTimelock(bytes4 selector, uint256 newDuration) external;
    function decreaseTimelock(bytes4 selector, uint256 newDuration) external;
    function abdicate(bytes4 selector) external;
    function setPerformanceFee(uint256 newPerformanceFee) external;
    function setManagementFee(uint256 newManagementFee) external;
    function setPerformanceFeeRecipient(address newPerformanceFeeRecipient) external;
    function setManagementFeeRecipient(address newManagementFeeRecipient) external;
    function increaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
    function decreaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
    function increaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
    function decreaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
    function setMaxRate(uint256 newMaxRate) external;
    function setForceDeallocatePenalty(address adapter, uint256 newForceDeallocatePenalty) external;

    // Allocator functions
    function allocate(address adapter, bytes memory data, uint256 assets) external;
    function deallocate(address adapter, bytes memory data, uint256 assets) external;
    function setLiquidityAdapterAndData(address newLiquidityAdapter, bytes memory newLiquidityData) external;

    // Exchange rate
    function accrueInterest() external;
    function accrueInterestView()
        external
        view
        returns (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares);

    // Force deallocate
    function forceDeallocate(address adapter, bytes memory data, uint256 assets, address onBehalf)
        external
        returns (uint256 penaltyShares);
}
"
    },
    "src/interfaces/IERC4626.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

import {IERC20} from "./IERC20.sol";

interface IERC4626 is IERC20 {
    function asset() external view returns (address);
    function totalAssets() external view returns (uint256);
    function convertToAssets(uint256 shares) external view returns (uint256 assets);
    function convertToShares(uint256 assets) external view returns (uint256 shares);
    function deposit(uint256 assets, address onBehalf) external returns (uint256 shares);
    function mint(uint256 shares, address onBehalf) external returns (uint256 assets);
    function withdraw(uint256 assets, address onBehalf, address receiver) external returns (uint256 shares);
    function redeem(uint256 shares, address onBehalf, address receiver) external returns (uint256 assets);
    function previewDeposit(uint256 assets) external view returns (uint256 shares);
    function previewMint(uint256 shares) external view returns (uint256 assets);
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);
    function previewRedeem(uint256 shares) external view returns (uint256 assets);
    function maxDeposit(address onBehalf) external view returns (uint256 assets);
    function maxMint(address onBehalf) external view returns (uint256 shares);
    function maxWithdraw(address onBehalf) external view returns (uint256 assets);
    function maxRedeem(address onBehalf) external view returns (uint256 shares);
}
"
    },
    "src/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IERC20 {
    function decimals() external view returns (uint8);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 shares) external returns (bool success);
    function transferFrom(address from, address to, uint256 shares) external returns (bool success);
    function approve(address spender, uint256 shares) external returns (bool success);
    function allowance(address owner, address spender) external view returns (uint256);
}
"
    },
    "src/adapters/interfaces/IERC4626MerklAdapter.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
// The implementation of this contract was inspired by Morpho Vault V2, developed by the Morpho Association in 2025.
pragma solidity >= 0.5.0;

import {IAdapter} from "../../interfaces/IAdapter.sol";

interface IERC4626MerklAdapter is IAdapter {
    /* STRUCTS */

    struct MerklParams {
        address[] users;
        address[] tokens;
        uint256[] amounts;
        bytes32[][] proofs;
    }

    struct SwapParams {
        address swapper;
        uint256 minAmountOut;
        bytes swapData;
    }

    /* EVENTS */

    event SetSkimRecipient(address indexed newSkimRecipient);
    event SetClaimer(address indexed newClaimer);
    event Skim(address indexed token, uint256 assets);
    event ClaimRewards(address indexed token, uint256 amount);
    event SwapRewards(address indexed swapper, address indexed token, uint256 amount, bytes swapData);

    /* ERRORS */

    error AssetMismatch();
    error CannotSkimERC4626Shares();
    error InvalidData();
    error NotAuthorized();
    error SwapperCannotBeTiedContract();
    error SwapReverted();
    error SlippageTooHigh();

    /* FUNCTIONS */

    function factory() external view returns (address);
    function parentVault() external view returns (address);
    function erc4626Vault() external view returns (address);
    function adapterId() external view returns (bytes32);
    function skimRecipient() external view returns (address);
    function claimer() external view returns (address);
    function allocation() external view returns (uint256);
    function ids() external view returns (bytes32[] memory);
    function setSkimRecipient(address newSkimRecipient) external;
    function setClaimer(address newClaimer) external;
    function skim(address token) external;
    function claim(bytes calldata data) external;
}
"
    },
    "src/interfaces/IMerklDistributor.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
pragma solidity >= 0.5.0;

/// @notice Interface for Merkl distributor contract
interface IMerklDistributor {
    function claim(
        address[] calldata users,
        address[] calldata tokens,
        uint256[] calldata amounts,
        bytes32[][] calldata proofs
    ) external;
}
"
    },
    "src/libraries/SafeERC20Lib.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

import {IERC20} from "../interfaces/IERC20.sol";
import {ErrorsLib} from "./ErrorsLib.sol";

library SafeERC20Lib {
    function safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));
        require(success, ErrorsLib.TransferReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferReturnedFalse());
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
        require(success, ErrorsLib.TransferFromReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferFromReturnedFalse());
    }

    function safeApprove(address token, address spender, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.approve, (spender, value)));
        require(success, ErrorsLib.ApproveReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.ApproveReturnedFalse());
    }
}
"
    },
    "src/interfaces/IERC2612.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IERC2612 {
    function permit(address owner, address spender, uint256 shares, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;
    function nonces(address owner) external view returns (uint256);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
"
    },
    "src/interfaces/IAdapter.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

/// @dev See VaultV2 NatSpec comments for more details on adapter's spec.
interface IAdapter {
    /// @dev Returns the market' ids and the change in assets on this market.
    function allocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
        external
        returns (bytes32[] memory ids, int256 change);

    /// @dev Returns the market' ids and the change in assets on this market.
    function deallocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
        external
        returns (bytes32[] memory ids, int256 change);

    /// @dev Returns the current value of the investments of the adapter (in underlying asset).
    function realAssets() external view returns (uint256 assets);
}
"
    },
    "src/libraries/ErrorsLib.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

library ErrorsLib {
    error Abdicated();
    error AbsoluteCapExceeded();
    error AbsoluteCapNotDecreasing();
    error AbsoluteCapNotIncreasing();
    error ApproveReturnedFalse();
    error ApproveReverted();
    error CannotReceiveShares();
    error CannotReceiveAssets();
    error CannotSendShares();
    error CannotSendAssets();
    error CapExceeded();
    error CastOverflow();
    error DataAlreadyPending();
    error DataNotTimelocked();
    error FeeInvariantBroken();
    error FeeTooHigh();
    error InvalidSigner();
    error MaxRateTooHigh();
    error NoCode();
    error NotAdapter();
    error NotInAdapterRegistry();
    error PenaltyTooHigh();
    error PermitDeadlineExpired();
    error RelativeCapAboveOne();
    error RelativeCapExceeded();
    error RelativeCapNotDecreasing();
    error RelativeCapNotIncreasing();
    error AutomaticallyTimelocked();
    error TimelockNotDecreasing();
    error TimelockNotExpired();
    error TimelockNotIncreasing();
    error TransferFromReturnedFalse();
    error TransferFromReverted();
    error TransferReturnedFalse();
    error TransferReverted();
    error Unauthorized();
    error ZeroAbsoluteCap();
    error ZeroAddress();
    error ZeroAllocation();
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
      "ds-test/=lib/morpho-blue/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/metamorpho/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/morpho-blue/lib/halmos-cheatcodes/src/",
      "metamorpho-v1.1/=lib/metamorpho-v1.1/",
      "metamorpho/=lib/metamorpho/",
      "morpho-blue-irm/=lib/metamorpho/lib/morpho-blue-irm/src/",
      "morpho-blue/=lib/morpho-blue/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "solmate/=lib/metamorpho/lib/morpho-blue-irm/lib/solmate/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 100000
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "none",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true
  }
}}

Tags:
ERC20, DeFi, Mintable, Swap, Liquidity, Factory|addr:0x576136011496367c7fef780445349060646c7cc1|verified:true|block:23532271|tx:0xaac63c73ac31b9b1c5c918e1bf509ee0f9770535cfc94c2997be2e198641cbf1|first_check:1759917358

Submitted on: 2025-10-08 11:55:58

Comments

Log in to comment.

No comments yet.