编译器
0.8.28+commit.7893614a
文件 1 的 11:CoreOwnable.sol
pragma solidity 0.8.28;
import {ICore} from "../interfaces/ICore.sol";
contract CoreOwnable {
ICore public immutable core;
constructor(address _core) {
core = ICore(_core);
}
modifier onlyOwner() {
require(msg.sender == address(core), "!core");
_;
}
function owner() public view returns (address) {
return address(core);
}
}
文件 2 的 11:DelegatedOps.sol
pragma solidity 0.8.28;
contract DelegatedOps {
event DelegateApprovalSet(address indexed account, address indexed delegate, bool isApproved);
mapping(address owner => mapping(address caller => bool isApproved)) public isApprovedDelegate;
modifier callerOrDelegated(address _account) {
require(msg.sender == _account || isApprovedDelegate[_account][msg.sender], "!CallerOrDelegated");
_;
}
function setDelegateApproval(address _delegate, bool _isApproved) external {
isApprovedDelegate[msg.sender][_delegate] = _isApproved;
emit DelegateApprovalSet(msg.sender, _delegate, _isApproved);
}
}
文件 3 的 11:Hashes.sol
pragma solidity ^0.8.20;
library Hashes {
function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
}
function _efficientKeccak256(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly ("memory-safe") {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 4 的 11:IAuthHook.sol
pragma solidity 0.8.28;
interface IAuthHook {
function preHook(address operator, address target, bytes calldata data) external returns (bool);
function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}
文件 5 的 11:ICore.sol
pragma solidity 0.8.28;
import { IAuthHook } from './IAuthHook.sol';
interface ICore {
struct OperatorAuth {
bool authorized;
IAuthHook hook;
}
event VoterSet(address indexed newVoter);
event OperatorExecuted(address indexed caller, address indexed target, bytes data);
event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);
function execute(address target, bytes calldata data) external returns (bytes memory);
function epochLength() external view returns (uint256);
function startTime() external view returns (uint256);
function voter() external view returns (address);
function ownershipTransferDeadline() external view returns (uint256);
function pendingOwner() external view returns (address);
function setOperatorPermissions(
address caller,
address target,
bytes4 selector,
bool authorized,
IAuthHook authHook
) external;
function setVoter(address newVoter) external;
function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}
文件 6 的 11:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 7 的 11:IGovStaker.sol
pragma solidity 0.8.28;
interface IGovStaker {
event RewardAdded(address indexed rewardToken, uint256 amount);
event RewardTokenAdded(address indexed rewardsToken, address indexed rewardsDistributor, uint256 rewardsDuration);
event Recovered(address indexed token, uint256 amount);
event RewardsDurationUpdated(address indexed rewardsToken, uint256 duration);
event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);
event Staked(address indexed account, uint indexed epoch, uint amount);
event Unstaked(address indexed account, uint amount);
event Cooldown(address indexed account, uint amount, uint end);
event CooldownEpochsUpdated(uint24 newDuration);
struct Reward {
address rewardsDistributor;
uint256 rewardsDuration;
uint256 periodFinish;
uint256 rewardRate;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
}
struct AccountData {
uint120 realizedStake;
uint120 pendingStake;
uint16 lastUpdateEpoch;
}
struct UserCooldown {
uint104 end;
uint152 amount;
}
enum ApprovalStatus {
None,
StakeOnly,
UnstakeOnly,
StakeAndUnstake
}
function rewardTokens(uint256 index) external view returns (address);
function rewardData(address token) external view returns (Reward memory);
function rewards(address account, address token) external view returns (uint256);
function userRewardPerTokenPaid(address account, address token) external view returns (uint256);
function CORE() external view returns (address);
function PRECISION() external view returns (uint256);
function ESCROW() external view returns (address);
function MAX_COOLDOWN_DURATION() external view returns (uint24);
function totalPending() external view returns (uint120);
function totalLastUpdateEpoch() external view returns (uint16);
function cooldownEpochs() external view returns (uint256);
function decimals() external view returns (uint8);
function approvedCaller(address account, address caller) external view returns (ApprovalStatus);
function accountData(address account) external view returns (AccountData memory);
function stakeToken() external view returns (address);
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
function getReward() external;
function getOneReward(address rewardsToken) external;
function addReward(address rewardsToken, address rewardsDistributor, uint256 rewardsDuration) external;
function notifyRewardAmount(address rewardsToken, uint256 rewardAmount) external;
function setRewardsDistributor(address rewardsToken, address rewardsDistributor) external;
function setRewardsDuration(address rewardsToken, uint256 rewardsDuration) external;
function recoverERC20(address tokenAddress, uint256 tokenAmount) external;
function stake(address account, uint amount) external returns (uint);
function stakeFor(address account, uint amount) external returns (uint);
function cooldown(address account, uint amount) external returns (uint);
function cooldowns(address account) external view returns (UserCooldown memory);
function cooldownFor(address account, uint amount) external returns (uint);
function exit(address account) external returns (uint);
function exitFor(address account) external returns (uint);
function unstake(address account, address receiver) external returns (uint);
function unstakeFor(address account, address receiver) external returns (uint);
function checkpointAccount(address account) external returns (AccountData memory, uint weight);
function checkpointAccountWithLimit(address account, uint epoch) external returns (AccountData memory, uint weight);
function checkpointTotal() external returns (uint);
function setApprovedCaller(address caller, ApprovalStatus status) external;
function setCooldownEpochs(uint24 epochs) external;
function getAccountWeight(address account) external view returns (uint);
function getAccountWeightAt(address account, uint epoch) external view returns (uint);
function getTotalWeight() external view returns (uint);
function getTotalWeightAt(uint epoch) external view returns (uint);
function getUnstakableAmount(address account) external view returns (uint);
function isCooldownEnabled() external view returns (bool);
function rewardTokensLength() external view returns (uint256);
function earned(address account, address rewardsToken) external view returns (uint256 pending);
function earnedMulti(address account) external view returns (uint256[] memory pending);
function rewardPerToken(address rewardsToken) external view returns (uint256 rewardAmount);
function lastTimeRewardApplicable(address rewardsToken) external view returns (uint256);
function getRewardForDuration(address rewardsToken) external view returns (uint256);
function owner() external view returns (address);
function guardian() external view returns (address);
function getEpoch() external view returns (uint);
function epochLength() external view returns (uint);
function startTime() external view returns (uint);
function irreversiblyCommitAccountAsPermanentStaker(address account) external;
function onPermaStakeMigrate(address account) external;
function migrateStake() external returns (uint amount);
function setDelegateApproval(address delegate, bool approved) external;
}
文件 8 的 11:IVestClaimCallback.sol
pragma solidity 0.8.28;
import { IGovStaker } from "./IGovStaker.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IVestClaimCallback {
event RecoveredERC20(address indexed token, address indexed recipient, uint256 amount);
function govStaker() external view returns (IGovStaker);
function vestManager() external view returns (address);
function token() external view returns (IERC20);
function onClaim(
address account,
address recipient,
uint256 amount
) external returns (bool success);
function recoverERC20(address token, address recipient, uint256 amount) external;
}
文件 9 的 11:MerkleProof.sol
pragma solidity ^0.8.20;
import {Hashes} from "./Hashes.sol";
library MerkleProof {
error MerkleProofInvalidMultiproof();
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
}
return computedHash;
}
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bool) {
return processProof(proof, leaf, hasher) == root;
}
function processProof(
bytes32[] memory proof,
bytes32 leaf,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = hasher(computedHash, proof[i]);
}
return computedHash;
}
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
}
return computedHash;
}
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bool) {
return processProofCalldata(proof, leaf, hasher) == root;
}
function processProofCalldata(
bytes32[] calldata proof,
bytes32 leaf,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = hasher(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofFlagsLen = proofFlags.length;
if (leavesLen + proof.length != proofFlagsLen + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](proofFlagsLen);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < proofFlagsLen; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = Hashes.commutativeKeccak256(a, b);
}
if (proofFlagsLen > 0) {
if (proofPos != proof.length) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[proofFlagsLen - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bool) {
return processMultiProof(proof, proofFlags, leaves, hasher) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofFlagsLen = proofFlags.length;
if (leavesLen + proof.length != proofFlagsLen + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](proofFlagsLen);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < proofFlagsLen; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = hasher(a, b);
}
if (proofFlagsLen > 0) {
if (proofPos != proof.length) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[proofFlagsLen - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofFlagsLen = proofFlags.length;
if (leavesLen + proof.length != proofFlagsLen + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](proofFlagsLen);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < proofFlagsLen; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = Hashes.commutativeKeccak256(a, b);
}
if (proofFlagsLen > 0) {
if (proofPos != proof.length) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[proofFlagsLen - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == root;
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves,
function(bytes32, bytes32) view returns (bytes32) hasher
) internal view returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofFlagsLen = proofFlags.length;
if (leavesLen + proof.length != proofFlagsLen + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](proofFlagsLen);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < proofFlagsLen; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = hasher(a, b);
}
if (proofFlagsLen > 0) {
if (proofPos != proof.length) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[proofFlagsLen - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
}
文件 10 的 11:VestManager.sol
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import { VestManagerBase } from "./VestManagerBase.sol";
interface IGovToken is IERC20 {
function INITIAL_SUPPLY() external view returns (uint256);
}
contract VestManager is VestManagerBase {
uint256 constant PRECISION = 1e18;
address immutable public prisma;
address immutable public yprisma;
address immutable public cvxprisma;
uint256 public immutable INITIAL_SUPPLY;
address public immutable BURN_ADDRESS;
bool public initialized;
uint256 public redemptionRatio;
mapping(AllocationType => uint256) public allocationByType;
mapping(AllocationType => uint256) public durationByType;
mapping(AllocationType => bytes32) public merkleRootByType;
mapping(address account => mapping(AllocationType => bool hasClaimed)) public hasClaimed;
enum AllocationType {
PERMA_STAKE,
LICENSING,
TREASURY,
REDEMPTIONS,
AIRDROP_TEAM,
AIRDROP_VICTIMS,
AIRDROP_LOCK_PENALTY
}
event TokenRedeemed(address indexed token, address indexed redeemer, address indexed recipient, uint256 amount);
event MerkleRootSet(AllocationType indexed allocationType, bytes32 root);
event AirdropClaimed(AllocationType indexed allocationType, address indexed account, address indexed recipient, uint256 amount);
event InitializationParamsSet();
constructor(
address _core,
address _token,
address _burnAddress,
address[3] memory _redemptionTokens
) VestManagerBase(_core, _token) {
INITIAL_SUPPLY = IGovToken(_token).INITIAL_SUPPLY();
require(IERC20(_token).balanceOf(address(this)) == INITIAL_SUPPLY, "VestManager not funded");
BURN_ADDRESS = _burnAddress;
prisma = _redemptionTokens[0];
yprisma = _redemptionTokens[1];
cvxprisma = _redemptionTokens[2];
}
function setInitializationParams(
uint256 _maxRedeemable,
bytes32[3] memory _merkleRoots,
address[4] memory _nonUserTargets,
uint256[8] memory _vestDurations,
uint256[8] memory _allocPercentages
) external onlyOwner {
require(!initialized, "params already set");
initialized = true;
uint256 totalPctAllocated;
uint256 airdropIndex;
require(_vestDurations[0] == _vestDurations[1], "perma-staker durations must match");
for (uint256 i = 0; i < _allocPercentages.length; i++) {
AllocationType allocType = i == 0 ? AllocationType(i) : AllocationType(i-1);
require(_vestDurations[i] > 0 && _vestDurations[i] <= type(uint32).max, "invalid duration");
durationByType[allocType] = uint32(_vestDurations[i]);
totalPctAllocated += _allocPercentages[i];
uint256 allocation = _allocPercentages[i] * INITIAL_SUPPLY / PRECISION;
allocationByType[allocType] += allocation;
if (i < _nonUserTargets.length) {
_createVest(
_nonUserTargets[i],
uint32(_vestDurations[i]),
uint112(allocation)
);
continue;
}
if (
allocType == AllocationType.AIRDROP_TEAM ||
allocType == AllocationType.AIRDROP_VICTIMS ||
allocType == AllocationType.AIRDROP_LOCK_PENALTY
) {
merkleRootByType[allocType] = _merkleRoots[airdropIndex];
emit MerkleRootSet(allocType, _merkleRoots[airdropIndex++]);
}
}
uint256 _redemptionRatio = (
allocationByType[AllocationType.REDEMPTIONS] * 1e18 / _maxRedeemable
);
redemptionRatio = _redemptionRatio;
require(_redemptionRatio != 0, "ratio is 0");
require(totalPctAllocated == PRECISION, "Total not 100%");
emit InitializationParamsSet();
}
function setLockPenaltyMerkleRoot(bytes32 _root, uint256 _allocation) external onlyOwner {
require(initialized, "init params not set");
require(merkleRootByType[AllocationType.AIRDROP_LOCK_PENALTY] == bytes32(0), "root already set");
merkleRootByType[AllocationType.AIRDROP_LOCK_PENALTY] = _root;
emit MerkleRootSet(AllocationType.AIRDROP_LOCK_PENALTY, _root);
allocationByType[AllocationType.AIRDROP_LOCK_PENALTY] = _allocation;
}
function merkleClaim(
address _account,
address _recipient,
uint256 _amount,
AllocationType _type,
bytes32[] calldata _proof,
uint256 _index
) external callerOrDelegated(_account) {
require(
_type == AllocationType.AIRDROP_TEAM ||
_type == AllocationType.AIRDROP_LOCK_PENALTY ||
_type == AllocationType.AIRDROP_VICTIMS,
"invalid type"
);
bytes32 _root = merkleRootByType[_type];
require(_root != bytes32(0), "root not set");
require(!hasClaimed[_account][_type], "already claimed");
bytes32 node = keccak256(abi.encodePacked(_account, _index, _amount));
require(MerkleProof.verifyCalldata(
_proof,
_root,
node
), "invalid proof");
_createVest(
_recipient,
uint32(durationByType[_type]),
uint112(_amount)
);
hasClaimed[_account][_type] = true;
emit AirdropClaimed(_type, _account, _recipient, _amount);
}
function redeem(address _token, address _recipient, uint256 _amount) external {
require(
_token == address(prisma) ||
_token == address(yprisma) ||
_token == address(cvxprisma),
"invalid token"
);
require(_amount > 0, "amount too low");
uint256 _ratio = redemptionRatio;
require(_ratio != 0, "ratio not set");
IERC20(_token).transferFrom(msg.sender, BURN_ADDRESS, _amount);
_createVest(
_recipient,
uint32(durationByType[AllocationType.REDEMPTIONS]),
uint112(_amount * _ratio / 1e18)
);
emit TokenRedeemed(_token, msg.sender, _recipient, _amount);
}
}
文件 11 的 11:VestManagerBase.sol
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { DelegatedOps } from '../../dependencies/DelegatedOps.sol';
import { CoreOwnable } from '../../dependencies/CoreOwnable.sol';
import { IVestClaimCallback } from 'src/interfaces/IVestClaimCallback.sol';
contract VestManagerBase is CoreOwnable, DelegatedOps {
uint256 public immutable VEST_GLOBAL_START_TIME;
IERC20 public immutable token;
mapping(address => Vest[]) public userVests;
mapping(address => ClaimSettings) public claimSettings;
struct Vest {
uint32 duration;
uint112 amount;
uint112 claimed;
}
struct ClaimSettings {
bool allowPermissionlessClaims;
address recipient;
}
event VestCreated(address indexed account, uint256 indexed duration, uint256 amount);
event Claimed(address indexed account, uint256 amount);
event ClaimSettingsSet(address indexed account, bool indexed allowPermissionlessClaims, address indexed recipient);
constructor(address _core, address _token) CoreOwnable(_core) {
token = IERC20(_token);
VEST_GLOBAL_START_TIME = block.timestamp;
}
function _createVest(
address _account,
uint32 _duration,
uint112 _amount
) internal returns (uint256) {
require(_account != address(0), "zero address");
require(_amount > 0, "Amount must be greater than zero");
uint256 length = numAccountVests(_account);
for (uint256 i = 0; i < length; i++) {
if (userVests[_account][i].duration == _duration) {
userVests[_account][i].amount += _amount;
return length;
}
}
userVests[_account].push(Vest(
_duration,
_amount,
0
));
emit VestCreated(_account, _duration, _amount);
return length + 1;
}
function numAccountVests(address _account) public view returns (uint256) {
return userVests[_account].length;
}
function claim(address _account) external returns (uint256 _claimed) {
address recipient = _enforceClaimSettings(_account);
_claimed = _claim(_account);
if (_claimed > 0) {
token.transfer(recipient, _claimed);
emit Claimed(_account, _claimed);
}
}
function claimWithCallback(
address _account,
address _callback
) external callerOrDelegated(_account) returns (uint256 _claimed) {
address recipient = _enforceClaimSettings(_account);
_claimed = _claim(_account);
if (_claimed > 0) {
token.transfer(_callback, _claimed);
require(IVestClaimCallback(_callback).onClaim(_account, recipient, _claimed), "callback failed");
emit Claimed(_account, _claimed);
}
}
function _claim(address _account) internal returns (uint256 _claimed) {
Vest[] storage vests = userVests[_account];
uint256 length = vests.length;
require(length > 0, "No vests to claim");
for (uint256 i = 0; i < length; i++) {
uint112 claimable = _claimableAmount(vests[i]);
if (claimable > 0) {
vests[i].claimed += claimable;
_claimed += claimable;
}
}
}
function _enforceClaimSettings(address _account) internal view returns (address) {
ClaimSettings memory settings = claimSettings[_account];
if (!settings.allowPermissionlessClaims) {
require(msg.sender == _account, "!authorized");
}
return settings.recipient != address(0) ? settings.recipient : _account;
}
function getAggregateVestData(address _account) external view returns (
uint256 _totalAmount,
uint256 _totalClaimable,
uint256 _totalClaimed
) {
uint256 length = numAccountVests(_account);
for (uint256 i = 0; i < length; i++) {
(uint256 _total, uint256 _claimable, uint256 _claimed,) = _vestData(userVests[_account][i]);
_totalAmount += _total;
_totalClaimable += _claimable;
_totalClaimed += _claimed;
}
}
function getSingleVestData(address _account, uint256 index) external view returns (
uint256 _total,
uint256 _claimable,
uint256 _claimed,
uint256 _timeRemaining
) {
return _vestData(userVests[_account][index]);
}
function _vestData(Vest memory vest) internal view returns (
uint256 _total,
uint256 _claimable,
uint256 _claimed,
uint256 _timeRemaining
){
uint256 vested = _vestedAmount(vest);
_total = vest.amount;
_claimable = vested - vest.claimed;
_claimed = vest.claimed;
uint256 elapsed = block.timestamp - VEST_GLOBAL_START_TIME;
_timeRemaining = elapsed > vest.duration ? 0 : vest.duration - elapsed;
}
function _claimableAmount(Vest storage vest) internal view returns (uint112) {
return uint112(_vestedAmount(vest) - vest.claimed);
}
function _vestedAmount(Vest memory vest) internal view returns (uint256) {
if (block.timestamp < VEST_GLOBAL_START_TIME) {
return 0;
} else if (block.timestamp >= VEST_GLOBAL_START_TIME + vest.duration) {
return vest.amount;
} else {
return (vest.amount * (block.timestamp - VEST_GLOBAL_START_TIME)) / vest.duration;
}
}
function setClaimSettings(
bool _allowPermissionlessClaims,
address _recipient
) external {
claimSettings[msg.sender] = ClaimSettings(_allowPermissionlessClaims, _recipient);
emit ClaimSettingsSet(msg.sender, _allowPermissionlessClaims, _recipient);
}
}
{
"compilationTarget": {
"src/dao/tge/VestManager.sol": "VestManager"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@axelar-network/=node_modules/@axelar-network/",
":@chainlink/=node_modules/@chainlink/",
":@eth-optimism/=node_modules/@eth-optimism/",
":@layerzerolabs/=node_modules/@layerzerolabs/",
":@mean-finance/=node_modules/@mean-finance/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@rari-capital/=node_modules/@rari-capital/",
":@uniswap/=node_modules/@uniswap/",
":base64-sol/=node_modules/base64-sol/",
":ds-test/=node_modules/ds-test/src/",
":forge-std/=node_modules/forge-std/src/",
":frax-standard-solidity/=node_modules/frax-standard-solidity/",
":frax-std/=node_modules/frax-standard-solidity/src/",
":hardhat-deploy/=node_modules/hardhat-deploy/",
":hardhat/=node_modules/hardhat/",
":solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
":solidity-stringutils/=lib/surl/lib/solidity-stringutils/",
":surl/=lib/surl/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_burnAddress","type":"address"},{"internalType":"address[3]","name":"_redemptionTokens","type":"address[3]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum VestManager.AllocationType","name":"allocationType","type":"uint8"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AirdropClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"allowPermissionlessClaims","type":"bool"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"ClaimSettingsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"DelegateApprovalSet","type":"event"},{"anonymous":false,"inputs":[],"name":"InitializationParamsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum VestManager.AllocationType","name":"allocationType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"MerkleRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VestCreated","type":"event"},{"inputs":[],"name":"BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VEST_GLOBAL_START_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"allocationByType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256","name":"_claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimSettings","outputs":[{"internalType":"bool","name":"allowPermissionlessClaims","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_callback","type":"address"}],"name":"claimWithCallback","outputs":[{"internalType":"uint256","name":"_claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cvxprisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"durationByType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAggregateVestData","outputs":[{"internalType":"uint256","name":"_totalAmount","type":"uint256"},{"internalType":"uint256","name":"_totalClaimable","type":"uint256"},{"internalType":"uint256","name":"_totalClaimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getSingleVestData","outputs":[{"internalType":"uint256","name":"_total","type":"uint256"},{"internalType":"uint256","name":"_claimable","type":"uint256"},{"internalType":"uint256","name":"_claimed","type":"uint256"},{"internalType":"uint256","name":"_timeRemaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"hasClaimed","outputs":[{"internalType":"bool","name":"hasClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"isApprovedDelegate","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"enum VestManager.AllocationType","name":"_type","type":"uint8"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"merkleClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"merkleRootByType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"numAccountVests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowPermissionlessClaims","type":"bool"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"setClaimSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"bool","name":"_isApproved","type":"bool"}],"name":"setDelegateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxRedeemable","type":"uint256"},{"internalType":"bytes32[3]","name":"_merkleRoots","type":"bytes32[3]"},{"internalType":"address[4]","name":"_nonUserTargets","type":"address[4]"},{"internalType":"uint256[8]","name":"_vestDurations","type":"uint256[8]"},{"internalType":"uint256[8]","name":"_allocPercentages","type":"uint256[8]"}],"name":"setInitializationParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint256","name":"_allocation","type":"uint256"}],"name":"setLockPenaltyMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userVests","outputs":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"uint112","name":"claimed","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yprisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]