Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- ElectroSwapLockerV3
- Optimization enabled
- true
- Compiler version
- v0.8.26+commit.8a97fa7a
- Optimization runs
- 200
- Verified at
- 2024-06-30T17:38:09.995775Z
Constructor Arguments
0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d000000000000000000000000043faa1b5c5fc9a7dc35171f290c29ecde0ccff1
Arg [0] (address) : 0x3a7f64c57433555b23dac4409a0ac7e84275398d
Arg [1] (address) : 0x043faa1b5c5fc9a7dc35171f290c29ecde0ccff1
contracts/ElectroSwapLockerV3/ElectroSwapLockerV3.sol
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity ^0.8.0; pragma abicoder v2; import "../UniswapV3/open-zeppelin/token/ERC721/ERC721Holder.sol"; import "../UniswapV3/open-zeppelin/token/ERC20/IERC20.sol"; import "../UniswapV3/v3-periphery/libraries/LiquidityAmounts.sol"; import "./TickMath.sol"; import "./ReentrancyGuard.sol"; import "./TransferHelper.sol"; contract ElectroSwapLockerV3 is ERC721Holder, ReentrancyGuard { INonfungiblePositionManager private immutable positionManager; address private immutable boltAddress; address private immutable deadAddress = address(0x000000000000000000000000000000000000dEaD); address payable private teamWallet; mapping(uint256 => LockInfo) private lockedPositions; mapping(address => uint256[]) private ownerToLocks; mapping(address => uint256[]) private poolToLocks; mapping(address => bool) private noFeeList; struct LockInfo { uint256 tokenId; address owner; uint256 created; uint256 duration; bool active; address token0; address token1; uint24 fee; uint256 lockedAmount0; uint256 lockedAmount1; address pool; uint256 poolAmount0; uint256 poolAmount1; } struct Fees { uint etnFlatFee; // Amount of ETN paid as lock creation fee to stop spam uint boltFlatFee; // Amount of BOLT to be burned when paying lock creation fee in BOLT uint128 lpPercentFee; // Platform fee as a percentage of locked ElectroSwap LP tokens } Fees public fees; // Stores the current fee structure IMigrator private migrator; modifier onlyTeam() { require(msg.sender == teamWallet, "Only contract owner can call this function"); _; } constructor(address _positionManager, address _boltAddress) { positionManager = INonfungiblePositionManager(_positionManager); teamWallet = payable(msg.sender); boltAddress = _boltAddress; fees.etnFlatFee = 1000; // 1000 ETN fees.boltFlatFee = 500; // 500 BOLT fees.lpPercentFee = 1; // 1% } // Owner must first approve this contract to interact with the LP position NFT by calling approve on the NFT Position Manager function lockPosition(uint256 tokenId, uint256 lockDuration, bool _flatFeeInETN) external payable nonReentrant returns (bool success){ require(lockDuration > 0, "Lock duration must be greater than zero"); require(!lockedPositions[tokenId].active, "Position already locked"); // Transfer the NFT to the locker contract positionManager.safeTransferFrom(msg.sender, address(this), tokenId); (,,address token0, address token1, uint24 fee,,,uint128 liquidity,,,,) = positionManager.positions(tokenId); //Process fees if applicable if (!noFeeList[msg.sender]) { // Process flat fee if (_flatFeeInETN) { // Flat rate fee to be paid in ETN require(msg.value == (fees.etnFlatFee * 1e18), "Flat rate ETN fee not met"); (bool etnTransferSuccess, ) = teamWallet.call{value: msg.value}(""); require(etnTransferSuccess, "Failed to transfer ETN"); } else { // Flat rate fee to be paid in BOLT Token, and then burned TransferHelper.safeTransferFrom(boltAddress, msg.sender, deadAddress, (fees.boltFlatFee * 1e18)); } // Process percentage of liquidity fee // Check if fees are collectable, if they are, then revert to ensure we don't collect more than the percent fee (uint256 amount0Collected, uint256 amount1Collected) = _collect(tokenId, address(this)); require(amount0Collected == 0 && amount1Collected == 0, "Must collect fees before locking"); // Decrease liquidity by fee percent INonfungiblePositionManager.DecreaseLiquidityParams memory params = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: (liquidity * fees.lpPercentFee) / 100, // 1% of total liquidity in position to be removed amount0Min: 0, amount1Min: 0, deadline: block.timestamp + 60 // 1 minute deadline }); positionManager.decreaseLiquidity(params); //Collect percentage fee to team wallet (amount0Collected, amount1Collected) = _collect(tokenId, teamWallet); require(amount0Collected > 0 || amount1Collected > 0, "Sufficient fee not paid"); } else if (msg.value > 0){ // refund ETN if whitelisted (bool etnRefundSuccess, ) = payable(msg.sender).call{value: msg.value}(""); require(etnRefundSuccess, "Failed to refund ETN"); } address poolAddress = IElectroSwapV3Factory(positionManager.factory()).getPool(token0, token1, fee); require(poolAddress != address(0), "ElectroSwap pool does not exist"); lockedPositions[tokenId] = LockInfo({ tokenId: tokenId, owner: msg.sender, created: block.timestamp, duration: lockDuration, active: true, token0: token0, token1: token1, fee: fee, lockedAmount0: 0, // amounts are transient - populated at time of retrieval lockedAmount1: 0, pool: poolAddress, poolAmount0: 0, poolAmount1: 0 }); ownerToLocks[msg.sender].push(tokenId); poolToLocks[poolAddress].push(tokenId); emit LockedV3(msg.sender, tokenId, block.timestamp, lockDuration, poolAddress, token0, token1); return true; } function unlockPosition(uint256 tokenId) external nonReentrant { LockInfo memory lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(msg.sender == lockInfo.owner, "Only the owner can unlock"); require(block.timestamp >= (lockInfo.created + lockInfo.duration), "Position still locked"); delete lockedPositions[tokenId]; removeLockId(true, lockInfo.owner, tokenId); removeLockId(false, lockInfo.pool, tokenId); // Transfer the NFT back to the owner positionManager.safeTransferFrom(address(this), lockInfo.owner, tokenId); emit UnlockedV3(lockInfo.owner, tokenId); } function withdrawFees(uint256 tokenId) external nonReentrant { LockInfo memory lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(msg.sender == lockInfo.owner, "Only the owner can withdraw fees"); (uint256 amount0, uint256 amount1) = _collect(tokenId, lockInfo.owner); emit FeesWithdrawnV3(lockInfo.owner, tokenId, amount0, amount1); } // Caller must first approve this LP Locker contract in the amounts passed in for each of the ERC-20 tokens requesting to be added to the Liquidity Pool function increaseLiquidity(uint256 tokenId, uint256 amount0Desired, uint256 amount1Desired) external nonReentrant { LockInfo memory lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(msg.sender == lockInfo.owner, "Only the owner can increase liquidity"); // Transfer tokens from the original owner to the contract IERC20(lockInfo.token0).transferFrom(msg.sender, address(this), amount0Desired); IERC20(lockInfo.token1).transferFrom(msg.sender, address(this), amount1Desired); // Approve the position manager to spend tokens IERC20(lockInfo.token0).approve(address(positionManager), amount0Desired); IERC20(lockInfo.token1).approve(address(positionManager), amount1Desired); // Increase liquidity INonfungiblePositionManager.IncreaseLiquidityParams memory params = INonfungiblePositionManager.IncreaseLiquidityParams({ tokenId: tokenId, amount0Desired: amount0Desired, amount1Desired: amount1Desired, amount0Min: 0, amount1Min: 0, deadline: block.timestamp + 60 // 1 minute deadline }); (uint128 addedLiquidity, uint256 amount0Actual, uint256 amount1Actual) = positionManager.increaseLiquidity(params); // Return any unspent tokens to the original owner if (amount0Actual < amount0Desired) { IERC20(lockInfo.token0).transfer(msg.sender, amount0Desired - amount0Actual); } if (amount1Actual < amount1Desired) { IERC20(lockInfo.token1).transfer(msg.sender, amount1Desired - amount1Actual); } emit LiquidityIncreasedV3(lockInfo.owner, tokenId, addedLiquidity, amount0Actual, amount1Actual); } function extendLock(uint256 tokenId, uint256 additionalDuration) external nonReentrant { LockInfo storage lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(msg.sender == lockInfo.owner, "Only the owner can extend the lock"); lockInfo.duration += additionalDuration; emit LockExtendedV3(lockInfo.owner, tokenId, lockInfo.created, lockInfo.duration); } function splitLock( uint256 tokenId, uint128 percentLiquidityToNewLock, uint256 durationPastOriginal) external nonReentrant { LockInfo memory lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(msg.sender == lockInfo.owner, "Only the owner can split the lock"); require(percentLiquidityToNewLock < 100 && percentLiquidityToNewLock > 0, "Invalid percentage"); // Check if fees are collectable, if they are, then revert to ensure we don't collect more than the percent fee (uint256 amount0Collected, uint256 amount1Collected) = _collect(tokenId, address(this)); require(amount0Collected == 0 && amount1Collected == 0, "Must collect fees before splitting lock"); (,,,,, int24 tickLower, int24 tickUpper, uint128 liquidity,,,,) = positionManager.positions(tokenId); // Step 1: Decrease liquidity INonfungiblePositionManager.DecreaseLiquidityParams memory decreaseParams = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: (liquidity * percentLiquidityToNewLock) / 100, amount0Min: 0, amount1Min: 0, deadline: block.timestamp + 60 }); positionManager.decreaseLiquidity(decreaseParams); // Step 2: Collect tokens from decreased liquidity (amount0Collected, amount1Collected) = _collect(tokenId, address(this)); // Step 3: Create new position with removed liquidity IERC20(lockInfo.token0).approve(address(positionManager), amount0Collected); IERC20(lockInfo.token1).approve(address(positionManager), amount1Collected); INonfungiblePositionManager.MintParams memory mintParams = INonfungiblePositionManager.MintParams({ token0: lockInfo.token0, token1: lockInfo.token1, fee: lockInfo.fee, tickLower: tickLower, tickUpper: tickUpper, amount0Desired: amount0Collected, amount1Desired: amount1Collected, amount0Min: 0, amount1Min: 0, recipient: address(this), deadline: block.timestamp + 60 }); (uint256 newTokenId, , , ) = positionManager.mint(mintParams); // Step 4: Lock the new position uint newDuration = (lockInfo.created + lockInfo.duration + durationPastOriginal - block.timestamp); lockedPositions[newTokenId] = LockInfo({ tokenId: newTokenId, owner: lockInfo.owner, created: block.timestamp, duration: newDuration, active: true, token0: lockInfo.token0, token1: lockInfo.token1, fee: lockInfo.fee, lockedAmount0: 0, // amounts are transient - populated at time of retrieval lockedAmount1: 0, pool: lockInfo.pool, poolAmount0: 0, poolAmount1: 0 }); ownerToLocks[msg.sender].push(newTokenId); poolToLocks[lockInfo.pool].push(newTokenId); // emit an event emit LockSplitV3(lockInfo.owner, tokenId, newTokenId, block.timestamp, newDuration); } function transferLockOwner(uint256 tokenId, address newOwner) external nonReentrant returns (bool success) { LockInfo storage lockInfo = lockedPositions[tokenId]; require(msg.sender == lockInfo.owner, "Only the owner can transfer the lock to new owner"); require(newOwner != address(0), "New owner cannot be zero address"); address oldOwner = lockInfo.owner; lockInfo.owner = newOwner; removeLockId(true, oldOwner, tokenId); ownerToLocks[newOwner].push(tokenId); emit LockTransferredV3(tokenId, oldOwner, newOwner); return true; } // To be used in future if Uniswap V4 type liquidity support is added function migrateLock(uint tokenId) external nonReentrant { require(address(migrator) != address(0), "Migrator not set"); LockInfo storage lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "Position not locked"); require(lockInfo.owner == msg.sender, "Only the owner can migrate the lock"); // Transfer the NFT to the Migrator positionManager.safeTransferFrom(address(this), address(migrator), tokenId); // Attempt to migrate the lock require(migrator.migrate(lockInfo.pool, lockInfo.owner, tokenId, lockInfo.created, lockInfo.duration), "Migration failed"); delete lockedPositions[tokenId]; removeLockId(true, lockInfo.owner, tokenId); removeLockId(false, lockInfo.pool, tokenId); emit LockMigratedFromV3(tokenId); } function getLockById(uint256 tokenId) external view returns (LockInfo memory lockInfo) { lockInfo = lockedPositions[tokenId]; require(lockInfo.active, "No lock exists"); (,,,,, int24 tickLower, int24 tickUpper, uint128 liquidity,,,,) = positionManager.positions(tokenId); IElectroSwapV3Pool pool = IElectroSwapV3Pool(lockInfo.pool); (uint160 sqrtPriceX96,,,,,,) = pool.slot0(); uint128 poolLiquidity = pool.liquidity(); (uint256 amount0, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity( sqrtPriceX96, TickMath.getSqrtRatioAtTick(tickLower), TickMath.getSqrtRatioAtTick(tickUpper), liquidity ); (uint256 poolAmount0, uint256 poolAmount1) = LiquidityAmounts.getAmountsForLiquidity( sqrtPriceX96, TickMath.getSqrtRatioAtTick(TickMath.MIN_TICK), TickMath.getSqrtRatioAtTick(TickMath.MAX_TICK), poolLiquidity ); lockInfo.lockedAmount0 = amount0; lockInfo.lockedAmount1 = amount1; lockInfo.poolAmount0 = poolAmount0; lockInfo.poolAmount1 = poolAmount1; return lockInfo; } function getLockIdsByOwner(address owner) external view returns (uint256[] memory) { return ownerToLocks[owner]; } function getLockIdsByPool(address poolAddress) external view returns (uint256[] memory) { return poolToLocks[poolAddress]; } function _collect(uint256 tokenId, address recipient) internal returns (uint256 amount0Collected, uint256 amount1Collected) { INonfungiblePositionManager.CollectParams memory collectParams = INonfungiblePositionManager.CollectParams({ tokenId: tokenId, recipient: recipient, amount0Max: type(uint128).max, amount1Max: type(uint128).max }); (amount0Collected, amount1Collected) = positionManager.collect(collectParams); } function removeLockId(bool _owner, address _address, uint256 _lockIdToRemove) internal { uint256[] storage values = _owner ? ownerToLocks[_address] : poolToLocks[_address]; uint256 length = values.length; // Find the index of the value to be removed for (uint256 i = 0; i < length; i++) { if (values[i] == _lockIdToRemove) { // Shift elements to the left to fill the gap for (uint256 j = i; j < length - 1; j++) { values[j] = values[j + 1]; } // Remove the last element values.pop(); break; } } } function adminSetFees(uint _etnFlatFee, uint _boltFlatFee, uint128 _lpPercentFee) external onlyTeam { require(_etnFlatFee <= 2000, "Flat fee cannot be greater than 2000 ETN"); require(_boltFlatFee <= 1000, "Flat fee cannot be greater than 1000 BOLT"); require(_lpPercentFee <= 2, "LP percentage cannot be greater than 2%"); fees.etnFlatFee = _etnFlatFee; fees.boltFlatFee = _boltFlatFee; fees.lpPercentFee = _lpPercentFee; emit LockerFeesUpdated(_etnFlatFee, _boltFlatFee, _lpPercentFee); } function adminSetTeamWallet(address payable _teamWallet) external onlyTeam { require(_teamWallet != address(0), "Team wallet cannot be zero address"); teamWallet = _teamWallet; emit TeamWalletUpdated(_teamWallet); } function adminUpdateFeeWhitelist(address _address, bool _whitelisted) external onlyTeam { noFeeList[_address] = _whitelisted; emit FeeWhitelistUpdated(_address, _whitelisted); } function adminSetMigrator(IMigrator _migrator) external onlyTeam { migrator = _migrator; emit MigratorUpdated(address(_migrator)); } event LockedV3(address indexed owner, uint256 indexed tokenId, uint256 created, uint256 duration, address poolAddress, address token0, address token1); event UnlockedV3(address indexed owner, uint256 indexed tokenId); event FeesWithdrawnV3(address indexed owner, uint256 indexed tokenId, uint256 amount0, uint256 amount1); event LiquidityIncreasedV3(address indexed owner, uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); event LockExtendedV3(address indexed owner, uint256 indexed tokenId, uint256 created, uint256 newDuration); event LockSplitV3(address indexed owner, uint256 indexed existingTokenId, uint256 indexed newTokenId, uint256 created, uint256 newDuration); event LockTransferredV3(uint256 indexed tokenId, address indexed oldOwner, address indexed newOwner); event LockMigratedFromV3(uint256 indexed tokenId); // Team/admin events event LockerFeesUpdated(uint256 etnFlatFee, uint boltFlatFee, uint128 lpPercentFee); event FeeWhitelistUpdated(address _address, bool whitelisted); event TeamWalletUpdated(address indexed newTeamWallet); event MigratorUpdated(address indexed migratorAddress); } interface IMigrator { function migrate(address poolAddress, address owner, uint256 tokenId, uint256 lockCreated, uint256 lockDuration) external returns (bool); } interface IElectroSwapV3Factory { function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool); } interface IElectroSwapV3Pool { function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked); function liquidity() external view returns (uint128 poolLiquidity); } interface INonfungiblePositionManager { 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 ); struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } function mint(MintParams calldata params) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); 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 safeTransferFrom(address from, address to, uint256 tokenId) external; function factory() external view returns (address factory); }
contracts/UniswapV3/open-zeppelin/token/ERC721/ERC721Holder.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
contracts/UniswapV3/open-zeppelin/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 `IERC721.onERC721Received.selector`. */ function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); }
contracts/UniswapV3/v3-core/libraries/FixedPoint96.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.4.0; /// @title FixedPoint96 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) /// @dev Used in SqrtPriceMath.sol library FixedPoint96 { uint8 internal constant RESOLUTION = 96; uint256 internal constant Q96 = 0x1000000000000000000000000; }
contracts/UniswapV3/v3-core/libraries/FullMath.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = (0 - denominator) & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } }
contracts/ElectroSwapLockerV3/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @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/ElectroSwapLockerV3/TickMath.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { error T(); error R(); /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { unchecked { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); if (absTick > uint256(int256(MAX_TICK))) revert T(); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { unchecked { // second inequality must be < because the price can never reach the price at the max tick if (!(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO)) revert R(); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } } }
contracts/ElectroSwapLockerV3/TransferHelper.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // helper methods for interacting with ERC20 tokens that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } }
contracts/UniswapV3/open-zeppelin/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @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); }
contracts/UniswapV3/v3-periphery/libraries/LiquidityAmounts.sol
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '../../v3-core/libraries/FullMath.sol'; import '../../v3-core/libraries/FixedPoint96.sol'; /// @title Liquidity amount functions /// @notice Provides functions for computing liquidity amounts from token amounts and prices library LiquidityAmounts { /// @notice Downcasts uint256 to uint128 /// @param x The uint258 to be downcasted /// @return y The passed value, downcasted to uint128 function toUint128(uint256 x) private pure returns (uint128 y) { require((y = uint128(x)) == x); } /// @notice Computes the amount of liquidity received for a given amount of token0 and price range /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount0 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount0( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96); return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the amount of liquidity received for a given amount of token1 and price range /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount1 The amount1 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount1( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount of token0 being sent in /// @param amount1 The amount of token1 being sent in /// @return liquidity The maximum amount of liquidity received function getLiquidityForAmounts( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); } else if (sqrtRatioX96 < sqrtRatioBX96) { uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; } else { liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); } } /// @notice Computes the amount of token0 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 function getAmount0ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv( uint256(liquidity) << FixedPoint96.RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96 ) / sqrtRatioAX96; } /// @notice Computes the amount of token1 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount1 The amount of token1 function getAmount1ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); } /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function getAmountsForLiquidity( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0, uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } else if (sqrtRatioX96 < sqrtRatioBX96) { amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity); amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity); } else { amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_positionManager","internalType":"address"},{"type":"address","name":"_boltAddress","internalType":"address"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"error","name":"T","inputs":[]},{"type":"event","name":"FeeWhitelistUpdated","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":false},{"type":"bool","name":"whitelisted","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FeesWithdrawnV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount0","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidityIncreasedV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint128","name":"liquidity","internalType":"uint128","indexed":false},{"type":"uint256","name":"amount0","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LockExtendedV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"created","internalType":"uint256","indexed":false},{"type":"uint256","name":"newDuration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LockMigratedFromV3","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"LockSplitV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"existingTokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"newTokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"created","internalType":"uint256","indexed":false},{"type":"uint256","name":"newDuration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LockTransferredV3","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"oldOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"LockedV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"created","internalType":"uint256","indexed":false},{"type":"uint256","name":"duration","internalType":"uint256","indexed":false},{"type":"address","name":"poolAddress","internalType":"address","indexed":false},{"type":"address","name":"token0","internalType":"address","indexed":false},{"type":"address","name":"token1","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"LockerFeesUpdated","inputs":[{"type":"uint256","name":"etnFlatFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"boltFlatFee","internalType":"uint256","indexed":false},{"type":"uint128","name":"lpPercentFee","internalType":"uint128","indexed":false}],"anonymous":false},{"type":"event","name":"MigratorUpdated","inputs":[{"type":"address","name":"migratorAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TeamWalletUpdated","inputs":[{"type":"address","name":"newTeamWallet","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UnlockedV3","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminSetFees","inputs":[{"type":"uint256","name":"_etnFlatFee","internalType":"uint256"},{"type":"uint256","name":"_boltFlatFee","internalType":"uint256"},{"type":"uint128","name":"_lpPercentFee","internalType":"uint128"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminSetMigrator","inputs":[{"type":"address","name":"_migrator","internalType":"contract IMigrator"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminSetTeamWallet","inputs":[{"type":"address","name":"_teamWallet","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminUpdateFeeWhitelist","inputs":[{"type":"address","name":"_address","internalType":"address"},{"type":"bool","name":"_whitelisted","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"extendLock","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"additionalDuration","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"etnFlatFee","internalType":"uint256"},{"type":"uint256","name":"boltFlatFee","internalType":"uint256"},{"type":"uint128","name":"lpPercentFee","internalType":"uint128"}],"name":"fees","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"lockInfo","internalType":"struct ElectroSwapLockerV3.LockInfo","components":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"owner","internalType":"address"},{"type":"uint256","name":"created","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"},{"type":"bool","name":"active","internalType":"bool"},{"type":"address","name":"token0","internalType":"address"},{"type":"address","name":"token1","internalType":"address"},{"type":"uint24","name":"fee","internalType":"uint24"},{"type":"uint256","name":"lockedAmount0","internalType":"uint256"},{"type":"uint256","name":"lockedAmount1","internalType":"uint256"},{"type":"address","name":"pool","internalType":"address"},{"type":"uint256","name":"poolAmount0","internalType":"uint256"},{"type":"uint256","name":"poolAmount1","internalType":"uint256"}]}],"name":"getLockById","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getLockIdsByOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getLockIdsByPool","inputs":[{"type":"address","name":"poolAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"increaseLiquidity","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"amount0Desired","internalType":"uint256"},{"type":"uint256","name":"amount1Desired","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"lockPosition","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"lockDuration","internalType":"uint256"},{"type":"bool","name":"_flatFeeInETN","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateLock","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","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":"nonpayable","outputs":[],"name":"splitLock","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint128","name":"percentLiquidityToNewLock","internalType":"uint128"},{"type":"uint256","name":"durationPastOriginal","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"success","internalType":"bool"}],"name":"transferLockOwner","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unlockPosition","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFees","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]}]
Deployed ByteCode
0x6080604052600436101561001257600080fd5b6000803560e01c8063070d66bf14612c1157806308f12470146127c3578063150b7a02146127385780631db28f3d1461269f5780633ac9f4ec1461262a5780634963e51d146125b8578063563cdb73146124555780635e318e07146122c1578063687cb35314611fe757806397afc30014611f195780639af1d35a14611ede578063a4375fcd14611bd6578063dd0228f514611b54578063e115bc5c1461154a578063e4feb61b14610c24578063eb6bc69b14610a5a5763ffc124e0146100d857600080fd5b6060366003190112610a57576004356024356044358015158103610a53576100fe6130de565b81156109fe57828452600260205260ff6004604086200154166109b9577f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d6001600160a01b031690813b156109aa57604051632142170760e11b8152336004820152306024820152604481018590528590818160648183885af180156109ae57610995575b505060405163133f757160e31b8152600481018590529161018083602481845afa801561098a578690879388958992610943575b503389526005602052604089205460ff166108e0571561079557600654670de0b6b3a7640000810290808204670de0b6b3a764000014901517156106b157340361075057878080803460018060a01b03600154165af16102156130ae565b5015610712575b610226308861367f565b90159081610709575b50156106c5576001600160801b0361024e606492826008541690613038565b1604603c42018042116106b1576102a8916040916001600160801b0383519261027684612d65565b8b84521660208301528a838301528a60608301526080820152815180938192630624e65f60e11b835260048301613071565b03818b875af180156106a657610678575b506001546102d0906001600160a01b03168761367f565b90159081159161066e575b50156106295760206004925b60405163c45a015560e01b815293849182905afa9182156105db5787926105e6575b50604051630b4c774160e11b81526001600160a01b03918216600482018190529382166024820181905262ffffff959095166044820181905292909160209183916064918391165afa9081156105db57879161059d575b506001600160a01b03169081156105585786808386938960405195869261038684612d32565b828452602084013381528a8d604087014281526060880191825260808801936001855260a0890193845260c0890196875260e089019586528a6101008a0198818a526101208b019a828c5261014081019c8d5261016081019d8e52610180019d8e5281526002602052604090209c518d55600160a01b6001900390511660018d0190600160a01b60019003166001600160601b0360a01b8254161790555160028c01555160038b015560048a019151151561044d90839060ff801983541691151516179055565b518154610100600160a81b031916600891821b610100600160a81b031617909155915160058901805492516001600160b81b03199093166001600160a01b039283161760a09390931b62ffffff60a01b16929092179091559151600688015591516007870155915190850180546001600160a01b0319169190921617905551600983015551600a909101553386526003602052604086206104ef908690612fe8565b808652600460205284604087209061050691612fe8565b604051934285526020850152604084015260608301526080820152339060a07fae141140f9e9f455b9444c2388d1f08b9203d1a4d301bb20b4b7ce07ed3f82f491a36001905560405160018152602090f35b60405162461bcd60e51b815260206004820152601f60248201527f456c656374726f5377617020706f6f6c20646f6573206e6f74206578697374006044820152606490fd5b90506020813d6020116105d3575b816105b860209383612d81565b810103126105cf576105c990612e5e565b38610360565b8680fd5b3d91506105ab565b6040513d89823e3d90fd5b9091506020813d602011610621575b8161060260209383612d81565b810103126105cf57602061061962ffffff92612e5e565b929150610309565b3d91506105f5565b60405162461bcd60e51b815260206004820152601760248201527f53756666696369656e7420666565206e6f7420706169640000000000000000006044820152606490fd5b90501515386102db565b6106999060403d60401161069f575b6106918183612d81565b81019061305b565b506102b9565b503d610687565b6040513d8a823e3d90fd5b634e487b7160e01b89526011600452602489fd5b606460405162461bcd60e51b815260206004820152602060248201527f4d75737420636f6c6c6563742066656573206265666f7265206c6f636b696e676044820152fd5b9050153861022f565b60405162461bcd60e51b81526020600482015260166024820152752330b4b632b2103a37903a3930b739b332b91022aa2760511b6044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f466c617420726174652045544e20666565206e6f74206d6574000000000000006044820152606490fd5b600754670de0b6b3a7640000810290808204670de0b6b3a764000014901517156106b1576040516323b872dd60e01b602082019081523360248301527f000000000000000000000000000000000000000000000000000000000000dead6001600160a01b031660448301526064808301939093529181528991829161081b608482612d81565b5190827f000000000000000000000000043faa1b5c5fc9a7dc35171f290c29ecde0ccff15af16108496130ae565b816108a5575b5061021c5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608490fd5b80518015925082156108ba575b50503861084f565b81925090602091810103126108dc5760206108d59101612f4e565b38806108b2565b8880fd5b5050346108f2575b60206004926102e7565b8680808034335af16109026130ae565b506108e85760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a37903932b33ab7321022aa2760611b6044820152606490fd5b925093505061096b9193506101803d8111610983575b6109638183612d81565b810190612e94565b505050509896505050949190925091939490386101b7565b503d610959565b6040513d88823e3d90fd5b8161099f91612d81565b6109aa578438610183565b8480fd5b6040513d84823e3d90fd5b60405162461bcd60e51b815260206004820152601760248201527f506f736974696f6e20616c7265616479206c6f636b65640000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602760248201527f4c6f636b206475726174696f6e206d7573742062652067726561746572207468604482015266616e207a65726f60c81b6064820152608490fd5b8380fd5b80fd5b5034610a57576060366003190112610a57576044356024356004356001600160801b0383168084036109aa57610a9b60018060a01b03600154163314612f5b565b6107d08211610bce576103e88311610b775760028111610b22577fe135e4e3f2308313ec0b6ced5f49746591fa28ff7363f9c5bd30f160b42b84c193610b1c9183600655846007556001600160801b03196008541617600855604051938493849160409194936001600160801b039160608501968552602085015216910152565b0390a180f35b60405162461bcd60e51b815260206004820152602760248201527f4c502070657263656e746167652063616e6e6f742062652067726561746572206044820152667468616e20322560c81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602960248201527f466c6174206665652063616e6e6f742062652067726561746572207468616e206044820152680c4c0c0c081093d31560ba1b6064820152608490fd5b60405162461bcd60e51b815260206004820152602860248201527f466c6174206665652063616e6e6f742062652067726561746572207468616e20604482015267191818181022aa2760c11b6064820152608490fd5b5034610a57576060366003190112610a57576024356001600160801b03811680820361133357610c526130de565b600435835260026020526040832090610d1860405192610c7184612d32565b8054845260018101546001600160a01b0390811660208601526002820154604086015260038201546060860152600482015460ff8116151560808701819052600891821c831660a080890191909152600585015480851660c08a0152901c62ffffff1660e088015260068401546101008801526007840154610120880152908301549091166101408601526009820154610160860152600a90910154610180850152612df9565b60208201516001600160a01b031633036114fb576064811090816114f1575b50156114b757610d493060043561367f565b901590816114ae575b50156114595760405163133f757160e31b81526004803590820152610180816024817f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d6001600160a01b03165afa92831561144e57849385928691611409575b50610dc76064926001600160801b0392613038565b1604603c420142116113f5576040610e25916001600160801b03825191610ded83612d65565b60043583521660208201528682820152866060820152603c42016080820152815180938192630624e65f60e11b835260048301613071565b0381887f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d6001600160a01b03165af180156113ea576113cc575b50610e6c3060043561367f565b60a084015160405163095ea7b360e01b81526001600160a01b037f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d81166004830152602482018590529294929091602091839160449183918c91165af180156105db57611395575b5060c084015160405163095ea7b360e01b81526001600160a01b037f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d81166004830152602482018690529091602091839160449183918c91165af180156105db5761135e575b5060a084015160c085015160e0860151604051979262ffffff909116916001600160a01b039081169116610160890189811067ffffffffffffffff82111761134a5760405288526020880152604087015260020b606086015260020b608085015260a084015260c08301528260e08301528261010083015230610120830152603c420161014083015261014060405192634418b22b60e11b845260018060a01b03815116600485015260018060a01b03602082015116602485015262ffffff6040820151166044850152606081015160020b6064850152608081015160020b608485015260a081015160a485015260c081015160c485015260e081015160e485015261010081015161010485015260018060a01b03610120820151166101248501520151610144830152608082610164818660018060a01b037f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d165af191821561133f5783926112f9575b50604081015142906044359060608401516110bf91612e3b565b906110c991612e3b565b906110d39161302b565b602082015160a083015160c084015160e085015161014086015160405195969594899485946001600160a01b039384169488948c949281169362ffffff909216928116911661112186612d32565b848652602086019182526040860142815260608701908d825260808801936001855260a0890193845260c0890196875260e089019586528a6101008a0198818a526101208b019a828c5261014081019c8d5261016081019d8e52610180019d8e5281526002602052604090209c518d55600160a01b6001900390511660018d0190600160a01b60019003166001600160601b0360a01b8254161790555160028c01555160038b015560048a01915115156111e790839060ff801983541691151516179055565b518154610100600160a81b031916600891821b610100600160a81b031617909155915160058901805492516001600160b81b03199093166001600160a01b039283161760a09390931b62ffffff60a01b16929092179091559151600688015591516007870155915190850180546001600160a01b0319169190921617905551600983015551600a90910155338452600360205260408420611289908490612fe8565b6101408101516001600160a01b031684526004602052604084206112ae908490612fe8565b600160a01b600190039060200151166040519142835260208301526004359160407f57ff7b05cc052545e51cd622b269e1d4091fa9ddde19a862f601825bce4a79c891a46001815580f35b9091506080813d608011611337575b8161131560809383612d81565b810103126113335761132b602082519201612e80565b5090386110a5565b8280fd5b3d9150611308565b6040513d85823e3d90fd5b634e487b7160e01b8b52604160045260248bfd5b6020813d60201161138d575b8161137760209383612d81565b810103126105cf5761138890612f4e565b610f3a565b3d915061136a565b6020813d6020116113c4575b816113ae60209383612d81565b810103126105cf576113bf90612f4e565b610ed4565b3d91506113a1565b6113e49060403d60401161069f576106918183612d81565b50610e5f565b6040513d87823e3d90fd5b634e487b7160e01b85526011600452602485fd5b6064929550610dc793506001600160801b039150611435906101803d8111610983576109638183612d81565b505050509996509a945092505050969492509250610db2565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152602760248201527f4d75737420636f6c6c6563742066656573206265666f72652073706c697474696044820152666e67206c6f636b60c81b6064820152608490fd5b90501538610d52565b60405162461bcd60e51b8152602060048201526012602482015271496e76616c69642070657263656e7461676560701b6044820152606490fd5b9050151538610d37565b60405162461bcd60e51b815260206004820152602160248201527f4f6e6c7920746865206f776e65722063616e2073706c697420746865206c6f636044820152606b60f81b6064820152608490fd5b5034610a57576060366003190112610a575760043560243560443561156d6130de565b8284526002602052604084209160405161158681612d32565b8354815260018401546001600160a01b03908116602083019081526002860154604084015260038601546060840152600486015460ff8116151560808501819052600891821c841660a080870191825260058a015480871660c08901908152911c62ffffff1660e088015260068a015461010088015260078a0154610120880152928901549094166101408601526009880154610160860152600a909701546101809094019390935291949193909161163e90612df9565b83516001600160a01b03163303611b015781516040516323b872dd60e01b81523360048201523060248201526044810185905290602090829060649082908c906001600160a01b03165af180156106a657611aca575b5084516040516323b872dd60e01b81523360048201523060248201526044810183905290602090829060649082908c906001600160a01b03165af180156106a657611a8f575b50815160405163095ea7b360e01b81526001600160a01b037f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d811660048301819052602483018790529792602091839160449183918e91165af18015611a4d57611a58575b50805160405163095ea7b360e01b81526001600160a01b038881166004830152602482018590529091602091839160449183918e91165af18015611a4d57611a16575b50603c4201958642116106b1576040519060c0820182811067ffffffffffffffff82111761134a57604090815289835260208301878152818401868152606085018d8152608086018e815260a087019c8d52935163219f5d1760e01b81529551600487015291516024860152516044850152516064840152516084830152965160a4820152958892919083908890815a9360c492606095f193841561133f578395849885966119c5575b509088828693821061195a575b5050505081841061189a575b505050906060917f4943191b10db7dcc51f77a22d3de748d2c233e28ebb36e071f0acf9d56ceecf59360018060a01b03905116946001600160801b036040519316835260208301526040820152a36001815580f35b516020916118e1916001600160a01b0316906118b790869061302b565b60405163a9059cbb60e01b8152336004820152602481019190915293849283919082906044820190565b03925af180156105db576118f8575b808791611845565b91906020833d602011611952575b8161191360209383612d81565b810103126105cf577f4943191b10db7dcc51f77a22d3de748d2c233e28ebb36e071f0acf9d56ceecf593611948606094612f4e565b50935090916118f0565b3d9150611906565b6118b76119749260209460018060a01b039051169261302b565b03925af1801561144e5761198c575b80888592611839565b6020813d6020116119bd575b816119a560209383612d81565b81010312610a53576119b690612f4e565b5038611983565b3d9150611998565b9650945096506060853d606011611a0e575b816119e460609383612d81565b8101031261133357826119f686612e80565b9760406020880151970151989680999691925061182c565b3d91506119d7565b6020813d602011611a45575b81611a2f60209383612d81565b810103126108dc57611a4090612f4e565b611782565b3d9150611a22565b6040513d8b823e3d90fd5b6020813d602011611a87575b81611a7160209383612d81565b810103126108dc57611a8290612f4e565b61173f565b3d9150611a64565b6020813d602011611ac2575b81611aa860209383612d81565b81010312611abe57611ab990612f4e565b6116da565b8780fd5b3d9150611a9b565b6020813d602011611af9575b81611ae360209383612d81565b81010312611abe57611af490612f4e565b611694565b3d9150611ad6565b60405162461bcd60e51b815260206004820152602560248201527f4f6e6c7920746865206f776e65722063616e20696e637265617365206c697175604482015264696469747960d81b6064820152608490fd5b5034610a57576020366003190112610a57576001600160a01b03611b76612d01565b168152600360205260408120604051918260208354918281520192825260208220915b818110611bc057611bbc85611bb081870382612d81565b60405191829182612dbf565b0390f35b8254845260209093019260019283019201611b99565b5034610a57576020366003190112610a5757600435611bf36130de565b6009546001600160a01b03168015611ea65781835260026020526040832090611c2260ff600484015416612df9565b6001820180549091906001600160a01b03163303611e555784907f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d6001600160a01b0316803b1561133357604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820186905282908290606490829084905af180156109ae57611e40575b505060095460088301805483546002860154600390960154604051633bdf278d60e21b81526001600160a01b03938416600482015291831660248301526044820188905260648201969096526084810195909552909391602091839160a49183918a91165af19081156113ea578591611e06575b5015611dce57611da391611d948480938188526002602052611d8560408920600a6000918281558260018201558260028201558260038201558260048201558260058201558260068201558260078201558260088201558260098201550155565b546001600160a01b031661350f565b546001600160a01b03166135f8565b7f9ee75c43a6302c49a446052e0e6d399b8f2096b5661e7f2eac49659d5ebb9f4c8280a26001815580f35b60405162461bcd60e51b815260206004820152601060248201526f135a59dc985d1a5bdb8819985a5b195960821b6044820152606490fd5b90506020813d602011611e38575b81611e2160209383612d81565b810103126109aa57611e3290612f4e565b38611d24565b3d9150611e14565b81611e4a91612d81565b610a53578338611cb0565b60405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920746865206f776e65722063616e206d69677261746520746865206c6044820152626f636b60e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152601060248201526f135a59dc985d1bdc881b9bdd081cd95d60821b6044820152606490fd5b5034610a575780600319360112610a57576006546007546008546040805193845260208401929092526001600160801b031690820152606090f35b5034610a57576020366003190112610a57576004356001600160a01b03811690819003611fe357600154611f57336001600160a01b03831614612f5b565b8115611f93576001600160a01b03191681176001557ff6215f245bfd24e51265c56ef650fdd856aa4ece6221ee1ef395bbe0a55580108280a280f35b60405162461bcd60e51b815260206004820152602260248201527f5465616d2077616c6c65742063616e6e6f74206265207a65726f206164647265604482015261737360f01b6064820152608490fd5b5080fd5b5034610a57576020366003190112610a57576004356120046130de565b8082526002602052604082206040519061201d82612d32565b8054825260018101546001600160a01b0390811660208401908152600283015460408501908152600384015460608601908152600485015460ff8116151560808801819052600891821c861660a0808a0191909152600588015480881660c08b0152901c62ffffff1660e0890152600687015461010089015260078701546101208901529086015490941661014087019081526009860154610160880152600a9095015461018090960195909552909390916120d890612df9565b83516001600160a01b0316330361227c576120f69151905190612e3b565b421061223f578261217791818652600260205261215260408720600a6000918281558260018201558260028201558260038201558260048201558260058201558260068201558260078201558260088201558260098201550155565b83516121689083906001600160a01b031661350f565b516001600160a01b03166135f8565b805183906001600160a01b03908116907f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d16803b1561133357604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820185905282908290606490829084905af180156109ae5761222a575b5050516001600160a01b03167fdefba4de08ec6c6f819a41857212db2623a7b0236f321b0ea44a099716a359978380a36001815580f35b8161223491612d81565b6113335782386121f3565b60405162461bcd60e51b8152602060048201526015602482015274141bdcda5d1a5bdb881cdd1a5b1b081b1bd8dad959605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920746865206f776e65722063616e20756e6c6f636b000000000000006044820152606490fd5b5034610a57576020366003190112610a57576004356122de6130de565b8082526002602052604082206123a8604051916122fa83612d32565b8054835260018101546001600160a01b03908116602085019081526002830154604086015260038301546060860152600483015460ff8116151560808701819052600891821c841660a080890191909152600586015480861660c08a0152901c62ffffff1660e088015260068501546101008801526007850154610120880152908401549092166101408601526009830154610160860152600a909201546101809094019390935291612df9565b80516001600160a01b031633036124115780517f65c3bc47cb9901213d61a2b375a8f343502e95b1c75e44108e4dc18239930d33906040906123f3906001600160a01b03168561367f565b9360018060a01b039051169382519182526020820152a36001815580f35b606460405162461bcd60e51b815260206004820152602060248201527f4f6e6c7920746865206f776e65722063616e20776974686472617720666565736044820152fd5b5034610a57576040366003190112610a5757600435612472612d1c565b9161247b6130de565b81815260026020526040812060010180546001600160a01b03169390919033859003612559576001600160a01b0316801561251557602094600193826001600160601b0360a01b8254161790556124d2858261350f565b818352600386526124e68560408520612fe8565b604051947f59782bedaa591ede99ca79908a0d72a01dd5728a328add02e64a21a5ab92a73f8480a45560018152f35b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b60405162461bcd60e51b815260206004820152603160248201527f4f6e6c7920746865206f776e65722063616e207472616e7366657220746865206044820152703637b1b5903a37903732bb9037bbb732b960791b6064820152608490fd5b5034610a57576020366003190112610a57576001600160a01b036125da612d01565b168152600460205260408120604051918260208354918281520192825260208220915b81811061261457611bbc85611bb081870382612d81565b82548452602090930192600192830192016125fd565b5034610a57576020366003190112610a57576004356001600160a01b03811690819003611fe35761266660018060a01b03600154163314612f5b565b600980546001600160a01b031916821790557f6d4faaba9390b6bfbd5cb72e0cd8dfb4781f53d262654f8aa7eca81a0e24b3158280a280f35b5034610a57576040366003190112610a57576126b9612d01565b6024359081151591828103610a53577f1edda118cbc893a00b312565b4e15205c24b89f3e2fe94825eeebb435318ed1c9261272a60409361270560018060a01b03600154163314612f5b565b60018060a01b03169283875260056020528487209060ff801983541691151516179055565b82519182526020820152a180f35b5034610a57576080366003190112610a5757612752612d01565b5061275b612d1c565b5060643567ffffffffffffffff8111611fe35736602382011215611fe357806004013561278781612da3565b6127946040519182612d81565b8181523660248385010111610a53578160246020940184830137010152604051630a85bd0160e11b8152602090f35b5034610a57576020366003190112610a5757600435816101806040516127e881612d32565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015282610140820152826101608201520152808252600260205260408220906040519161284d83612d32565b8054835260018101546001600160a01b0390811660208501526002820154604085015260038201546060850152600482015460ff81161580156080870152600891821c831660a080880191909152600585015480851660c0890152901c62ffffff1660e087015260068401546101008701526007840154610120870152908301549091166101408501526009820154610160850152600a90910154610180840152612bdb5760405163133f757160e31b81526004810191909152610180816024817f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d6001600160a01b03165afa801561133f57839084928591612bab575b50610140840151604051633850c7bd60e01b81526001600160a01b0390911693909260e084600481885afa9384156105db578794612b12575b5060206004949560405195868092630d34328160e11b82525afa9384156105db578794612abc575b506129ef926101a09794926129cc6129c66129d394613100565b91613100565b908761348d565b949093506401000276a36129e9620d89e8613100565b9161348d565b929091610100850152610120840152610160830152610180820152610180604051918051835260018060a01b036020820151166020840152604081015160408401526060810151606084015260808101511515608084015260018060a01b0360a08201511660a084015260018060a01b0360c08201511660c084015262ffffff60e08201511660e084015261010081015161010084015261012081015161012084015260018060a01b03610140820151166101408401526101608101516101608401520151610180820152f35b9093506020813d602011612b0a575b81612ad860209383612d81565b810103126105cf576129ef926101a09794926129cc6129c6612afc6129d395612e80565b979a505050929150926129ac565b3d9150612acb565b935060e0843d60e011612ba3575b81612b2d60e09383612d81565b810103126105cf578351936001600160a01b0385168503611abe57612b5460208201612e72565b50612b6160408201612f3f565b50612b6e60608201612f3f565b50612b7b60808201612f3f565b5060a081015160ff811603611abe57600494612b9b60c060209301612f4e565b509450612984565b3d9150612b20565b915050612bc791506101803d8111610983576109638183612d81565b50505050965094509250505090913861294b565b60405162461bcd60e51b815260206004820152600e60248201526d4e6f206c6f636b2065786973747360901b6044820152606490fd5b5034610a57576040366003190112610a5757600435612c2e6130de565b808252600260205260408220612c4a60ff600483015416612df9565b60018101546001600160a01b03169033829003612cb157604081600260037fa53e7cbf68cc072c52a1cdd1598b3f8cad3c4b16109e5891377317b531e4ce61940191612c996024358454612e3b565b80935501549082519182526020820152a36001815580f35b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c7920746865206f776e65722063616e20657874656e6420746865206c6f604482015261636b60f01b6064820152608490fd5b600435906001600160a01b0382168203612d1757565b600080fd5b602435906001600160a01b0382168203612d1757565b6101a0810190811067ffffffffffffffff821117612d4f57604052565b634e487b7160e01b600052604160045260246000fd5b60a0810190811067ffffffffffffffff821117612d4f57604052565b90601f8019910116810190811067ffffffffffffffff821117612d4f57604052565b67ffffffffffffffff8111612d4f57601f01601f191660200190565b602060408183019282815284518094520192019060005b818110612de35750505090565b8251845260209384019390920191600101612dd6565b15612e0057565b60405162461bcd60e51b8152602060048201526013602482015272141bdcda5d1a5bdb881b9bdd081b1bd8dad959606a1b6044820152606490fd5b91908201809211612e4857565b634e487b7160e01b600052601160045260246000fd5b51906001600160a01b0382168203612d1757565b51908160020b8203612d1757565b51906001600160801b0382168203612d1757565b919082610180910312612d175781516001600160601b0381168103612d175791612ec060208201612e5e565b91612ecd60408301612e5e565b91612eda60608201612e5e565b91608082015162ffffff81168103612d175791612ef960a08201612e72565b91612f0660c08301612e72565b91612f1360e08201612e80565b916101008201519161012081015191612f3c610160612f356101408501612e80565b9301612e80565b90565b519061ffff82168203612d1757565b51908115158203612d1757565b15612f6257565b60405162461bcd60e51b815260206004820152602a60248201527f4f6e6c7920636f6e7472616374206f776e65722063616e2063616c6c207468696044820152693990333ab731ba34b7b760b11b6064820152608490fd5b8054821015612fd25760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b9081549168010000000000000000831015612d4f578261301091600161302995018155612fba565b90919082549060031b91821b91600019901b1916179055565b565b91908203918211612e4857565b906001600160801b03809116911602906001600160801b038216918203612e4857565b9190826040910312612d17576020825192015190565b91909160808060a0830194805184526001600160801b03602082015116602085015260408101516040850152606081015160608501520151910152565b3d156130d9573d906130bf82612da3565b916130cd6040519384612d81565b82523d6000602084013e565b606090565b6002600054146130ef576002600055565b633ee5aeb560e01b60005260046000fd5b60020b60008112156134875780600003905b620d89e88211613476576001821615613464576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116613448575b6004811661342c575b60088116613410575b601081166133f4575b602081166133d8575b604081166133bc575b608081166133a0575b6101008116613384575b6102008116613368575b610400811661334c575b6108008116613330575b6110008116613314575b61200081166132f8575b61400081166132dc575b61800081166132c0575b6201000081166132a4575b620200008116613289575b62040000811661326e575b6208000016613255575b600012613230575b63ffffffff8116613228576000905b60201c60ff91909116016001600160a01b031690565b600190613212565b801561323f5760001904613203565b634e487b7160e01b600052601260045260246000fd5b6b048a170391f7dc42444e8fa290910260801c906131fb565b6d2216e584f5fa1ea926041bedfe9890920260801c916131f1565b916e5d6af8dedb81196699c329225ee6040260801c916131e6565b916f09aa508b5b7a84e1c677de54f3e99bc90260801c916131db565b916f31be135f97d08fd981231505542fcfa60260801c916131d0565b916f70d869a156d2a1b890bb3df62baf32f70260801c916131c6565b916fa9f746462d870fdf8a65dc1f90e061e50260801c916131bc565b916fd097f3bdfd2022b8845ad8f792aa58250260801c916131b2565b916fe7159475a2c29b7443b29c7fa6e889d90260801c916131a8565b916ff3392b0822b70005940c7a398e4b70f30260801c9161319e565b916ff987a7253ac413176f2b074cf7815e540260801c91613194565b916ffcbe86c7900a88aedcffc83b479aa3a40260801c9161318a565b916ffe5dee046a99a2a811c461f1969c30530260801c91613180565b916fff2ea16466c96a3843ec78b326b528610260801c91613177565b916fff973b41fa98c081472e6896dfb254c00260801c9161316e565b916fffcb9843d60f6159c9db58835c9266440260801c91613165565b916fffe5caca7e10e4e61c3624eaa0941cd00260801c9161315c565b916ffff2e50f5f656932ef12357cf3c7fdcc0260801c91613153565b916ffff97272373d413259a46990580e213a0260801c9161314a565b6001600160881b03600160801b61313f565b6315e4079d60e11b60005260046000fd5b80613112565b9093926000929091836001600160a01b0380841690881611613507575b6001600160a01b0382811690881681116134cf575050506134cc9293946137bf565b91565b93945090926001600160a01b03831611156134fb5750906134f583612f3c9493836137bf565b9461377c565b94612f3c93925061377c565b9591956134aa565b6001600160a01b0316600090815260036020526040812080549092915b81811061353a575b50505050565b826135458286612fba565b90549060031b1c146135595760010161352c565b9293600019820191821193909250835b612e4857818110156135a8576001810190818111612e48576135a161359060019388612fba565b90549060031b1c6130108389612fba565b0183613569565b5050919050805480156135e25760001901906135d86135c78383612fba565b8154906000199060031b1b19169055565b5538808080613534565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b0316600090815260046020526040812080549092915b8181106136225750505050565b8261362d8286612fba565b90549060031b1c1461364157600101613615565b9293600019820191821193909250835b612e4857818110156135a8576001810190818111612e485761367861359060019388612fba565b0183613651565b60405191608083019183831067ffffffffffffffff841117612d4f57604092835283526001600160a01b03908116602084019081526001600160801b0384840181815260608601828152855163fc6f786560e01b81529651600488015292518416602487015251811660448601529051166064840152829060849082906000907f0000000000000000000000003a7f64c57433555b23dac4409a0ac7e84275398d165af180156137575760009160009161373857509091565b9050613753915060403d60401161069f576106918183612d81565b9091565b6040513d6000823e3d90fd5b6001600160a01b039182169082160391908211612e4857565b612f3c92916001600160801b03916001600160a01b03808316908216116137b9575b6001600160a01b03916137b19190613763565b169116613832565b9061379e565b91613816916001600160a01b038082169085161161382c575b6001600160a01b036137ea8583613763565b6001600160a01b039092169291169060601b6fffffffffffffffffffffffffffffffff60601b16613881565b6001600160a01b0390911690811561323f570490565b926137d8565b60009190600019828209918082029384808510940393808503941461387757600160601b841015610a575750600160601b910990828211900360a01b910360601c1790565b5050505060601c90565b9160001982840992828102928380861095039480860395146138fb5784831115612d1757829109818060000316809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b505080925015612d1757049056fea26469706673582212207afcb4f9cf4a48a95fbd1e72dbe3c4cc77cf6d08a415e2686b450b9b0a23de8564736f6c634300081a0033