Contract 0x549855586afc1283e90295088ba5eb51e7236ae8 12

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x58d645977e1ec13259ef4cc97d253743fe5efa1876f2a4fe8ef514ffa5136b41Deposit All1949136682024-03-28 0:07:4512 hrs 31 mins ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000005990.01
0x26e126491630c7e85470bc06ab154c57081eb9d1d780cf39a9ccefdcea17cf4cWithdraw All1947003112024-03-27 9:14:171 day 3 hrs ago0x8a193e2b660547a7b01eee6a57442df0b2003113 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000365 0.01
0xdf1d8384435193d458625b15845535464877a5c701ad2eb4d198d57772864efcDeposit All1946887162024-03-27 8:25:571 day 4 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000370.01
0xa98371192b7ce5157831b5493d62f5f187550e7d579d0f8ce263102a948801e7Get Reward1946012032024-03-27 2:20:201 day 10 hrs ago0x8a193e2b660547a7b01eee6a57442df0b2003113 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000261 0.01
0xbc3a1814bb9bba95bd44e4c71f51ed7eba9b3b390e000519af3bea0c460b2d79Deposit All1945748742024-03-27 0:30:131 day 12 hrs ago0x8a193e2b660547a7b01eee6a57442df0b2003113 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000517 0.01
0xd74c4300c5e5a2ae90d1c629c18ea426f4f519aa21f956c621c721638f4b4a44Deposit All1945429672024-03-26 22:16:341 day 14 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000410.01
0x9f56e072b9ceefce04d76755142bbc1d57a4d1f2803bf0ecc00594b9beb3f4eaDeposit All1943755902024-03-26 10:38:162 days 2 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003510.01
0xa1c454ee518e2476aa2180e9e7ca83d812bdb44d5975aa1ceec7f0198129df76Deposit All1943737312024-03-26 10:30:312 days 2 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003610.01
0x6aef62cade00f497b9c0ba8fbb21f688fe505ad2a17e12d528825a46556a2d52Get Reward1941388352024-03-25 18:11:292 days 18 hrs ago0xd50894e82e61daecdf5cd712c2eb67d8972dfce4 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000548 0.01
0xba86f449563e7592ec288808989c742a2a77a5413349cc3ff7c9fea076c1026fGet Reward1941335582024-03-25 17:49:332 days 18 hrs ago0x69725346044aefb4df81079ca9ba742416576d19 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000531 0.01
0x8b8c659b5f4ee100b5dc9b501db5b8dfeec7bf5e3eb59317d9fbb6cafd9c6752Deposit All1941164502024-03-25 16:38:062 days 20 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000004180.010177
0x8446dd4039f558bcbf33e6a6c1a83a13b17a1c8fa38b6ecdc578b38bcc764599Deposit All1940844912024-03-25 14:24:272 days 22 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000015950.048078
0xb7a12d5c6e88ecf64dc8a23b0d589b1403be51e7c0fbc8d0ef2bb85b83b8fd64Deposit All1940314632024-03-25 10:43:373 days 1 hr ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003570.01
0xb838572857421f9dac74d7999eba2aac3ef9663ed34f9e80d7e6ecad9b4e84bdDeposit All1940293622024-03-25 10:34:503 days 2 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003670.01
0x8f477d8d3173c72214a9cd2e3c91162ff0d32a2fafedf677859f8d4b47e2ce65Deposit All1940071992024-03-25 9:02:243 days 3 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003630.01
0xcf6792f9af435214d44f4b0160b215c4aa05774caf1433585b087b1bfcb9ec5eDeposit All1940069042024-03-25 9:01:103 days 3 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003710.01
0x8f2117ded7cb4ec53c435b53fd9d3cf52eff0a3b56c9fcd0d8c75f112d3041c4Get Reward1936688512024-03-24 9:29:364 days 3 hrs ago0xfb85c9b9314c45661e0d553e271efefac154c839 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000448 0.01
0x78ba76a41f321e10cdd53b86f44dd85313b55db5f790cac10f42eddb05bf56d9Deposit All1935198452024-03-23 23:07:334 days 13 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003540.01
0x6ba43e752912bc59c602441438e7743f3c8f4bc8911075637e22c424824053daDeposit All1934697342024-03-23 19:36:554 days 17 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000003550.01
0x476b9b8eecd603d102e92d193c99cda8ae30be1669c4b6ed7ffae77868911e1aDeposit All1934680162024-03-23 19:29:434 days 17 hrs ago0x28b394a90721b33143171b7162e762a8faf7fdef IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.000004070.01
0x5ccf46ee5fd565f6536730beb458e5b7e1216d7baf5031cdf7dbe54c36611a05Get Reward1934508442024-03-23 18:17:534 days 18 hrs ago0x270b1908b77eb397d4e67abcbdb997b25097fd28 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000469 0.01
0xdb9b2a122b8df23483095b6a7b96d23073de4c4cc5205e7ffe2ea7c5951bc0e5Withdraw All1934499832024-03-23 18:14:174 days 18 hrs ago0x270b1908b77eb397d4e67abcbdb997b25097fd28 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000357 0.01
0x0664e396b76fcee0186be88213952e2ac2fe4fd8d4c2332c3efd7753a1622572Withdraw All1933351822024-03-23 10:14:415 days 2 hrs ago0xd91432ea17a0b4ff2c28af958d4b175353c7c730 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000347 0.01
0x178b717f563c6c31bd424e3a1a4722c3dbce6174a53948c1ad21546d0da06713Get Reward1933347552024-03-23 10:12:545 days 2 hrs ago0xd91432ea17a0b4ff2c28af958d4b175353c7c730 IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000464 0.01
0x3ebbbd5513f0bdfcc99d2663aaf98499b9399850610357db4810f9f1e56fc373Get Reward1923315102024-03-20 12:13:378 days 25 mins ago0x145abc3a1cbb663c53b1136a73932a91df6cbbbc IN  0x549855586afc1283e90295088ba5eb51e7236ae80 ETH0.00000553 0.01
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 Solid Lizard Finance: voter0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 0x751f3b8ca139bc1f3482b193297485f14208826a0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: SLIZ Token0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago Solid Lizard Finance: voter 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 Solid Lizard Finance: voter0 ETH
0xeb6c6185bd454ad45f753e627de5793150f50084532478203c1900c5fa584f4f720862972023-03-21 10:17:20373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 Solid Lizard Finance: voter0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 0x751f3b8ca139bc1f3482b193297485f14208826a0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: veSLIZ Token0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 SolidLizard: SLIZ Token0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago Solid Lizard Finance: voter 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x549855586afc1283e90295088ba5eb51e7236ae8 Solid Lizard Finance: voter0 ETH
0x04b087b88af82fa5bdddfb7b6253885f40d28c80fea7801329da832db37badaf720862852023-03-21 10:17:17373 days 2 hrs ago 0x699c5e23357ab1bf658bd0b38070d746e37671f3 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
0xf32e1829e28e7bad1ed7304e4fddc4d6d3af43440723f78b219b86bc60f795ba720861012023-03-21 10:16:30373 days 2 hrs ago 0xf4ffe5e59f0b29b77b71ebfb1135f138403aca2a 0x549855586afc1283e90295088ba5eb51e7236ae80 ETH
[ Download CSV Export 
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x0322CEbACF1f235913bE3FCE407F9F81632ede8B
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Gauge

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : Gauge.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

import "../../interface/IGauge.sol";
import "../../interface/IPair.sol";
import "../../interface/IVoter.sol";
import "../../interface/IBribe.sol";
import "../../interface/IERC721.sol";
import "../../interface/IVe.sol";
import "./MultiRewardsPoolBase.sol";

/// @title Gauges are used to incentivize pools, they emit reward tokens over 7 days for staked LP tokens
contract Gauge is IGauge, MultiRewardsPoolBase {
  using SafeERC20 for IERC20;

  /// @dev The ve token used for gauges
  address public immutable ve;
  address public immutable bribe;
  address public immutable voter;

  mapping(address => uint) public tokenIds;

  uint public fees0;
  uint public fees1;

  event ClaimFees(address indexed from, uint claimed0, uint claimed1);
  event VeTokenLocked(address indexed account, uint tokenId);
  event VeTokenUnlocked(address indexed account, uint tokenId);

  constructor(
    address _stake,
    address _bribe,
    address _ve,
    address _voter,
    address[] memory _allowedRewardTokens
  ) MultiRewardsPoolBase(
    _stake,
    _voter,
    _allowedRewardTokens
  ) {
    bribe = _bribe;
    ve = _ve;
    voter = _voter;
  }

  function claimFees() external lock override returns (uint claimed0, uint claimed1) {
    return _claimFees();
  }

  function _claimFees() internal returns (uint claimed0, uint claimed1) {
    address _underlying = underlying;
    (claimed0, claimed1) = IPair(_underlying).claimFees();
    if (claimed0 > 0 || claimed1 > 0) {
      uint _fees0 = fees0 + claimed0;
      uint _fees1 = fees1 + claimed1;
      (address _token0, address _token1) = IPair(_underlying).tokens();
      if (_fees0 > IMultiRewardsPool(bribe).left(_token0)) {
        fees0 = 0;
        IERC20(_token0).safeIncreaseAllowance(bribe, _fees0);
        IBribe(bribe).notifyRewardAmount(_token0, _fees0);
      } else {
        fees0 = _fees0;
      }
      if (_fees1 > IMultiRewardsPool(bribe).left(_token1)) {
        fees1 = 0;
        IERC20(_token1).safeIncreaseAllowance(bribe, _fees1);
        IBribe(bribe).notifyRewardAmount(_token1, _fees1);
      } else {
        fees1 = _fees1;
      }

      emit ClaimFees(msg.sender, claimed0, claimed1);
    }
  }

  function getReward(address account, address[] memory tokens) external override {
    require(msg.sender == account || msg.sender == voter, "Forbidden");
    IVoter(voter).distribute(address(this));
    _getReward(account, tokens, account);
  }

  function depositAll(uint tokenId) external {
    deposit(IERC20(underlying).balanceOf(msg.sender), tokenId);
  }

  function deposit(uint amount, uint tokenId) public {
    if (tokenId > 0) {
      _lockVeToken(msg.sender, tokenId);
    }
    _deposit(amount);
    IVoter(voter).emitDeposit(tokenId, msg.sender, amount);
  }

  function withdrawAll() external {
    withdraw(balanceOf[msg.sender]);
  }

  function withdraw(uint amount) public {
    uint tokenId = 0;
    if (amount == balanceOf[msg.sender]) {
      tokenId = tokenIds[msg.sender];
    }
    withdrawToken(amount, tokenId);
    IVoter(voter).emitWithdraw(tokenId, msg.sender, amount);
  }

  function withdrawToken(uint amount, uint tokenId) public {
    if (tokenId > 0) {
      _unlockVeToken(msg.sender, tokenId);
    }
    _withdraw(amount);
  }

  /// @dev Balance should be recalculated after the lock
  ///      For locking a new ve token withdraw all funds and deposit again
  function _lockVeToken(address account, uint tokenId) internal {
    require(IERC721(ve).ownerOf(tokenId) == account, "Not ve token owner");
    if (tokenIds[account] == 0) {
      tokenIds[account] = tokenId;
      IVoter(voter).attachTokenToGauge(tokenId, account);
    }
    require(tokenIds[account] == tokenId, "Wrong token");
    emit VeTokenLocked(account, tokenId);
  }

  /// @dev Balance should be recalculated after the unlock
  function _unlockVeToken(address account, uint tokenId) internal {
    require(tokenId == tokenIds[account], "Wrong token");
    tokenIds[account] = 0;
    IVoter(voter).detachTokenFromGauge(tokenId, account);
    emit VeTokenUnlocked(account, tokenId);
  }

  /// @dev Similar to Curve https://resources.curve.fi/reward-gauges/boosting-your-crv-rewards#formula
  function _derivedBalance(address account) internal override view returns (uint) {
    uint _tokenId = tokenIds[account];
    uint _balance = balanceOf[account];
    uint _derived = _balance * 40 / 100;
    uint _adjusted = 0;
    uint _supply = IERC20(ve).totalSupply();
    if (account == IERC721(ve).ownerOf(_tokenId) && _supply > 0) {
      _adjusted = (totalSupply * IVe(ve).balanceOfNFT(_tokenId) / _supply) * 60 / 100;
    }
    return Math.min((_derived + _adjusted), _balance);
  }

  function notifyRewardAmount(address token, uint amount) external {
    // claim rewards should not ruin distribution process
    try Gauge(address(this)).claimFees() {} catch {}
    _notifyRewardAmount(token, amount);
  }

}

File 2 of 16 : IGauge.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IGauge {

  function notifyRewardAmount(address token, uint amount) external;

  function getReward(address account, address[] memory tokens) external;

  function claimFees() external returns (uint claimed0, uint claimed1);

}

File 3 of 16 : IPair.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IPair {

  // Structure to capture time period obervations every 30 minutes, used for local oracles
  struct Observation {
    uint timestamp;
    uint reserve0Cumulative;
    uint reserve1Cumulative;
  }

  function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

  function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;

  function burn(address to) external returns (uint amount0, uint amount1);

  function mint(address to) external returns (uint liquidity);

  function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);

  function getAmountOut(uint, address) external view returns (uint);

  function claimFees() external returns (uint, uint);

  function tokens() external view returns (address, address);

  function token0() external view returns (address);

  function token1() external view returns (address);

  function stable() external view returns (bool);

  function metadata() external view returns (
    uint dec0,
    uint dec1,
    uint r0,
    uint r1,
    bool st,
    address t0,
    address t1
  );
}

File 4 of 16 : IVoter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IVoter {

  function ve() external view returns (address);

  function attachTokenToGauge(uint _tokenId, address account) external;

  function detachTokenFromGauge(uint _tokenId, address account) external;

  function emitDeposit(uint _tokenId, address account, uint amount) external;

  function emitWithdraw(uint _tokenId, address account, uint amount) external;

  function distribute(address _gauge) external;

  function notifyRewardAmount(uint amount) external;

}

File 5 of 16 : IBribe.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IBribe {

  function notifyRewardAmount(address token, uint amount) external;

  function _deposit(uint amount, uint tokenId) external;

  function _withdraw(uint amount, uint tokenId) external;

  function getRewardForOwner(uint tokenId, address[] memory tokens) external;

}

File 6 of 16 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

import "./IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
  /**
   * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
   */
  event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

  /**
   * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
   */
  event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

  /**
   * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
   */
  event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

  /**
   * @dev Returns the number of tokens in ``owner``'s account.
   */
  function balanceOf(address owner) external view returns (uint256 balance);

  /**
   * @dev Returns the owner of the `tokenId` token.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function ownerOf(uint256 tokenId) external view returns (address owner);

  /**
   * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
   * are aware of the ERC721 protocol to prevent tokens from being forever locked.
   *
   * Requirements:
   *
   * - `from` cannot be the zero address.
   * - `to` cannot be the zero address.
   * - `tokenId` token must exist and be owned by `from`.
   * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
   *
   * Emits a {Transfer} event.
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId
  ) external;

  /**
   * @dev Transfers `tokenId` token from `from` to `to`.
   *
   * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
   *
   * Requirements:
   *
   * - `from` cannot be the zero address.
   * - `to` cannot be the zero address.
   * - `tokenId` token must be owned by `from`.
   * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
   *
   * Emits a {Transfer} event.
   */
  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  ) external;

  /**
   * @dev Gives permission to `to` to transfer `tokenId` token to another account.
   * The approval is cleared when the token is transferred.
   *
   * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
   *
   * Requirements:
   *
   * - The caller must own the token or be an approved operator.
   * - `tokenId` must exist.
   *
   * Emits an {Approval} event.
   */
  function approve(address to, uint256 tokenId) external;

  /**
   * @dev Returns the account approved for `tokenId` token.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function getApproved(uint256 tokenId) external view returns (address operator);

  /**
   * @dev Approve or remove `operator` as an operator for the caller.
   * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
   *
   * Requirements:
   *
   * - The `operator` cannot be the caller.
   *
   * Emits an {ApprovalForAll} event.
   */
  function setApprovalForAll(address operator, bool _approved) external;

  /**
   * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
   *
   * See {setApprovalForAll}
   */
  function isApprovedForAll(address owner, address operator) external view returns (bool);

  /**
   * @dev Safely transfers `tokenId` token from `from` to `to`.
   *
   * Requirements:
   *
   * - `from` cannot be the zero address.
   * - `to` cannot be the zero address.
   * - `tokenId` token must exist and be owned by `from`.
   * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
   *
   * Emits a {Transfer} event.
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes calldata data
  ) external;
}

File 7 of 16 : IVe.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IVe {

  enum DepositType {
    DEPOSIT_FOR_TYPE,
    CREATE_LOCK_TYPE,
    INCREASE_LOCK_AMOUNT,
    INCREASE_UNLOCK_TIME,
    MERGE_TYPE
  }

  struct Point {
    int128 bias;
    int128 slope; // # -dweight / dt
    uint ts;
    uint blk; // block
  }
  /* We cannot really do block numbers per se b/c slope is per time, not per block
  * and per block could be fairly bad b/c Ethereum changes blocktimes.
  * What we can do is to extrapolate ***At functions */

  struct LockedBalance {
    int128 amount;
    uint end;
  }

  function token() external view returns (address);

  function balanceOfNFT(uint) external view returns (uint);

  function isApprovedOrOwner(address, uint) external view returns (bool);

  function createLockFor(uint, uint, address) external returns (uint);

  function userPointEpoch(uint tokenId) external view returns (uint);

  function epoch() external view returns (uint);

  function userPointHistory(uint tokenId, uint loc) external view returns (Point memory);

  function pointHistory(uint loc) external view returns (Point memory);

  function checkpoint() external;

  function depositFor(uint tokenId, uint value) external;

  function attachToken(uint tokenId) external;

  function detachToken(uint tokenId) external;

  function voting(uint tokenId) external;

  function abstain(uint tokenId) external;
}

File 8 of 16 : MultiRewardsPoolBase.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

import "../../interface/IERC20.sol";
import "../../interface/IMultiRewardsPool.sol";
import "../../lib/Math.sol";
import "../../lib/SafeERC20.sol";
import "../../lib/CheckpointLib.sol";
import "../Reentrancy.sol";

abstract contract MultiRewardsPoolBase is Reentrancy, IMultiRewardsPool {
  using SafeERC20 for IERC20;
  using CheckpointLib for mapping(uint => CheckpointLib.Checkpoint);

  /// @dev Operator can add/remove reward tokens
  address public operator;

  /// @dev The LP token that needs to be staked for rewards
  address public immutable override underlying;

  uint public override derivedSupply;
  mapping(address => uint) public override derivedBalances;

  /// @dev Rewards are released over 7 days
  uint internal constant DURATION = 7 days;
  uint internal constant PRECISION = 10 ** 18;
  uint internal constant MAX_REWARD_TOKENS = 10;

  /// Default snx staking contract implementation
  /// https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol

  /// @dev Reward rate with precision 1e18
  mapping(address => uint) public rewardRate;
  mapping(address => uint) public periodFinish;
  mapping(address => uint) public lastUpdateTime;
  mapping(address => uint) public rewardPerTokenStored;

  mapping(address => mapping(address => uint)) public lastEarn;
  mapping(address => mapping(address => uint)) public userRewardPerTokenStored;

  uint public override totalSupply;
  mapping(address => uint) public override balanceOf;

  address[] public override rewardTokens;
  mapping(address => bool) public override isRewardToken;

  /// @notice A record of balance checkpoints for each account, by index
  mapping(address => mapping(uint => CheckpointLib.Checkpoint)) public checkpoints;
  /// @notice The number of checkpoints for each account
  mapping(address => uint) public numCheckpoints;
  /// @notice A record of balance checkpoints for each token, by index
  mapping(uint => CheckpointLib.Checkpoint) public supplyCheckpoints;
  /// @notice The number of checkpoints
  uint public supplyNumCheckpoints;
  /// @notice A record of balance checkpoints for each token, by index
  mapping(address => mapping(uint => CheckpointLib.Checkpoint)) public rewardPerTokenCheckpoints;
  /// @notice The number of checkpoints for each token
  mapping(address => uint) public rewardPerTokenNumCheckpoints;

  event Deposit(address indexed from, uint amount);
  event Withdraw(address indexed from, uint amount);
  event NotifyReward(address indexed from, address indexed reward, uint amount);
  event ClaimRewards(address indexed from, address indexed reward, uint amount, address recepient);

  constructor(address _stake, address _operator, address[] memory _allowedRewardTokens) {
    underlying = _stake;
    operator = _operator;
    for (uint i; i < _allowedRewardTokens.length; i++) {
      if (_allowedRewardTokens[i] != address(0)) {
        _registerRewardToken(_allowedRewardTokens[i]);
      }
    }
  }

  modifier onlyOperator() {
    require(msg.sender == operator, "Not operator");
    _;
  }

  //**************************************************************************
  //************************ VIEWS *******************************************
  //**************************************************************************

  function rewardTokensLength() external view override returns (uint) {
    return rewardTokens.length;
  }

  function rewardPerToken(address token) external view returns (uint) {
    return _rewardPerToken(token);
  }

  function _rewardPerToken(address token) internal view returns (uint) {
    if (derivedSupply == 0) {
      return rewardPerTokenStored[token];
    }
    return rewardPerTokenStored[token]
    + (
    (_lastTimeRewardApplicable(token) - Math.min(lastUpdateTime[token], periodFinish[token]))
    * rewardRate[token]
    / derivedSupply
    );
  }

  function derivedBalance(address account) external view override returns (uint) {
    return _derivedBalance(account);
  }

  function left(address token) external view override returns (uint) {
    if (block.timestamp >= periodFinish[token]) return 0;
    uint _remaining = periodFinish[token] - block.timestamp;
    return _remaining * rewardRate[token] / PRECISION;
  }

  function earned(address token, address account) external view override returns (uint) {
    return _earned(token, account);
  }

  //**************************************************************************
  //************************ OPERATOR ACTIONS ********************************
  //**************************************************************************

  function registerRewardToken(address token) external onlyOperator {
    _registerRewardToken(token);
  }

  function _registerRewardToken(address token) internal {
    require(rewardTokens.length < MAX_REWARD_TOKENS, "Too many reward tokens");
    require(!isRewardToken[token], "Already registered");
    isRewardToken[token] = true;
    rewardTokens.push(token);
  }

  function removeRewardToken(address token) external onlyOperator {
    require(periodFinish[token] < block.timestamp, "Rewards not ended");
    require(isRewardToken[token], "Not reward token");

    isRewardToken[token] = false;
    uint length = rewardTokens.length;
    require(length > 3, "First 3 tokens should not be removed");
    // keep 3 tokens as guarantee against malicious actions
    // assume it will be LIZARD + pool tokens
    uint i = 3;
    bool found = false;
    for (; i < length; i++) {
      address t = rewardTokens[i];
      if (t == token) {
        found = true;
        break;
      }
    }
    require(found, "First tokens forbidden to remove");
    rewardTokens[i] = rewardTokens[length - 1];
    rewardTokens.pop();
  }

  //**************************************************************************
  //************************ USER ACTIONS ************************************
  //**************************************************************************

  function _deposit(uint amount) internal virtual lock {
    require(amount > 0, "Zero amount");
    _increaseBalance(msg.sender, amount);
    IERC20(underlying).safeTransferFrom(msg.sender, address(this), amount);
    emit Deposit(msg.sender, amount);
  }

  function _increaseBalance(address account, uint amount) internal virtual {
    _updateRewardForAllTokens();

    totalSupply += amount;
    balanceOf[account] += amount;

    _updateDerivedBalanceAndWriteCheckpoints(account);
  }

  function _withdraw(uint amount) internal lock virtual {
    _decreaseBalance(msg.sender, amount);
    IERC20(underlying).safeTransfer(msg.sender, amount);
    emit Withdraw(msg.sender, amount);
  }

  function _decreaseBalance(address account, uint amount) internal virtual {
    _updateRewardForAllTokens();

    totalSupply -= amount;
    balanceOf[account] -= amount;

    _updateDerivedBalanceAndWriteCheckpoints(account);
  }

  /// @dev Implement restriction checks!
  function _getReward(address account, address[] memory tokens, address recipient) internal lock virtual {

    for (uint i = 0; i < tokens.length; i++) {
      (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint).max, true);

      uint _reward = _earned(tokens[i], account);
      lastEarn[tokens[i]][account] = block.timestamp;
      userRewardPerTokenStored[tokens[i]][account] = rewardPerTokenStored[tokens[i]];
      if (_reward > 0) {
        IERC20(tokens[i]).safeTransfer(recipient, _reward);
      }

      emit ClaimRewards(msg.sender, tokens[i], _reward, recipient);
    }

    _updateDerivedBalanceAndWriteCheckpoints(account);
  }

  function _updateDerivedBalanceAndWriteCheckpoints(address account) internal {
    uint __derivedBalance = derivedBalances[account];
    derivedSupply -= __derivedBalance;
    __derivedBalance = _derivedBalance(account);
    derivedBalances[account] = __derivedBalance;
    derivedSupply += __derivedBalance;

    _writeCheckpoint(account, __derivedBalance);
    _writeSupplyCheckpoint();
  }

  //**************************************************************************
  //************************ REWARDS CALCULATIONS ****************************
  //**************************************************************************

  // earned is an estimation, it won't be exact till the supply > rewardPerToken calculations have run
  function _earned(address token, address account) internal view returns (uint) {
    // zero checkpoints means zero deposits
    if (numCheckpoints[account] == 0) {
      return 0;
    }
    // last claim rewards time
    uint _startTimestamp = Math.max(lastEarn[token][account], rewardPerTokenCheckpoints[token][0].timestamp);

    // find an index of the balance that the user had on the last claim
    uint _startIndex = _getPriorBalanceIndex(account, _startTimestamp);
    uint _endIndex = numCheckpoints[account] - 1;

    uint reward = 0;

    // calculate previous snapshots if exist
    if (_endIndex > 0) {
      for (uint i = _startIndex; i <= _endIndex - 1; i++) {
        CheckpointLib.Checkpoint memory cp0 = checkpoints[account][i];
        CheckpointLib.Checkpoint memory cp1 = checkpoints[account][i + 1];
        (uint _rewardPerTokenStored0,) = _getPriorRewardPerToken(token, cp0.timestamp);
        (uint _rewardPerTokenStored1,) = _getPriorRewardPerToken(token, cp1.timestamp);
        reward += cp0.value * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / PRECISION;
      }
    }

    CheckpointLib.Checkpoint memory cp = checkpoints[account][_endIndex];
    (uint _rewardPerTokenStored,) = _getPriorRewardPerToken(token, cp.timestamp);
    reward += cp.value * (_rewardPerToken(token) - Math.max(_rewardPerTokenStored, userRewardPerTokenStored[token][account])) / PRECISION;
    return reward;
  }

  function _derivedBalance(address account) internal virtual view returns (uint) {
    // supposed to be implemented in a parent contract
    return balanceOf[account];
  }

  /// @dev Update stored rewardPerToken values without the last one snapshot
  ///      If the contract will get "out of gas" error on users actions this will be helpful
  function batchUpdateRewardPerToken(address token, uint maxRuns) external {
    (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, maxRuns, false);
  }

  function _updateRewardForAllTokens() internal {
    uint length = rewardTokens.length;
    for (uint i; i < length; i++) {
      address token = rewardTokens[i];
      (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true);
    }
  }

  /// @dev Should be called only with properly updated snapshots, or with actualLast=false
  function _updateRewardPerToken(address token, uint maxRuns, bool actualLast) internal returns (uint, uint) {
    uint _startTimestamp = lastUpdateTime[token];
    uint reward = rewardPerTokenStored[token];

    if (supplyNumCheckpoints == 0) {
      return (reward, _startTimestamp);
    }

    if (rewardRate[token] == 0) {
      return (reward, block.timestamp);
    }
    uint _startIndex = _getPriorSupplyIndex(_startTimestamp);
    uint _endIndex = Math.min(supplyNumCheckpoints - 1, maxRuns);

    if (_endIndex > 0) {
      for (uint i = _startIndex; i <= _endIndex - 1; i++) {
        CheckpointLib.Checkpoint memory sp0 = supplyCheckpoints[i];
        if (sp0.value > 0) {
          CheckpointLib.Checkpoint memory sp1 = supplyCheckpoints[i + 1];
          (uint _reward, uint _endTime) = _calcRewardPerToken(
            token,
            sp1.timestamp,
            sp0.timestamp,
            sp0.value,
            _startTimestamp
          );
          reward += _reward;
          _writeRewardPerTokenCheckpoint(token, reward, _endTime);
          _startTimestamp = _endTime;
        }
      }
    }

    // need to override the last value with actual numbers only on deposit/withdraw/claim/notify actions
    if (actualLast) {
      CheckpointLib.Checkpoint memory sp = supplyCheckpoints[_endIndex];
      if (sp.value > 0) {
        (uint _reward,) = _calcRewardPerToken(token, _lastTimeRewardApplicable(token), Math.max(sp.timestamp, _startTimestamp), sp.value, _startTimestamp);
        reward += _reward;
        _writeRewardPerTokenCheckpoint(token, reward, block.timestamp);
        _startTimestamp = block.timestamp;
      }
    }

    return (reward, _startTimestamp);
  }

  function _calcRewardPerToken(
    address token,
    uint lastSupplyTs1,
    uint lastSupplyTs0,
    uint supply,
    uint startTimestamp
  ) internal view returns (uint, uint) {
    uint endTime = Math.max(lastSupplyTs1, startTimestamp);
    uint _periodFinish = periodFinish[token];
    return (
    (Math.min(endTime, _periodFinish) - Math.min(Math.max(lastSupplyTs0, startTimestamp), _periodFinish))
    * rewardRate[token] / supply
    , endTime);
  }

  /// @dev Returns the last time the reward was modified or periodFinish if the reward has ended
  function _lastTimeRewardApplicable(address token) internal view returns (uint) {
    return Math.min(block.timestamp, periodFinish[token]);
  }

  //**************************************************************************
  //************************ NOTIFY ******************************************
  //**************************************************************************

  function _notifyRewardAmount(address token, uint amount) internal lock virtual {
    require(token != underlying, "Wrong token for rewards");
    require(amount > 0, "Zero amount");
    require(isRewardToken[token], "Token not allowed");
    if (rewardRate[token] == 0) {
      _writeRewardPerTokenCheckpoint(token, 0, block.timestamp);
    }
    (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true);

    if (block.timestamp >= periodFinish[token]) {
      IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
      rewardRate[token] = amount * PRECISION / DURATION;
    } else {
      uint _remaining = periodFinish[token] - block.timestamp;
      uint _left = _remaining * rewardRate[token];
      // not sure what the reason was in the original solidly implementation for this restriction
      // however, by design probably it is a good idea against human errors
      require(amount > _left / PRECISION, "Amount should be higher than remaining rewards");
      IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
      rewardRate[token] = (amount * PRECISION + _left) / DURATION;
    }

    periodFinish[token] = block.timestamp + DURATION;
    emit NotifyReward(msg.sender, token, amount);
  }

  //**************************************************************************
  //************************ CHECKPOINTS *************************************
  //**************************************************************************

  function getPriorBalanceIndex(address account, uint timestamp) external view returns (uint) {
    return _getPriorBalanceIndex(account, timestamp);
  }

  /// @notice Determine the prior balance for an account as of a block number
  /// @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
  /// @param account The address of the account to check
  /// @param timestamp The timestamp to get the balance at
  /// @return The balance the account had as of the given block
  function _getPriorBalanceIndex(address account, uint timestamp) internal view returns (uint) {
    uint nCheckpoints = numCheckpoints[account];
    if (nCheckpoints == 0) {
      return 0;
    }
    return checkpoints[account].findLowerIndex(nCheckpoints, timestamp);
  }

  function getPriorSupplyIndex(uint timestamp) external view returns (uint) {
    return _getPriorSupplyIndex(timestamp);
  }

  function _getPriorSupplyIndex(uint timestamp) internal view returns (uint) {
    uint nCheckpoints = supplyNumCheckpoints;
    if (nCheckpoints == 0) {
      return 0;
    }
    return supplyCheckpoints.findLowerIndex(nCheckpoints, timestamp);
  }

  function getPriorRewardPerToken(address token, uint timestamp) external view returns (uint, uint) {
    return _getPriorRewardPerToken(token, timestamp);
  }

  function _getPriorRewardPerToken(address token, uint timestamp) internal view returns (uint, uint) {
    uint nCheckpoints = rewardPerTokenNumCheckpoints[token];
    if (nCheckpoints == 0) {
      return (0, 0);
    }
    mapping(uint => CheckpointLib.Checkpoint) storage cps = rewardPerTokenCheckpoints[token];
    uint lower = cps.findLowerIndex(nCheckpoints, timestamp);
    CheckpointLib.Checkpoint memory cp = cps[lower];
    return (cp.value, cp.timestamp);
  }

  function _writeCheckpoint(address account, uint balance) internal {
    uint _timestamp = block.timestamp;
    uint _nCheckPoints = numCheckpoints[account];

    if (_nCheckPoints > 0 && checkpoints[account][_nCheckPoints - 1].timestamp == _timestamp) {
      checkpoints[account][_nCheckPoints - 1].value = balance;
    } else {
      checkpoints[account][_nCheckPoints] = CheckpointLib.Checkpoint(_timestamp, balance);
      numCheckpoints[account] = _nCheckPoints + 1;
    }
  }

  function _writeRewardPerTokenCheckpoint(address token, uint reward, uint timestamp) internal {
    uint _nCheckPoints = rewardPerTokenNumCheckpoints[token];

    if (_nCheckPoints > 0 && rewardPerTokenCheckpoints[token][_nCheckPoints - 1].timestamp == timestamp) {
      rewardPerTokenCheckpoints[token][_nCheckPoints - 1].value = reward;
    } else {
      rewardPerTokenCheckpoints[token][_nCheckPoints] = CheckpointLib.Checkpoint(timestamp, reward);
      rewardPerTokenNumCheckpoints[token] = _nCheckPoints + 1;
    }
  }

  function _writeSupplyCheckpoint() internal {
    uint _nCheckPoints = supplyNumCheckpoints;
    uint _timestamp = block.timestamp;

    if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) {
      supplyCheckpoints[_nCheckPoints - 1].value = derivedSupply;
    } else {
      supplyCheckpoints[_nCheckPoints] = CheckpointLib.Checkpoint(_timestamp, derivedSupply);
      supplyNumCheckpoints = _nCheckPoints + 1;
    }
  }
}

File 9 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
  /**
   * @dev Returns true if this contract implements the interface defined by
   * `interfaceId`. See the corresponding
   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
   * to learn more about how these ids are created.
   *
   * This function call must use less than 30 000 gas.
   */
  function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 10 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

/**
 * @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);
}

File 11 of 16 : IMultiRewardsPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

interface IMultiRewardsPool {

  function underlying() external view returns (address);

  function derivedSupply() external view returns (uint);

  function derivedBalances(address account) external view returns (uint);

  function totalSupply() external view returns (uint);

  function balanceOf(address account) external view returns (uint);

  function rewardTokens(uint id) external view returns (address);

  function isRewardToken(address token) external view returns (bool);

  function rewardTokensLength() external view returns (uint);

  function derivedBalance(address account) external view returns (uint);

  function left(address token) external view returns (uint);

  function earned(address token, address account) external view returns (uint);

  function registerRewardToken(address token) external;

  function removeRewardToken(address token) external;

}

File 12 of 16 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

library Math {

  function max(uint a, uint b) internal pure returns (uint) {
    return a >= b ? a : b;
  }

  function min(uint a, uint b) internal pure returns (uint) {
    return a < b ? a : b;
  }

  function positiveInt128(int128 value) internal pure returns (int128) {
    return value < 0 ? int128(0) : value;
  }

  function closeTo(uint a, uint b, uint target) internal pure returns (bool) {
    if (a > b) {
      if (a - b <= target) {
        return true;
      }
    } else {
      if (b - a <= target) {
        return true;
      }
    }
    return false;
  }

  function sqrt(uint y) internal pure returns (uint z) {
    if (y > 3) {
      z = y;
      uint x = y / 2 + 1;
      while (x < z) {
        z = x;
        x = (y / x + x) / 2;
      }
    } else if (y != 0) {
      z = 1;
    }
  }

}

File 13 of 16 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity 0.8.15;

import "../interface/IERC20.sol";
import "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  using Address for address;

  function safeTransfer(
    IERC20 token,
    address to,
    uint value
  ) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  }

  function safeTransferFrom(
    IERC20 token,
    address from,
    address to,
    uint value
  ) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
  }

  function safeIncreaseAllowance(
    IERC20 token,
    address spender,
    uint value
  ) internal {
    uint newAllowance = token.allowance(address(this), spender) + value;
    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  }

  /**
   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
  function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
    if (returndata.length > 0) {
      // Return data is optional
      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
  }

}

File 14 of 16 : CheckpointLib.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

library CheckpointLib {

  /// @notice A checkpoint for uint value
  struct Checkpoint {
    uint timestamp;
    uint value;
  }

  function findLowerIndex(mapping(uint => Checkpoint) storage checkpoints, uint size, uint timestamp) internal view returns (uint) {
    require(size != 0, "Empty checkpoints");

    // First check most recent value
    if (checkpoints[size - 1].timestamp <= timestamp) {
      return (size - 1);
    }

    // Next check implicit zero value
    if (checkpoints[0].timestamp > timestamp) {
      return 0;
    }

    uint lower = 0;
    uint upper = size - 1;
    while (upper > lower) {
      // ceil, avoiding overflow
      uint center = upper - (upper - lower) / 2;
      Checkpoint memory cp = checkpoints[center];
      if (cp.timestamp == timestamp) {
        return center;
      } else if (cp.timestamp < timestamp) {
        lower = center;
      } else {
        upper = center - 1;
      }
    }
    return lower;
  }

}

File 15 of 16 : Reentrancy.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

abstract contract Reentrancy {

  /// @dev simple re-entrancy check
  uint internal _unlocked = 1;

  modifier lock() {
    require(_unlocked == 1, "Reentrant call");
    _unlocked = 2;
    _;
    _unlocked = 1;
  }

}

File 16 of 16 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity 0.8.15;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
  /**
   * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
  function isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize/address.code.length, which returns 0
    // for contracts in construction, since the code is only stored at the end
    // of the constructor execution.

    return account.code.length > 0;
  }

  function functionCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal returns (bytes memory) {
    require(isContract(target), "Address: call to non-contract");
    (bool success, bytes memory returndata) = target.call(data);
    return verifyCallResult(success, returndata, errorMessage);
  }

  /**
   * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
  function verifyCallResult(
    bool success,
    bytes memory returndata,
    string memory errorMessage
  ) internal pure returns (bytes memory) {
    if (success) {
      return returndata;
    } else {
      // Look for revert reason and bubble it up if present
      if (returndata.length > 0) {
        // The easiest way to bubble the revert reason is using memory via assembly
        assembly {
          let returndata_size := mload(returndata)
          revert(add(32, returndata), returndata_size)
        }
      } else {
        revert(errorMessage);
      }
    }
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_stake","type":"address"},{"internalType":"address","name":"_bribe","type":"address"},{"internalType":"address","name":"_ve","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address[]","name":"_allowedRewardTokens","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimed1","type":"uint256"}],"name":"ClaimFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recepient","type":"address"}],"name":"ClaimRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NotifyReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"VeTokenLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"VeTokenUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxRuns","type":"uint256"}],"name":"batchUpdateRewardPerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bribe","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"checkpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimFees","outputs":[{"internalType":"uint256","name":"claimed0","type":"uint256"},{"internalType":"uint256","name":"claimed1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"derivedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"derivedBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"derivedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorBalanceIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getPriorSupplyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isRewardToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"lastEarn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"left","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"registerRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"removeRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardPerTokenCheckpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardPerTokenNumCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"supplyCheckpoints","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyNumCheckpoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061027f5760003560e01c80637bb7bed11161015c578063d294f093116100ce578063e8111a1211610087578063e8111a12146106a8578063f1229777146106b1578063f7412baf146106c4578063fc97a303146106eb578063fd3140981461070b578063fdb483c71461071e57600080fd5b8063d294f0931461063e578063d35e254414610646578063d7da4bb014610659578063da09d19d14610662578063e2bbb15814610682578063e46dbc981461069557600080fd5b8063a495e5b511610120578063a495e5b514610592578063aa479652146105bd578063b5fd73f8146105dd578063b66503cf14610610578063bf199e6214610623578063c6f678bd1461062b57600080fd5b80637bb7bed11461053b578063853828b61461054e57806393f1c4421461055657806399bcc0521461055f5780639ce43f901461057257600080fd5b80633ca068b6116101f557806363fb415b116101b957806363fb415b1461048e57806368fcee1a146104ae5780636f307dc3146104c15780636fcfff45146104e857806370a082311461050857806376f4be361461052857600080fd5b80633ca068b61461040d5780633d509c971461043857806346c96aac1461044b5780634c02a21c14610472578063570ca7351461047b57600080fd5b8063211dc32d11610247578063211dc32d1461036b578063221ca18c1461037e5780632ce9aead1461039e5780632e1a7d4d146103be57806331279d3d146103d357806337d0208c146103e657600080fd5b806301316ddf146102845780630cdfebfa146102d0578063115c6f391461030257806318160ddd146103235780631f8507161461032c575b600080fd5b6102b66102923660046131db565b60126020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152015b60405180910390f35b6102b66102de3660046131db565b600e6020908152600092835260408084209091529082529020805460019091015482565b6103156103103660046131db565b610731565b6040519081526020016102c7565b610315600a5481565b6103537f00000000000000000000000029d3622c78615a1e7459e4be434d816b7de293e481565b6040516001600160a01b0390911681526020016102c7565b610315610379366004613207565b610746565b61031561038c366004613240565b60046020526000908152604090205481565b6103156103ac366004613240565b60066020526000908152604090205481565b6103d16103cc36600461325d565b610752565b005b6103d16103e136600461328c565b610810565b6103537f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec0959981565b61031561041b366004613207565b600960209081526000928352604080842090915290825290205481565b6103d1610446366004613240565b610914565b6103537f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc81565b61031560165481565b600154610353906001600160a01b031681565b61031561049c366004613240565b60036020526000908152604090205481565b6103d16104bc3660046131db565b610bef565b6103537f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a81565b6103156104f6366004613240565b600f6020526000908152604090205481565b610315610516366004613240565b600b6020526000908152604090205481565b61031561053636600461325d565b610c29565b61035361054936600461325d565b610c34565b6103d1610c5e565b61031560155481565b61031561056d366004613240565b610c79565b610315610580366004613240565b60076020526000908152604090205481565b6103156105a0366004613207565b600860209081526000928352604080842090915290825290205481565b6103156105cb366004613240565b60136020526000908152604090205481565b6106006105eb366004613240565b600d6020526000908152604090205460ff1681565b60405190151581526020016102c7565b6103d161061e3660046131db565b610d05565b600c54610315565b6103d161063936600461325d565b610d72565b6102b6610e07565b610315610654366004613240565b610e46565b61031560025481565b610315610670366004613240565b60056020526000908152604090205481565b6103d1610690366004613366565b610e51565b6103d16106a3366004613240565b610ec4565b61031560115481565b6103156106bf366004613240565b610f16565b6102b66106d236600461325d565b6010602052600090815260409020805460019091015482565b6103156106f9366004613240565b60146020526000908152604090205481565b6102b66107193660046131db565b610f21565b6103d161072c366004613366565b610f3a565b600061073d8383610f53565b90505b92915050565b600061073d8383610fa8565b336000908152600b6020526040812054820361077a5750336000908152601460205260409020545b6107848282610f3a565b604051633aa53b9160e21b815260048101829052336024820152604481018390527f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc6001600160a01b03169063ea94ee44906064015b600060405180830381600087803b1580156107f457600080fd5b505af1158015610808573d6000803e3d6000fd5b505050505050565b336001600160a01b038316148061084f5750336001600160a01b037f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc16145b61088c5760405162461bcd60e51b81526020600482015260096024820152682337b93134b23232b760b91b60448201526064015b60405180910390fd5b6040516363453ae160e01b81523060048201527f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc6001600160a01b0316906363453ae190602401600060405180830381600087803b1580156108ed57600080fd5b505af1158015610901573d6000803e3d6000fd5b50505050610910828284611229565b5050565b6001546001600160a01b0316331461095d5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610883565b6001600160a01b03811660009081526005602052604090205442116109b85760405162461bcd60e51b815260206004820152601160248201527014995dd85c991cc81b9bdd08195b991959607a1b6044820152606401610883565b6001600160a01b0381166000908152600d602052604090205460ff16610a135760405162461bcd60e51b815260206004820152601060248201526f2737ba103932bbb0b932103a37b5b2b760811b6044820152606401610883565b6001600160a01b0381166000908152600d60205260409020805460ff19169055600c5460038111610a925760405162461bcd60e51b8152602060048201526024808201527f4669727374203320746f6b656e732073686f756c64206e6f742062652072656d6044820152631bdd995960e21b6064820152608401610883565b600360005b82821015610af2576000600c8381548110610ab457610ab4613388565b6000918252602090912001546001600160a01b03908116915085168103610adf576001915050610af2565b5081610aea816133b4565b925050610a97565b80610b3f5760405162461bcd60e51b815260206004820181905260248201527f466972737420746f6b656e7320666f7262696464656e20746f2072656d6f76656044820152606401610883565b600c610b4c6001856133cd565b81548110610b5c57610b5c613388565b600091825260209091200154600c80546001600160a01b039092169184908110610b8857610b88613388565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600c805480610bc757610bc76133e4565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b610bfb82826000611502565b6001600160a01b03909316600090815260076020908152604080832060069092529091209390935590915550565b6000610740826116f2565b600c8181548110610c4457600080fd5b6000918252602090912001546001600160a01b0316905081565b336000908152600b6020526040902054610c7790610752565b565b6001600160a01b0381166000908152600560205260408120544210610ca057506000919050565b6001600160a01b038216600090815260056020526040812054610cc49042906133cd565b6001600160a01b038416600090815260046020526040902054909150670de0b6b3a764000090610cf490836133fa565b610cfe9190613419565b9392505050565b306001600160a01b031663d294f0936040518163ffffffff1660e01b815260040160408051808303816000875af1925050508015610d60575060408051601f3d908101601f19168201909252610d5d9181019061343b565b60015b15610d685750505b6109108282611714565b6040516370a0823160e01b8152336004820152610e04907f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a6001600160a01b0316906370a0823190602401602060405180830381865afa158015610dda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfe919061345f565b82610e51565b50565b600080600054600114610e2c5760405162461bcd60e51b815260040161088390613478565b6002600055610e39611aa2565b9150915060016000559091565b600061074082611ec8565b8015610e6157610e613382612117565b610e6a8261234f565b60405163530e389d60e11b815260048101829052336024820152604481018390527f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc6001600160a01b03169063a61c713a906064016107da565b6001546001600160a01b03163314610f0d5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1037b832b930ba37b960a11b6044820152606401610883565b610e048161242e565b60006107408261253d565b600080610f2e84846125e8565b915091505b9250929050565b8015610f4a57610f4a3382612672565b6109108261279a565b6001600160a01b0382166000908152600f6020526040812054808203610f7d576000915050610740565b6001600160a01b0384166000908152600e60205260409020610fa0908285612831565b949350505050565b6001600160a01b0381166000908152600f60205260408120548103610fcf57506000610740565b6001600160a01b038084166000818152600860209081526040808320948716835293815283822054928252601281528382208280529052918220546110149190612977565b905060006110228483610f53565b6001600160a01b0385166000908152600f60205260408120549192509061104b906001906133cd565b90506000811561115d57825b6110626001846133cd565b811161115b576001600160a01b0387166000818152600e6020818152604080842086855280835281852082518084019093528054835260019081015483850152958552929091529282906110b79086906134a0565b815260200190815260200160002060405180604001604052908160008201548152602001600182015481525050905060006110f68b84600001516125e8565b50905060006111098c84600001516125e8565b509050670de0b6b3a764000061111f83836133cd565b856020015161112e91906133fa565b6111389190613419565b61114290876134a0565b9550505050508080611153906133b4565b915050611057565b505b6001600160a01b0386166000908152600e602090815260408083208584528252808320815180830190925280548083526001909101549282019290925291906111a7908a906125e8565b506001600160a01b03808b166000908152600960209081526040808320938d1683529290522054909150670de0b6b3a7640000906111e6908390612977565b6111ef8b61253d565b6111f991906133cd565b836020015161120891906133fa565b6112129190613419565b61121c90846134a0565b9998505050505050505050565b60005460011461124b5760405162461bcd60e51b815260040161088390613478565b600260009081555b82518110156114ee5761128383828151811061127157611271613388565b60200260200101516000196001611502565b6007600086858151811061129957611299613388565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000600660008887815181106112d9576112d9613388565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000849190505583919050555050600061133484838151811061132657611326613388565b602002602001015186610fa8565b9050426008600086858151811061134d5761134d613388565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002081905550600760008584815181106113b2576113b2613388565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054600960008685815181106113f1576113f1613388565b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938a168152929052902055801561146357611463838286858151811061144357611443613388565b60200260200101516001600160a01b031661298e9092919063ffffffff16565b83828151811061147557611475613388565b60200260200101516001600160a01b0316336001600160a01b03167fe4394b3c25e336e9d6b7fcefab7e3234f1c6b373f13655dc3920664b080b098d83866040516114d39291909182526001600160a01b0316602082015260400190565b60405180910390a350806114e6816133b4565b915050611253565b506114f8836129f6565b5050600160005550565b6001600160a01b038316600090815260066020908152604080832054600790925282205460115483929190830361153c57925090506116ea565b6001600160a01b03871660009081526004602052604081205490036115675792504291506116ea9050565b6000611572836116f2565b9050600061158e600160115461158891906133cd565b89612a7b565b9050801561166757815b6115a36001836133cd565b81116116655760008181526010602090815260409182902082518084019093528054835260010154908201819052156116525760006010816115e68560016134a0565b81526020019081526020016000206040518060400160405290816000820154815260200160018201548152505090506000806116318e8460000151866000015187602001518d612a8a565b909250905061164082896134a0565b975061164d8e8983612b0e565b975050505b508061165d816133b4565b915050611598565b505b86156116e15760008181526010602090815260409182902082518084019093528054835260010154908201819052156116df5760006116c08b6116a98d612c17565b84516116b5908a612977565b85602001518a612a8a565b5090506116cd81866134a0565b94506116da8b8642612b0e565b429550505b505b50909350909150505b935093915050565b6011546000908082036117085750600092915050565b610cfe60108285612831565b6000546001146117365760405162461bcd60e51b815260040161088390613478565b60026000556001600160a01b037f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a8116908316036117b65760405162461bcd60e51b815260206004820152601760248201527f57726f6e6720746f6b656e20666f7220726577617264730000000000000000006044820152606401610883565b600081116117f45760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610883565b6001600160a01b0382166000908152600d602052604090205460ff166118505760405162461bcd60e51b8152602060048201526011602482015270151bdad95b881b9bdd08185b1b1bddd959607a1b6044820152606401610883565b6001600160a01b038216600090815260046020526040812054900361187b5761187b82600042612b0e565b611889826000196001611502565b6001600160a01b0384166000908152600760209081526040808320600683528184209490945593909255600590915220544210611913576118d56001600160a01b038316333084612c3b565b62093a806118eb670de0b6b3a7640000836133fa565b6118f59190613419565b6001600160a01b038316600090815260046020526040902055611a33565b6001600160a01b0382166000908152600560205260408120546119379042906133cd565b6001600160a01b0384166000908152600460205260408120549192509061195e90836133fa565b9050611972670de0b6b3a764000082613419565b83116119d75760405162461bcd60e51b815260206004820152602e60248201527f416d6f756e742073686f756c6420626520686967686572207468616e2072656d60448201526d61696e696e67207265776172647360901b6064820152608401610883565b6119ec6001600160a01b038516333086612c3b565b62093a8081611a03670de0b6b3a7640000866133fa565b611a0d91906134a0565b611a179190613419565b6001600160a01b03851660009081526004602052604090205550505b611a4062093a80426134a0565b6001600160a01b0383166000818152600560205260409081902092909255905133907ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf5082690611a919085815260200190565b60405180910390a350506001600055565b60008060007f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a9050806001600160a01b031663d294f0936040518163ffffffff1660e01b815260040160408051808303816000875af1158015611b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2d919061343b565b909350915082151580611b405750600082115b15611ec357600083601554611b5591906134a0565b9050600083601654611b6791906134a0565b9050600080846001600160a01b0316639d63848a6040518163ffffffff1660e01b81526004016040805180830381865afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd91906134b8565b604051634cde602960e11b81526001600160a01b0380841660048301529294509092507f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec09599909116906399bcc05290602401602060405180830381865afa158015611c3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5f919061345f565b841115611d26576000601555611c9f6001600160a01b0383167f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec0959986612c73565b60405163b66503cf60e01b81526001600160a01b038381166004830152602482018690527f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec09599169063b66503cf90604401600060405180830381600087803b158015611d0957600080fd5b505af1158015611d1d573d6000803e3d6000fd5b50505050611d2c565b60158490555b604051634cde602960e11b81526001600160a01b0382811660048301527f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec0959916906399bcc05290602401602060405180830381865afa158015611d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db6919061345f565b831115611e7d576000601655611df66001600160a01b0382167f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec0959985612c73565b60405163b66503cf60e01b81526001600160a01b038281166004830152602482018590527f000000000000000000000000bc5d11490dacecde548f6d145b66b1f8cec09599169063b66503cf90604401600060405180830381600087803b158015611e6057600080fd5b505af1158015611e74573d6000803e3d6000fd5b50505050611e83565b60168390555b604080518881526020810188905233917fbc567d6cbad26368064baa0ab5a757be46aae4d70f707f9203d9d9b6c8ccbfa3910160405180910390a2505050505b509091565b6001600160a01b038116600090815260146020908152604080832054600b909252822054826064611efa8360286133fa565b611f049190613419565b90506000807f00000000000000000000000029d3622c78615a1e7459e4be434d816b7de293e46001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8b919061345f565b6040516331a9108f60e11b8152600481018790529091507f00000000000000000000000029d3622c78615a1e7459e4be434d816b7de293e46001600160a01b031690636352211e90602401602060405180830381865afa158015611ff3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201791906134e7565b6001600160a01b0316876001600160a01b03161480156120375750600081115b156120f9576040516339f890b560e21b81526004810186905260649082906001600160a01b037f00000000000000000000000029d3622c78615a1e7459e4be434d816b7de293e4169063e7e242d490602401602060405180830381865afa1580156120a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ca919061345f565b600a546120d791906133fa565b6120e19190613419565b6120ec90603c6133fa565b6120f69190613419565b91505b61210c61210683856134a0565b85612a7b565b979650505050505050565b816001600160a01b03167f00000000000000000000000029d3622c78615a1e7459e4be434d816b7de293e46001600160a01b0316636352211e836040518263ffffffff1660e01b815260040161216f91815260200190565b602060405180830381865afa15801561218c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b091906134e7565b6001600160a01b0316146121fb5760405162461bcd60e51b81526020600482015260126024820152712737ba103b32903a37b5b2b71037bbb732b960711b6044820152606401610883565b6001600160a01b03821660009081526014602052604081205490036122b3576001600160a01b03828116600081815260146020526040908190208490555163698473e360e01b81526004810184905260248101919091527f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc9091169063698473e390604401600060405180830381600087803b15801561229a57600080fd5b505af11580156122ae573d6000803e3d6000fd5b505050505b6001600160a01b03821660009081526014602052604090205481146123085760405162461bcd60e51b815260206004820152600b60248201526a2bb937b733903a37b5b2b760a91b6044820152606401610883565b816001600160a01b03167fa88ad287ee039276852a62661add3a03e736aca1a2987ceaebcf4ecfd018ae3f8260405161234391815260200190565b60405180910390a25050565b6000546001146123715760405162461bcd60e51b815260040161088390613478565b6002600055806123b15760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610883565b6123bb3382612d25565b6123f06001600160a01b037f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a16333084612c3b565b60405181815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906020015b60405180910390a2506001600055565b600c54600a116124795760405162461bcd60e51b8152602060048201526016602482015275546f6f206d616e792072657761726420746f6b656e7360501b6044820152606401610883565b6001600160a01b0381166000908152600d602052604090205460ff16156124d75760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b6044820152606401610883565b6001600160a01b03166000818152600d60205260408120805460ff19166001908117909155600c805491820181559091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180546001600160a01b0319169091179055565b600060025460000361256557506001600160a01b031660009081526007602052604090205490565b6002546001600160a01b0383166000908152600460209081526040808320546006835281842054600590935292205461259e9190612a7b565b6125a785612c17565b6125b191906133cd565b6125bb91906133fa565b6125c59190613419565b6001600160a01b03831660009081526007602052604090205461074091906134a0565b6001600160a01b0382166000908152601360205260408120548190808203612617576000809250925050610f33565b6001600160a01b03851660009081526012602052604081209061263b828488612831565b6000908152602092835260409081902081518083019092528054808352600190910154919093018190529791965090945050505050565b6001600160a01b03821660009081526014602052604090205481146126c75760405162461bcd60e51b815260206004820152600b60248201526a2bb937b733903a37b5b2b760a91b6044820152606401610883565b6001600160a01b03828116600081815260146020526040808220919091555163411b1f7760e01b81526004810184905260248101919091527f00000000000000000000000098a1de08715800801e9764349f5a71cbe63f99cc9091169063411b1f7790604401600060405180830381600087803b15801561274757600080fd5b505af115801561275b573d6000803e3d6000fd5b50505050816001600160a01b03167f25842dad107a4bb4efa3824996f6140a5f6f3de5197debed6d780dc08bb0a0a08260405161234391815260200190565b6000546001146127bc5760405162461bcd60e51b815260040161088390613478565b60026000556127cb3382612d7b565b6127ff6001600160a01b037f000000000000000000000000751f3b8ca139bc1f3482b193297485f14208826a16338361298e565b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200161241e565b6000826000036128775760405162461bcd60e51b8152602060048201526011602482015270456d70747920636865636b706f696e747360781b6044820152606401610883565b818460006128866001876133cd565b815260200190815260200160002060000154116128af576128a86001846133cd565b9050610cfe565b6000808052602085905260409020548210156128cd57506000610cfe565b6000806128db6001866133cd565b90505b8181111561296e57600060026128f484846133cd565b6128fe9190613419565b61290890836133cd565b6000818152602089815260409182902082518084019093528054808452600190910154918301919091529192509086900361294857509250610cfe915050565b805186111561295957819350612967565b6129646001836133cd565b92505b50506128de565b50949350505050565b600081831015612987578161073d565b5090919050565b6040516001600160a01b0383166024820152604481018290526129f190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612dc2565b505050565b6001600160a01b0381166000908152600360205260408120546002805491928392612a229084906133cd565b90915550612a31905082611ec8565b6001600160a01b0383166000908152600360205260408120829055600280549293508392909190612a639084906134a0565b90915550612a7390508282612e94565b610910612f85565b6000818310612987578161073d565b6000806000612a998785612977565b6001600160a01b038916600090815260056020908152604080832054600490925290912054919250908690612ad7612ad18a89612977565b84612a7b565b612ae18585612a7b565b612aeb91906133cd565b612af591906133fa565b612aff9190613419565b99919850909650505050505050565b6001600160a01b0383166000908152601360205260409020548015801590612b6a57506001600160a01b03841660009081526012602052604081208391612b566001856133cd565b815260200190815260200160002060000154145b15612bad576001600160a01b03841660009081526012602052604081208491612b946001856133cd565b8152602081019190915260400160002060010155612c11565b60408051808201825283815260208082018681526001600160a01b038816600090815260128352848120868252909252929020905181559051600191820155612bf79082906134a0565b6001600160a01b0385166000908152601360205260409020555b50505050565b6001600160a01b038116600090815260056020526040812054610740904290612a7b565b6040516001600160a01b0380851660248301528316604482015260648101829052612c119085906323b872dd60e01b906084016129ba565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015612cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce8919061345f565b612cf291906134a0565b6040516001600160a01b038516602482015260448101829052909150612c1190859063095ea7b360e01b906064016129ba565b612d2d613029565b80600a6000828254612d3f91906134a0565b90915550506001600160a01b0382166000908152600b602052604081208054839290612d6c9084906134a0565b909155506109109050826129f6565b612d83613029565b80600a6000828254612d9591906133cd565b90915550506001600160a01b0382166000908152600b602052604081208054839290612d6c9084906133cd565b6000612e17826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130ad9092919063ffffffff16565b8051909150156129f15780806020019051810190612e359190613504565b6129f15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610883565b6001600160a01b0382166000908152600f602052604090205442908015801590612ef257506001600160a01b0384166000908152600e602052604081208391612ede6001856133cd565b815260200190815260200160002060000154145b15612f1c576001600160a01b0384166000908152600e602052604081208491612b946001856133cd565b60408051808201825283815260208082018681526001600160a01b0388166000908152600e8352848120868252909252929020905181559051600191820155612f669082906134a0565b6001600160a01b0385166000908152600f602052604090205550505050565b601154428115801590612fb757508060106000612fa36001866133cd565b815260200190815260200160002060000154145b15612fe65760025460106000612fce6001866133cd565b81526020810191909152604001600020600101555050565b604080518082018252828152600254602080830191825260008681526010909152929092209051815590516001918201556130229083906134a0565b6011555050565b600c5460005b81811015610910576000600c828154811061304c5761304c613388565b6000918252602090912001546001600160a01b03169050613071816000196001611502565b6001600160a01b0390921660009081526007602090815260408083206006909252909120929092559055806130a5816133b4565b91505061302f565b60606001600160a01b0384163b6131065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610883565b600080856001600160a01b0316856040516131219190613552565b6000604051808303816000865af19150503d806000811461315e576040519150601f19603f3d011682016040523d82523d6000602084013e613163565b606091505b509150915061317382828661317d565b9695505050505050565b6060831561318c575081610cfe565b82511561319c5782518084602001fd5b8160405162461bcd60e51b8152600401610883919061356e565b6001600160a01b0381168114610e0457600080fd5b80356131d6816131b6565b919050565b600080604083850312156131ee57600080fd5b82356131f9816131b6565b946020939093013593505050565b6000806040838503121561321a57600080fd5b8235613225816131b6565b91506020830135613235816131b6565b809150509250929050565b60006020828403121561325257600080fd5b8135610cfe816131b6565b60006020828403121561326f57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561329f57600080fd5b82356132aa816131b6565b915060208381013567ffffffffffffffff808211156132c857600080fd5b818601915086601f8301126132dc57600080fd5b8135818111156132ee576132ee613276565b8060051b604051601f19603f8301168101818110858211171561331357613313613276565b60405291825284820192508381018501918983111561333157600080fd5b938501935b8285101561335657613347856131cb565b84529385019392850192613336565b8096505050505050509250929050565b6000806040838503121561337957600080fd5b50508035926020909101359150565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016133c6576133c661339e565b5060010190565b6000828210156133df576133df61339e565b500390565b634e487b7160e01b600052603160045260246000fd5b60008160001904831182151516156134145761341461339e565b500290565b60008261343657634e487b7160e01b600052601260045260246000fd5b500490565b6000806040838503121561344e57600080fd5b505080516020909101519092909150565b60006020828403121561347157600080fd5b5051919050565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b600082198211156134b3576134b361339e565b500190565b600080604083850312156134cb57600080fd5b82516134d6816131b6565b6020840151909250613235816131b6565b6000602082840312156134f957600080fd5b8151610cfe816131b6565b60006020828403121561351657600080fd5b81518015158114610cfe57600080fd5b60005b83811015613541578181015183820152602001613529565b83811115612c115750506000910152565b60008251613564818460208701613526565b9190910192915050565b602081526000825180602084015261358d816040850160208701613526565b601f01601f1916919091016040019291505056fea26469706673582212207a0792d1690da6f82ef24cc436965908d9f22abc48a2c8af306886a0a90a5e2464736f6c634300080f0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.