JAMMFactory Contract
JAMMFactory is the core factory contract of JAMM DEX, responsible for creating and managing all trading pairs. It uses CREATE2 deterministic deployment, supports a multi-tier fee system, and has built-in referrer management functionality. The Factory contract is the entry point and control center of the entire protocol.
Contract Basic Information
contract JAMMFactory is IJAMMFactory {
// Contract Address: 0x6b5d54E6F73e96Ca960DBA71D778b98221939aa6 (Mainnet)
// Contract Address: 0xbddd716a9d6325700d1c29562c819987e5b1f6a8 (Testnet)
}
Fee Constants
Supported Fee Tiers
uint24 public constant FEE_0_5_PERCENT = 50; // 0.5%
uint24 public constant FEE_1_PERCENT = 100; // 1.0%
uint24 public constant FEE_2_PERCENT = 200; // 2.0%
uint24 public constant FEE_3_PERCENT = 300; // 3.0%
These four constants define all fee tiers supported by JAMM DEX:
Base: 10000 (i.e., 100%)
0.5%: 50/10000 = 0.005
1.0%: 100/10000 = 0.01
2.0%: 200/10000 = 0.02
3.0%: 300/10000 = 0.03
State Variables
Management Addresses
address public override mintTo; // Protocol fee recipient address
address public override feeTo; // Trading fee recipient address
address public override feeToSetter; // Fee setting administrator
Address Description:
mintTo
: Address receiving protocol fees (in LP token form)feeTo
: Address receiving trading feesfeeToSetter
: Administrator with exclusive permission to modify the above addresses
Trading Pair Registry
mapping(address => mapping(address => mapping(uint24 => address))) public override getPair;
address[] public override allPairs;
Data Structure:
getPair[tokenA][tokenB][fee]
: Three-dimensional mapping to find trading pairs by token addresses and fee rateallPairs
: Array of all trading pair addresses for iteration
Referrer System
mapping(address => address) public referrer;
Records the referrer address corresponding to each user (tx.origin).
Initialization Code Hash
bytes32 public constant override INIT_CODE_PAIR_HASH =
keccak256(type(JAMMPair).creationCode);
This hash value is used for CREATE2 address calculation to ensure deterministic trading pair addresses. The actual value is determined at contract deployment time.
Core Functions
Constructor
constructor(address _feeToSetter) {
feeToSetter = _feeToSetter;
}
Sets the fee administrator address during deployment, which is the only initialization parameter.
Create Trading Pair
function createPair(
address tokenA,
address tokenB,
uint24 fee
) external override returns (address pair) {
require(tokenA != tokenB, "JAMMFactory: IDENTICAL_ADDRESSES");
require(
tokenA != address(0) && tokenB != address(0),
"JAMMFactory: ZERO_ADDRESS"
);
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(
fee == FEE_0_5_PERCENT ||
fee == FEE_1_PERCENT ||
fee == FEE_2_PERCENT ||
fee == FEE_3_PERCENT,
"JAMMFactory: INVALID_FEE"
);
require(
getPair[token0][token1][fee] == address(0),
"JAMMFactory: PAIR_EXISTS"
);
bytes memory bytecode = type(JAMMPair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1, fee));
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
JAMMPair(pair).initialize(token0, token1, fee);
getPair[token0][token1][fee] = pair;
getPair[token1][token0][fee] = pair; // Bidirectional mapping
allPairs.push(pair);
emit PairCreated(token0, token1, fee, pair, allPairs.length);
}
Creation Process:
Parameter Validation: Check token address validity and fee rate legality
Token Sorting: Ensure token0 < token1 to guarantee uniqueness
Duplicate Check: Ensure trading pair with same parameters doesn't exist
CREATE2 Deployment: Deploy new JAMMPair contract using deterministic address
Initialization: Call initialize function of new contract
Registration: Update mapping tables and arrays
Event Emission: Emit PairCreated event
Query Functions
function allPairsLength() external view override returns (uint) {
return allPairs.length;
}
Returns the total number of created trading pairs.
Management Functions
Set Protocol Fee Recipient Address
function setMintTo(address _mintTo) external override {
require(msg.sender == feeToSetter, "JAMMFactory: FORBIDDEN");
mintTo = _mintTo;
}
Set Trading Fee Recipient Address
function setFeeTo(address _feeTo) external override {
require(msg.sender == feeToSetter, "JAMMFactory: FORBIDDEN");
feeTo = _feeTo;
}
Set Fee Administrator
function setFeeToSetter(address _feeToSetter) external override {
require(msg.sender == feeToSetter, "JAMMFactory: FORBIDDEN");
feeToSetter = _feeToSetter;
}
Access Control: All management functions can only be called by the current feeToSetter
.
Referrer Management
function setReferrer(address _referrer) external override {
require(
referrer[tx.origin] == address(0),
"JAMMFactory: REFERER_EXISTS"
);
referrer[tx.origin] = _referrer;
emit Referrer(tx.origin, _referrer);
}
Features:
Uses
tx.origin
instead ofmsg.sender
Each user can only set referrer once
Cannot be modified after setting
Event System
PairCreated Event
event PairCreated(
address indexed token0,
address indexed token1,
uint24 fee,
address pair,
uint
);
Records the creation of new trading pairs, including:
token0
: First token address after sortingtoken1
: Second token address after sortingfee
: Fee ratepair
: Address of newly created trading pairLast parameter: Current total number of trading pairs
Referrer Event
event Referrer(address indexed sender, address indexed referrer);
Records the establishment of referrer relationships.
CREATE2 Address Calculation
Address Pre-calculation
Trading pair addresses can be pre-calculated using the following method:
function computePairAddress(
address factory,
address tokenA,
address tokenB,
uint24 fee
) pure returns (address pair) {
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
pair = address(uint160(uint256(keccak256(abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1, fee)),
INIT_CODE_PAIR_HASH // Use actual hash value from Factory contract
)))));
}
Salt Calculation
bytes32 salt = keccak256(abi.encodePacked(token0, token1, fee));
Salt consists of three parameters:
token0
: Smaller token addresstoken1
: Larger token addressfee
: Fee rate value
Usage Examples
Create New Trading Pair
const factory = new ethers.Contract(factoryAddress, factoryABI, signer);
// Create USDC/USDT trading pair with 0.5% fee rate
const tx = await factory.createPair(
"0xUSDC_ADDRESS",
"0xUSDT_ADDRESS",
50 // 0.5%
);
const receipt = await tx.wait();
const pairCreatedEvent = receipt.events.find(e => e.event === 'PairCreated');
const pairAddress = pairCreatedEvent.args.pair;
console.log("New trading pair address:", pairAddress);
Query Trading Pairs
// Query specific trading pair
const pairAddress = await factory.getPair(tokenA, tokenB, fee);
if (pairAddress === ethers.constants.AddressZero) {
console.log("Trading pair does not exist");
} else {
console.log("Trading pair address:", pairAddress);
}
// Query all trading pairs
const totalPairs = await factory.allPairsLength();
console.log("Total trading pairs:", totalPairs.toString());
for (let i = 0; i < totalPairs; i++) {
const pairAddress = await factory.allPairs(i);
console.log(`Trading pair ${i}:`, pairAddress);
}
Set Referrer
// Check current referrer
const currentReferrer = await factory.referrer(userAddress);
if (currentReferrer === ethers.constants.AddressZero) {
// Set referrer
const tx = await factory.setReferrer(referrerAddress);
await tx.wait();
console.log("Referrer set successfully");
} else {
console.log("Existing referrer:", currentReferrer);
}
Listen to Events
// Listen to new trading pair creation
factory.on("PairCreated", (token0, token1, fee, pair, totalPairs) => {
console.log("New trading pair created:");
console.log("- Token0:", token0);
console.log("- Token1:", token1);
console.log("- Fee rate:", fee);
console.log("- Address:", pair);
console.log("- Total:", totalPairs.toString());
});
// Listen to referrer setting
factory.on("Referrer", (sender, referrer) => {
console.log(`User ${sender} set referrer to ${referrer}`);
});
Last updated