编译器
0.8.23+commit.f704f362
文件 1 的 11:Epoch.sol
pragma solidity ^0.8.0;
uint256 constant EPOCH_DURATION = 7 days;
文件 2 的 11:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 3 的 11:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function transfer(address recipient, uint amount) external returns (bool);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function balanceOf(address) external view returns (uint);
function transferFrom(address sender, address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
文件 4 的 11:IERC721.sol
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 5 的 11:IERC721Metadata.sol
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 6 的 11:IMinter.sol
pragma solidity ^0.8.0;
interface IMinter {
function update_period() external returns (uint256);
function check() external view returns (bool);
function period() external view returns (uint256);
function active_period() external view returns (uint256);
function calculate_emission() external view returns (uint256);
function calculate_growth(uint256 _weeklyMinted) external view returns (uint256);
}
文件 7 的 11:IRewardsDistributor.sol
pragma solidity ^0.8.0;
interface IRewardsDistributor {
function checkpoint_token() external;
function voting_escrow() external view returns (address);
function checkpoint_total_supply() external;
function claimable(uint256 _tokenId) external view returns (uint256);
}
文件 8 的 11:IVotingEscrow.sol
pragma solidity ^0.8.0;
import {IERC721, IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
interface IVotingEscrow is IERC721, IERC721Metadata {
struct Point {
int128 bias;
int128 slope;
uint256 ts;
uint256 blk;
}
struct LockedBalance {
int128 amount;
uint256 end;
}
function create_lock_for(uint256 _value, uint256 _lock_duration, address _to) external returns (uint256);
function locked(uint256 id) external view returns (LockedBalance memory);
function tokenOfOwnerByIndex(address _owner, uint256 _tokenIndex) external view returns (uint256);
function token() external view returns (address);
function team() external returns (address);
function epoch() external view returns (uint256);
function point_history(uint256 loc) external view returns (Point memory);
function user_point_history(uint256 tokenId, uint256 loc) external view returns (Point memory);
function user_point_epoch(uint256 tokenId) external view returns (uint256);
function ownerOf(uint256) external view returns (address);
function isApprovedOrOwner(address, uint256) external view returns (bool);
function transferFrom(address, address, uint256) external;
function voted(uint256) external view returns (bool);
function voting(uint256 tokenId) external;
function voter() external view returns (address);
function abstain(uint256 tokenId) external;
function checkpoint() external;
function deposit_for(uint256 tokenId, uint256 value) external;
function balanceOfNFT(uint256 _id) external view returns (uint256);
function balanceOfNFTAt(uint _tokenId, uint _t) external view returns (uint);
function balanceOf(address _owner) external view returns (uint256);
function totalSupply() external view returns (uint256);
function supply() external view returns (uint256);
function decimals() external view returns (uint8);
function isTransferWhitelisted(address account) external view returns (bool);
function split(uint256[] memory amounts, uint256 _tokenId) external;
function merge(uint256 _from, uint256 _to) external;
function tokenId() external returns (uint256);
function safeTransferFrom(address _from, address _to, uint256 _tokenId ) external;
}
文件 9 的 11:Math.sol
pragma solidity ^0.8.0;
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 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;
}
}
function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
uint256 x = 0;
for (uint256 y = 1 << 255; y > 0; y >>= 3) {
x <<= 1;
uint256 z = 3 * x * (x + 1) + 1;
if (n / y >= z) {
n -= y * z;
x += 1;
}
}
return x;
}}
}
文件 10 的 11:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 11 的 11:RewardDistro.sol
pragma solidity ^0.8.0;
import "./libraries/Math.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IRewardsDistributor.sol";
import "./interfaces/IVotingEscrow.sol";
import "./interfaces/IMinter.sol";
import "contracts/Epoch.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract RewardDistributorV2 is ReentrancyGuard, IRewardsDistributor {
event CheckpointToken(uint time, uint tokens);
event Claimed(
uint tokenId,
uint amount,
uint claim_epoch,
uint max_epoch
);
uint public start_time;
uint public last_token_time;
uint public last_week;
uint public total_distributed;
uint public token_claimed;
uint public time_cursor;
uint[1000000000000000] public tokens_per_week;
uint[1000000000000000] public ve_supply;
address public owner;
address public voting_escrow;
address public token;
address public depositor;
mapping(uint => uint) public time_cursor_of;
mapping(address => bool) public lockAddress;
constructor(address _voting_escrow, address _depositor) {
uint _t = (block.timestamp / EPOCH_DURATION) * EPOCH_DURATION;
last_token_time = _t;
time_cursor = _t;
address _token = IVotingEscrow(_voting_escrow).token();
token = _token;
voting_escrow = _voting_escrow;
depositor = _depositor;
start_time = _t;
owner = msg.sender;
require(IERC20(_token).approve(_voting_escrow, type(uint).max));
}
function timestamp() public view returns (uint) {
return (block.timestamp / EPOCH_DURATION) * EPOCH_DURATION;
}
function checkpoint_total_supply() external {
assert(msg.sender == depositor || msg.sender == owner);
_checkpoint_total_supply();
}
function _checkpoint_total_supply() internal {
address ve = voting_escrow;
uint t = time_cursor;
uint rounded_timestamp = (block.timestamp / EPOCH_DURATION) * EPOCH_DURATION;
IVotingEscrow(ve).checkpoint();
for (uint i = 0; i < 20; i++) {
if (t > rounded_timestamp) {
break;
} else {
uint epoch = _find_timestamp_epoch(ve, t);
IVotingEscrow.Point memory pt = IVotingEscrow(ve).point_history(
epoch
);
int128 dt = 0;
if (t > pt.ts) {
dt = int128(int256(t - pt.ts));
}
ve_supply[t] = Math.max(
uint(int256(pt.bias - pt.slope * dt)),
0
);
}
t += EPOCH_DURATION;
}
time_cursor = t;
}
function _find_timestamp_epoch(
address ve,
uint _timestamp
) internal view returns (uint) {
uint _min = 0;
uint _max = IVotingEscrow(ve).epoch();
for (uint i = 0; i < 128; i++) {
if (_min >= _max) break;
uint _mid = (_min + _max + 2) / 2;
IVotingEscrow.Point memory pt = IVotingEscrow(ve).point_history(
_mid
);
if (pt.ts <= _timestamp) {
_min = _mid;
} else {
_max = _mid - 1;
}
}
return _min;
}
function checkpoint_token() external {
assert(msg.sender == depositor || msg.sender == owner);
_checkpoint_token();
}
function _checkpoint_token() internal {
last_week = (block.timestamp / EPOCH_DURATION) * EPOCH_DURATION;
last_token_time = block.timestamp;
uint token_balance = IERC20(token).balanceOf(address(this));
uint diff = total_distributed - token_claimed;
uint to_distribute = token_balance - diff;
tokens_per_week[last_week] += to_distribute;
total_distributed += to_distribute;
emit CheckpointToken(block.timestamp, to_distribute);
}
function claimable(uint _tokenId) external view returns (uint) {
uint t = time_cursor_of[_tokenId];
if (t == 0) t = start_time;
uint _last_week = last_week;
uint to_claim = 0;
for (uint i = 0; i < 100; i++) {
if (t > _last_week) break;
to_claim += _toClaim(_tokenId, t);
t += EPOCH_DURATION;
}
return to_claim;
}
function claim_many(
uint[] memory tokenIds
) external nonReentrant returns (bool) {
require(tokenIds.length <= 25);
for (uint i = 0; i < tokenIds.length; i++) {
_claim(tokenIds[i]);
}
return true;
}
function claim(uint _tokenId) external nonReentrant returns (uint) {
return _claim(_tokenId);
}
function _claim(uint _tokenId) internal returns (uint) {
address _owner = IVotingEscrow(voting_escrow).ownerOf(_tokenId);
if (lockAddress[_owner])
require(
IVotingEscrow(voting_escrow).isApprovedOrOwner(
msg.sender,
_tokenId
),
"not approved"
);
IVotingEscrow.LockedBalance memory _locked = IVotingEscrow(
voting_escrow
).locked(_tokenId);
require(_locked.amount > 0, "No existing lock found");
require(
_locked.end > block.timestamp,
"Cannot add to expired lock. Withdraw"
);
uint t = time_cursor_of[_tokenId];
if (t < start_time) t = start_time;
uint _last_week = last_week;
uint to_claim = 0;
for (uint i = 0; i < 100; i++) {
if (t > _last_week) break;
to_claim += _toClaim(_tokenId, t);
t += EPOCH_DURATION;
}
if (to_claim > 0)
IVotingEscrow(voting_escrow).deposit_for(_tokenId, to_claim);
time_cursor_of[_tokenId] = t;
token_claimed += to_claim;
emit Claimed(
_tokenId,
to_claim,
last_week,
_find_timestamp_epoch(voting_escrow, last_week)
);
return to_claim;
}
function _toClaim(uint id, uint t) internal view returns (uint to_claim) {
IVotingEscrow.Point memory userData = IVotingEscrow(voting_escrow).user_point_history(id, 1);
if (ve_supply[t] == 0) return 0;
if (tokens_per_week[t] == 0) return 0;
if (userData.ts > t) return 0;
uint id_bal = IVotingEscrow(voting_escrow).balanceOfNFTAt(id, t);
uint share = (id_bal * 1e18) / ve_supply[t];
to_claim = (share * tokens_per_week[t]) / 1e18;
}
function _lockAddress(address caller) external {
require(msg.sender == caller || msg.sender == owner);
lockAddress[caller] = true;
}
function _unlockAddress(address caller) external {
require(msg.sender == caller || msg.sender == owner);
lockAddress[caller] = false;
}
function setDepositor(address _depositor) external {
require(msg.sender == owner);
depositor = _depositor;
}
function setOwner(address _owner) external {
require(msg.sender == owner);
owner = _owner;
}
function increaseOrRemoveAllowances(bool what) external {
require(msg.sender == owner);
what == true ? IERC20(token).approve(voting_escrow, type(uint).max) : IERC20(token).approve(voting_escrow, 0);
}
function withdrawERC20(address _token) external {
require(msg.sender == owner);
require(_token != address(0));
uint256 _balance = IERC20(_token).balanceOf(address(this));
IERC20(_token).transfer(msg.sender, _balance);
}
}
{
"compilationTarget": {
"contracts/RewardDistro.sol": "RewardDistributorV2"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_voting_escrow","type":"address"},{"internalType":"address","name":"_depositor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"CheckpointToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claim_epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"max_epoch","type":"uint256"}],"name":"Claimed","type":"event"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"_lockAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"_unlockAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpoint_token","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpoint_total_supply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claim_many","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"what","type":"bool"}],"name":"increaseOrRemoveAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"last_token_time","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last_week","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"setDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"start_time","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"time_cursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"time_cursor_of","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token_claimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens_per_week","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"total_distributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ve_supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voting_escrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]