Contract Overview
My Name Tag:
Not Available, login to update
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xd7b8290f15f00aed00d62255793041a1d131de44838e15c864f6d2159871a757 | 41739264 | 332 days 7 hrs ago | 0xe42bb367c958e0e624c164f2491c37d8fd713515 | Contract Creation | 0 FTM |
[ Download CSV Export ]
Contract Name:
BaseV1Fees
Compiler Version
v0.8.11+commit.d7f03943
Contract Source Code (Solidity)
/** *Submitted for verification at FtmScan.com on 2022-08-29 */ // SPDX-License-Identifier: MIT pragma solidity ^0.8.11; interface erc20 { function totalSupply() external view returns (uint256); function transfer(address recipient, uint amount) external returns (bool); function decimals() external view returns (uint8); function symbol() external view returns (string memory); function balanceOf(address) external view returns (uint); function transferFrom(address sender, address recipient, uint amount) external returns (bool); function approve(address spender, uint value) external returns (bool); } library Math { function min(uint a, uint b) internal pure returns (uint) { return a < b ? a : b; } function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } interface IBaseV1Callee { function hook(address sender, uint amount0, uint amount1, bytes calldata data) external; } interface IBaseV1Factory { function protocolAddresses(address _pair) external returns (address); function spiritMaker() external returns (address); function stableFee() external returns (uint256); function variableFee() external returns (uint256); } // Base V1 Fees contract is used as a 1:1 pair relationship to split out fees, this ensures that the curve does not need to be modified for LP shares contract BaseV1Fees { address internal immutable factory; // Factory that created the pairs address internal immutable pair; // The pair it is bonded to address internal immutable token0; // token0 of pair, saved localy and statically for gas optimization address internal immutable token1; // Token1 of pair, saved localy and statically for gas optimization constructor(address _token0, address _token1, address _factory) { pair = msg.sender; factory = _factory; token0 = _token0; token1 = _token1; } function _safeTransfer(address token,address to,uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(erc20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } // Allow the pair to transfer fees to users function claimFeesFor(address recipient, uint amount0, uint amount1) external returns (uint256 claimed0, uint256 claimed1) { require(msg.sender == pair); uint256 counter = 4; // send 25% to protocol address if protocol address exists address protocolAddress = IBaseV1Factory(factory).protocolAddresses(pair); if (protocolAddress != address(0x0)) { if (amount0 > 0) _safeTransfer(token0, protocolAddress, amount0 / 4); if (amount1 > 0) _safeTransfer(token1, protocolAddress, amount1 / 4); counter--; } // send 25% to spiritMaker address spiritMaker = IBaseV1Factory(factory).spiritMaker(); if (spiritMaker != address(0x0)) { if (amount0 > 0) _safeTransfer(token0, spiritMaker, amount0 / 4); if (amount1 > 0) _safeTransfer(token1, spiritMaker, amount1 / 4); counter--; } claimed0 = amount0 * counter / 4; claimed1 = amount1 * counter / 4; // send the rest to owner of LP if (amount0 > 0) _safeTransfer(token0, recipient, claimed0); if (amount1 > 0) _safeTransfer(token1, recipient, claimed1); } } // The base pair of pools, either stable or volatile contract BaseV1Pair { string public name; string public symbol; uint8 public constant decimals = 18; // Used to denote stable or volatile pair, not immutable since construction happens in the initialize method for CREATE2 deterministic addresses bool public immutable stable; uint256 public fee; uint public totalSupply = 0; mapping(address => mapping (address => uint)) public allowance; mapping(address => uint) public balanceOf; bytes32 internal DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 internal constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint) public nonces; uint internal constant MINIMUM_LIQUIDITY = 10**3; address public immutable token0; address public immutable token1; address public immutable fees; address immutable factory; // Structure to capture time period obervations every 30 minutes, used for local oracles struct Observation { uint timestamp; uint reserve0Cumulative; uint reserve1Cumulative; } // Capture oracle reading every 30 minutes uint constant periodSize = 1800; Observation[] public observations; uint internal immutable decimals0; uint internal immutable decimals1; uint public reserve0; uint public reserve1; uint public blockTimestampLast; uint public reserve0CumulativeLast; uint public reserve1CumulativeLast; // index0 and index1 are used to accumulate fees, this is split out from normal trades to keep the swap "clean" // this further allows LP holders to easily claim fees for tokens they have/staked uint public index0 = 0; uint public index1 = 0; // position assigned to each LP to track their current index0 & index1 vs the global position mapping(address => uint) public supplyIndex0; mapping(address => uint) public supplyIndex1; // tracks the amount of unclaimed, but claimable tokens off of fees for token0 and token1 mapping(address => uint) public claimable0; mapping(address => uint) public claimable1; event Fees(address indexed sender, uint amount0, uint amount1); event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint reserve0, uint reserve1); event Claim(address indexed sender, address indexed recipient, uint amount0, uint amount1); event Transfer(address indexed from, address indexed to, uint amount); event Approval(address indexed owner, address indexed spender, uint amount); constructor() { factory = msg.sender; (address _token0, address _token1, bool _stable) = BaseV1Factory(msg.sender).getInitializable(); (token0, token1, stable) = (_token0, _token1, _stable); fees = address(new BaseV1Fees(_token0, _token1, factory)); if (_stable) { name = string(abi.encodePacked("StableV1 AMM - ", erc20(_token0).symbol(), "/", erc20(_token1).symbol())); symbol = string(abi.encodePacked("sAMM-", erc20(_token0).symbol(), "/", erc20(_token1).symbol())); fee = IBaseV1Factory(factory).stableFee(); } else { name = string(abi.encodePacked("VolatileV1 AMM - ", erc20(_token0).symbol(), "/", erc20(_token1).symbol())); symbol = string(abi.encodePacked("vAMM-", erc20(_token0).symbol(), "/", erc20(_token1).symbol())); fee = IBaseV1Factory(factory).variableFee(); } decimals0 = 10**erc20(_token0).decimals(); decimals1 = 10**erc20(_token1).decimals(); observations.push(Observation(block.timestamp, 0, 0)); } // simple re-entrancy check uint internal _unlocked = 1; modifier lock() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } function updateFee() external { if (stable) { fee = IBaseV1Factory(factory).stableFee(); } else { fee = IBaseV1Factory(factory).variableFee(); } } function observationLength() external view returns (uint) { return observations.length; } function lastObservation() public view returns (Observation memory) { return observations[observations.length-1]; } function metadata() external view returns (uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1) { return (decimals0, decimals1, reserve0, reserve1, stable, token0, token1); } function tokens() external view returns (address, address) { return (token0, token1); } function spiritMaker() external returns (address) { return IBaseV1Factory(factory).spiritMaker(); } function protocol() external returns (address) { return IBaseV1Factory(factory).protocolAddresses(address(this)); } // claim accumulated but unclaimed fees (viewable via claimable0 and claimable1) function claimFees() external returns (uint claimed0, uint claimed1) { _updateFor(msg.sender); claimed0 = claimable0[msg.sender]; claimed1 = claimable1[msg.sender]; if (claimed0 > 0 || claimed1 > 0) { claimable0[msg.sender] = 0; claimable1[msg.sender] = 0; (claimed0, claimed1) = BaseV1Fees(fees).claimFeesFor(msg.sender, claimed0, claimed1); emit Claim(msg.sender, msg.sender, claimed0, claimed1); } } // Accrue fees on token0 function _update0(uint amount) internal { _safeTransfer(token0, fees, amount); // transfer the fees out to BaseV1Fees uint256 _ratio = amount * 1e18 / totalSupply; // 1e18 adjustment is removed during claim if (_ratio > 0) { index0 += _ratio; } emit Fees(msg.sender, amount, 0); } // Accrue fees on token1 function _update1(uint amount) internal { _safeTransfer(token1, fees, amount); uint256 _ratio = amount * 1e18 / totalSupply; if (_ratio > 0) { index1 += _ratio; } emit Fees(msg.sender, 0, amount); } // this function MUST be called on any balance changes, otherwise can be used to infinitely claim fees // Fees are segregated from core funds, so fees can never put liquidity at risk function _updateFor(address recipient) internal { uint _supplied = balanceOf[recipient]; // get LP balance of `recipient` if (_supplied > 0) { uint _supplyIndex0 = supplyIndex0[recipient]; // get last adjusted index0 for recipient uint _supplyIndex1 = supplyIndex1[recipient]; uint _index0 = index0; // get global index0 for accumulated fees uint _index1 = index1; supplyIndex0[recipient] = _index0; // update user current position to global position supplyIndex1[recipient] = _index1; uint _delta0 = _index0 - _supplyIndex0; // see if there is any difference that need to be accrued uint _delta1 = _index1 - _supplyIndex1; if (_delta0 > 0) { uint _share = _supplied * _delta0 / 1e18; // add accrued difference for each supplied token claimable0[recipient] += _share; } if (_delta1 > 0) { uint _share = _supplied * _delta1 / 1e18; claimable1[recipient] += _share; } } else { supplyIndex0[recipient] = index0; // new users are set to the default global state supplyIndex1[recipient] = index1; } } function getReserves() public view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } // update reserves and, on the first call per block, price accumulators function _update(uint balance0, uint balance1, uint _reserve0, uint _reserve1) internal { uint blockTimestamp = block.timestamp; uint timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { reserve0CumulativeLast += _reserve0 * timeElapsed; reserve1CumulativeLast += _reserve1 * timeElapsed; } Observation memory _point = lastObservation(); timeElapsed = blockTimestamp - _point.timestamp; // compare the last observation with current timestamp, if greater than 30 minutes, record a new event if (timeElapsed > periodSize) { observations.push(Observation(blockTimestamp, reserve0CumulativeLast, reserve1CumulativeLast)); } reserve0 = balance0; reserve1 = balance1; blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices() public view returns (uint reserve0Cumulative, uint reserve1Cumulative, uint blockTimestamp) { blockTimestamp = block.timestamp; reserve0Cumulative = reserve0CumulativeLast; reserve1Cumulative = reserve1CumulativeLast; // if time has elapsed since the last update on the pair, mock the accumulated price values (uint _reserve0, uint _reserve1, uint _blockTimestampLast) = getReserves(); if (_blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint timeElapsed = blockTimestamp - _blockTimestampLast; reserve0Cumulative += _reserve0 * timeElapsed; reserve1Cumulative += _reserve1 * timeElapsed; } } // gives the current twap price measured from amountIn * tokenIn gives amountOut function current(address tokenIn, uint amountIn) external view returns (uint amountOut) { Observation memory _observation = lastObservation(); (uint reserve0Cumulative, uint reserve1Cumulative,) = currentCumulativePrices(); if (block.timestamp == _observation.timestamp) { _observation = observations[observations.length-2]; } uint timeElapsed = block.timestamp - _observation.timestamp; uint _reserve0 = (reserve0Cumulative - _observation.reserve0Cumulative) / timeElapsed; uint _reserve1 = (reserve1Cumulative - _observation.reserve1Cumulative) / timeElapsed; amountOut = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1); } // as per `current`, however allows user configured granularity, up to the full window size function quote(address tokenIn, uint amountIn, uint granularity) external view returns (uint amountOut) { uint [] memory _prices = sample(tokenIn, amountIn, granularity, 1); uint priceAverageCumulative; for (uint i = 0; i < _prices.length; i++) { priceAverageCumulative += _prices[i]; } return priceAverageCumulative / granularity; } // returns a memory set of twap prices function prices(address tokenIn, uint amountIn, uint points) external view returns (uint[] memory) { return sample(tokenIn, amountIn, points, 1); } function sample(address tokenIn, uint amountIn, uint points, uint window) public view returns (uint[] memory) { uint[] memory _prices = new uint[](points); uint length = observations.length-1; uint i = length - (points * window); uint nextIndex = 0; uint index = 0; for (; i < length; i+=window) { nextIndex = i + window; uint timeElapsed = observations[nextIndex].timestamp - observations[i].timestamp; uint _reserve0 = (observations[nextIndex].reserve0Cumulative - observations[i].reserve0Cumulative) / timeElapsed; uint _reserve1 = (observations[nextIndex].reserve1Cumulative - observations[i].reserve1Cumulative) / timeElapsed; _prices[index] = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1); index = index + 1; } return _prices; } // this low-level function should be called from a contract which performs important safety checks // standard uniswap v2 implementation function mint(address to) external lock returns (uint liquidity) { (uint _reserve0, uint _reserve1) = (reserve0, reserve1); uint _balance0 = erc20(token0).balanceOf(address(this)); uint _balance1 = erc20(token1).balanceOf(address(this)); uint _amount0 = _balance0 - _reserve0; uint _amount1 = _balance1 - _reserve1; uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { liquidity = Math.sqrt(_amount0 * _amount1) - MINIMUM_LIQUIDITY; _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(_amount0 * _totalSupply / _reserve0, _amount1 * _totalSupply / _reserve1); } require(liquidity > 0, 'ILM'); // BaseV1: INSUFFICIENT_LIQUIDITY_MINTED _mint(to, liquidity); _update(_balance0, _balance1, _reserve0, _reserve1); emit Mint(msg.sender, _amount0, _amount1); } // this low-level function should be called from a contract which performs important safety checks // standard uniswap v2 implementation function burn(address to) external lock returns (uint amount0, uint amount1) { (uint _reserve0, uint _reserve1) = (reserve0, reserve1); (address _token0, address _token1) = (token0, token1); uint _balance0 = erc20(_token0).balanceOf(address(this)); uint _balance1 = erc20(_token1).balanceOf(address(this)); uint _liquidity = balanceOf[address(this)]; uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = _liquidity * _balance0 / _totalSupply; // using balances ensures pro-rata distribution amount1 = _liquidity * _balance1 / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'ILB'); // BaseV1: INSUFFICIENT_LIQUIDITY_BURNED _burn(address(this), _liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); _balance0 = erc20(_token0).balanceOf(address(this)); _balance1 = erc20(_token1).balanceOf(address(this)); _update(_balance0, _balance1, _reserve0, _reserve1); emit Burn(msg.sender, amount0, amount1, to); } // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { require(!BaseV1Factory(factory).isPaused()); require(amount0Out > 0 || amount1Out > 0, 'IOA'); // BaseV1: INSUFFICIENT_OUTPUT_AMOUNT (uint _reserve0, uint _reserve1) = (reserve0, reserve1); require(amount0Out < _reserve0 && amount1Out < _reserve1, 'IL'); // BaseV1: INSUFFICIENT_LIQUIDITY uint _balance0; uint _balance1; { // scope for _token{0,1}, avoids stack too deep errors (address _token0, address _token1) = (token0, token1); require(to != _token0 && to != _token1, 'IT'); // BaseV1: INVALID_TO if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens if (data.length > 0) IBaseV1Callee(to).hook(msg.sender, amount0Out, amount1Out, data); // callback, used for flash loans _balance0 = erc20(_token0).balanceOf(address(this)); _balance1 = erc20(_token1).balanceOf(address(this)); } uint amount0In = _balance0 > _reserve0 - amount0Out ? _balance0 - (_reserve0 - amount0Out) : 0; uint amount1In = _balance1 > _reserve1 - amount1Out ? _balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'IIA'); // BaseV1: INSUFFICIENT_INPUT_AMOUNT { // scope for reserve{0,1}Adjusted, avoids stack too deep errors (address _token0, address _token1) = (token0, token1); if (amount0In > 0) _update0(amount0In / fee); // accrue fees for token0 and move them out of pool if (amount1In > 0) _update1(amount1In / fee); // accrue fees for token1 and move them out of pool _balance0 = erc20(_token0).balanceOf(address(this)); // since we removed tokens, we need to reconfirm balances, can also simply use previous balance - amountIn/ 10000, but doing balanceOf again as safety check _balance1 = erc20(_token1).balanceOf(address(this)); // The curve, either x3y+y3x for stable pools, or x*y for volatile pools require(_k(_balance0, _balance1) >= _k(_reserve0, _reserve1), 'K'); // BaseV1: K } _update(_balance0, _balance1, _reserve0, _reserve1); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); } // force balances to match reserves function skim(address to) external lock { (address _token0, address _token1) = (token0, token1); _safeTransfer(_token0, to, erc20(_token0).balanceOf(address(this)) - (reserve0)); _safeTransfer(_token1, to, erc20(_token1).balanceOf(address(this)) - (reserve1)); } // force reserves to match balances function sync() external lock { _update(erc20(token0).balanceOf(address(this)), erc20(token1).balanceOf(address(this)), reserve0, reserve1); } function _f(uint x0, uint y) internal pure returns (uint) { return x0*(y*y/1e18*y/1e18)/1e18+(x0*x0/1e18*x0/1e18)*y/1e18; } function _d(uint x0, uint y) internal pure returns (uint) { return 3*x0*(y*y/1e18)/1e18+(x0*x0/1e18*x0/1e18); } function _get_y(uint x0, uint xy, uint y) internal pure returns (uint) { for (uint i = 0; i < 255; i++) { uint y_prev = y; uint k = _f(x0, y); if (k < xy) { uint dy = (xy - k)*1e18/_d(x0, y); y = y + dy; } else { uint dy = (k - xy)*1e18/_d(x0, y); y = y - dy; } if (y > y_prev) { if (y - y_prev <= 1) { return y; } } else { if (y_prev - y <= 1) { return y; } } } return y; } function getAmountOut(uint amountIn, address tokenIn) external view returns (uint) { (uint _reserve0, uint _reserve1) = (reserve0, reserve1); amountIn -= amountIn / fee; // remove fee from amount received return _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1); } function _getAmountOut(uint amountIn, address tokenIn, uint _reserve0, uint _reserve1) internal view returns (uint) { if (stable) { uint xy = _k(_reserve0, _reserve1); _reserve0 = _reserve0 * 1e18 / decimals0; _reserve1 = _reserve1 * 1e18 / decimals1; (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0); amountIn = tokenIn == token0 ? amountIn * 1e18 / decimals0 : amountIn * 1e18 / decimals1; uint y = reserveB - _get_y(amountIn+reserveA, xy, reserveB); return y * (tokenIn == token0 ? decimals1 : decimals0) / 1e18; } else { (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0); return amountIn * reserveB / (reserveA + amountIn); } } function _k(uint x, uint y) internal view returns (uint) { if (stable) { uint _x = x * 1e18 / decimals0; uint _y = y * 1e18 / decimals1; uint _a = (_x * _y) / 1e18; uint _b = ((_x * _x) / 1e18 + (_y * _y) / 1e18); return _a * _b / 1e18; // x3y+y3x >= k } else { return x * y; // xy >= k } } function _mint(address dst, uint amount) internal { _updateFor(dst); // balances must be updated on mint/burn/transfer totalSupply += amount; balanceOf[dst] += amount; emit Transfer(address(0), dst, amount); } function _burn(address dst, uint amount) internal { _updateFor(dst); totalSupply -= amount; balanceOf[dst] -= amount; emit Transfer(dst, address(0), amount); } function approve(address spender, uint amount) external returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { require(deadline >= block.timestamp, 'BaseV1: EXPIRED'); DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256('1'), block.chainid, address(this) ) ); bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'BaseV1: INVALID_SIGNATURE'); allowance[owner][spender] = value; emit Approval(owner, spender, value); } function transfer(address dst, uint amount) external returns (bool) { _transferTokens(msg.sender, dst, amount); return true; } function transferFrom(address src, address dst, uint amount) external returns (bool) { address spender = msg.sender; uint spenderAllowance = allowance[src][spender]; if (spender != src && spenderAllowance != type(uint).max) { uint newAllowance = spenderAllowance - amount; allowance[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } function _transferTokens(address src, address dst, uint amount) internal { _updateFor(src); // update fee position for src _updateFor(dst); // update fee position for dst balanceOf[src] -= amount; balanceOf[dst] += amount; emit Transfer(src, dst, amount); } function _safeTransfer(address token,address to,uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(erc20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } } contract BaseV1Factory { bool public isPaused; address public owner; address public pendingOwner; address public admin; uint256 public stableFee = 2000; uint256 public variableFee = 500; mapping(address => mapping(address => mapping(bool => address))) public getPair; address[] public allPairs; mapping(address => bool) public isPair; // simplified check if its a pair, given that `stable` flag might not be available in peripherals address internal _temp0; address internal _temp1; bool internal _temp; mapping(address => address) public protocolAddresses; // pair => protocolAddress address public spiritMaker; event PairCreated(address indexed token0, address indexed token1, bool stable, address pair, uint); constructor() { owner = msg.sender; isPaused = false; } function setStableFee(uint256 _fee) external { require(msg.sender == owner); require(_fee >= 100 && _fee <= 10000, "!range"); stableFee = _fee; } function setVariableFee(uint256 _fee) external { require(msg.sender == owner); require(_fee >= 100 && _fee <= 10000, "!range"); variableFee = _fee; } function allPairsLength() external view returns (uint) { return allPairs.length; } function setOwner(address _owner) external { require(msg.sender == owner); pendingOwner = _owner; } function setAdmin(address _admin) external { require(msg.sender == owner || msg.sender == admin); admin = _admin; } function acceptOwner() external { require(msg.sender == pendingOwner); owner = pendingOwner; } function setPause(bool _state) external { require(msg.sender == owner); isPaused = _state; } function setProtocolAddress(address _pair, address _protocolAddress) external { require (msg.sender == owner || msg.sender == admin || msg.sender == protocolAddresses[_pair]); protocolAddresses[_pair] = _protocolAddress; } function setSpiritMaker(address _spiritMaker) external { require (msg.sender == owner); spiritMaker = _spiritMaker; } function pairCodeHash() external pure returns (bytes32) { return keccak256(type(BaseV1Pair).creationCode); } function getInitializable() external view returns (address, address, bool) { return (_temp0, _temp1, _temp); } function createPair(address tokenA, address tokenB, bool stable) external returns (address pair) { require(tokenA != tokenB, 'IA'); // BaseV1: IDENTICAL_ADDRESSES (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'ZA'); // BaseV1: ZERO_ADDRESS require(getPair[token0][token1][stable] == address(0), 'PE'); // BaseV1: PAIR_EXISTS - single check is sufficient bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters (_temp0, _temp1, _temp) = (token0, token1, stable); pair = address(new BaseV1Pair{salt:salt}()); getPair[token0][token1][stable] = pair; getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction allPairs.push(pair); isPair[pair] = true; emit PairCreated(token0, token1, stable, pair, allPairs.length); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"address","name":"_factory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"claimFeesFor","outputs":[{"internalType":"uint256","name":"claimed0","type":"uint256"},{"internalType":"uint256","name":"claimed1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61010060405234801561001157600080fd5b506040516106f63803806106f68339810160408190526100309161006d565b3360a0526001600160a01b0390811660805291821660c0521660e0526100b0565b80516001600160a01b038116811461006857600080fd5b919050565b60008060006060848603121561008257600080fd5b61008b84610051565b925061009960208501610051565b91506100a760408501610051565b90509250925092565b60805160a05160c05160e0516105e66101106000396000818161019e015281816102af0152610354015260008181610163015281816102790152610323015260008181606a015260aa01526000818160da01526101db01526105e66000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063533cf5ce14610030575b600080fd5b61004361003e36600461048c565b61005c565b6040805192835260208301919091520160405180910390f35b600080336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461009457600080fd5b60405162a9652960e61b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600480840191909152916000917f00000000000000000000000000000000000000000000000000000000000000001690632a594a40906024016020604051808303816000875af1158015610123573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014791906104c1565b90506001600160a01b038116156101d7578515610193576101937f00000000000000000000000000000000000000000000000000000000000000008261018e60048a6104fb565b610385565b84156101c9576101c97f00000000000000000000000000000000000000000000000000000000000000008261018e6004896104fb565b816101d38161051d565b9250505b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663149f2b276040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025d91906104c1565b90506001600160a01b038116156102e85786156102a4576102a47f00000000000000000000000000000000000000000000000000000000000000008261018e60048b6104fb565b85156102da576102da7f00000000000000000000000000000000000000000000000000000000000000008261018e60048a6104fb565b826102e48161051d565b9350505b60046102f48489610534565b6102fe91906104fb565b9450600461030c8488610534565b61031691906104fb565b93508615610349576103497f00000000000000000000000000000000000000000000000000000000000000008987610385565b851561037a5761037a7f00000000000000000000000000000000000000000000000000000000000000008986610385565b505050935093915050565b6000836001600160a01b03163b1161039c57600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916103f89190610553565b6000604051808303816000865af19150503d8060008114610435576040519150601f19603f3d011682016040523d82523d6000602084013e61043a565b606091505b5091509150818015610464575080511580610464575080806020019051810190610464919061058e565b61046d57600080fd5b5050505050565b6001600160a01b038116811461048957600080fd5b50565b6000806000606084860312156104a157600080fd5b83356104ac81610474565b95602085013595506040909401359392505050565b6000602082840312156104d357600080fd5b81516104de81610474565b9392505050565b634e487b7160e01b600052601160045260246000fd5b60008261051857634e487b7160e01b600052601260045260246000fd5b500490565b60008161052c5761052c6104e5565b506000190190565b600081600019048311821515161561054e5761054e6104e5565b500290565b6000825160005b81811015610574576020818601810151858301520161055a565b81811115610583576000828501525b509190910192915050565b6000602082840312156105a057600080fd5b815180151581146104de57600080fdfea26469706673582212204bac78d116270fb57afdda2bece111fae0a7f01d390bf88ae01474c7e139bd1f64736f6c634300080b003300000000000000000000000010b620b2dbac4faa7d7ffd71da486f5d44cd86f900000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c830000000000000000000000009d3591719038752db0c8beee2040ffcc3b2c6b9c
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000010b620b2dbac4faa7d7ffd71da486f5d44cd86f900000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c830000000000000000000000009d3591719038752db0c8beee2040ffcc3b2c6b9c
-----Decoded View---------------
Arg [0] : _token0 (address): 0x10b620b2dbac4faa7d7ffd71da486f5d44cd86f9
Arg [1] : _token1 (address): 0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83
Arg [2] : _factory (address): 0x9d3591719038752db0c8beee2040ffcc3b2c6b9c
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000010b620b2dbac4faa7d7ffd71da486f5d44cd86f9
Arg [1] : 00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83
Arg [2] : 0000000000000000000000009d3591719038752db0c8beee2040ffcc3b2c6b9c
Deployed ByteCode Sourcemap
1567:2175:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2527:1210;;;;;;:::i;:::-;;:::i;:::-;;;;712:25:1;;;768:2;753:18;;746:34;;;;685:18;2527:1210:0;;;;;;;;2614:16;;2669:10;-1:-1:-1;;;;;2683:4:0;2669:18;;2661:27;;;;;;2823:47;;-1:-1:-1;;;2823:47:0;;-1:-1:-1;;;;;2865:4:0;955:32:1;;2717:1:0;2823:47;;;937:51:1;;;;2717:1:0;-1:-1:-1;;2838:7:0;2823:41;;;;910:18:1;;2823:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2797:73;-1:-1:-1;;;;;;2885:31:0;;;2881:239;;2937:11;;2933:68;;2950:51;2964:6;2972:15;2989:11;2999:1;2989:7;:11;:::i;:::-;2950:13;:51::i;:::-;3020:11;;3016:68;;3033:51;3047:6;3055:15;3072:11;3082:1;3072:7;:11;:::i;3033:51::-;3099:9;;;;:::i;:::-;;;;2881:239;3166:19;3203:7;-1:-1:-1;;;;;3188:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3166:59;-1:-1:-1;;;;;;3240:27:0;;;3236:227;;3288:11;;3284:64;;3301:47;3315:6;3323:11;3336;3346:1;3336:7;:11;:::i;3301:47::-;3367:11;;3363:64;;3380:47;3394:6;3402:11;3415;3425:1;3415:7;:11;:::i;3380:47::-;3442:9;;;;:::i;:::-;;;;3236:227;3504:1;3484:17;3494:7;3484;:17;:::i;:::-;:21;;;;:::i;:::-;3473:32;-1:-1:-1;3547:1:0;3527:17;3537:7;3527;:17;:::i;:::-;:21;;;;:::i;:::-;3516:32;-1:-1:-1;3604:11:0;;3600:59;;3617:42;3631:6;3639:9;3650:8;3617:13;:42::i;:::-;3674:11;;3670:59;;3687:42;3701:6;3709:9;3720:8;3687:13;:42::i;:::-;2650:1087;;;2527:1210;;;;;;:::o;2146:324::-;2257:1;2237:5;-1:-1:-1;;;;;2237:17:0;;:21;2229:30;;;;;;2326:58;;;-1:-1:-1;;;;;2115:32:1;;;2326:58:0;;;2097:51:1;2164:18;;;;2157:34;;;2326:58:0;;;;;;;;;;2070:18:1;;;;2326:58:0;;;;;;;-1:-1:-1;;;;;2326:58:0;-1:-1:-1;;;2326:58:0;;;2315:70;;-1:-1:-1;;;;2315:10:0;;;;:70;;2326:58;2315:70;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2270:115;;;;2404:7;:57;;;;-1:-1:-1;2416:11:0;;:16;;:44;;;2447:4;2436:24;;;;;;;;;;;;:::i;:::-;2396:66;;;;;;2218:252;;2146:324;;;:::o;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;69:70;14:131;:::o;150:383::-;227:6;235;243;296:2;284:9;275:7;271:23;267:32;264:52;;;312:1;309;302:12;264:52;351:9;338:23;370:31;395:5;370:31;:::i;:::-;420:5;472:2;457:18;;444:32;;-1:-1:-1;523:2:1;508:18;;;495:32;;150:383;-1:-1:-1;;;150:383:1:o;999:251::-;1069:6;1122:2;1110:9;1101:7;1097:23;1093:32;1090:52;;;1138:1;1135;1128:12;1090:52;1170:9;1164:16;1189:31;1214:5;1189:31;:::i;:::-;1239:5;999:251;-1:-1:-1;;;999:251:1:o;1255:127::-;1316:10;1311:3;1307:20;1304:1;1297:31;1347:4;1344:1;1337:15;1371:4;1368:1;1361:15;1387:217;1427:1;1453;1443:132;;1497:10;1492:3;1488:20;1485:1;1478:31;1532:4;1529:1;1522:15;1560:4;1557:1;1550:15;1443:132;-1:-1:-1;1589:9:1;;1387:217::o;1609:136::-;1648:3;1676:5;1666:39;;1685:18;;:::i;:::-;-1:-1:-1;;;1721:18:1;;1609:136::o;1750:168::-;1790:7;1856:1;1852;1848:6;1844:14;1841:1;1838:21;1833:1;1826:9;1819:17;1815:45;1812:71;;;1863:18;;:::i;:::-;-1:-1:-1;1903:9:1;;1750:168::o;2202:426::-;2331:3;2369:6;2363:13;2394:1;2404:129;2418:6;2415:1;2412:13;2404:129;;;2516:4;2500:14;;;2496:25;;2490:32;2477:11;;;2470:53;2433:12;2404:129;;;2551:6;2548:1;2545:13;2542:48;;;2586:1;2577:6;2572:3;2568:16;2561:27;2542:48;-1:-1:-1;2606:16:1;;;;;2202:426;-1:-1:-1;;2202:426:1:o;2633:277::-;2700:6;2753:2;2741:9;2732:7;2728:23;2724:32;2721:52;;;2769:1;2766;2759:12;2721:52;2801:9;2795:16;2854:5;2847:13;2840:21;2833:5;2830:32;2820:60;;2876:1;2873;2866:12
Swarm Source
ipfs://4bac78d116270fb57afdda2bece111fae0a7f01d390bf88ae01474c7e139bd1f
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Validator ID :
0 FTM
Amount Staked
0
Amount Delegated
0
Staking Total
0
Staking Start Epoch
0
Staking Start Time
0
Proof of Importance
0
Origination Score
0
Validation Score
0
Active
0
Online
0
Downtime
0 s
Address | Amount | claimed Rewards | Created On Epoch | Created On |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.