Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- YieldFarm
- Optimization enabled
- true
- Compiler version
- v0.8.26+commit.8a97fa7a
- Optimization runs
- 500
- Verified at
- 2024-11-09T04:41:34.817491Z
Constructor Arguments
000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000021e19e0c9bab24000000000000000000000000000000000000000000000000000000005b605a7b06400000000000000000000000000138dafbda0ccb3d8e39c19edb0510fc31b7c1c77000000000000000000000000043faa1b5c5fc9a7dc35171f290c29ecde0ccff1000000000000000000000000203d550ed6fa9dab8a4190720cf9f65138abd15b000000000000000000000000072d4706f9a383d5608bd14b09b41683cb95ffd7000000000000000000000000bf6bcbe2be545135391777f3b4698be92e2eb8ca0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d000000000000000000000000a1a60e03139b65cda4f0d1d7ad833064bb3dfef2000000000000000000000000000000000000000000000000000000000000000644796e616d6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444594e4f00000000000000000000000000000000000000000000000000000000
Arg [0] (string) : Dynamo
Arg [1] (string) : DYNO
Arg [2] (uint256) : 10000000000000000000000
Arg [3] (uint256) : 1607510288000000
Arg [4] (address) : 0x138dafbda0ccb3d8e39c19edb0510fc31b7c1c77
Arg [5] (address) : 0x043faa1b5c5fc9a7dc35171f290c29ecde0ccff1
Arg [6] (address) : 0x203d550ed6fa9dab8a4190720cf9f65138abd15b
Arg [7] (address) : 0x072d4706f9a383d5608bd14b09b41683cb95ffd7
Arg [8] (address) : 0xbf6bcbe2be545135391777f3b4698be92e2eb8ca
Arg [9] (address) : 0x3a7f64c57433555b23dac4409a0ac7e84275398d
Arg [10] (address) : 0xa1a60e03139b65cda4f0d1d7ad833064bb3dfef2
contracts/YieldFarm.sol
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "./interfaces.sol"; import "./RewardToken.sol"; contract YieldFarm is Ownable, ReentrancyGuard, IERC721Receiver { struct Farm { uint256 id; // Farm ID uint8 version; // V2 or V3 string name; // Descriptor of the farm address poolAddr; // Address of V2 pair or V3 pool uint256 liquidity; // Total liquidity deposited uint256 allocPoint; // Allocation points assigned to the pool uint256 lastCalcBlock; // Last block number the user had their rewards calculated uint256 accRewardsPerShare; // Accumulated rewards per share times CALC_PRECISION uint256 accThirdPartyRewardsPerShare; // Accumulated third party rewards per share times CALC_PRECISION address[] farmers; // Array of all farmer addresses in the farm uint256 farmerCount; // Array of all farmer addresses in the farm address token0; // Address of the 1st token in the pair address token1; // Address of the 2nd token in the pair // Only used for V3 uint256 tokenId; int24 tickLower; int24 tickUpper; uint24 fee; uint256 accFees0PerShare; // Accumulated fees0 per share times CALC_PRECISION uint256 accFees1PerShare; // Accumulated fees1 per share times CALC_PRECISION bool active; } struct Farmer { address addr; uint256 liquidity; // How much liquidity the farmer has provided uint256 boltMultiplier; // Multiplier for deposited/staked BOLT, stored as percentage with two decimals uint256 boltDeposited; // Amount of BOLT depositted uint256 durationMultiplier; // Transient, populated by getFarmerByFarmIdAndAddress uint256 startingBlock; // Used in calculation of duration bonus multiplier uint256 rewards; // Transient uint256 rewardDebt; // The amount relative to farm.accRewardsPerShare the user can't get as reward uint256 thirdPartyRewards; // Transient uint256 thirdPartyRewardDebt; // The amount relative to farm.accThirdPartyRewardsPerShare the user can't get as reward // Only used for V3 uint256 fees0; // Transient uint256 fees0Debt; // The amount relative to farm.accFees0PerShare the user can't claim uint256 fees1; // Transient uint256 fees1Debt; // The amount relative to farm.accFees1PerShare the user can't claim } struct ThirdPartyReward { address token; address tokenManager; uint256 tokensPerBlock; uint256 endBlock; } RewardToken public rewardToken; // Token to be minted as farming reward IElectroSwapV2Router internal v2Router; // For adding and removing V2 liquidity IElectroSwapV3Factory internal v3Factory; // Used to get V3 pool addresses INonfungiblePositionManager internal positionManager; // Used to get position info and add/remove liquidity IUncollectedFeeHelper internal feeHelper; address internal wetnAddress; address internal v2Factory; // Used to verify ElectroSwap V2 LP tokens address internal boltToken; // BOLT Token address uint256 public totalAllocPoint; // Tracks total allocation points across all pools uint256 public rewardPerBlock; // Number of rewards per block shared across all incentivized pools uint256 internal constant CALC_PRECISION = 1e18; // A big number to perform mul and div operations uint256 internal constant MAX_BLOCKS_FOR_BONUS = 6307200; // 1 year worth of blocks address internal constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD; // Tracks state of current farms and farmers uint256 public farmCount; mapping(address => uint256[]) internal poolFarmIds; // mapping(address => farmId[]) mapping(uint256 => Farm) internal farmInfo; // mapping(farmId => Farm)) mapping(uint256 => mapping(address => Farmer)) internal farmerInfo; // mapping(farmId => mapping(farmerAddr => Farmer)) mapping(uint256 => ThirdPartyReward) internal thirdPartyRewards; // mapping(farmId => ThirdPartyReward)) mapping(uint256 => uint256) internal boltMultipliers; // mapping(valid BOLT deposit => bonus multiplier padded by 10000X) constructor( string memory _rewardName, string memory _rewardSymbol, uint256 _rewardSupply, uint256 _rewardPerBlock, // Reward related params address _wetnAddress, address _boltToken, // WETN and BOLT address address _v2Factory, address _v2Router, // V2 params address _v3Factory, address _positionManager, address _feeHelper // V3 params ) Ownable(msg.sender) { rewardToken = new RewardToken(_rewardName, _rewardSymbol); rewardToken.mint(msg.sender, _rewardSupply); rewardToken.renounceOwnership(); rewardPerBlock = _rewardPerBlock; boltToken = _boltToken; v2Factory = _v2Factory; v2Router = IElectroSwapV2Router(_v2Router); positionManager = INonfungiblePositionManager(_positionManager); v3Factory = IElectroSwapV3Factory(_v3Factory); feeHelper = IUncollectedFeeHelper(_feeHelper); wetnAddress = _wetnAddress; boltMultipliers[0] = 10000; // 1.00X Reward multiplier (not changeable) boltMultipliers[50000 * 1e18] = 10500; // 1.05X Reward multiplier boltMultipliers[100000 * 1e18] = 11500; // 1.15X Reward multiplier } /** ==================== ADMIN FUNCTIONS ==================== */ // Add a new incentivized V2 farm by passing an existing V2 pair address. Can only be called by the owner (ElectroSwap). function adminCreateFarm_V2(string memory _name, address _pairAddr, uint256 _allocPoint) external onlyOwner nonReentrant { require(_pairAddr != address(0), "Cannot add zero address"); require(poolFarmIds[_pairAddr].length == 0, "Pool already added"); require(IElectroSwapV2Pair(_pairAddr).factory() == v2Factory, "Invalid LP Token"); _updateAllFarmRewardsAndFees(); totalAllocPoint += _allocPoint; IElectroSwapV2Pair pair = IElectroSwapV2Pair(_pairAddr); address token0 = pair.token0(); address token1 = pair.token1(); farmCount++; poolFarmIds[_pairAddr].push(farmCount); address[] memory farmerAddresses; // empty array farmInfo[farmCount] = Farm({ id: farmCount, version: 2, name: _name, poolAddr: _pairAddr, liquidity: 0, allocPoint: _allocPoint, lastCalcBlock: block.number, accRewardsPerShare: 0, accThirdPartyRewardsPerShare: 0, farmers: farmerAddresses, farmerCount: 0, token0: token0, token1: token1, tokenId: 0, tickLower: 0, tickUpper: 0, fee: 0, accFees0PerShare: 0, accFees1PerShare: 0, active: true }); emit FarmCreated(farmCount, _pairAddr, 2, 0, _allocPoint, totalAllocPoint); } // Add a new incentivized V3 farm by passing a position token ID, which requires prior approval. Can only be called by the owner (ElectroSwap). function adminCreateFarm_V3(string memory _name, uint256 _tokenId, uint256 _allocPoint) external onlyOwner nonReentrant { Position memory position = _getPosition(_tokenId); require(position.token0 != address(0) && position.token1 != address(0), "Invalid tokenId"); positionManager.safeTransferFrom(msg.sender, address(this), _tokenId); address poolAddr = v3Factory.getPool(position.token0, position.token1, position.fee); _updateAllFarmRewardsAndFees(); totalAllocPoint += _allocPoint; farmCount++; poolFarmIds[poolAddr].push(farmCount); address[] memory farmerAddresses = new address[](1); farmerAddresses[0] = msg.sender; farmInfo[farmCount] = Farm({ id: farmCount, version: 3, name: _name, poolAddr: poolAddr, liquidity: position.liquidity, allocPoint: _allocPoint, lastCalcBlock: block.number, accRewardsPerShare: 0, accThirdPartyRewardsPerShare: 0, farmers: farmerAddresses, farmerCount: 1, tokenId: _tokenId, token0: position.token0, token1: position.token1, tickLower: position.tickLower, tickUpper: position.tickUpper, fee: position.fee, accFees0PerShare: 0, accFees1PerShare: 0, active: true }); farmerInfo[farmCount][msg.sender] = Farmer({ addr: msg.sender, liquidity: position.liquidity, boltMultiplier: boltMultipliers[0], // 1.00X boltDeposited: 0, durationMultiplier: 0, startingBlock: block.number, rewards: 0, rewardDebt: 0, thirdPartyRewards: 0, thirdPartyRewardDebt: 0, fees0: 0, fees0Debt: 0, fees1: 0, fees1Debt: 0 }); emit FarmCreated(farmCount, poolAddr, 3, _tokenId, _allocPoint, totalAllocPoint); } // Update the farm's allocation points. Can only be called by the owner (ElectroSwap). function adminUpdateFarmAllocPoints(uint256 _farmId, uint256 _allocPoint) external onlyOwner nonReentrant { Farm storage farm = farmInfo[_farmId]; require(farm.poolAddr != address(0), "Invalid pool"); _updateAllFarmRewardsAndFees(); totalAllocPoint = totalAllocPoint - farm.allocPoint + _allocPoint; farm.allocPoint = _allocPoint; emit FarmAllocationUpdated(_farmId, farm.poolAddr, _allocPoint, totalAllocPoint); } // Update the farm's name. Can only be called by the owner (ElectroSwap). function adminUpdateFarmName(uint256 _farmId, string memory _name) external onlyOwner nonReentrant { Farm storage farm = farmInfo[_farmId]; require(farm.poolAddr != address(0), "Invalid pool"); farm.name = _name; emit FarmNameUpdated(_farmId, farm.poolAddr, _name); } // Update the number of rewards per block. Can only be called by the owner (ElectroSwap). function adminUpdateRewardsPerBlock(uint256 _rewardPerBlock) external onlyOwner nonReentrant { uint256 prevRewardPerBlock = rewardPerBlock; rewardPerBlock = _rewardPerBlock; _updateAllFarmRewardsAndFees(); emit RewardsPerBlockUpdated(rewardPerBlock, prevRewardPerBlock); } // Update the valid BOLT deposit amounts and corresponding multipliers. Can only be called by the owner (ElectroSwap). function adminUpdateBoltMultiplier(uint256 _amountBolt, uint256 _multiplier) external onlyOwner nonReentrant { require(_multiplier >= 10000, "Multiplier must be >= 10000"); require(_amountBolt > 0, "Amount must be > 0"); boltMultipliers[_amountBolt] = _multiplier; emit BoltMultiplierUpdated(_amountBolt, _multiplier); } // Remove an incentivized farm. Still allows withdrawls, but no deposits. Can only be called by the owner (ElectroSwap). function adminDeactivateFarm(uint256 _farmId) external onlyOwner nonReentrant { Farm storage farm = farmInfo[_farmId]; require(farm.poolAddr != address(0), "Nothing to deactivate"); _updateAllFarmRewardsAndFees(); totalAllocPoint -= farm.allocPoint; emit FarmDeactivated(_farmId, farm.poolAddr, farm.version, farm.tokenId); farm.active = false; farm.allocPoint = 0; } // Add third party rewards to a farm. Can only be called by the owner (ElectroSwap). function adminAddThirdPartyReward(uint256 _farmId, address _token, address _tokenManager) external onlyOwner nonReentrant { require(_token != address(0) && _tokenManager != address(0), "Cannot be zero address"); thirdPartyRewards[_farmId] = ThirdPartyReward({ token: _token, tokenManager: _tokenManager, // Address of user that can update the tokensPerBlock tokensPerBlock: 0, endBlock: 0 }); emit ThirdPartyRewardAdded(_farmId, _token, _tokenManager); } /** ==================== PRIMARY FUNCTIONS ==================== */ // Deposit tokens into yield farm for rewards allocation. function deposit(uint256 _farmId, uint256 _amount0, uint256 _amount1, uint256 _amountBolt) payable external nonReentrant { Farm storage farm = farmInfo[_farmId]; require(farm.active, "Inactive farm"); _updateFarmRewardsAndFees(_farmId); Farmer storage farmer = farmerInfo[_farmId][msg.sender]; bool token0Native = false; bool token1Native = false; // Wrap native ETN and transfer other token from msg.sender to the yield farming contract. Requires prior approval if(msg.value > 0){ require(farm.token0 == wetnAddress || farm.token1 == wetnAddress, "Native ETN sent to unsupporting farm"); IWETN(wetnAddress).deposit{value: msg.value}(); if(farm.token0 == wetnAddress){ _amount0 = msg.value; token0Native = true; IERC20(farm.token1).transferFrom(msg.sender, address(this), _amount1); } else { _amount1 = msg.value; token1Native = true; IERC20(farm.token0).transferFrom(msg.sender, address(this), _amount0); } } // Transfer both tokens from msg.sender to the yield farming contract. Requires prior approval else { IERC20(farm.token0).transferFrom(msg.sender, address(this), _amount0); IERC20(farm.token1).transferFrom(msg.sender, address(this), _amount1); } require(_amount0 > 0 && _amount1 > 0, "Both amounts must be positive"); (uint256 liquidityAdded, uint256 amount0Added, uint256 amount1Added) = farm.version == 2 ? _depositV2(farm, _amount0, _amount1) : _depositV3(farm, _amount0, _amount1); // Refund whatever was not added to the position to msg.sender _refundIfNeeded(farm.token0, token0Native, _amount0, amount0Added); _refundIfNeeded(farm.token1, token1Native, _amount1, amount1Added); farm.liquidity += liquidityAdded; // New farmer if (farmer.liquidity == 0) { farm.farmers.push(msg.sender); // Add farmer to the pool's farmer list farm.farmerCount += 1; farmer.addr = msg.sender; farmer.liquidity = liquidityAdded; farmer.boltMultiplier = boltMultipliers[0]; // Default value farmer.startingBlock = block.number; farmer.rewardDebt = liquidityAdded * farm.accRewardsPerShare / CALC_PRECISION; farmer.thirdPartyRewardDebt = liquidityAdded * farm.accThirdPartyRewardsPerShare / CALC_PRECISION; farmer.fees0Debt = liquidityAdded * farm.accFees0PerShare / CALC_PRECISION; farmer.fees1Debt = liquidityAdded * farm.accFees1PerShare / CALC_PRECISION; emit FarmDeposit(_farmId, msg.sender, amount0Added, amount1Added, liquidityAdded); } else { // Adjust starting block based on amount of liquidity added to prevent unfair duration multiplier manipulation uint256 increaseOfTotal = (liquidityAdded * 1e18) / (farmer.liquidity + liquidityAdded); uint256 blocksServed = block.number - farmer.startingBlock; uint256 adjustedBlocksServed = blocksServed - ((blocksServed * increaseOfTotal) / 1e18); // Resolves to zero if negative farmer.startingBlock = block.number - adjustedBlocksServed; uint256 rewardsEarned = (farmer.liquidity * farm.accRewardsPerShare / CALC_PRECISION) - farmer.rewardDebt; uint256 thirdPartyRewardsEarned = (farmer.liquidity * farm.accThirdPartyRewardsPerShare / CALC_PRECISION) - farmer.thirdPartyRewardDebt; uint256 fees0Earned = (farmer.liquidity * farm.accFees0PerShare / CALC_PRECISION) - farmer.fees0Debt; uint256 fees1Earned = (farmer.liquidity * farm.accFees1PerShare / CALC_PRECISION) - farmer.fees1Debt; farmer.liquidity += liquidityAdded; farmer.rewardDebt = (farmer.liquidity * farm.accRewardsPerShare / CALC_PRECISION) - rewardsEarned; farmer.thirdPartyRewardDebt = (farmer.liquidity * farm.accThirdPartyRewardsPerShare / CALC_PRECISION) - thirdPartyRewardsEarned; farmer.fees0Debt = (farmer.liquidity * farm.accFees0PerShare / CALC_PRECISION) - fees0Earned; farmer.fees1Debt = (farmer.liquidity * farm.accFees1PerShare / CALC_PRECISION) - fees1Earned; emit FarmIncrease(_farmId, msg.sender, amount0Added, amount1Added, liquidityAdded, farmer.startingBlock); } if(_amountBolt > 0){ uint256 totalBolt = _amountBolt + farmer.boltDeposited; require(boltMultipliers[totalBolt] != 0, "Invalid BOLT deposit"); IERC20(boltToken).transferFrom(msg.sender, address(this), _amountBolt); farmer.boltDeposited = totalBolt; farmer.boltMultiplier = boltMultipliers[totalBolt]; } } // Withdraw tokens AND rewards. If _asNative is true AND the pair contains WETN, native ETN will be sent. function withdraw(uint256 _farmId, uint256 _liquidityAmt, bool _asNative) external nonReentrant { Farm storage farm = farmInfo[_farmId]; Farmer storage farmer = farmerInfo[_farmId][msg.sender]; require(farmer.liquidity >= _liquidityAmt, "Cannot withdraw more than deposited"); (uint256 rewardsMinted, uint256 fees0Collected, uint256 fees1Collected, uint256 thirdPartyRewardsCollected) = _collectRewardsAndFees(_farmId, _asNative); farmer.liquidity -= _liquidityAmt; farmer.rewardDebt = farmer.liquidity * farm.accRewardsPerShare / CALC_PRECISION; if(farm.version == 3){ farmer.fees0Debt = farmer.liquidity * farm.accFees0PerShare / CALC_PRECISION; farmer.fees1Debt = farmer.liquidity * farm.accFees1PerShare / CALC_PRECISION; } if(thirdPartyRewards[_farmId].token != address(0)){ farmer.thirdPartyRewardDebt = farmer.liquidity * farm.accThirdPartyRewardsPerShare / CALC_PRECISION; } // Just withdraw rewards and fees if(_liquidityAmt == 0){ emit FarmWithdrawl(_farmId, msg.sender, 0, 0, rewardsMinted, fees0Collected, fees1Collected, thirdPartyRewardsCollected); return; } if(_asNative){ require(farm.token0 == wetnAddress || farm.token1 == wetnAddress, "Unsupporting farm"); } // Includes removed liquidity and fees (uint256 amount0, uint256 amount1) = farm.version == 2 ? _withdrawV2(farm, _liquidityAmt, _asNative) : _withdrawV3(farm, _liquidityAmt, _asNative); // Clear state on removal of all liquidity if (farmer.liquidity == 0) { // Withdraw all BOLT if(farmer.boltDeposited > 0){ IERC20(boltToken).transfer(msg.sender, farmer.boltDeposited); } delete farmerInfo[_farmId][msg.sender]; _removeFarmer(_farmId, msg.sender); } farm.liquidity -= _liquidityAmt; emit FarmWithdrawl(_farmId, msg.sender, amount0, amount1, rewardsMinted, fees0Collected, fees1Collected, thirdPartyRewardsCollected); } /** ==================== INTERNAL FUNCTIONS ==================== */ // Deposits tokens into V2 yield farm for rewards allocation. function _depositV2(Farm memory _farm, uint256 _amount0, uint256 _amount1) internal returns (uint256 liquidityAdded, uint256 amount0Added, uint256 amount1Added) { // Approve the router to spend the tokens IERC20(_farm.token0).approve(address(v2Router), _amount0); IERC20(_farm.token1).approve(address(v2Router), _amount1); (amount0Added, amount1Added, liquidityAdded) = v2Router.addLiquidity( _farm.token0, _farm.token1, _amount0, _amount1, 1, 1, address(this), block.timestamp ); } // Withdraw tokens AND rewards. function _withdrawV2(Farm memory _farm, uint256 _liquidityAmt, bool _asNative) internal returns (uint256 amount0, uint256 amount1){ // Transfers token0 and token1 back to this contract IERC20(_farm.poolAddr).approve(address(v2Router), _liquidityAmt); (amount0, amount1) = v2Router.removeLiquidity(_farm.token0, _farm.token1, _liquidityAmt, 1, 1, address(this), block.timestamp); _transferTokens(_farm, amount0, amount1, _asNative); } // Deposit tokens into V3 yield farm for rewards allocation. function _depositV3(Farm memory _farm, uint256 _amount0, uint256 _amount1) internal returns (uint256 liquidityAdded, uint256 amount0Added, uint256 amount1Added) { // Approve the positionManager to spend the tokens IERC20(_farm.token0).approve(address(positionManager), _amount0); IERC20(_farm.token1).approve(address(positionManager), _amount1); // Add liquidity to the existing position (liquidityAdded, amount0Added, amount1Added) = positionManager.increaseLiquidity( INonfungiblePositionManager.IncreaseLiquidityParams({ tokenId: _farm.tokenId, amount0Desired: _amount0, amount1Desired: _amount1, amount0Min: 1, amount1Min: 1, deadline: block.timestamp }) ); } function _withdrawV3(Farm storage _farm, uint256 _liquidityAmt, bool _asNative) internal returns (uint256 amount0, uint256 amount1) { // Decreases available liquidity before collecting (amount0, amount1) = positionManager.decreaseLiquidity( INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: _farm.tokenId, liquidity: uint128(_liquidityAmt), amount0Min: 1, amount1Min: 1, deadline: block.timestamp }) ); // Transfers token0 and token back to this contract _collectV3(_farm.tokenId); _transferTokens(_farm, amount0, amount1, _asNative); } function _transferTokens(Farm memory _farm, uint256 amount0, uint256 amount1, bool _asNative) internal { if(_asNative && _farm.token0 == wetnAddress){ _withdrawNativeETN(amount0); IERC20(_farm.token1).transfer(msg.sender, amount1); } else if(_asNative && _farm.token1 == wetnAddress){ _withdrawNativeETN(amount1); IERC20(_farm.token0).transfer(msg.sender, amount0); } else { IERC20(_farm.token0).transfer(msg.sender, amount0); IERC20(_farm.token1).transfer(msg.sender, amount1); } } function _refundIfNeeded(address token, bool tokenIsNative, uint256 amountDeposited, uint256 amountAdded) internal { if(amountDeposited > amountAdded){ uint256 refundAmount = amountDeposited - amountAdded; if(tokenIsNative){ _withdrawNativeETN(refundAmount); } else { IERC20(token).transfer(msg.sender, refundAmount); } } } function _withdrawNativeETN(uint256 amount) internal { IWETN(wetnAddress).withdraw(amount); (bool success, ) = payable(msg.sender).call{value: amount}(""); require(success, "ETN transfer failed"); } function _collectV3(uint256 tokenId) internal returns (uint256 amount0Collected, uint256 amount1Collected){ (amount0Collected, amount1Collected) = positionManager.collect( INonfungiblePositionManager.CollectParams({ tokenId: tokenId, recipient: address(this), amount0Max: type(uint128).max, amount1Max: type(uint128).max }) ); } function _collectRewardsAndFees(uint256 _farmId, bool _asNative) internal returns (uint256 rewardsCollected, uint256 fees0Collected, uint256 fees1Collected, uint256 thirdPartyRewardsCollected) { _updateFarmRewardsAndFees(_farmId); Farmer storage farmer = farmerInfo[_farmId][msg.sender]; if(farmer.liquidity > 0){ Farm storage farm = farmInfo[_farmId]; uint256 newRewardDebt = farmer.liquidity * farm.accRewardsPerShare / CALC_PRECISION; uint256 rewardsEarned = newRewardDebt - farmer.rewardDebt; // boltMultiplier and durationMultiplier are both multiplied by 10000, so we divide by 100000000 rewardsCollected = (rewardsEarned * farmer.boltMultiplier * _calculateDurationMultiplier(block.number - farmer.startingBlock)) / 100000000; if (rewardsCollected != 0) { rewardToken.mint(msg.sender, rewardsCollected); } if(farm.version == 3){ uint256 newFee0Debt = farmer.liquidity * farm.accFees0PerShare / CALC_PRECISION; fees0Collected = newFee0Debt - farmer.fees0Debt; uint256 newFee1Debt = farmer.liquidity * farm.accFees1PerShare / CALC_PRECISION; fees1Collected = newFee1Debt - farmer.fees1Debt; _transferTokens(farm, fees0Collected, fees1Collected, _asNative); } ThirdPartyReward memory thirdPartyReward = thirdPartyRewards[_farmId]; if(thirdPartyReward.token != address(0)){ uint256 newThirdPartyDebt = farmer.liquidity * farm.accThirdPartyRewardsPerShare / CALC_PRECISION; thirdPartyRewardsCollected = newThirdPartyDebt - farmer.thirdPartyRewardDebt; if (thirdPartyRewardsCollected != 0) { IERC20(thirdPartyReward.token).transfer(msg.sender, thirdPartyRewardsCollected); } } } } // Called prior to modifying totalAllocPoint or rewardPerBlock (by admin) function _updateAllFarmRewardsAndFees() private { for (uint256 i = 1; i <= farmCount; i++) { _updateFarmRewardsAndFees(i); } } // Sets accumulated amounts for rewards, third party rewards and fees by share function _updateFarmRewardsAndFees(uint256 _farmId) private { Farm storage farm = farmInfo[_farmId]; if (farm.liquidity == 0 || !farm.active) { farm.lastCalcBlock = block.number; return; } uint256 blocksSinceLastCalc = block.number - farm.lastCalcBlock; uint256 rewards = blocksSinceLastCalc * ((rewardPerBlock * farm.allocPoint) / totalAllocPoint); farm.accRewardsPerShare += rewards * CALC_PRECISION / farm.liquidity; if(farm.version == 3){ (uint256 fees0Collected, uint256 fees1Collected) = _collectV3(farm.tokenId); farm.accFees0PerShare += fees0Collected * CALC_PRECISION / farm.liquidity; farm.accFees1PerShare += fees1Collected * CALC_PRECISION / farm.liquidity; } ThirdPartyReward storage thirdPartyReward = thirdPartyRewards[_farmId]; if(thirdPartyReward.token != address(0) && thirdPartyReward.tokensPerBlock > 0){ uint256 thirdPartyRewardTokens; // Third party rewards ended between last calculation and now if(farm.lastCalcBlock < thirdPartyReward.endBlock && thirdPartyReward.endBlock <= block.number){ uint256 blocksAbleToPay = thirdPartyReward.endBlock - farm.lastCalcBlock; thirdPartyRewardTokens = blocksAbleToPay * thirdPartyReward.tokensPerBlock; thirdPartyReward.tokensPerBlock = 0; } else { thirdPartyRewardTokens = blocksSinceLastCalc * thirdPartyReward.tokensPerBlock; } farm.accThirdPartyRewardsPerShare += thirdPartyRewardTokens * CALC_PRECISION / farm.liquidity; } farm.lastCalcBlock = block.number; } // Internal function that calculates duration bonus multiplier function _calculateDurationMultiplier(uint256 blocksServed) internal view returns (uint256) { // Occurs when farmer is undefined if(blocksServed == block.number){ return 10000; } // If blockCount is greater than or equal to maxBlockCount, return 25000 else if (blocksServed >= MAX_BLOCKS_FOR_BONUS) { return 25000; } // Calculate the linear yield return 10000 + (15000 * blocksServed) / MAX_BLOCKS_FOR_BONUS; } struct Position { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint128 liquidity; } function _getPosition(uint256 _tokenId) internal view returns (Position memory) { (, ,address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, , , ,) = positionManager.positions(_tokenId); return Position({ token0: token0, token1: token1, fee: fee, tickLower: tickLower, tickUpper: tickUpper, liquidity: liquidity }); } // Remove farmer address from a farm function _removeFarmer(uint256 _farmId, address _address) internal { Farm storage farm = farmInfo[_farmId]; uint farmerCount = farm.farmers.length; uint indexToRemove = farmerCount; for (uint i = 0; i < farmerCount; i++) { if (farm.farmers[i] == _address) { indexToRemove = i; break; } } if (indexToRemove < farmerCount) { farm.farmers[indexToRemove] = farm.farmers[farmerCount - 1]; farm.farmers.pop(); farm.farmerCount -= 1; } } /** ==================== EXTERNAL HELPER FUNCTIONS ==================== */ // Exposes function that calculates duration bonus multiplier - for gas savings function calculateDurationMultiplier(uint256 blocksServed) external view returns (uint256) { return _calculateDurationMultiplier(blocksServed); } // At least one farmer should be active when depositing, otherwise third party rewards go unaccounted for function depositThirdPartyReward(uint256 _farmId, uint256 _amountToken, uint256 _distributeOverBlockCount) external { ThirdPartyReward storage thirdPartyReward = thirdPartyRewards[_farmId]; require(thirdPartyReward.token != address(0), "Third party reward not defined"); require(owner() == msg.sender || thirdPartyReward.tokenManager == msg.sender, "Only token manager can deposit"); _updateFarmRewardsAndFees(_farmId); IERC20(thirdPartyReward.token).transferFrom(msg.sender, address(this), _amountToken); uint256 blocksTillEnd = thirdPartyReward.endBlock >= block.number ? thirdPartyReward.endBlock - block.number : 0; uint256 unaccountedTokens = blocksTillEnd * thirdPartyReward.tokensPerBlock; thirdPartyReward.tokensPerBlock = (unaccountedTokens + _amountToken) / _distributeOverBlockCount; thirdPartyReward.endBlock = block.number + _distributeOverBlockCount; emit ThirdPartyRewardDeposited(_farmId, thirdPartyReward.token, thirdPartyReward.tokensPerBlock, thirdPartyReward.endBlock); } // Update the third party reward manager for a farm. Can only be called by the ElectroSwap or Third-Party token manager. function updateThirdPartyRewardManager(uint256 _farmId, address _tokenManager) external { require(_tokenManager != address(0), "Cannot be zero address"); require(owner() == msg.sender || thirdPartyRewards[_farmId].tokenManager == msg.sender, "Only token manager can update"); thirdPartyRewards[_farmId].tokenManager = _tokenManager; emit ThirdPartyRewardUpdated(_farmId, _tokenManager); } function getFarmById(uint256 _farmId) external view returns (Farm memory farm) { farm = farmInfo[_farmId]; uint256 blocksSinceLastCalc = block.number - farm.lastCalcBlock; if(farm.liquidity > 0){ uint256 rewards = blocksSinceLastCalc * ((rewardPerBlock * farm.allocPoint) / totalAllocPoint); farm.accRewardsPerShare += rewards * CALC_PRECISION / farm.liquidity; if(farm.version == 3){ (uint256 uncollectedFee0, uint256 uncollectedFee1) = feeHelper.getUncollectedFees(farm.tokenId); farm.accFees0PerShare += uncollectedFee0 * CALC_PRECISION / farm.liquidity; farm.accFees1PerShare += uncollectedFee1 * CALC_PRECISION / farm.liquidity; } if(thirdPartyRewards[_farmId].token != address(0)){ uint256 thirdPartyRewardTokens = blocksSinceLastCalc * thirdPartyRewards[_farmId].tokensPerBlock; farm.accThirdPartyRewardsPerShare += thirdPartyRewardTokens * CALC_PRECISION / farm.liquidity; } } // Prevent large responses by sending empty farmer array address[] memory emptyArr; farm.farmers = emptyArr; } function getFarmIdsByPoolAddress(address _poolAddr) external view returns (uint256[] memory) { return poolFarmIds[_poolAddr]; } function getFarmerByFarmIdAndIndex(uint256 _farmId, uint256 _farmerIndex) external view returns (Farmer memory) { address farmerAddress = farmInfo[_farmId].farmers[_farmerIndex]; return getFarmerByFarmIdAndAddress(_farmId, farmerAddress); } function getFarmerByFarmIdAndAddress(uint256 _farmId, address _farmerAddress) public view returns (Farmer memory farmer) { Farm memory farm = farmInfo[_farmId]; farmer = farmerInfo[_farmId][_farmerAddress]; farmer.durationMultiplier = _calculateDurationMultiplier(block.number - farmer.startingBlock); uint256 blocksSinceLastCalc = block.number - farm.lastCalcBlock; if(farm.liquidity > 0){ uint256 rewards = blocksSinceLastCalc * ((rewardPerBlock * farm.allocPoint) / totalAllocPoint); farm.accRewardsPerShare += rewards * CALC_PRECISION / farm.liquidity; } uint256 rewardsEarned = (farmer.liquidity * farm.accRewardsPerShare / CALC_PRECISION) - farmer.rewardDebt; farmer.rewards = (rewardsEarned * farmer.boltMultiplier * farmer.durationMultiplier) / 100000000; ThirdPartyReward memory thirdPartyReward = thirdPartyRewards[_farmId]; if(thirdPartyReward.token != address(0)){ if(farm.liquidity > 0){ uint256 thirdPartyRewardTokens; if(farm.lastCalcBlock < thirdPartyReward.endBlock && thirdPartyReward.endBlock <= block.number){ uint256 blocksAbleToPay = thirdPartyReward.endBlock - farm.lastCalcBlock; thirdPartyRewardTokens = blocksAbleToPay * thirdPartyReward.tokensPerBlock; } else { thirdPartyRewardTokens = blocksSinceLastCalc * thirdPartyReward.tokensPerBlock; } farm.accThirdPartyRewardsPerShare += thirdPartyRewardTokens * CALC_PRECISION / farm.liquidity; } farmer.thirdPartyRewards = (farmer.liquidity * farm.accThirdPartyRewardsPerShare / CALC_PRECISION) - farmer.thirdPartyRewardDebt; } if(farm.version == 3){ if(farm.liquidity > 0){ (uint256 uncollectedFee0, uint256 uncollectedFee1) = feeHelper.getUncollectedFees(farm.tokenId); farm.accFees0PerShare += uncollectedFee0 * CALC_PRECISION / farm.liquidity; farm.accFees1PerShare += uncollectedFee1 * CALC_PRECISION / farm.liquidity; } farmer.fees0 = (farmer.liquidity * farm.accFees0PerShare / CALC_PRECISION) - farmer.fees0Debt; farmer.fees1 = (farmer.liquidity * farm.accFees1PerShare / CALC_PRECISION) - farmer.fees1Debt; } } function getThirdPartyRewardConfigByFarmId(uint256 _farmId) external view returns (ThirdPartyReward memory) { return thirdPartyRewards[_farmId]; } /** ==================== EVENTS ==================== */ event FarmCreated(uint256 indexed farmId, address indexed poolAddr, uint256 version, uint256 tokenId, uint256 allocPoints, uint256 totalAllocPoints); event FarmDeactivated(uint256 indexed farmId, address indexed poolAddr, uint256 version, uint256 tokenId); event FarmAllocationUpdated(uint256 indexed farmId, address indexed poolAddr, uint256 allocPoints, uint256 totalAllocPoints); event FarmNameUpdated(uint256 indexed farmId, address indexed poolAddr, string _name); event FarmDeposit(uint256 indexed farmId, address indexed farmer, uint256 amount0Added, uint256 amount1Added, uint256 liquidityAdded); event FarmIncrease(uint256 indexed farmId, address indexed farmer, uint256 amount0Added, uint256 amount1Added, uint256 liquidityAdded, uint256 adjustedStartingBlock); event FarmWithdrawl(uint256 indexed farmId, address indexed farmer, uint256 amount0Withdrawn, uint256 amount1Withdrawn, uint256 amountRewards, uint256 fees0Collected, uint256 fees1Collected, uint256 thirdPartyRewardsCollected); event ThirdPartyRewardAdded(uint256 indexed farmId, address indexed rewardToken, address indexed tokenManager); event ThirdPartyRewardUpdated(uint256 indexed farmId, address tokenManager); event ThirdPartyRewardDeposited(uint256 indexed farmId, address indexed rewardToken, uint256 tokensPerBlock, uint256 endBlock); event RewardsPerBlockUpdated(uint256 rewardPerBlock, uint256 prevRewardPerBlock); event BoltMultiplierUpdated(uint256 amountBolt, uint256 multiplier); function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } receive() external payable {} fallback() external payable {} }
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
@openzeppelin/contracts/interfaces/draft-IERC6093.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows _totalSupply += value; } else { uint256 fromBalance = _balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. _balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. _totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. _balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } _allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
@openzeppelin/contracts/utils/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
contracts/RewardToken.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract RewardToken is ERC20, Ownable { // Mapping to store contracts that are allowed to mint mapping(address => bool) public minters; constructor(string memory name, string memory symbol) ERC20(name, symbol) Ownable(msg.sender) { minters[msg.sender] = true; } function mint(address _to, uint256 _amount) external { require(minters[msg.sender], "Caller is not authorized to mint"); _mint(_to, _amount); emit TokensMinted(_to, _amount); } event TokensMinted(address indexed to, uint256 amount); }
contracts/interfaces.sol
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity ^0.8.0; interface IWETN { function deposit() external payable; function withdraw(uint256 amount) external; } interface IElectroSwapV2Pair { function token0() external view returns (address); function token1() external view returns (address); function factory() external returns (address); function totalSupply() external returns (uint256); } interface IElectroSwapV2Router { function addLiquidity(address token0, address token1, uint amount0Desired, uint amount1Desired, uint amount0Min, uint amount1Min, address to, uint deadline) external returns (uint amount0, uint amount1, uint liquidity); function removeLiquidity(address token0, address token1, uint liquidity, uint amount0Min, uint amount1Min, address to, uint deadline) external returns (uint amount0, uint amount1); function WETH() external returns (address wetnAddress); } interface IElectroSwapV3Factory { function getPool(address, address, uint24) external view returns (address); } interface IUncollectedFeeHelper { function getUncollectedFees(uint256 positionTokenId) external view returns (uint256 uncollectedFee0, uint256 uncollectedFee1); } interface INonfungiblePositionManager { struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } function increaseLiquidity(IncreaseLiquidityParams calldata params) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1); struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } function decreaseLiquidity(DecreaseLiquidityParams calldata params) external payable returns (uint256 amount0, uint256 amount1); struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); function positions(uint256 tokenId) external view returns ( uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); function safeTransferFrom(address from, address to, uint256 tokenId) external; function factory() external view returns (address factory); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"string","name":"_rewardName","internalType":"string"},{"type":"string","name":"_rewardSymbol","internalType":"string"},{"type":"uint256","name":"_rewardSupply","internalType":"uint256"},{"type":"uint256","name":"_rewardPerBlock","internalType":"uint256"},{"type":"address","name":"_wetnAddress","internalType":"address"},{"type":"address","name":"_boltToken","internalType":"address"},{"type":"address","name":"_v2Factory","internalType":"address"},{"type":"address","name":"_v2Router","internalType":"address"},{"type":"address","name":"_v3Factory","internalType":"address"},{"type":"address","name":"_positionManager","internalType":"address"},{"type":"address","name":"_feeHelper","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"event","name":"BoltMultiplierUpdated","inputs":[{"type":"uint256","name":"amountBolt","internalType":"uint256","indexed":false},{"type":"uint256","name":"multiplier","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmAllocationUpdated","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"poolAddr","internalType":"address","indexed":true},{"type":"uint256","name":"allocPoints","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAllocPoints","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmCreated","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"poolAddr","internalType":"address","indexed":true},{"type":"uint256","name":"version","internalType":"uint256","indexed":false},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false},{"type":"uint256","name":"allocPoints","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAllocPoints","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmDeactivated","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"poolAddr","internalType":"address","indexed":true},{"type":"uint256","name":"version","internalType":"uint256","indexed":false},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmDeposit","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"farmer","internalType":"address","indexed":true},{"type":"uint256","name":"amount0Added","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1Added","internalType":"uint256","indexed":false},{"type":"uint256","name":"liquidityAdded","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmIncrease","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"farmer","internalType":"address","indexed":true},{"type":"uint256","name":"amount0Added","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1Added","internalType":"uint256","indexed":false},{"type":"uint256","name":"liquidityAdded","internalType":"uint256","indexed":false},{"type":"uint256","name":"adjustedStartingBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FarmNameUpdated","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"poolAddr","internalType":"address","indexed":true},{"type":"string","name":"_name","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"FarmWithdrawl","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"farmer","internalType":"address","indexed":true},{"type":"uint256","name":"amount0Withdrawn","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1Withdrawn","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountRewards","internalType":"uint256","indexed":false},{"type":"uint256","name":"fees0Collected","internalType":"uint256","indexed":false},{"type":"uint256","name":"fees1Collected","internalType":"uint256","indexed":false},{"type":"uint256","name":"thirdPartyRewardsCollected","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RewardsPerBlockUpdated","inputs":[{"type":"uint256","name":"rewardPerBlock","internalType":"uint256","indexed":false},{"type":"uint256","name":"prevRewardPerBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ThirdPartyRewardAdded","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"rewardToken","internalType":"address","indexed":true},{"type":"address","name":"tokenManager","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ThirdPartyRewardDeposited","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"rewardToken","internalType":"address","indexed":true},{"type":"uint256","name":"tokensPerBlock","internalType":"uint256","indexed":false},{"type":"uint256","name":"endBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ThirdPartyRewardUpdated","inputs":[{"type":"uint256","name":"farmId","internalType":"uint256","indexed":true},{"type":"address","name":"tokenManager","internalType":"address","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminAddThirdPartyReward","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_tokenManager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminCreateFarm_V2","inputs":[{"type":"string","name":"_name","internalType":"string"},{"type":"address","name":"_pairAddr","internalType":"address"},{"type":"uint256","name":"_allocPoint","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminCreateFarm_V3","inputs":[{"type":"string","name":"_name","internalType":"string"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_allocPoint","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminDeactivateFarm","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminUpdateBoltMultiplier","inputs":[{"type":"uint256","name":"_amountBolt","internalType":"uint256"},{"type":"uint256","name":"_multiplier","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminUpdateFarmAllocPoints","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"uint256","name":"_allocPoint","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminUpdateFarmName","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"string","name":"_name","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminUpdateRewardsPerBlock","inputs":[{"type":"uint256","name":"_rewardPerBlock","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculateDurationMultiplier","inputs":[{"type":"uint256","name":"blocksServed","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"deposit","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"uint256","name":"_amount0","internalType":"uint256"},{"type":"uint256","name":"_amount1","internalType":"uint256"},{"type":"uint256","name":"_amountBolt","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"depositThirdPartyReward","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"uint256","name":"_amountToken","internalType":"uint256"},{"type":"uint256","name":"_distributeOverBlockCount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"farmCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"farm","internalType":"struct YieldFarm.Farm","components":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"uint8","name":"version","internalType":"uint8"},{"type":"string","name":"name","internalType":"string"},{"type":"address","name":"poolAddr","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"allocPoint","internalType":"uint256"},{"type":"uint256","name":"lastCalcBlock","internalType":"uint256"},{"type":"uint256","name":"accRewardsPerShare","internalType":"uint256"},{"type":"uint256","name":"accThirdPartyRewardsPerShare","internalType":"uint256"},{"type":"address[]","name":"farmers","internalType":"address[]"},{"type":"uint256","name":"farmerCount","internalType":"uint256"},{"type":"address","name":"token0","internalType":"address"},{"type":"address","name":"token1","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"int24","name":"tickLower","internalType":"int24"},{"type":"int24","name":"tickUpper","internalType":"int24"},{"type":"uint24","name":"fee","internalType":"uint24"},{"type":"uint256","name":"accFees0PerShare","internalType":"uint256"},{"type":"uint256","name":"accFees1PerShare","internalType":"uint256"},{"type":"bool","name":"active","internalType":"bool"}]}],"name":"getFarmById","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getFarmIdsByPoolAddress","inputs":[{"type":"address","name":"_poolAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"farmer","internalType":"struct YieldFarm.Farmer","components":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"boltMultiplier","internalType":"uint256"},{"type":"uint256","name":"boltDeposited","internalType":"uint256"},{"type":"uint256","name":"durationMultiplier","internalType":"uint256"},{"type":"uint256","name":"startingBlock","internalType":"uint256"},{"type":"uint256","name":"rewards","internalType":"uint256"},{"type":"uint256","name":"rewardDebt","internalType":"uint256"},{"type":"uint256","name":"thirdPartyRewards","internalType":"uint256"},{"type":"uint256","name":"thirdPartyRewardDebt","internalType":"uint256"},{"type":"uint256","name":"fees0","internalType":"uint256"},{"type":"uint256","name":"fees0Debt","internalType":"uint256"},{"type":"uint256","name":"fees1","internalType":"uint256"},{"type":"uint256","name":"fees1Debt","internalType":"uint256"}]}],"name":"getFarmerByFarmIdAndAddress","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"address","name":"_farmerAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct YieldFarm.Farmer","components":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"liquidity","internalType":"uint256"},{"type":"uint256","name":"boltMultiplier","internalType":"uint256"},{"type":"uint256","name":"boltDeposited","internalType":"uint256"},{"type":"uint256","name":"durationMultiplier","internalType":"uint256"},{"type":"uint256","name":"startingBlock","internalType":"uint256"},{"type":"uint256","name":"rewards","internalType":"uint256"},{"type":"uint256","name":"rewardDebt","internalType":"uint256"},{"type":"uint256","name":"thirdPartyRewards","internalType":"uint256"},{"type":"uint256","name":"thirdPartyRewardDebt","internalType":"uint256"},{"type":"uint256","name":"fees0","internalType":"uint256"},{"type":"uint256","name":"fees0Debt","internalType":"uint256"},{"type":"uint256","name":"fees1","internalType":"uint256"},{"type":"uint256","name":"fees1Debt","internalType":"uint256"}]}],"name":"getFarmerByFarmIdAndIndex","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"uint256","name":"_farmerIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct YieldFarm.ThirdPartyReward","components":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"tokenManager","internalType":"address"},{"type":"uint256","name":"tokensPerBlock","internalType":"uint256"},{"type":"uint256","name":"endBlock","internalType":"uint256"}]}],"name":"getThirdPartyRewardConfigByFarmId","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerBlock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract RewardToken"}],"name":"rewardToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAllocPoint","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateThirdPartyRewardManager","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"address","name":"_tokenManager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_farmId","internalType":"uint256"},{"type":"uint256","name":"_liquidityAmt","internalType":"uint256"},{"type":"bool","name":"_asNative","internalType":"bool"}]},{"type":"receive","stateMutability":"payable"}]
Deployed ByteCode
0x608080604052600436101561001a575b50361561001857005b005b600090813560e01c9081630a8e214c14612fd857508063150b7a0214612f6257806317caf6f114612f445780632505c3d9146123325780632e12ba7d1461228e57806333cfcd3b146122525780633d3d2547146120415780633db6b35d14611f3b5780634c763f2e14611e86578063555d405c14611e385780635ddca72a14611d8e5780636980ff8814611c89578063704cf56d14611b8d578063715018a614611b3b5780637e15dc6014611b145780638ae39cac14611af65780638da5cb5b14611ad057806391e758fd146119d4578063a8aff3bc146117e0578063ae9679791461170a578063e11dd11014611020578063eb4bfb5014610fb4578063f2fde38b14610f21578063f3a65da0146105c7578063f7c618c1146105a05763fd3cb4510361000f573461059d57602036600319011261059d576004358161026060405161016581613089565b828152826020820152606060408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201526060610120820152826101408201528261016082015282610180820152826101a0820152826101c0820152826101e08201528261020082015282610220820152826102408201520152808252600e6020526101f7604083206131db565b9160c083019161020883514361342c565b9060808501918251610379575b50509061012084016060815260405193602085528551602086015260ff6020870151166040860152610258604087015161028060608801526102a0870190613148565b936001600160a01b0360608801511660808701525160a086015260a086015160c08601525160e085015260e08501516101008501526101008501516101208501525191601f1984820301610140850152602080845192838152019301915b81811061035a5750505061026083610140849501516101608501526001600160a01b03610160820151166101808501526001600160a01b03610180820151166101a08501526101a08101516101c08501526101c081015160020b6101e08501526101e081015160020b61020085015262ffffff6102008201511661022085015261022081015161024085015261024081015182850152015115156102808301520390f35b82516001600160a01b03168452602093840193909201916001016102b6565b61039f610399610390600b5460a08a0151906133f9565b600a549061340c565b826133f9565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156105385783516103cb9161340c565b6103da60e088019182516133d6565b9052600360ff60208801511614610479575b81845260106020526001600160a01b03604085205416156102155761042091845260106020526002604085200154906133f9565b670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561046557815161044c9161340c565b61045c61010086019182516133d6565b90523880610215565b634e487b7160e01b83526011600452602483fd5b6001600160a01b036006541660406101a088015160248251809481936363bcf82760e01b835260048301525afa9081156105925785908692610560575b50670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561054c5784516104e39161340c565b6104f361022089019182516133d6565b9052670de0b6b3a7640000810290808204670de0b6b3a764000014901517156105385783516105219161340c565b61053161024088019182516133d6565b90526103ec565b634e487b7160e01b85526011600452602485fd5b634e487b7160e01b86526011600452602486fd5b9050610584915060403d60401161058b575b61057c81836130c3565b810190613ed6565b90386104b6565b503d610572565b6040513d87823e3d90fd5b80fd5b503461059d578060031936011261059d5760206001600160a01b0360025416604051908152f35b503461059d57606036600319011261059d5760043567ffffffffffffffff8111610df0576105f9903690600401613101565b6106016146e8565b610609614400565b8160a06040516106188161303b565b82815282602082015282604082015282606082015282608082015201526001600160a01b03600554166040519163133f757160e31b8352602435600484015261018083602481855afa908115610f1657849185908694879188978991610e43575b506001600160a01b036040519661068f8861303b565b168087526001600160801b036001600160a01b036020890196169283875262ffffff60408a019a168a52606089019560020b8652608089019a60020b8b521660a088015215159081610e39575b5015610df4578088913b15610df057604051632142170760e11b8152336004820152306024808301919091523560448201529082908290606490829084905af18015610de557610dcc575b50506001600160a01b03600454169460206001600160a01b0386511660646001600160a01b038651169162ffffff855116996040519a8b948593630b4c774160e11b85526004850152602484015260448301525afa958615610dc1578896610d81575b50610793614711565b6107a1604435600a546133d6565b600a556107d06107b2600c546143bc565b80600c556001600160a01b0388168a52600d60205260408a206143cb565b6040968751926107e089856130c3565b6001845260208401601f198a01368237845115610d6d57339052600c54946001600160801b0360a0890151169462ffffff6001600160a01b03808b5116935116935160020b945160020b955116958b519861083a8a613089565b888a52600360208b01528c8a01526001600160a01b038b1660608a0152608089015260443560a08901524360c08901528b60e08901528b61010089015261012088015260016101408801526101608701526101808601526024356101a08601526101c08501526101e0840152610200830152856102208301528561024083015260016102608301528552600e60205283852090805182556001820160ff60208301511660ff198254161790558481015180519067ffffffffffffffff8211610ca257819061090b60028601546131a1565b601f8111610d2f575b50602090601f8311600114610cc1578992610cb6575b50508160011b916000199060031b1c19161760028301555b6001600160a01b036060820151166001600160a01b036003840191166001600160a01b03198254161790556080810151600483015560a0810151600583015560c0810151600683015560e08101516007830155610100810151600883015561012081015180519067ffffffffffffffff8211610ca257600160401b8211610ca2576020906009850154836009870155808410610c85575b500160098401885260208820885b838110610c68575050505091610aed60a0926011610260866101406001600160801b03980151600a8501556001600160a01b03610160820151166001600160a01b03600b860191166001600160a01b03198254161790556001600160a01b03610180820151166001600160a01b03600c860191166001600160a01b03198254161790556101a0810151600d850155600e84016101c082015181546101e084015160181b9062ffffff68ffffff00000000000061020087015160301b1693169068ffffffffffffffffff1916179065ffffff0000001617179055610220810151600f85015561024081015160108501550151151591019060ff801983541691151516179055565b0151168380526011602052600d6101a084862054855190610b0d826130a6565b33825260208201948552868201908152606082018881526080830189815260a084019143835260c08501938b85528b60e08701528b6101008701528b6101208701528b6101408701528b6101608701528b6101808701528b87870152600c548c52600f6020528a808d206000906001600160a01b033316825260205220986001600160a01b0380885116166001600160a01b03198b5416178a555160018a015551600289015551600388015551600487015551600586015551600685015560e0810151600785015561010081015160088501556101208101516009850155610140810151600a850155610160810151600b850155610180810151600c85015501519101557f51e07fb38ff3282be5c5a25bb4097bc0b78ccdbf629103926bf82d7f8ea3715b60806001600160a01b03600c5493600a548651966003885260243560208901526044359088015260608701521693a36001805580f35b60019060206001600160a01b0385511694019381840155016109e7565b600986018a52828a20610c9c918101908501613ebf565b386109d9565b634e487b7160e01b88526041600452602488fd5b01519050388061092a565b92506002850189528089209089935b601f1984168510610d14576001945083601f19811610610cfb575b505050811b016002830155610942565b015160001960f88460031b161c19169055388080610ceb565b81810151835560209485019460019093019290910190610cd0565b610d5d90600287018b5260208b20601f850160051c81019160208610610d63575b601f0160051c0190613ebf565b38610914565b9091508190610d50565b634e487b7160e01b8b52603260045260248bfd5b9095506020813d602011610db9575b81610d9d602093836130c3565b81010312610db557610dae906143a8565b943861078a565b8780fd5b3d9150610d90565b6040513d8a823e3d90fd5b81610dd6916130c3565b610de1578638610727565b8680fd5b6040513d84823e3d90fd5b5080fd5b60405162461bcd60e51b815260206004820152600f60248201527f496e76616c696420746f6b656e496400000000000000000000000000000000006044820152606490fd5b90501515386106dc565b975050945050509050610180833d8211610f0e575b81610e6661018093836130c3565b81010312610f0a5782516bffffffffffffffffffffffff811603610f0a57610e90602084016143a8565b50610e9d604084016143a8565b90610eaa606085016143a8565b9160808501519062ffffff82168203610de157610ec960a0870161477d565b94610ed660c0880161477d565b91610efe610160610ee960e08b0161463e565b99610ef7610140820161463e565b500161463e565b50949295919638610679565b8380fd5b3d9150610e58565b6040513d86823e3d90fd5b503461059d57602036600319011261059d576001600160a01b03610f43612ff4565b610f4b6146e8565b168015610fa057815473ffffffffffffffffffffffffffffffffffffffff198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b503461059d57602036600319011261059d57610fce6146e8565b610fd6614400565b7fd76943207bf317503ab19e2502c0c76842f97bcb94d539322b494e191551d2066040600b54600435600b5561100a614711565b600b549082519182526020820152a16001805580f35b503461059d57606036600319011261059d5760043567ffffffffffffffff8111610df057611052903690600401613101565b61105a61300f565b906110636146e8565b61106b614400565b6001600160a01b038216156116c5576001600160a01b0382168352600d60205260408320546116805760405163c45a015560e01b8152602081600481876001600160a01b0388165af1908115610f16578491611646575b506001600160a01b038060085416911603611601576110df614711565b6110ed604435600a546133d6565b600a55604051630dfe168160e01b81526020816004816001600160a01b0387165afa908115610f165784916115c7575b5060405163d21220a760e01b81526020816004816001600160a01b0388165afa8015610592578590611583575b6001600160a01b039150611179611162600c546143bc565b80600c558387168852600d602052604088206143cb565b81600c54936040519561118b87613089565b858752600260208801526040870152818716606087015287608087015260443560a08701524360c08701528760e0870152876101008701526060610120870152876101408701521661016085015216610180830152836101a0830152836101c0830152836101e083015283610200830152836102208301528361024083015260016102608301528352600e6020526040832090805182556001820160ff60208301511660ff19825416179055604081015180519067ffffffffffffffff82116114c357819061125d60028601546131a1565b601f8111611550575b50602090601f83116001146114e25787926114d7575b50508160011b916000199060031b1c19161760028301555b6001600160a01b036060820151166001600160a01b036003840191166001600160a01b03198254161790556080810151600483015560a0810151600583015560c0810151600683015560e08101516007830155610100810151600883015561012081015180519067ffffffffffffffff82116114c357600160401b82116114c35760209060098501548360098701558084106114a6575b500160098401865260208620865b8381106114895787876114328860116102608a610140810151600a8501556001600160a01b03610160820151166001600160a01b03600b860191166001600160a01b03198254161790556001600160a01b03610180820151166001600160a01b03600c860191166001600160a01b03198254161790556101a0810151600d850155600e84016101c082015181546101e084015160181b9062ffffff68ffffff00000000000061020087015160301b1693169068ffffffffffffffffff1916179065ffffff0000001617179055610220810151600f85015561024081015160108501550151151591019060ff801983541691151516179055565b600c547f51e07fb38ff3282be5c5a25bb4097bc0b78ccdbf629103926bf82d7f8ea3715b60806001600160a01b03600a54946040519560028752876020880152604435604088015260608701521693a36001805580f35b60019060206001600160a01b038551169401938184015501611339565b6009860188528288206114bd918101908501613ebf565b3861132b565b634e487b7160e01b86526041600452602486fd5b01519050388061127c565b92506002850187528087209087935b601f1984168510611535576001945083601f1981161061151c575b505050811b016002830155611294565b015160001960f88460031b161c1916905538808061150c565b818101518355602094850194600190930192909101906114f1565b61157d9060028701895260208920601f850160051c81019160208610610d6357601f0160051c0190613ebf565b38611266565b506020813d6020116115bf575b8161159d602093836130c3565b810103126115bb576115b66001600160a01b03916143a8565b61114a565b8480fd5b3d9150611590565b90506020813d6020116115f9575b816115e2602093836130c3565b81010312610f0a576115f3906143a8565b3861111d565b3d91506115d5565b60405162461bcd60e51b815260206004820152601060248201527f496e76616c6964204c5020546f6b656e000000000000000000000000000000006044820152606490fd5b90506020813d602011611678575b81611661602093836130c3565b81010312610f0a57611672906143a8565b386110c2565b3d9150611654565b60405162461bcd60e51b815260206004820152601260248201527f506f6f6c20616c726561647920616464656400000000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f43616e6e6f7420616464207a65726f20616464726573730000000000000000006044820152606490fd5b503461059d57604036600319011261059d576117dc61173261172a61300f565b600435613eec565b604051918291829190916101a0806101c08301946001600160a01b0381511684526020810151602085015260408101516040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c085015260e081015160e08501526101008101516101008501526101208101516101208501526101408101516101408501526101608101516101608501526101808101516101808501520151910152565b0390f35b503461059d57604036600319011261059d576004359060243567ffffffffffffffff8111610df057611816903690600401613101565b61181e6146e8565b611826614400565b828252600e60205260408220926002600385019461184f6001600160a01b038754161515613e84565b019382519467ffffffffffffffff86116119c05761186d81546131a1565b601f8111611990575b50602095601f811160011461190057916001600160a01b0391836118eb9488997f0b7d901ae393500dff5a3466e8f2830aafbb8e764beb43fc543c5a2b7ad6cf39979899916118f5575b508160011b916000199060031b1c19161790555b541693604051918291602083526020830190613148565b0390a36001805580f35b9050880151386118c0565b818652868620601f198216875b8181106119785750826001600160a01b0394927f0b7d901ae393500dff5a3466e8f2830aafbb8e764beb43fc543c5a2b7ad6cf399798999a6118eb97956001941061195f575b5050811b0190556118d4565b8a015160001960f88460031b161c191690553880611953565b878a015183556020998a01996001909301920161190d565b6119ba9082875260208720601f890160051c81019160208a10610d6357601f0160051c0190613ebf565b38611876565b634e487b7160e01b85526041600452602485fd5b503461059d57604036600319011261059d576004356001600160a01b036119f961300f565b16611a05811515613dd1565b6001600160a01b0383541633148015611aaf575b15611a6a5760207f25a540d6e0a0f5fef26dac1ae340f4965dbcbe19402ebda71353fdf92e44e229918385526010825260016040862001816001600160a01b0319825416179055604051908152a280f35b60405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920746f6b656e206d616e616765722063616e207570646174650000006044820152606490fd5b508183526010602052336001600160a01b0360016040862001541614611a19565b503461059d578060031936011261059d576001600160a01b036020915416604051908152f35b503461059d578060031936011261059d576020600b54604051908152f35b503461059d57602036600319011261059d576020611b33600435614737565b604051908152f35b503461059d578060031936011261059d57611b546146e8565b806001600160a01b038154811981168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461059d57611b9c36613025565b611ba46146e8565b611bac614400565b6127108110611c44578115611bff57816040917f9c1c6b832a81475c34b096f71606cd45a11db174926001426848d13ef06677bb9385526011602052808386205582519182526020820152a16001805580f35b60405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e203000000000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f4d756c7469706c696572206d757374206265203e3d20313030303000000000006044820152606490fd5b503461059d57602036600319011261059d57600435611ca66146e8565b611cae614400565b808252600e602052604082209060038201906001600160a01b0382541615611d49578392601191611cdd614711565b6001600160a01b036005830194611cf78654600a5461342c565b600a555416907ff117694fabc4ec9e484bdba96e172c17701ffc85e1e15a06940d1ad46d24ddb1604060ff600186015416600d86015482519182526020820152a301805460ff19169055556001805580f35b60405162461bcd60e51b815260206004820152601560248201527f4e6f7468696e6720746f206465616374697661746500000000000000000000006044820152606490fd5b503461059d57611d9d36613025565b90611da66146e8565b611dae614400565b808352600e6020527fa568a242f66b52a4969248e1bcfe826b40dee71c1a5dd3730ee4d2ec6175424e60406001600160a01b03818620856003820191611df8848454161515613e84565b611e00614711565b611e1c82611e176005600a5494019384549061342c565b6133d6565b600a5555541693600a5482519182526020820152a36001805580f35b503461059d576117326117dc916001600160a01b03611e7860406009611e5d36613025565b929095611e68613e1d565b50868152600e6020522001613439565b90549060031b1c1690613eec565b503461059d57602036600319011261059d576001600160a01b03611ea8612ff4565b168152600d60205260408120604051908160208254918281520190819285526020852090855b818110611f255750505082611ee49103836130c3565b604051928392602084019060208552518091526040840192915b818110611f0c575050500390f35b8251845285945060209384019390920191600101611efe565b8254845260209093019260019283019201611ece565b503461059d57606036600319011261059d57600435611f5861300f565b90604435916001600160a01b038316809303610f0a576001600160a01b0390611f7f6146e8565b611f87614400565b169081151580612038575b611f9b90613dd1565b604051611fa78161306d565b828152600360208201858152604083018781526001600160a01b036060850192898452868a526010602052818060408c2097511616821987541617865551166001600160a01b036001860191166001600160a01b0319825416179055516002840155519101557f7bbbf626944758d872c4ec0f49288af94151f90f27a0d41b4d90691d960c58168480a46001805580f35b50821515611f92565b503461059d57606036600319011261059d576004356024359060443591818452601060205260408420906001600160a01b038254161561220d576001600160a01b03855416331480156121f7575b156121b25761209d83614422565b81546040516323b872dd60e01b8152336004820152306024820152604481018390529190602090839060649082908a906001600160a01b03165af180156121a7577f28d96120359a20f2e5501040c185f0e0f5e3603aa58507e2b1be4cecf3936550936040936001600160a01b039261217a575b506003810180549097612157918143821061216b5761214961213761214e93439061342c565b975b611e1760028801998a54906133f9565b61340c565b809555436133d6565b80975554169482519182526020820152a380f35b61214e91506121498c97612139565b61219b9060203d6020116121a0575b61219381836130c3565b810190613189565b612111565b503d612189565b6040513d88823e3d90fd5b60405162461bcd60e51b815260206004820152601e60248201527f4f6e6c7920746f6b656e206d616e616765722063616e206465706f73697400006044820152606490fd5b50336001600160a01b036001840154161461208f565b60405162461bcd60e51b815260206004820152601e60248201527f546869726420706172747920726577617264206e6f7420646566696e656400006044820152606490fd5b503461059d57606036600319011261059d576044358015158103610df0576122879061227c614400565b602435600435613467565b6001805580f35b503461059d57602036600319011261059d57604081608092606083516122b38161306d565b8281528260208201528285820152015260043581526010602052206040516122da8161306d565b6001600160a01b03825416918282526001600160a01b03806001830154166020840190815260606003600285015494604087019586520154940193845260405194855251166020840152516040830152516060820152f35b50608036600319011261059d57602435606435604435600435612353614400565b8184828752600e602052604087209060ff60118301541615612f0f5761237884614422565b838852600f602052604088206001600160a01b033316895260205260408820968891898095341515600014612e50575050600b84016001600160a01b038154166001600160a01b03600754168091148015612e3a575b15612de9578b813b1561059d57604051630d0e30db60e41b8152918290600490829034905af18015612ad457612dce575b506001600160a01b03905416926001600160a01b03600754168414600014612d5f5750505050600c8101546040516323b872dd60e01b81523360048201523060248201526044810186905234929160019190602090829060649082908e906001600160a01b03165af18015612aac57612d40575b505b82151580612d37575b15612cf257600182015460ff16600203612afc5761249b826131db565b6101608101805160035460405163095ea7b360e01b81526001600160a01b039182166004820152602481018890529299938d929091602091859160449183918791165af1928315610de557612545936101809350612adf575b50016020838d6001600160a01b03845116906001600160a01b03600354169060405180978195829463095ea7b360e01b845260048401602090939291936001600160a01b0360408201951681520152565b03925af1918215612ad457606092612ab7575b506101046001600160a01b038080600354169b5116925116918d6040519b8c94859362e8e33760e81b85526004850152602484015289604484015286606484015260016084840152600160a48401523060c48401524260e48401525af1948515612aac578a958b988c91612a5d575b50906125ec6125ff94939297809a9788955b6001600160a01b03600b8a015416614652565b6001600160a01b03600c86015416614652565b6004810161260e8482546133d6565b90556001870180548061285a575060098201805490600160401b821015612846578161264291600161266094018155613439565b33906001600160a01b038084549260031b9316831b921b1916179055565b600a8201805490600182018092116128325792856126ff93601093670de0b6b3a764000096556001600160a01b0333166001600160a01b03198d5416178c55558a8052601160205260408b205460028b01554360058b0155836126c76007830154886133f9565b0460078b0155836126dc6008830154886133f9565b0460098b0155836126f1600f830154886133f9565b04600b8b01550154846133f9565b04600d870155604051938452602084015260408301527f141912e5b44b5d07ab89056d17b819c5672cbcb022c8997d64631719b3a9863960603393a35b8061274a575b826001805580f35b600382019061275a8254826133d6565b9182855260116020526040852054156127ed576009546040516323b872dd60e01b815233600482015230602482015260448101939093526020908390606490829089906001600160a01b03165af19182156105925783926127d0575b505582526011602052600260408320549101553880612742565b6127e89060203d6020116121a05761219381836130c3565b6127b6565b60405162461bcd60e51b815260206004820152601460248201527f496e76616c696420424f4c54206465706f7369740000000000000000000000006044820152606490fd5b634e487b7160e01b8b52601160045260248bfd5b634e487b7160e01b8b52604160045260248bfd5b670de0b6b3a76400008594939502848104670de0b6b3a764000014851517156128325791818a9361288c8780956133d6565b6128959161340c565b966005850197885443906128a89161342c565b906128b390826133f9565b670de0b6b3a764000090046128c79161342c565b6128d1904361342c565b809855600781019081546128e590846133f9565b670de0b6b3a76400009004600787019081546129009161342c565b906008830190815461291290876133f9565b670de0b6b3a764000090049160098a0192835461292e9161342c565b91600f8601948554612940908a6133f9565b670de0b6b3a7640000900497600b8d0198895461295c9161342c565b97601001998a5461296d90826133f9565b670de0b6b3a764000090049d600d019d8e546129889161342c565b9c612992916133d6565b809b55546129a0908b6133f9565b670de0b6b3a76400009004906129b59161342c565b9055546129c290886133f9565b670de0b6b3a76400009004906129d79161342c565b9055546129e490856133f9565b670de0b6b3a76400009004906129f99161342c565b905554612a05916133f9565b670de0b6b3a7640000900490612a1a9161342c565b9055604051948552602085015260408401526060830152339160807fb2f6073a8c991ae638b8825ad59ac07373632bbdb61cce0d6a9b9be4943f3c3291a361273c565b9650509650906060853d606011612aa4575b81612a7c606093836130c3565b81010312612aa05784516020860151604090960151959790959192916125ec6125c7565b8980fd5b3d9150612a6f565b6040513d8c823e3d90fd5b612acf9060203d6020116121a05761219381836130c3565b612558565b6040513d8e823e3d90fd5b612af79060203d6020116121a05761219381836130c3565b6124f4565b612b08829694966131db565b61016081015160055460405163095ea7b360e01b81526001600160a01b0391821660048201526024810187905292969291602091839116818e816044810103925af18015612cca57612cd5575b5061018085015160055460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905291602091839116818e816044810103925af18015612cca57612cad575b5060606101a06001600160a01b036005541696015160405190612bc28261303b565b815260c460208201918783528d6040820199868b5285830160018152608084016001815260a08501914283526040519d8e98899763219f5d1760e01b89525160048901525160248801525160448701525160648601525160848501525160a48401525af1968715612aac578a8b968c99612c56575b50906125ec6001600160801b036125ff9594931697809a9788956125d9565b9850509450906060873d606011612ca5575b81612c75606093836130c3565b81010312612aa0576125ff91612c8a8861463e565b602089015160409099015198969293509091906125ec612c37565b3d9150612c68565b612cc59060203d6020116121a05761219381836130c3565b612ba0565b6040513d8d823e3d90fd5b612ced9060203d6020116121a05761219381836130c3565b612b55565b60405162461bcd60e51b815260206004820152601d60248201527f426f746820616d6f756e7473206d75737420626520706f7369746976650000006044820152606490fd5b5085151561247e565b612d589060203d6020116121a05761219381836130c3565b5038612473565b6040516323b872dd60e01b81523360048201523060248201526044810193909352349750600195509093929091906020908290818d81606481015b03925af18015612aac57612daf575b50612475565b612dc79060203d6020116121a05761219381836130c3565b5038612da9565b9a612de2816001600160a01b03939d6130c3565b9a906123ff565b60405162461bcd60e51b8152602060048201526024808201527f4e61746976652045544e2073656e7420746f20756e737570706f7274696e67206044820152636661726d60e01b6064820152608490fd5b50806001600160a01b03600c88015416146123ce565b600b8601546040516323b872dd60e01b815233600482015230602482015260448101959095529295949391926020908390606490829087906001600160a01b03165af1908115612f0457602092612d9a92612ee9575b50600c8601546040516323b872dd60e01b81523360048201523060248201526044810192909252909384926001600160a01b039092169183919082906064820190565b612eff90843d86116121a05761219381836130c3565b612ea6565b6040513d85823e3d90fd5b60405162461bcd60e51b815260206004820152600d60248201526c496e616374697665206661726d60981b6044820152606490fd5b503461059d578060031936011261059d576020600a54604051908152f35b503461059d57608036600319011261059d57612f7c612ff4565b50612f8561300f565b5060643567ffffffffffffffff8111610df05736602382011215610df057806004013567ffffffffffffffff8111612fd4573691016024011161059d57604051630a85bd0160e11b8152602090f35b8280fd5b905034610df05781600319360112610df057602090600c548152f35b600435906001600160a01b038216820361300a57565b600080fd5b602435906001600160a01b038216820361300a57565b604090600319011261300a576004359060243590565b60c0810190811067ffffffffffffffff82111761305757604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761305757604052565b610280810190811067ffffffffffffffff82111761305757604052565b6101c0810190811067ffffffffffffffff82111761305757604052565b90601f8019910116810190811067ffffffffffffffff82111761305757604052565b67ffffffffffffffff811161305757601f01601f191660200190565b81601f8201121561300a57803590613118826130e5565b9261312660405194856130c3565b8284526020838301011161300a57816000926020809301838601378301015290565b919082519283825260005b848110613174575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201613153565b9081602091031261300a5751801515810361300a5790565b90600182811c921680156131d1575b60208310146131bb57565b634e487b7160e01b600052602260045260246000fd5b91607f16916131b0565b906040516131e881613089565b80928054825260ff60018201541660208301526002810160405190816000825492613212846131a1565b80845293600181169081156133b4575060011461336d575b50613237925003826130c3565b60408301526001600160a01b03600382015416606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e083015260088101546101008301526009810160405190816020825491828152019160005260206000209060005b81811061334e5750505061026092826132c060ff9460119403826130c3565b610120860152600a8101546101408601526001600160a01b03600b820154166101608601526001600160a01b03600c82015416610180860152600d8101546101a086015262ffffff600e8201548060020b6101c08801528060181c60020b6101e088015260301c16610200860152600f81015461022086015260108101546102408601520154161515910152565b82546001600160a01b03168452602090930192600192830192016132a1565b90506000929192526020600020906000915b818310613398575050906020613237928201013861322a565b602091935080600191548385880101520191019091839261337f565b90506020925061323794915060ff191682840152151560051b8201013861322a565b919082018092116133e357565b634e487b7160e01b600052601160045260246000fd5b818102929181159184041417156133e357565b8115613416570490565b634e487b7160e01b600052601260045260246000fd5b919082039182116133e357565b80548210156134515760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b906000828152600e60205260408120838252600f602052604082206001600160a01b033316835260205260408220926001840181815410613d8057839184938580976134b28a614422565b898252600f602052604082206001600160a01b033316835260205260408220600181019081548c81613b2d575b505050506134ee84865461342c565b808655670de0b6b3a76400006135086007860154836133f9565b0460078301556001840190600360ff83541614613aee575b8b845260106020526001600160a01b03604085205416613aca575b508415613a7b578b6139f5575b5460ff166002036138e15761355c836131db565b606081015160035460405163095ea7b360e01b81526001600160a01b03918216600482015260248101889052929d92911681604481875a94602095f18015610f16576138c4575b506001600160a01b03600354169060408d60e46001600160a01b03610180816101608501511693015116918784519687948593635d5155ef60e11b8552600485015260248401528b604484015260016064840152600160848401523060a48401524260c48401525af19c8d15610f16578492859e61389b575b50908d8361362993614902565b9a945b541561368d575b50506004613644910191825461342c565b9055604051968752602087015260408601526060850152608084015260a08301527fc78493ea26eae4d9218158e9f1f6207ffe0f8926aa240f8c79a353b729ffb3f860c03393a3565b60038291015480613834575b50899052600f60205280600d60408083206000906001600160a01b03331682526020522082815582600182015582600282015582600382015582600482015582600582015582600682015582600782015582600882015582600982015582600a82015582600b82015582600c8201550155888152600e6020526040812060098101805480845b818110613802575b50808210613738575b505050613633565b6000198101908111610538579061376c6001600160a01b0361375d61378b9486613439565b90549060031b1c169184613439565b9091906001600160a01b038084549260031b9316831b921b1916179055565b805480156137ee5790600a929160001901906137a78282613439565b6001600160a01b0382549160031b1b19169055550180549160001983019283116137da5750556004613644388080613730565b634e487b7160e01b81526011600452602490fd5b634e487b7160e01b84526031600452602484fd5b6001600160a01b036138148286613439565b905460039190911b1c16331461382c5760010161371f565b915038613727565b60095460405163a9059cbb60e01b81523360048201526024810192909252909160209183916044918391906001600160a01b03165af18015610de55761387c575b8190613699565b6138949060203d6020116121a05761219381836130c3565b5038613875565b6138bb919e5061362992935060403d60401161058b5761057c81836130c3565b9d90929161361c565b6138dc9060203d6020116121a05761219381836130c3565b6135a3565b6001600160a01b03600554169a600d84019b8c546040519060a0820182811067ffffffffffffffff8211176139e1576040926001600160801b0395949260a49285528152876020820193878c168552858301600181526060840160018152608085019142835288519a8b988997630624e65f60e11b8952516004890152511660248701525160448601525160648501525160848401525af19c8d15610f16578492859e6139b1575b50906139986139aa925461478b565b50508d836139a5886131db565b614902565b9a9461362c565b6139aa92919e5061399893506139d59060403d60401161058b5761057c81836130c3565b9390939e919250613989565b634e487b7160e01b87526041600452602487fd5b6001600160a01b03600b850154166001600160a01b0360075416809114908115613a64575b506135485760405162461bcd60e51b815260206004820152601160248201527f556e737570706f7274696e67206661726d0000000000000000000000000000006044820152606490fd5b90506001600160a01b03600c860154161438613a1a565b5050985050505060405195808752602087015260408601526060850152608084015260a08301527fc78493ea26eae4d9218158e9f1f6207ffe0f8926aa240f8c79a353b729ffb3f860c03393a3565b613ae2670de0b6b3a7640000916008870154906133f9565b0460098301553861353b565b670de0b6b3a7640000613b05600f870154836133f9565b04600b840155670de0b6b3a7640000613b226010870154836133f9565b04600d840155613520565b60079950613b79613b6e670de0b6b3a7640000613b626305f5e10095613b95958b52600e60205260408b209e8f0154906133f9565b0460078601549061342c565b6002850154906133f9565b613b8f613b8a60058601544361342c565b614737565b906133f9565b049788613d1c575b8d600360ff60018401541614613ca9575b508c85526010602052604085209260405193613bc98561306d565b60036001600160a01b03825416918287526001600160a01b0360018201541660208801526002810154604088015201546060860152613c0a575b508c6134df565b85939c50670de0b6b3a7640000613c2e613c389493600860099454910154906133f9565b049101549061342c565b998a613c46575b8080613c03565b5160405163a9059cbb60e01b8152336004820152602481018c90529160209183916044918391906001600160a01b03165af18015612f0457613c8a575b8290613c3f565b613ca29060203d6020116121a05761219381836130c3565b5038613c83565b9a509850815498600f810154613cbf908b6133f9565b670de0b6b3a76400009004600b830154613cd89161342c565b809a6010830154613ce8916133f9565b670de0b6b3a76400009004600d840154613d019161342c565b9b8c613d0c846131db565b92613d1693614902565b8d613bae565b6001600160a01b0360025416803b15613d7c576040516340c10f1960e01b8152336004820152602481018b90529086908290604490829084905af180156121a757613d68575b50613b9d565b85613d75919692966130c3565b9338613d62565b8580fd5b60405162461bcd60e51b815260206004820152602360248201527f43616e6e6f74207769746864726177206d6f7265207468616e206465706f73696044820152621d195960ea1b6064820152608490fd5b15613dd857565b60405162461bcd60e51b815260206004820152601660248201527f43616e6e6f74206265207a65726f2061646472657373000000000000000000006044820152606490fd5b60405190613e2a826130a6565b60006101a0838281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201528261014082015282610160820152826101808201520152565b15613e8b57565b60405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a59081c1bdbdb60a21b6044820152606490fd5b818110613eca575050565b60008155600101613ebf565b919082604091031261300a576020825192015190565b9190613ef6613e1d565b5082600052600e6020526040600020613f0e906131db565b9083600052600f60205260406000206000916001600160a01b031682526020526040902090604051613f3f816130a6565b82546001600160a01b03168152600183015460208201908152600284015495604083019687526003850154606084015260048501549660808401978852846005870154988960a087015260068801549360c0870194855260078901549160e0880192835260088a015492610100890193845260098b0154926101208a01938452600a8c0154976101408b01988952600b8d0154978d6101608d01998a52600c01549d6101808d019e8f52600d01549b6101a081019c8d529f43906140029161342c565b61400b90614737565b855260c08801948551439061401f9161342c565b9460808a01998d8b51614315575b936140616140699493670de0b6b3a76400006140586140619560e06305f5e1009a51910151906133f9565b0490519061342c565b9051906133f9565b04905260005260106020526040600020906040516140868161306d565b6001600160a01b03835416918282526001600160a01b0360018501541660208301526002840154916060600360408301968588520154910193818552614249575b5050505050505050600360ff602088015116146140e8575b50505050505050565b8051614135575b5093610240836140589361411b61412798670de0b6b3a7640000614058819951610220890151906133f9565b905251910151906133f9565b9052388080808080806140df565b6001600160a01b0360069692939654169360406101a084015160248251809881936363bcf82760e01b835260048301525afa94851561423d57600090600096614219575b50670de0b6b3a7640000810290808204670de0b6b3a764000014901517156133e35782516141a69161340c565b6141b661022085019182516133d6565b9052670de0b6b3a7640000850294808604670de0b6b3a764000014901517156133e3576141279661411b614058956141fc670de0b6b3a76400009861024096519061340c565b61420a8688019182516133d6565b905294985050935093506140ef565b905061423591955060403d60401161058b5761057c81836130c3565b949038614179565b6040513d6000823e3d90fd5b8851614283575b50505050505061427490670de0b6b3a764000061405888516101008c0151906133f9565b905238808080808080806140c7565b80865110908161430a575b50156142f65750506142a792614061915190519061342c565b905b670de0b6b3a7640000820291808304670de0b6b3a764000014901517156133e3576142d96142749285519061340c565b6142e96101008b019182516133d6565b9052903880808080614250565b9150915061430492506133f9565b906142a9565b90504310153861428e565b506143316103906143379260a0600b96959654910151906133f9565b876133f9565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156133e3578f936140618f94670de0b6b3a76400006140588f9860e061406999614387614061996305f5e1009d519061340c565b6143958385019182516133d6565b9052969a5050955050509394505061402d565b51906001600160a01b038216820361300a57565b60001981146133e35760010190565b8054600160401b811015613057576143e891600182018155613439565b819291549060031b91821b91600019901b1916179055565b600260015414614411576002600155565b633ee5aeb560e01b60005260046000fd5b80600052600e60205260406000206004810180548015801561462f575b61462357600683019361445385544361342c565b9161447161446b610390600b546005890154906133f9565b846133f9565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156133e35761449c9161340c565b6144ab600786019182546133d6565b9055600360ff60018601541614614597575b60005260106020526040600020906001600160a01b0382541615158061458a575b6144ec575b50505050439055565b84549060038301549081831080614580575b1561456a575060026145156000936145209361342c565b9301928354906133f9565b91555b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156133e35761455560089161455f93549061340c565b92019182546133d6565b9055388080806144e3565b915050600261457b920154906133f9565b614523565b50438211156144fe565b50600282015415156144de565b6145a4600d85015461478b565b90670de0b6b3a7640000810290808204670de0b6b3a764000014901517156133e3576145d28554809261340c565b6145e1600f88019182546133d6565b9055670de0b6b3a7640000820291808304670de0b6b3a764000014901517156133e35761460d9161340c565b61461c601086019182546133d6565b90556144bd565b50509050600643910155565b5060ff6011840154161561443f565b51906001600160801b038216820361300a57565b919092808211614663575b50505050565b61466c9161342c565b9115614685575061467c9061482f565b3880808061465d565b60405163a9059cbb60e01b81523360048201526024810192909252602090829060449082906000906001600160a01b03165af1801561423d576146c9575b5061467c565b6146e19060203d6020116121a05761219381836130c3565b50386146c3565b6001600160a01b036000541633036146fc57565b63118cdaa760e01b6000523360045260246000fd5b60015b600c548111614734578061472a61472f92614422565b6143bc565b614714565b50565b438103614745575061271090565b62603d808110156147765780613a980290613a988204036133e35762603d8090046127100180612710116133e35790565b506161a890565b51908160020b820361300a57565b60406001600160a01b039160848360055416918351906147aa8261306d565b8152600060208201933085526001600160801b0386840181815281606086019181835289519a8b998a9863fc6f786560e01b8a525160048a01525116602488015251166044860152511660648401525af1801561423d5760009160009161481057509091565b905061482b915060403d60401161058b5761057c81836130c3565b9091565b6007546001600160a01b0360009116803b15610df057818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610de5576148f2575b508080808094335af1903d156148ec573d90614889826130e5565b9161489760405193846130c3565b825260203d92013e5b156148a757565b60405162461bcd60e51b815260206004820152601360248201527f45544e207472616e73666572206661696c6564000000000000000000000000006044820152606490fd5b506148a0565b816148fc916130c3565b3861486e565b906000938080614a7d575b85146149895750916001600160a01b036101806149609361492f60209661482f565b015160405163a9059cbb60e01b81523360048201526024810193909352919485939190921691839182906044820190565b03925af1801561423d576149715750565b6147349060203d6020116121a05761219381836130c3565b90929080614a5b575b84146149b357916001600160a01b036101606149609361492f60209661482f565b61016082015160405163a9059cbb60e01b8152336004820152602481019490945292939092602091859160449183916001600160a01b03165af191821561423d576001600160a01b0361018061496093600096602096614a40575b50015160405163a9059cbb60e01b81523360048201526024810193909352919485939190921691839182906044820190565b614a5690873d89116121a05761219381836130c3565b614a0e565b506001600160a01b03610180830151166001600160a01b036007541614614992565b506001600160a01b03610160840151166001600160a01b03600754161461490d56fea2646970667358221220dee168380a7ec1ad80414ffe07d22c3e108ff8bde18d4161917093ed675dc21964736f6c634300081a0033