{ "address": "0xfc8dE5A5087c8825AA54E2C57B3FFe0e23784bc3", "name": "EticaSwapFactory", "compilerVersion": "0.8.26+commit.8a97fa7a", "optimizer": { "enabled": true, "runs": 1000000 }, "evmVersion": "paris", "sources": { "src/swap/EticaSwapERC20.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.26;\n\n/// @title EticaSwap LP token (base ERC20 with EIP-2612 permit).\n/// @notice Uniswap V2–compatible LP token. Inherited by EticaSwapPair.\ncontract EticaSwapERC20 {\n string public constant name = \"EticaSwap V2\";\n string public constant symbol = \"ETICA-V2\";\n uint8 public constant decimals = 18;\n\n uint256 public totalSupply;\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\")\n bytes32 public constant PERMIT_TYPEHASH =\n 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint256) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n constructor() {\n uint256 chainId = block.chainid;\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n ),\n keccak256(bytes(name)),\n keccak256(bytes(\"1\")),\n chainId,\n address(this)\n )\n );\n }\n\n function _mint(address to, uint256 value) internal {\n totalSupply += value;\n unchecked {\n balanceOf[to] += value;\n }\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint256 value) internal {\n balanceOf[from] -= value;\n unchecked {\n totalSupply -= value;\n }\n emit Transfer(from, address(0), value);\n }\n\n function _approve(address owner, address spender, uint256 value) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(address from, address to, uint256 value) private {\n balanceOf[from] -= value;\n unchecked {\n balanceOf[to] += value;\n }\n emit Transfer(from, to, value);\n }\n\n function approve(address spender, uint256 value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint256 value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(address from, address to, uint256 value) external returns (bool) {\n uint256 allowed = allowance[from][msg.sender];\n if (allowed != type(uint256).max) {\n allowance[from][msg.sender] = allowed - value;\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"ESwap: EXPIRED\");\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(\n abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)\n )\n )\n );\n address recovered = ecrecover(digest, v, r, s);\n require(recovered != address(0) && recovered == owner, \"ESwap: INVALID_SIGNATURE\");\n _approve(owner, spender, value);\n }\n}\n" }, "src/swap/EticaSwapFactory.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.26;\n\nimport {EticaSwapPair} from \"./EticaSwapPair.sol\";\nimport {IEticaSwapFactory} from \"./interfaces/IEticaSwapFactory.sol\";\nimport {TransferHelper} from \"./libraries/TransferHelper.sol\";\n\n/// @title EticaSwap V2 factory (ETX hub-and-spoke)\n/// @notice Deploys deterministic pair contracts via CREATE2. Every pair MUST\n/// include ETX on one side: routes all liquidity through the ETX hub,\n/// making ETX the reserve asset of the DEX. 0.05% protocol fee (1/6 of\n/// the 0.30% swap fee) can be enabled by setting `feeTo`.\n/// @dev The `trustedCreators` allow-list is the one and only exception to\n/// the ETX-only rule: addresses in the set may create pairs that do\n/// not include ETX. It exists so the proposal-token launchpad can\n/// open `token/ETI` pools alongside `token/ETX`. Everyone else stays\n/// forced onto the ETX hub.\ncontract EticaSwapFactory is IEticaSwapFactory {\n /// @notice Default pair-creation fee, denominated in ETX (18 dp). Callers\n /// not in `trustedCreators` must pay this in ETX on `createPair`.\n /// Fee is skipped when `feeTo == 0x0` so a freshly-deployed\n /// factory can bootstrap before treasury wiring.\n uint256 public constant DEFAULT_PAIR_CREATION_FEE = 10_000 ether;\n\n address public immutable etx;\n address public feeTo;\n address public feeToSetter;\n\n mapping(address => mapping(address => address)) public getPair;\n address[] public allPairs;\n mapping(address => bool) public trustedCreators;\n uint256 public pairCreationFee;\n\n constructor(address _feeToSetter, address _etx) {\n require(_etx != address(0), \"ESwap: ETX_ZERO_ADDRESS\");\n feeToSetter = _feeToSetter;\n etx = _etx;\n pairCreationFee = DEFAULT_PAIR_CREATION_FEE;\n }\n\n function allPairsLength() external view returns (uint256) {\n return allPairs.length;\n }\n\n function createPair(address tokenA, address tokenB) external returns (address pair) {\n require(tokenA != tokenB, \"ESwap: IDENTICAL_ADDRESSES\");\n require(\n tokenA == etx || tokenB == etx || trustedCreators[msg.sender],\n \"ESwap: MUST_PAIR_WITH_ETX\"\n );\n (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);\n require(token0 != address(0), \"ESwap: ZERO_ADDRESS\");\n require(getPair[token0][token1] == address(0), \"ESwap: PAIR_EXISTS\");\n\n // Collect the pair-creation fee in ETX. Trusted creators (e.g. the\n // proposal-token launchpad, which already pays its own 250 ETX +\n // 250 ETI per launch) are exempt. The fee is also skipped while\n // `feeTo` is unset so a freshly-deployed factory can bootstrap.\n address recipient = feeTo;\n uint256 fee = pairCreationFee;\n if (!trustedCreators[msg.sender] && fee > 0 && recipient != address(0)) {\n TransferHelper.safeTransferFrom(etx, msg.sender, recipient, fee);\n }\n\n bytes32 salt = keccak256(abi.encodePacked(token0, token1));\n pair = address(new EticaSwapPair{salt: salt}());\n EticaSwapPair(pair).initialize(token0, token1);\n\n getPair[token0][token1] = pair;\n getPair[token1][token0] = pair;\n allPairs.push(pair);\n emit PairCreated(token0, token1, pair, allPairs.length);\n }\n\n function setFeeTo(address _feeTo) external {\n require(msg.sender == feeToSetter, \"ESwap: FORBIDDEN\");\n feeTo = _feeTo;\n }\n\n function setFeeToSetter(address _feeToSetter) external {\n require(msg.sender == feeToSetter, \"ESwap: FORBIDDEN\");\n feeToSetter = _feeToSetter;\n }\n\n /// @notice Grant or revoke a creator's permission to open non-ETX pairs.\n /// @dev Only the fee-to setter (i.e. governance / admin) can flip this.\n /// Intended use: whitelist the proposal-token launchpad so it can\n /// open `token/ETI` pools. Any address not in the set is still\n /// subject to the ETX-only rule.\n function setTrustedCreator(address creator, bool trusted) external {\n require(msg.sender == feeToSetter, \"ESwap: FORBIDDEN\");\n require(creator != address(0), \"ESwap: ZERO_ADDRESS\");\n trustedCreators[creator] = trusted;\n emit TrustedCreatorSet(creator, trusted);\n }\n\n /// @notice Update the ETX fee charged on `createPair` to non-trusted\n /// callers. Set to zero to disable the fee entirely.\n function setPairCreationFee(uint256 fee) external {\n require(msg.sender == feeToSetter, \"ESwap: FORBIDDEN\");\n pairCreationFee = fee;\n emit PairCreationFeeSet(fee);\n }\n\n /// @notice Init code hash for pairs — useful for off-chain CREATE2 address prediction.\n function pairCodeHash() external pure returns (bytes32) {\n return keccak256(type(EticaSwapPair).creationCode);\n }\n}\n" }, "src/swap/EticaSwapPair.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.26;\n\nimport {EticaSwapERC20} from \"./EticaSwapERC20.sol\";\nimport {Math} from \"./libraries/Math.sol\";\nimport {UQ112x112} from \"./libraries/UQ112x112.sol\";\nimport {IERC20Minimal} from \"./interfaces/IERC20Minimal.sol\";\nimport {IEticaSwapFactory} from \"./interfaces/IEticaSwapFactory.sol\";\nimport {IEticaSwapCallee} from \"./interfaces/IEticaSwapCallee.sol\";\n\n/// @title EticaSwap V2 pair\n/// @notice Constant-product AMM pair (x*y=k), 0.30% swap fee.\n/// @dev Port of UniswapV2Pair to Solidity 0.8.x. Invariants and math are\n/// equivalent to the audited V2 contract.\ncontract EticaSwapPair is EticaSwapERC20 {\n using UQ112x112 for uint224;\n\n uint256 public constant MINIMUM_LIQUIDITY = 10 ** 3;\n bytes4 private constant SELECTOR_TRANSFER =\n bytes4(keccak256(bytes(\"transfer(address,uint256)\")));\n\n address public factory;\n address public token0;\n address public token1;\n\n uint112 private reserve0;\n uint112 private reserve1;\n uint32 private blockTimestampLast;\n\n uint256 public price0CumulativeLast;\n uint256 public price1CumulativeLast;\n // reserve0 * reserve1 immediately after the most recent liquidity event\n uint256 public kLast;\n\n uint256 private unlocked = 1;\n\n modifier lock() {\n require(unlocked == 1, \"ESwap: LOCKED\");\n unlocked = 0;\n _;\n unlocked = 1;\n }\n\n event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);\n event Swap(\n address indexed sender,\n uint256 amount0In,\n uint256 amount1In,\n uint256 amount0Out,\n uint256 amount1Out,\n address indexed to\n );\n event Sync(uint112 reserve0, uint112 reserve1);\n\n constructor() {\n factory = msg.sender;\n }\n\n /// @notice Called once by the factory at deploy time.\n function initialize(address _token0, address _token1) external {\n require(msg.sender == factory, \"ESwap: FORBIDDEN\");\n token0 = _token0;\n token1 = _token1;\n }\n\n function getReserves()\n public\n view\n returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)\n {\n _reserve0 = reserve0;\n _reserve1 = reserve1;\n _blockTimestampLast = blockTimestampLast;\n }\n\n function _safeTransfer(address token, address to, uint256 value) private {\n (bool ok, bytes memory data) =\n token.call(abi.encodeWithSelector(SELECTOR_TRANSFER, to, value));\n require(ok && (data.length == 0 || abi.decode(data, (bool))), \"ESwap: TRANSFER_FAILED\");\n }\n\n function _update(uint256 balance0, uint256 balance1, uint112 _reserve0, uint112 _reserve1)\n private\n {\n require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, \"ESwap: OVERFLOW\");\n uint32 blockTimestamp = uint32(block.timestamp % 2 ** 32);\n unchecked {\n uint32 timeElapsed = blockTimestamp - blockTimestampLast;\n if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {\n price0CumulativeLast += uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0))\n * timeElapsed;\n price1CumulativeLast += uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1))\n * timeElapsed;\n }\n }\n reserve0 = uint112(balance0);\n reserve1 = uint112(balance1);\n blockTimestampLast = blockTimestamp;\n emit Sync(reserve0, reserve1);\n }\n\n /// @dev Mints fee equivalent to 1/6 of the growth in sqrt(k) to `feeTo`.\n function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {\n address feeTo = IEticaSwapFactory(factory).feeTo();\n feeOn = feeTo != address(0);\n uint256 _kLast = kLast;\n if (feeOn) {\n if (_kLast != 0) {\n uint256 rootK = Math.sqrt(uint256(_reserve0) * _reserve1);\n uint256 rootKLast = Math.sqrt(_kLast);\n if (rootK > rootKLast) {\n uint256 numerator = totalSupply * (rootK - rootKLast);\n uint256 denominator = rootK * 5 + rootKLast;\n uint256 liquidity = numerator / denominator;\n if (liquidity > 0) _mint(feeTo, liquidity);\n }\n }\n } else if (_kLast != 0) {\n kLast = 0;\n }\n }\n\n /// @notice Mints LP tokens for the caller based on amounts transferred in beforehand.\n function mint(address to) external lock returns (uint256 liquidity) {\n (uint112 _reserve0, uint112 _reserve1,) = getReserves();\n uint256 balance0 = IERC20Minimal(token0).balanceOf(address(this));\n uint256 balance1 = IERC20Minimal(token1).balanceOf(address(this));\n uint256 amount0 = balance0 - _reserve0;\n uint256 amount1 = balance1 - _reserve1;\n\n bool feeOn = _mintFee(_reserve0, _reserve1);\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;\n _mint(address(0), MINIMUM_LIQUIDITY);\n } else {\n liquidity = Math.min(\n (amount0 * _totalSupply) / _reserve0, (amount1 * _totalSupply) / _reserve1\n );\n }\n require(liquidity > 0, \"ESwap: INSUFFICIENT_LIQUIDITY_MINTED\");\n _mint(to, liquidity);\n\n _update(balance0, balance1, _reserve0, _reserve1);\n if (feeOn) kLast = uint256(reserve0) * reserve1;\n emit Mint(msg.sender, amount0, amount1);\n }\n\n /// @notice Burns LP tokens from this contract and sends the underlyings to `to`.\n function burn(address to) external lock returns (uint256 amount0, uint256 amount1) {\n (uint112 _reserve0, uint112 _reserve1,) = getReserves();\n address _token0 = token0;\n address _token1 = token1;\n uint256 balance0 = IERC20Minimal(_token0).balanceOf(address(this));\n uint256 balance1 = IERC20Minimal(_token1).balanceOf(address(this));\n uint256 liquidity = balanceOf[address(this)];\n\n bool feeOn = _mintFee(_reserve0, _reserve1);\n uint256 _totalSupply = totalSupply;\n amount0 = (liquidity * balance0) / _totalSupply;\n amount1 = (liquidity * balance1) / _totalSupply;\n require(amount0 > 0 && amount1 > 0, \"ESwap: INSUFFICIENT_LIQUIDITY_BURNED\");\n _burn(address(this), liquidity);\n _safeTransfer(_token0, to, amount0);\n _safeTransfer(_token1, to, amount1);\n balance0 = IERC20Minimal(_token0).balanceOf(address(this));\n balance1 = IERC20Minimal(_token1).balanceOf(address(this));\n\n _update(balance0, balance1, _reserve0, _reserve1);\n if (feeOn) kLast = uint256(reserve0) * reserve1;\n emit Burn(msg.sender, amount0, amount1, to);\n }\n\n /// @notice Swap: the caller must have pre-paid `amount{0,1}In` (constant-product check).\n /// Supports flash swaps via the `data` callback to `IEticaSwapCallee.eticaSwapCall`.\n function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data)\n external\n lock\n {\n require(amount0Out > 0 || amount1Out > 0, \"ESwap: INSUFFICIENT_OUTPUT_AMOUNT\");\n (uint112 _reserve0, uint112 _reserve1,) = getReserves();\n require(amount0Out < _reserve0 && amount1Out < _reserve1, \"ESwap: INSUFFICIENT_LIQUIDITY\");\n\n uint256 balance0;\n uint256 balance1;\n {\n address _token0 = token0;\n address _token1 = token1;\n require(to != _token0 && to != _token1, \"ESwap: INVALID_TO\");\n if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out);\n if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out);\n if (data.length > 0) {\n IEticaSwapCallee(to).eticaSwapCall(msg.sender, amount0Out, amount1Out, data);\n }\n balance0 = IERC20Minimal(_token0).balanceOf(address(this));\n balance1 = IERC20Minimal(_token1).balanceOf(address(this));\n }\n uint256 amount0In =\n balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;\n uint256 amount1In =\n balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;\n require(amount0In > 0 || amount1In > 0, \"ESwap: INSUFFICIENT_INPUT_AMOUNT\");\n {\n uint256 balance0Adjusted = balance0 * 1000 - amount0In * 3;\n uint256 balance1Adjusted = balance1 * 1000 - amount1In * 3;\n require(\n balance0Adjusted * balance1Adjusted >= uint256(_reserve0) * _reserve1 * (1000 ** 2),\n \"ESwap: K\"\n );\n }\n\n _update(balance0, balance1, _reserve0, _reserve1);\n emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);\n }\n\n /// @notice Force balances to match reserves (sends excess to `to`).\n function skim(address to) external lock {\n address _token0 = token0;\n address _token1 = token1;\n _safeTransfer(_token0, to, IERC20Minimal(_token0).balanceOf(address(this)) - reserve0);\n _safeTransfer(_token1, to, IERC20Minimal(_token1).balanceOf(address(this)) - reserve1);\n }\n\n /// @notice Force reserves to match balances.\n function sync() external lock {\n _update(\n IERC20Minimal(token0).balanceOf(address(this)),\n IERC20Minimal(token1).balanceOf(address(this)),\n reserve0,\n reserve1\n );\n }\n}\n" }, "src/swap/interfaces/IERC20Minimal.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\ninterface IERC20Minimal {\n function balanceOf(address owner) external view returns (uint256);\n function totalSupply() external view returns (uint256);\n function transfer(address to, uint256 value) external returns (bool);\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n function approve(address spender, uint256 value) external returns (bool);\n function allowance(address owner, address spender) external view returns (uint256);\n function decimals() external view returns (uint8);\n function symbol() external view returns (string memory);\n function name() external view returns (string memory);\n}\n" }, "src/swap/interfaces/IEticaSwapCallee.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\n/// @title Flash-swap callback.\n/// @notice Contracts receiving flash swaps from a pair must implement this.\ninterface IEticaSwapCallee {\n function eticaSwapCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data)\n external;\n}\n" }, "src/swap/interfaces/IEticaSwapFactory.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\n/// @title EticaSwap V2 factory interface\n/// @notice Uniswap V2–compatible factory deploying CREATE2 pair contracts.\ninterface IEticaSwapFactory {\n event PairCreated(address indexed token0, address indexed token1, address pair, uint256);\n event TrustedCreatorSet(address indexed creator, bool trusted);\n event PairCreationFeeSet(uint256 fee);\n\n function etx() external view returns (address);\n function feeTo() external view returns (address);\n function feeToSetter() external view returns (address);\n function trustedCreators(address creator) external view returns (bool);\n function pairCreationFee() external view returns (uint256);\n\n function getPair(address tokenA, address tokenB) external view returns (address pair);\n function allPairs(uint256) external view returns (address pair);\n function allPairsLength() external view returns (uint256);\n\n function createPair(address tokenA, address tokenB) external returns (address pair);\n\n function setFeeTo(address) external;\n function setFeeToSetter(address) external;\n function setTrustedCreator(address creator, bool trusted) external;\n function setPairCreationFee(uint256 fee) external;\n}\n" }, "src/swap/libraries/Math.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\nlibrary Math {\n function min(uint256 x, uint256 y) internal pure returns (uint256 z) {\n z = x < y ? x : y;\n }\n\n /// @notice Babylonian square root.\n function sqrt(uint256 y) internal pure returns (uint256 z) {\n if (y > 3) {\n z = y;\n uint256 x = y / 2 + 1;\n while (x < z) {\n z = x;\n x = (y / x + x) / 2;\n }\n } else if (y != 0) {\n z = 1;\n }\n }\n}\n" }, "src/swap/libraries/TransferHelper.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\n/// @notice Safe transfer helpers that tolerate ERC20s that don't return a boolean.\nlibrary TransferHelper {\n function safeApprove(address token, address to, uint256 value) internal {\n (bool ok, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n require(ok && (data.length == 0 || abi.decode(data, (bool))), \"TH: APPROVE_FAILED\");\n }\n\n function safeTransfer(address token, address to, uint256 value) internal {\n (bool ok, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n require(ok && (data.length == 0 || abi.decode(data, (bool))), \"TH: TRANSFER_FAILED\");\n }\n\n function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n (bool ok, bytes memory data) =\n token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n require(ok && (data.length == 0 || abi.decode(data, (bool))), \"TH: TRANSFER_FROM_FAILED\");\n }\n\n function safeTransferEGAZ(address to, uint256 value) internal {\n (bool ok,) = to.call{value: value}(new bytes(0));\n require(ok, \"TH: EGAZ_TRANSFER_FAILED\");\n }\n}\n" }, "src/swap/libraries/UQ112x112.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.0;\n\n/// @title UQ112x112 fixed-point\n/// @notice Represents a range [0, 2^112 - 1] with a resolution of 1 / 2^112.\n/// @dev Ported from Uniswap V2 core. Range-safe for reserves stored as uint112.\nlibrary UQ112x112 {\n uint224 internal constant Q112 = 2 ** 112;\n\n function encode(uint112 y) internal pure returns (uint224 z) {\n z = uint224(y) * Q112;\n }\n\n function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {\n z = x / uint224(y);\n }\n}\n" } }, "abi": [ { "type": "constructor", "inputs": [ { "name": "_feeToSetter", "type": "address", "internalType": "address" }, { "name": "_etx", "type": "address", "internalType": "address" } ], "stateMutability": "nonpayable" }, { "type": "function", "name": "DEFAULT_PAIR_CREATION_FEE", "inputs": [], "outputs": [ { "name": "", "type": "uint256", "internalType": "uint256" } ], "stateMutability": "view" }, { "type": "function", "name": "allPairs", "inputs": [ { "name": "", "type": "uint256", "internalType": "uint256" } ], "outputs": [ { "name": "", "type": "address", "internalType": "address" } ], "stateMutability": "view" }, { "type": "function", "name": "allPairsLength", "inputs": [], "outputs": [ { "name": "", "type": "uint256", "internalType": "uint256" } ], "stateMutability": "view" }, { "type": "function", "name": "createPair", "inputs": [ { "name": "tokenA", "type": "address", "internalType": "address" }, { "name": "tokenB", "type": "address", "internalType": "address" } ], "outputs": [ { "name": "pair", "type": "address", "internalType": "address" } ], "stateMutability": "nonpayable" }, { "type": "function", "name": "etx", "inputs": [], "outputs": [ { "name": "", "type": "address", "internalType": "address" } ], "stateMutability": "view" }, { "type": "function", "name": "feeTo", "inputs": [], "outputs": [ { "name": "", "type": "address", "internalType": "address" } ], "stateMutability": "view" }, { "type": "function", "name": "feeToSetter", "inputs": [], "outputs": [ { "name": "", "type": "address", "internalType": "address" } ], "stateMutability": "view" }, { "type": "function", "name": "getPair", "inputs": [ { "name": "", "type": "address", "internalType": "address" }, { "name": "", "type": "address", "internalType": "address" } ], "outputs": [ { "name": "", "type": "address", "internalType": "address" } ], "stateMutability": "view" }, { "type": "function", "name": "pairCodeHash", "inputs": [], "outputs": [ { "name": "", "type": "bytes32", "internalType": "bytes32" } ], "stateMutability": "pure" }, { "type": "function", "name": "pairCreationFee", "inputs": [], "outputs": [ { "name": "", "type": "uint256", "internalType": "uint256" } ], "stateMutability": "view" }, { "type": "function", "name": "setFeeTo", "inputs": [ { "name": "_feeTo", "type": "address", "internalType": "address" } ], "outputs": [], "stateMutability": "nonpayable" }, { "type": "function", "name": "setFeeToSetter", "inputs": [ { "name": "_feeToSetter", "type": "address", "internalType": "address" } ], "outputs": [], "stateMutability": "nonpayable" }, { "type": "function", "name": "setPairCreationFee", "inputs": [ { "name": "fee", "type": "uint256", "internalType": "uint256" } ], "outputs": [], "stateMutability": "nonpayable" }, { "type": "function", "name": "setTrustedCreator", "inputs": [ { "name": "creator", "type": "address", "internalType": "address" }, { "name": "trusted", "type": "bool", "internalType": "bool" } ], "outputs": [], "stateMutability": "nonpayable" }, { "type": "function", "name": "trustedCreators", "inputs": [ { "name": "", "type": "address", "internalType": "address" } ], "outputs": [ { "name": "", "type": "bool", "internalType": "bool" } ], "stateMutability": "view" }, { "type": "event", "name": "PairCreated", "inputs": [ { "name": "token0", "type": "address", "indexed": true, "internalType": "address" }, { "name": "token1", "type": "address", "indexed": true, "internalType": "address" }, { "name": "pair", "type": "address", "indexed": false, "internalType": "address" }, { "name": "", "type": "uint256", "indexed": false, "internalType": "uint256" } ], "anonymous": false }, { "type": "event", "name": "PairCreationFeeSet", "inputs": [ { "name": "fee", "type": "uint256", "indexed": false, "internalType": "uint256" } ], "anonymous": false }, { "type": "event", "name": "TrustedCreatorSet", "inputs": [ { "name": "creator", "type": "address", "indexed": true, "internalType": "address" }, { "name": "trusted", "type": "bool", "indexed": false, "internalType": "bool" } ], "anonymous": false } ], "verifiedAt": "2026-04-22T03:35:57.462Z", "bytecodeMatch": "with-immutables" }