PoolFactory
0xfa5429aeba338bea2bfcc1b9a889862ee395bc28
Verification
Verified
v0.8.19+commit.7dd6d404
Type
Contract
3,506 bytes
ABI entries
41
16 read · 8 write
License
none
Contract information
- Address
- 0xfa5429aeba338bea2bfcc1b9a889862ee395bc28
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.19+commit.7dd6d404
- Optimization
- Enabled
- Creator
- 0x85Fb9f9BC8…459C096651
- Creation tx
- 0x4f463dc72e…5dce2184e7
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (16)
MAX_FEE() → uint256
ZERO_FEE_INDICATOR() → uint256
allPools(uint256) → address
allPoolsLength() → uint256
customFee(address) → uint256
feeManager() → address
getFee(address, bool) → uint256
getPool(address, address, uint24) → address
getPool(address, address, bool) → address
implementation() → address
isPaused() → bool
isPool(address) → bool
pauser() → address
stableFee() → uint256
volatileFee() → uint256
voter() → address
Events (6)
PoolCreatedSetCustomFeeSetFeeManagerSetPauseStateSetPauserSetVoter
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_implementation",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "FeeInvalid",
"type": "error"
},
{
"inputs": [],
"name": "FeeTooHigh",
"type": "error"
},
{
"inputs": [],
"name": "InvalidPool",
"type": "error"
},
{
"inputs": [],
"name": "NotFeeManager",
"type": "error"
},
{
"inputs": [],
"name": "NotPauser",
"type": "error"
},
{
"inputs": [],
"name": "NotVoter",
"type": "error"
},
{
"inputs": [],
"name": "PoolAlreadyExists",
"type": "error"
},
{
"inputs": [],
"name": "SameAddress",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "ZeroFee",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token0",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "token1",
"type": "address"
},
{
"indexed": true,
"internalType": "bool",
"name": "stable",
"type": "bool"
},
{
"indexed": false,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "PoolCreated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"name": "SetCustomFee",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "feeManager",
"type": "address"
}
],
"name": "SetFeeManager",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bool",
"name": "state",
"type": "bool"
}
],
"name": "SetPauseState",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "pauser",
"type": "address"
}
],
"name": "SetPauser",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "voter",
"type": "address"
}
],
"name": "SetVoter",
"type": "event"
},
{
"inputs": [],
"name": "MAX_FEE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ZERO_FEE_INDICATOR",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "allPools",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allPoolsLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenA",
"type": "address"
},
{
"internalType": "address",
"name": "tokenB",
"type": "address"
},
{
"internalType": "bool",
"name": "stable",
"type": "bool"
}
],
"name": "createPool",
"outputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenA",
"type": "address"
},
{
"internalType": "address",
"name": "tokenB",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
}
],
"name": "createPool",
"outputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "customFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "bool",
"name": "_stable",
"type": "bool"
}
],
"name": "getFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenA",
"type": "address"
},
{
"internalType": "address",
"name": "tokenB",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
}
],
"name": "getPool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tokenA",
"type": "address"
},
{
"internalType": "address",
"name": "tokenB",
"type": "address"
},
{
"internalType": "bool",
"name": "stable",
"type": "bool"
}
],
"name": "getPool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "implementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "isPaused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"name": "isPool",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pauser",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"name": "setCustomFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "_stable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "_fee",
"type": "uint256"
}
],
"name": "setFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_feeManager",
"type": "address"
}
],
"name": "setFeeManager",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "_state",
"type": "bool"
}
],
"name": "setPauseState",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_pauser",
"type": "address"
}
],
"name": "setPauser",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_voter",
"type": "address"
}
],
"name": "setVoter",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "stableFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "volatileFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "voter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import {IPoolFactory} from "../interfaces/factories/IPoolFactory.sol";
import {IPool} from "../interfaces/IPool.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
contract PoolFactory is IPoolFactory {
address public immutable implementation;
bool public isPaused;
address public pauser;
uint256 public stableFee;
uint256 public volatileFee;
uint256 public constant MAX_FEE = 300; // 3%
// Override to indicate there is custom 0% fee - as a 0 value in the customFee mapping indicates
// that no custom fee rate has been set
uint256 public constant ZERO_FEE_INDICATOR = 420;
address public feeManager;
/// @dev used to change the name/symbol of the pool by calling emergencyCouncil
address public voter;
mapping(address => mapping(address => mapping(bool => address))) private _getPool;
address[] public allPools;
mapping(address => bool) private _isPool; // simplified check if its a pool, given that `stable` flag might not be available in peripherals
mapping(address => uint256) public customFee; // override for custom fees
address internal _temp0;
address internal _temp1;
bool internal _temp;
constructor(address _implementation) {
implementation = _implementation;
voter = msg.sender;
pauser = msg.sender;
feeManager = msg.sender;
isPaused = false;
stableFee = 5; // 0.05%
volatileFee = 30; // 0.3%
}
/// @inheritdoc IPoolFactory
function allPoolsLength() external view returns (uint256) {
return allPools.length;
}
/// @inheritdoc IPoolFactory
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address) {
return fee > 1 ? address(0) : fee == 1 ? _getPool[tokenA][tokenB][true] : _getPool[tokenA][tokenB][false];
}
/// @inheritdoc IPoolFactory
function getPool(address tokenA, address tokenB, bool stable) external view returns (address) {
return _getPool[tokenA][tokenB][stable];
}
/// @inheritdoc IPoolFactory
function isPool(address pool) external view returns (bool) {
return _isPool[pool];
}
/// @inheritdoc IPoolFactory
function setVoter(address _voter) external {
if (msg.sender != voter) revert NotVoter();
voter = _voter;
emit SetVoter(_voter);
}
function setPauser(address _pauser) external {
if (msg.sender != pauser) revert NotPauser();
if (_pauser == address(0)) revert ZeroAddress();
pauser = _pauser;
emit SetPauser(_pauser);
}
function setPauseState(bool _state) external {
if (msg.sender != pauser) revert NotPauser();
isPaused = _state;
emit SetPauseState(_state);
}
function setFeeManager(address _feeManager) external {
if (msg.sender != feeManager) revert NotFeeManager();
if (_feeManager == address(0)) revert ZeroAddress();
feeManager = _feeManager;
emit SetFeeManager(_feeManager);
}
/// @inheritdoc IPoolFactory
function setFee(bool _stable, uint256 _fee) external {
if (msg.sender != feeManager) revert NotFeeManager();
if (_fee > MAX_FEE) revert FeeTooHigh();
if (_fee == 0) revert ZeroFee();
if (_stable) {
stableFee = _fee;
} else {
volatileFee = _fee;
}
}
/// @inheritdoc IPoolFactory
function setCustomFee(address pool, uint256 fee) external {
if (msg.sender != feeManager) revert NotFeeManager();
if (fee > MAX_FEE && fee != ZERO_FEE_INDICATOR) revert FeeTooHigh();
if (!_isPool[pool]) revert InvalidPool();
customFee[pool] = fee;
emit SetCustomFee(pool, fee);
}
/// @inheritdoc IPoolFactory
function getFee(address pool, bool _stable) public view returns (uint256) {
uint256 fee = customFee[pool];
return fee == ZERO_FEE_INDICATOR ? 0 : fee != 0 ? fee : _stable ? stableFee : volatileFee;
}
/// @inheritdoc IPoolFactory
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool) {
if (fee > 1) revert FeeInvalid();
return createPool(tokenA, tokenB, fee == 1);
}
/// @inheritdoc IPoolFactory
function createPool(address tokenA, address tokenB, bool stable) public returns (address pool) {
if (tokenA == tokenB) revert SameAddress();
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
if (token0 == address(0)) revert ZeroAddress();
if (_getPool[token0][token1][stable] != address(0)) revert PoolAlreadyExists();
bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // salt includes stable as well, 3 parameters
pool = Clones.cloneDeterministic(implementation, salt);
IPool(pool).initialize(token0, token1, stable);
_getPool[token0][token1][stable] = pool;
_getPool[token1][token0][stable] = pool; // populate mapping in the reverse direction
allPools.push(pool);
_isPool[pool] = true;
emit PoolCreated(token0, token1, stable, pool, allPools.length);
}
}
Chain explorer3415msChain node80ms