文件 1 的 10:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 10:AddressUpgradeable.sol
pragma solidity ^0.8.1;
library AddressUpgradeable {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 3 的 10:ContextUpgradeable.sol
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
uint256[50] private __gap;
}
文件 4 的 10:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 10:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 6 的 10:Initializable.sol
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
abstract contract Initializable {
uint8 private _initialized;
bool private _initializing;
event Initialized(uint8 version);
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
文件 7 的 10:OwnableUpgradeable.sol
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
uint256[49] private __gap;
}
文件 8 的 10:ReentrancyGuardUpgradeable.sol
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
abstract contract ReentrancyGuardUpgradeable is Initializable {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_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;
}
uint256[49] private __gap;
}
文件 9 的 10:SHOVesting.sol
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
contract SHOVesting is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20;
uint32 constant public VERSION = 2;
uint32 constant internal HUNDRED_PERCENT = 1e6;
struct User {
uint120 allocation;
uint120 refundableAmount;
uint16 claimedUnlocksCount;
uint16 eliminatedAfterUnlock;
bool refunded;
}
struct InitParameters {
IERC20 shoToken;
uint32[] unlockPercentagesDiff;
uint32[] unlockPeriodsDiff;
uint32 baseFeePercentage1;
address feeCollector;
uint64 startTime;
IERC20 refundToken;
address refundReceiver;
uint64 refundStartTime;
uint64 refundEndTime;
}
mapping(address => User) public users1;
mapping(address => bool) public blockedUsers;
uint32[] public unlockPercentages;
uint32[] public unlockPeriods;
IERC20 public shoToken;
uint64 public startTime;
address public feeCollector;
uint32 public baseFeePercentage1;
IERC20 public refundToken;
address public refundReceiver;
uint64 public refundStartTime;
uint64 public refundEndTime;
bool public whitelistingAllowed;
uint16 passedUnlocksCount;
uint120 public globalTotalAllocation1;
uint120 public totalRefundedAllocation;
uint120 public totalRefundableAmount;
uint120 public totalRefundedAmount;
uint16 public collectedFeesUnlocksCount;
uint120 public extraFees1Allocation;
uint120 public extraFees1AllocationUncollectable;
event Whitelist(
address user,
uint120 allocation
);
event Claim(
address indexed user,
uint16 currentUnlock,
uint120 claimedTokens
);
event FeeCollection(
uint16 currentUnlock,
uint120 totalFee,
uint120 extraFee
);
event UserElimination(
address user,
uint16 currentUnlock
);
event Update(
uint16 passedUnlocksCount
);
event Refund(
address user,
uint refundAmount
);
event BlockUsers(
address[] userAddresses,
bool state
);
modifier onlyWhitelistedUser(address userAddress) {
require(users1[userAddress].allocation > 0, "SHOVesting: not whitelisted");
_;
}
function init(
InitParameters calldata params
) external initializer {
__ReentrancyGuard_init();
__Ownable_init();
require(address(params.shoToken) != address(0), "SHOVesting: sho token zero address");
require(params.unlockPercentagesDiff.length > 0, "SHOVesting: 0 unlock percentages");
require(params.unlockPeriodsDiff.length == params.unlockPercentagesDiff.length, "SHOVesting: different array lengths");
require(params.baseFeePercentage1 <= HUNDRED_PERCENT, "SHOVesting: base fee percentage 1 higher than 100%");
require(params.feeCollector != address(0), "SHOVesting: fee collector zero address");
require(params.startTime > block.timestamp, "SHOVesting: start time must be in future");
uint32[] memory _unlockPercentages = _buildArraySum(params.unlockPercentagesDiff);
uint32[] memory _unlockPeriods = _buildArraySum(params.unlockPeriodsDiff);
require(_unlockPercentages[_unlockPercentages.length - 1] == HUNDRED_PERCENT, "SHOVesting: invalid unlock percentages");
require(params.shoToken != params.refundToken, "SHOVesting: same tokens");
if (address(params.refundToken) != address(0)) {
require(params.refundStartTime >= params.startTime, "SHOVesting: invalid refundStartTime");
require(params.refundEndTime > params.refundStartTime, "SHOVesting: invalid refundEndTime");
require(params.refundReceiver != address(0), "SHOVesting: invalid refundReceiver");
} else {
require(params.refundStartTime == 0, "SHOVesting: invalid refundStartTime");
require(params.refundEndTime == 0, "SHOVesting: invalid refundEndTime");
require(params.refundReceiver == address(0), "SHOVesting: invalid refundReceiver");
}
shoToken = params.shoToken;
unlockPercentages = _unlockPercentages;
unlockPeriods = _unlockPeriods;
baseFeePercentage1 = params.baseFeePercentage1;
feeCollector = params.feeCollector;
startTime = params.startTime;
refundToken = params.refundToken;
refundReceiver = params.refundReceiver;
refundStartTime = params.refundStartTime;
refundEndTime = params.refundEndTime;
whitelistingAllowed = true;
}
function recoverRefundToken() external {
require(msg.sender == owner() || msg.sender == refundReceiver, "SHOVesting: unauthorized");
refundToken.safeTransfer(refundReceiver, refundToken.balanceOf(address(this)));
}
function whitelistUsers(
address[] calldata userAddresses,
uint120[] calldata allocations,
uint120[] calldata refundableAmounts,
bool last
) external onlyOwner {
require(whitelistingAllowed, "SHOVesting: whitelisting not allowed anymore");
require(userAddresses.length != 0, "SHOVesting: zero length array");
require(userAddresses.length == allocations.length, "SHOVesting: different array lengths");
require(userAddresses.length == refundableAmounts.length, "SHOVesting: different array lengths");
uint120 _globalTotalAllocation1;
uint120 _totalRefundableAmount;
for (uint256 i; i < userAddresses.length; i++) {
address userAddress = userAddresses[i];
if (userAddress == feeCollector) {
globalTotalAllocation1 += allocations[i];
extraFees1Allocation += _applyBaseFee(allocations[i]);
continue;
}
require(users1[userAddress].allocation == 0, "SHOVesting: already whitelisted");
users1[userAddress].allocation = allocations[i];
users1[userAddress].refundableAmount = refundableAmounts[i];
_globalTotalAllocation1 += allocations[i];
_totalRefundableAmount += refundableAmounts[i];
emit Whitelist(userAddresses[i], allocations[i]);
}
globalTotalAllocation1 += _globalTotalAllocation1;
totalRefundableAmount += _totalRefundableAmount;
if (last) {
whitelistingAllowed = false;
}
}
function blockUsers(address[] calldata userAddresses, bool state) external onlyOwner {
for (uint i; i < userAddresses.length; i++) {
blockedUsers[userAddresses[i]] = state;
}
emit BlockUsers(userAddresses, state);
}
function claimUser1(address userAddress) onlyWhitelistedUser(userAddress) public nonReentrant returns (uint120 amountToClaim) {
update();
User memory user = users1[userAddress];
if (userAddress != msg.sender) {
require(block.timestamp > refundEndTime, "SHOVesting: refund period");
}
require(passedUnlocksCount > 0, "SHOVesting: no unlocks passed");
require(user.claimedUnlocksCount < passedUnlocksCount, "SHOVesting: nothing to claim");
require(!user.refunded, "SHOVesting: refunded");
require(!blockedUsers[userAddress], "SHOVesting: blocked");
uint16 currentUnlock = passedUnlocksCount - 1;
if (user.eliminatedAfterUnlock > 0) {
require(user.claimedUnlocksCount < user.eliminatedAfterUnlock, "SHOVesting: nothing to claim");
currentUnlock = user.eliminatedAfterUnlock - 1;
}
uint32 lastUnlockPercentage = user.claimedUnlocksCount > 0 ? unlockPercentages[user.claimedUnlocksCount - 1] : 0;
amountToClaim = _applyPercentage(user.allocation, unlockPercentages[currentUnlock] - lastUnlockPercentage);
amountToClaim = _applyBaseFee(amountToClaim);
user.claimedUnlocksCount = currentUnlock + 1;
users1[userAddress] = user;
shoToken.safeTransfer(userAddress, amountToClaim);
emit Claim(userAddress, currentUnlock, amountToClaim);
}
function claimUser1() external returns (uint120 amountToClaim) {
return claimUser1(msg.sender);
}
function refund() external nonReentrant {
update();
require(block.timestamp >= refundStartTime && block.timestamp <= refundEndTime, "SHOVesting: no refund period");
address userAddress = msg.sender;
User storage user = users1[userAddress];
require(user.claimedUnlocksCount == 0, "SHOVesting: claimed");
require(user.eliminatedAfterUnlock == 0, "SHOVesting: eliminated");
require(user.refundableAmount > 0, "SHOVesting: not refundable");
require(!user.refunded, "SHOVesting: already refunded");
uint120 refundAmount = user.refundableAmount;
shoToken.safeTransfer(refundReceiver, user.allocation);
refundToken.safeTransfer(userAddress, refundAmount);
totalRefundedAllocation += user.allocation;
totalRefundedAmount += refundAmount;
user.refunded = true;
emit Refund(userAddress, refundAmount);
}
function eliminateUsers1(address[] calldata userAddresses) external onlyOwner {
update();
require(passedUnlocksCount > 0, "SHOVesting: no unlocks passed");
uint16 currentUnlock = passedUnlocksCount - 1;
require(currentUnlock < unlockPeriods.length - 1, "SHOVesting: eliminating in the last unlock");
for (uint256 i; i < userAddresses.length; i++) {
address userAddress = userAddresses[i];
User memory user = users1[userAddress];
require(user.allocation > 0, "SHOVesting: not whitelisted");
require(!user.refunded, "SHOVesting: refunded");
require(user.eliminatedAfterUnlock == 0, "SHOVesting: already eliminated");
uint120 userAllocation = _applyBaseFee(user.allocation);
uint120 uncollectable = _applyPercentage(userAllocation, unlockPercentages[currentUnlock]);
extraFees1Allocation += userAllocation;
extraFees1AllocationUncollectable += uncollectable;
users1[userAddress].eliminatedAfterUnlock = currentUnlock + 1;
emit UserElimination(userAddress, currentUnlock);
}
}
function collectFees() external nonReentrant returns (uint120 baseFee, uint120 extraFee) {
update();
require(collectedFeesUnlocksCount < passedUnlocksCount, "SHOVesting: no fees to collect");
uint16 currentUnlock = passedUnlocksCount - 1;
uint32 lastUnlockPercentage = collectedFeesUnlocksCount > 0 ? unlockPercentages[collectedFeesUnlocksCount - 1] : 0;
uint120 globalAllocation1 = _applyPercentage(globalTotalAllocation1 - totalRefundedAllocation, unlockPercentages[currentUnlock] - lastUnlockPercentage);
baseFee = _applyPercentage(globalAllocation1, baseFeePercentage1);
uint120 extraFees1AllocationTillNow = _applyPercentage(extraFees1Allocation, unlockPercentages[currentUnlock]);
extraFee = extraFees1AllocationTillNow - extraFees1AllocationUncollectable;
extraFees1AllocationUncollectable = extraFees1AllocationTillNow;
uint120 totalFee = baseFee + extraFee;
collectedFeesUnlocksCount = currentUnlock + 1;
shoToken.safeTransfer(feeCollector, totalFee);
emit FeeCollection(currentUnlock, totalFee, extraFee);
}
function update() public {
uint16 _passedUnlocksCount = getPassedUnlocksCount();
if (_passedUnlocksCount > passedUnlocksCount) {
passedUnlocksCount = _passedUnlocksCount;
emit Update(_passedUnlocksCount);
}
}
function getPassedUnlocksCount() public view returns (uint16 _passedUnlocksCount) {
require(block.timestamp >= startTime, "SHOVesting: before startTime");
uint256 timeSinceStart = block.timestamp - startTime;
uint256 maxReleases = unlockPeriods.length;
_passedUnlocksCount = passedUnlocksCount;
while (_passedUnlocksCount < maxReleases && timeSinceStart >= unlockPeriods[_passedUnlocksCount]) {
_passedUnlocksCount++;
}
}
function getTotalUnlocksCount() public view returns (uint16 totalUnlocksCount) {
return uint16(unlockPercentages.length);
}
function _applyPercentage(uint120 value, uint32 percentage) private pure returns (uint120) {
return uint120(uint256(value) * percentage / HUNDRED_PERCENT);
}
function _applyBaseFee(uint120 value) private view returns (uint120) {
return value - _applyPercentage(value, baseFeePercentage1);
}
function _buildArraySum(uint32[] memory diffArray) internal pure returns (uint32[] memory) {
uint256 len = diffArray.length;
uint32[] memory sumArray = new uint32[](len);
uint32 lastSum = 0;
for (uint256 i; i < len; i++) {
if (i > 0) {
lastSum = sumArray[i - 1];
}
sumArray[i] = lastSum + diffArray[i];
}
return sumArray;
}
}
文件 10 的 10:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
{
"compilationTarget": {
"contracts/SHOVesting.sol": "SHOVesting"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"userAddresses","type":"address[]"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"BlockUsers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint16","name":"currentUnlock","type":"uint16"},{"indexed":false,"internalType":"uint120","name":"claimedTokens","type":"uint120"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"currentUnlock","type":"uint16"},{"indexed":false,"internalType":"uint120","name":"totalFee","type":"uint120"},{"indexed":false,"internalType":"uint120","name":"extraFee","type":"uint120"}],"name":"FeeCollection","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"passedUnlocksCount","type":"uint16"}],"name":"Update","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint16","name":"currentUnlock","type":"uint16"}],"name":"UserElimination","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint120","name":"allocation","type":"uint120"}],"name":"Whitelist","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseFeePercentage1","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"userAddresses","type":"address[]"},{"internalType":"bool","name":"state","type":"bool"}],"name":"blockUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blockedUsers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"claimUser1","outputs":[{"internalType":"uint120","name":"amountToClaim","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimUser1","outputs":[{"internalType":"uint120","name":"amountToClaim","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectFees","outputs":[{"internalType":"uint120","name":"baseFee","type":"uint120"},{"internalType":"uint120","name":"extraFee","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectedFeesUnlocksCount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"userAddresses","type":"address[]"}],"name":"eliminateUsers1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"extraFees1Allocation","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extraFees1AllocationUncollectable","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPassedUnlocksCount","outputs":[{"internalType":"uint16","name":"_passedUnlocksCount","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalUnlocksCount","outputs":[{"internalType":"uint16","name":"totalUnlocksCount","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalTotalAllocation1","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"shoToken","type":"address"},{"internalType":"uint32[]","name":"unlockPercentagesDiff","type":"uint32[]"},{"internalType":"uint32[]","name":"unlockPeriodsDiff","type":"uint32[]"},{"internalType":"uint32","name":"baseFeePercentage1","type":"uint32"},{"internalType":"address","name":"feeCollector","type":"address"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"contract IERC20","name":"refundToken","type":"address"},{"internalType":"address","name":"refundReceiver","type":"address"},{"internalType":"uint64","name":"refundStartTime","type":"uint64"},{"internalType":"uint64","name":"refundEndTime","type":"uint64"}],"internalType":"struct SHOVesting.InitParameters","name":"params","type":"tuple"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recoverRefundToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refundEndTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundStartTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shoToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefundableAmount","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefundedAllocation","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefundedAmount","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"unlockPercentages","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"unlockPeriods","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users1","outputs":[{"internalType":"uint120","name":"allocation","type":"uint120"},{"internalType":"uint120","name":"refundableAmount","type":"uint120"},{"internalType":"uint16","name":"claimedUnlocksCount","type":"uint16"},{"internalType":"uint16","name":"eliminatedAfterUnlock","type":"uint16"},{"internalType":"bool","name":"refunded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"userAddresses","type":"address[]"},{"internalType":"uint120[]","name":"allocations","type":"uint120[]"},{"internalType":"uint120[]","name":"refundableAmounts","type":"uint120[]"},{"internalType":"bool","name":"last","type":"bool"}],"name":"whitelistUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelistingAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]