// SPDX-License-Identifier: MIT
// File: @openzeppelin/contracts@v4.9.0/utils/Context.sol
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// File: @openzeppelin/contracts@v4.9.0/access/Ownable.sol
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: @openzeppelin/contracts@v4.9.0/security/ReentrancyGuard.sol
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
// File: contracts/trebleswap/contracts/IDO/libraries/TransferHelper.sol
pragma solidity ^0.8.13;
library TransferHelper {
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FAILED"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FROM_FAILED"
);
}
function safeTransferNative(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper: NATIVE_TRANSFER_FAILED");
}
}
// File: @openzeppelin/contracts@4.9.0/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}
// File: contracts/trebleswap/contracts/IDO/interfaces/IDOInterface.sol
pragma solidity ^0.8.13;
abstract contract IERC20Extented is IERC20 {
function decimals() public view virtual returns (uint8);
}
enum UnlockToken {
TOKEN,
XTOKEN
}
struct UnlockPercentWithType {
uint256 percent;
}
// File: contracts/trebleswap/contracts/utils/address.sol
pragma solidity ^0.8.13;
library Address {
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in construction,
// since the code is only stored at the end of the constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
// File: contracts/trebleswap/contracts/IDO/IDOProject.sol
pragma solidity ^0.8.21;
contract IDOProject is Ownable, ReentrancyGuard {
using Address for address;
event EProject(bytes32 indexed id, Project project);
// Errors
error EmptyName();
error MustBeContractAddress();
error ProjectNotExist();
error RoundNotExist();
IERC20 USDC;
struct Project {
bytes32 id;
string name;
address tokenAddress;
address xTokenAddress;
uint256 createdAt;
bool active;
}
bytes32[] internal _projectIds;
mapping(bytes32 => Project) internal _projects;
function getProjectIds() external view returns (bytes32[] memory ids) {
return _projectIds;
}
function getProjectInfo(
bytes32 _id
) external view returns (Project memory) {
return _projects[_id];
}
function addProject(
string memory _name,
address _tokenAddress,
address _xTokenAddress
) external onlyOwner returns (bytes32) {
if (bytes(_name).length == 0) {
revert EmptyName();
}
if (!_tokenAddress.isContract()) {
revert MustBeContractAddress();
}
if (!_xTokenAddress.isContract()) {
revert MustBeContractAddress();
}
bytes32 id = keccak256(
abi.encodePacked(msg.sender, _name, block.timestamp, blockhash(block.number - 1))
);
_projects[id] = Project({
id: id,
name: _name,
tokenAddress: _tokenAddress,
xTokenAddress: _xTokenAddress,
createdAt: block.timestamp,
active: true
});
_projectIds.push(id);
emit EProject(id, _projects[id]);
return id;
}
function updateProject(
bytes32 _id,
string memory _name,
address _tokenAddress,
address _xTokenAddress,
bool _active
) external onlyOwner {
if (_projects[_id].createdAt == 0) {
revert ProjectNotExist();
}
_projects[_id].name = _name;
_projects[_id].tokenAddress = _tokenAddress;
_projects[_id].xTokenAddress = _xTokenAddress;
_projects[_id].active = _active;
emit EProject(_id, _projects[_id]);
}
function setUSDCContractAddress(address _address) public onlyOwner {
if (!_address.isContract()) {
revert MustBeContractAddress();
}
USDC = IERC20(_address);
}
function withdrawAnyToken(
address _tokenAddr,
address _to,
uint256 _amount
) external onlyOwner {
TransferHelper.safeTransfer(_tokenAddr, _to, _amount);
}
function withdrawNativeToken(
address _to,
uint256 _amount
) external onlyOwner {
TransferHelper.safeTransferNative(_to, _amount);
}
}
// File: contracts/trebleswap/contracts/IDO/IDORound.sol
pragma solidity ^0.8.21;
contract IDORound is IDOProject {
struct UnlockTable {
uint256[] percent;
uint8[] month;
UnlockToken[] unlockToken;
}
enum DepositToken {
ETH,
ERC20
}
struct Round {
uint256 swapRate;
uint256 start;
uint256 end;
uint256 startClaim;
uint256 allocationToken;
uint256 raisedFunds;
uint256 raisedTokens;
uint256 maxPerWallet;
uint256 minPerWallet;
UnlockTable unlockTable;
uint256 createdAt;
bool checkAllocation;
bool active;
DepositToken depositToken;
}
struct AddRoundToProject {
bytes32 _projectId;
uint256 _swapRate;
uint256 _start;
uint256 _end;
uint256 _startClaim;
uint256 _allocationToken;
uint256 _maxPerWallet;
uint256 _minPerWallet;
UnlockTable _unlockTable;
bool _checkAllocation;
bool _active;
DepositToken _depositToken;
}
mapping(bytes32 => Round[]) internal _rounds;
mapping(address => bool) public whitelists;
modifier checkRound(bytes32 _projectId, uint256 _roundId) {
if (_rounds[_projectId][_roundId].createdAt == 0) {
revert RoundNotExist();
}
_;
}
modifier notContract() {
if (!whitelists[msg.sender]) {
require(!Address.isContract(msg.sender), "Contract not allowed");
require(msg.sender == tx.origin, "Proxy contract not allowed");
}
_;
}
modifier checkPossibilityChangeDataAfterStartRound(
uint256 _start,
uint256 _end
) {
require(
_start > block.timestamp && _end > block.timestamp,
"IDO:: You cannot change data after the start of the round"
);
_;
}
modifier validateCreateRound(AddRoundToProject memory roundData) {
if (_projects[roundData._projectId].createdAt == 0) {
revert ProjectNotExist();
}
require(
roundData._end > roundData._start,
"IDO:: End must be more than start"
);
require(
roundData._startClaim > roundData._end,
"IDO:: Start claim must be more than end"
);
require(roundData._swapRate > 0, "IDO:: Swap rate must be more 0");
require(
roundData._start > block.timestamp,
"IDO:: Start must be more than now"
);
require(
roundData._allocationToken > 0,
"IDO:: AllocationToken must be more 0"
);
require(
roundData._unlockTable.percent.length ==
roundData._unlockTable.month.length &&
roundData._unlockTable.percent.length ==
roundData._unlockTable.unlockToken.length,
"IDO:: UnlockTable must be the same length."
);
_;
}
function updateWhitelist(
address _address,
bool _status
) external onlyOwner {
whitelists[_address] = _status;
}
function addRoundToProject(
AddRoundToProject memory roundData
) external onlyOwner validateCreateRound(roundData) returns (uint256) {
_rounds[roundData._projectId].push(
Round({
swapRate: roundData._swapRate,
start: roundData._start,
end: roundData._end,
startClaim: roundData._startClaim,
allocationToken: roundData._allocationToken,
raisedFunds: 0,
raisedTokens: 0,
unlockTable: roundData._unlockTable,
active: roundData._active,
checkAllocation: roundData._checkAllocation,
createdAt: block.timestamp,
depositToken: roundData._depositToken,
maxPerWallet: roundData._maxPerWallet,
minPerWallet: roundData._minPerWallet
})
);
uint256 roundIndex = _rounds[roundData._projectId].length - 1;
return roundIndex;
}
function updateRound(
AddRoundToProject memory roundData,
uint256 _roundId
)
external
onlyOwner
validateCreateRound(roundData)
checkRound(roundData._projectId, _roundId)
{
if (
possibilityChangeData(
_rounds[roundData._projectId][_roundId].start,
_rounds[roundData._projectId][_roundId].end
)
) {
_rounds[roundData._projectId][_roundId].swapRate = roundData
._swapRate;
_rounds[roundData._projectId][_roundId].start = roundData._start;
_rounds[roundData._projectId][_roundId].end = roundData._end;
_rounds[roundData._projectId][_roundId].startClaim = roundData
._startClaim;
_rounds[roundData._projectId][_roundId].allocationToken = roundData
._allocationToken;
_rounds[roundData._projectId][_roundId].unlockTable = roundData
._unlockTable;
_rounds[roundData._projectId][_roundId].active = roundData._active;
_rounds[roundData._projectId][_roundId].checkAllocation = roundData
._checkAllocation;
_rounds[roundData._projectId][_roundId].depositToken = roundData
._depositToken;
_rounds[roundData._projectId][_roundId].maxPerWallet = roundData
._maxPerWallet;
_rounds[roundData._projectId][_roundId].minPerWallet = roundData
._minPerWallet;
}
}
function updateRoundActive(
bytes32 _projectId,
uint256 _roundId,
bool _active
) external onlyOwner checkRound(_projectId, _roundId) {
_rounds[_projectId][_roundId].active = _active;
}
function updateRoundCheckAllocation(
bytes32 _projectId,
uint256 _roundId,
bool _status
) external onlyOwner checkRound(_projectId, _roundId) {
_rounds[_projectId][_roundId].checkAllocation = _status;
}
function updateRoundAllocation(
bytes32 _projectId,
uint256 _roundId,
uint256 _allocation
) external onlyOwner checkRound(_projectId, _roundId) {
_rounds[_projectId][_roundId].allocationToken = _allocation;
}
function updateRoundMinPerWallet(
bytes32 _projectId,
uint256 _roundId,
uint256 _value
) external onlyOwner checkRound(_projectId, _roundId) {
_rounds[_projectId][_roundId].minPerWallet = _value;
}
function updateRoundMaxPerWallet(
bytes32 _projectId,
uint256 _roundId,
uint256 _value
) external onlyOwner checkRound(_projectId, _roundId) {
_rounds[_projectId][_roundId].maxPerWallet = _value;
}
function roundsByProject(
bytes32 _projectId
) external view returns (Round[] memory) {
return _rounds[_projectId];
}
function roundInfo(
bytes32 _projectId,
uint256 _roundId
) external view returns (Round memory) {
return _rounds[_projectId][_roundId];
}
function possibilityChangeData(
uint256 _start,
uint256 _end
)
public
view
checkPossibilityChangeDataAfterStartRound(_start, _end)
returns (bool)
{
return true;
}
}
// File: contracts/trebleswap/contracts/IDO/libraries/IDOLibrary.sol
pragma solidity ^0.8.13;
library IDOLibrary {
struct CalculatePercent {
uint256 calcPercent;
uint256 lastPercent;
uint8 lastMonth;
UnlockToken lastUnlockToken;
bool checkLastMonth;
bool checkDetectMonth;
UnlockPercentWithType[2] unlockPercentWithType;
}
function _convertFromDecimalToDecimal(
uint256 a,
uint256 b,
uint256 decimalFrom,
uint256 decimalTo
) internal pure returns (uint256) {
if (decimalFrom >= decimalTo) {
return
((a * (10 ** decimalFrom)) / (b)) /
(10 ** ((decimalFrom - decimalTo)));
}
return
((a * (10 ** (decimalFrom + decimalTo))) / (b)) *
(10 ** ((decimalFrom)));
}
function _calcul(
uint256 a,
uint256 b,
uint256 precision
) internal pure returns (uint256) {
return (a * (10 ** precision)) / b;
}
uint256 internal constant _daysInMonth = 30 days;
uint256 internal constant _secondsInDay = 86400;
uint256 internal constant _maxPercent = 100000000000000000000;
function _diffDays(
uint256 _startClaim,
uint256 _timeNow,
uint8 _month
) private pure returns (uint256) {
return ((_startClaim + (_month * _daysInMonth)) - _timeNow) / 1 days;
}
function _diffSeconds(
uint256 _timeNow,
uint256 _startClaim,
uint8 _month
) private pure returns (uint256) {
return _timeNow - ((_month * _daysInMonth) + _startClaim);
}
function _recalculatePercent(
uint256 _timeNow,
uint256 _startClaim,
uint256 _unlockedPercent,
uint8 _month
) private pure returns (uint256) {
uint256 diffSeconds = _diffSeconds(_timeNow, _startClaim, _month);
uint256 apySeconds = (_unlockedPercent / 30) / _secondsInDay;
return diffSeconds * apySeconds;
}
function _percentClaim(
uint256[] memory _percents,
uint8[] memory _months,
UnlockToken[] memory _unlockTokens,
uint256 _startClaim,
uint256 _timeNow
) internal pure returns (uint256, UnlockPercentWithType[2] memory) {
CalculatePercent memory vars;
for (uint8 i = 0; i < _percents.length; i++) {
UnlockToken unLockedToken = _unlockTokens[i];
if (_timeNow < _startClaim + (_months[i] * _daysInMonth)) {
uint256 diffDays = _diffDays(
_startClaim,
_timeNow,
_months[i]
);
if (vars.checkDetectMonth == false && diffDays <= 30) {
uint8 prevMonth = 0;
if (i != 0) {
prevMonth = _months[i - 1];
}
uint256 calcul = _recalculatePercent(
_timeNow,
_startClaim,
_percents[i],
prevMonth
);
vars.calcPercent += calcul;
vars.unlockPercentWithType[uint256(unLockedToken)]
.percent += calcul;
vars.checkDetectMonth = true;
} else {
continue;
}
if (i == _percents.length - 1) {
vars.checkLastMonth = true;
vars.lastPercent = _percents[i];
vars.lastMonth = _months[i];
vars.lastUnlockToken = unLockedToken;
}
} else {
vars.calcPercent += _percents[i];
vars.unlockPercentWithType[uint256(unLockedToken)]
.percent += _percents[i];
if (i == _percents.length - 1) {
vars.checkLastMonth = true;
vars.lastPercent = _percents[i];
vars.lastMonth = _months[i];
vars.lastUnlockToken = unLockedToken;
}
}
}
if (vars.checkLastMonth && vars.calcPercent < _maxPercent) {
vars.checkDetectMonth == false;
uint256 calcMissingMonth = (_maxPercent - vars.calcPercent) /
vars.lastPercent;
for (uint8 i = 1; i <= calcMissingMonth; i++) {
uint8 nextMonth = vars.lastMonth + i;
if (_timeNow < _startClaim + (nextMonth * _daysInMonth)) {
uint256 diffDays = _diffDays(
_startClaim,
_timeNow,
nextMonth
);
if (vars.checkDetectMonth == false && diffDays <= 30) {
uint8 prevMonth = nextMonth - 1;
uint256 calcul = _recalculatePercent(
_timeNow,
_startClaim,
vars.lastPercent,
prevMonth
);
vars.calcPercent += calcul;
vars.unlockPercentWithType[uint256(vars.lastUnlockToken)]
.percent += calcul;
vars.checkDetectMonth = true;
} else {
continue;
}
} else {
vars.calcPercent += vars.lastPercent;
vars.unlockPercentWithType[uint256(vars.lastUnlockToken)]
.percent += vars.lastPercent;
}
}
}
return (vars.calcPercent, vars.unlockPercentWithType);
}
function _calculateLastMonth(
uint256[] memory _percents,
uint8[] memory _months
) internal pure returns (uint8) {
CalculatePercent memory vars;
for (uint8 i = 0; i < _percents.length; i++) {
uint256 percent = _percents[i];
vars.calcPercent += percent;
if (i == _percents.length - 1) {
vars.checkLastMonth = true;
vars.lastPercent = percent;
vars.lastMonth = _months[i];
}
}
if (vars.checkLastMonth && vars.calcPercent < _maxPercent) {
uint256 calcMissingMonth = (_maxPercent - vars.calcPercent) /
vars.lastPercent;
for (uint8 i = 1; i <= calcMissingMonth; i++) {
vars.lastMonth += 1;
}
}
return vars.lastMonth;
}
}
// File: contracts/trebleswap/contracts/IDO/IDOPurchase.sol
pragma solidity ^0.8.21;
contract IDOPurchase is IDORound {
event EPurchase(
Purchase pur
);
struct Purchase {
address user;
uint256 amountToken;
uint256 amount;
uint256 factAmount;
uint256 roundId;
uint256 timestamp;
bytes32 projectId;
}
struct CreatePurchase {
bytes32 _projectId;
uint8 _roundId;
uint256 _deposit;
uint256 _factDeposit;
address _destination;
}
mapping(address => mapping(bytes32 => mapping(uint8 => uint256)))
internal _balances;
mapping(address => mapping(bytes32 => mapping(uint8 => uint256)))
internal _investments;
mapping(address => Purchase[]) internal _purchases;
mapping(bytes32 => mapping(uint8 => address[])) internal _purchaseUsers;
modifier checkPurchase(
bytes32 _projectId,
uint8 _roundId,
uint256 _deposit
) {
require(
_rounds[_projectId][_roundId].start < block.timestamp &&
_rounds[_projectId][_roundId].end > block.timestamp &&
_rounds[_projectId][_roundId].active == true,
"IDO::purchase: Round NA."
);
require(_deposit > 0, "IDO::purchase: MM 0.");
if (_rounds[_projectId][_roundId].minPerWallet > 0) {
require(
_rounds[_projectId][_roundId].minPerWallet <= _deposit,
"IDO::purchase: MIN PW."
);
}
if (_rounds[_projectId][_roundId].maxPerWallet > 0) {
require(
investmentInfo(_projectId, _roundId) + _deposit <=
_rounds[_projectId][_roundId].maxPerWallet,
"IDO::purchase: MAX PW"
);
}
uint8 decimals = IERC20Extented(_projects[_projectId].tokenAddress)
.decimals();
uint256 amountToken = IDOLibrary._convertFromDecimalToDecimal(
_deposit,
_rounds[_projectId][_roundId].swapRate,
_rounds[_projectId][_roundId].depositToken == DepositToken.ETH
? 18
: 6,
decimals
);
if (_rounds[_projectId][_roundId].checkAllocation) {
require(
_rounds[_projectId][_roundId].allocationToken >=
_rounds[_projectId][_roundId].raisedTokens + amountToken,
"Your deposit exceeds the Total Raise limit"
);
}
_;
}
modifier checkPurchaseByWl(
uint256 _deposit,
uint256 _factDeposit,
address _destination
) {
if (!whitelists[msg.sender]) {
require(msg.sender == _destination, "Dest must be eq sender");
require(_deposit == _factDeposit, "Deposits must be eq");
}
_;
}
function balanceOf(
bytes32 _projectId,
uint8 _roundId
) public view returns (uint256) {
return _balances[msg.sender][_projectId][_roundId];
}
function investmentInfo(
bytes32 _projectId,
uint8 _roundId
) public view returns (uint256) {
return _investments[msg.sender][_projectId][_roundId];
}
function purchase(
CreatePurchase memory p
)
external
payable
checkRound(p._projectId, p._roundId)
checkPurchase(p._projectId, p._roundId, p._factDeposit)
nonReentrant
notContract
checkPurchaseByWl(p._deposit, p._factDeposit, p._destination)
{
_purchase(p);
}
function _purchase(
CreatePurchase memory pur
) internal {
uint256 timeStamp = block.timestamp;
uint8 depositDecimals = 6;
bool admin = false;
if (msg.sender == owner()) {
admin = true;
}
if (_rounds[pur._projectId][pur._roundId].depositToken == DepositToken.ETH) {
if (!admin) {
require(msg.value == pur._deposit, "IDO::p: Eth NE deposit");
}
depositDecimals = 18;
} else {
if (!admin) {
require(
USDC.allowance(msg.sender, address(this)) >= pur._deposit,
"IDO::p: Error Allowance"
);
require(
USDC.transferFrom(msg.sender, address(this), pur._deposit) == true,
"IDO::p: Transfer error"
);
}
}
uint8 decimals = IERC20Extented(_projects[pur._projectId].tokenAddress)
.decimals();
uint256 amountToken = IDOLibrary._convertFromDecimalToDecimal(
pur._deposit,
_rounds[pur._projectId][pur._roundId].swapRate,
depositDecimals,
decimals
);
_investments[pur._destination][pur._projectId][pur._roundId] += pur._factDeposit;
uint256 convertToken = IDOLibrary._convertFromDecimalToDecimal(
_investments[pur._destination][pur._projectId][pur._roundId],
_rounds[pur._projectId][pur._roundId].swapRate,
depositDecimals,
decimals
);
_balances[pur._destination][pur._projectId][pur._roundId] = convertToken;
Purchase memory p = Purchase({
user: pur._destination,
amount: pur._deposit,
amountToken: amountToken,
factAmount: pur._factDeposit,
roundId: pur._roundId,
projectId: pur._projectId,
timestamp: timeStamp
});
_purchases[pur._destination].push(p);
_rounds[pur._projectId][pur._roundId].raisedFunds += pur._factDeposit;
uint256 convertDeposit = IDOLibrary._convertFromDecimalToDecimal(
_rounds[pur._projectId][pur._roundId].raisedFunds,
_rounds[pur._projectId][pur._roundId].swapRate,
depositDecimals,
decimals
);
_rounds[pur._projectId][pur._roundId].raisedTokens = convertDeposit;
bool checkUser = false;
for (
uint256 i = 0;
i < _purchaseUsers[pur._projectId][pur._roundId].length;
i++
) {
address item = _purchaseUsers[pur._projectId][pur._roundId][i];
if (item == pur._destination) {
checkUser = true;
break;
}
}
if (checkUser == false) {
_purchaseUsers[pur._projectId][pur._roundId].push(pur._destination);
}
emit EPurchase(p);
}
function purchasesByUser(
address _account
) external view returns (Purchase[] memory) {
return _purchases[_account];
}
function usersByProjectRound(
bytes32 _projectId,
uint8 _roundId
) external view onlyOwner returns (address[] memory) {
return _purchaseUsers[_projectId][_roundId];
}
}
// File: contracts/trebleswap/contracts/IDO/IDOClaim.sol
pragma solidity ^0.8.21;
contract IDOClaim is IDOPurchase {
struct Claim {
address user;
uint256 amountToken;
uint256 standardAmoutToken;
uint256 xAmountToken;
uint256 roundId;
uint256 timestamp;
bytes32 projectId;
}
struct PossibilityClaim {
uint256 token;
uint256 xToken;
}
struct ClaimInfo {
address account;
Project project;
PossibilityClaim possibilityClaim;
uint256 balance;
}
event EClaim(address indexed user, Claim claim);
mapping(address => Claim[]) internal _claims;
mapping(address => mapping(bytes32 => mapping(uint8 => uint256)))
internal _distributionMaxPossibility;
modifier checkStartClaim(bytes32 _projectId, uint256 _roundId) {
require(
block.timestamp > _rounds[_projectId][_roundId].startClaim &&
_rounds[_projectId][_roundId].active == true,
"IDO::Claim hasn't started"
);
_;
}
modifier setDistributionTokenBeforeFirstClaim(
bytes32 _projectId,
uint256 _roundId
) {
if (
_distributionMaxPossibility[msg.sender][_projectId][
uint8(_roundId)
] == 0
) {
uint256 distributionValue = _balances[msg.sender][_projectId][
uint8(_roundId)
];
_distributionMaxPossibility[msg.sender][_projectId][
uint8(_roundId)
] = distributionValue;
}
_;
}
constructor(address _usdc) {
setUSDCContractAddress(_usdc);
}
function claim(
bytes32 _projectId,
uint256 _roundId
)
external
checkRound(_projectId, _roundId)
checkStartClaim(_projectId, _roundId)
setDistributionTokenBeforeFirstClaim(_projectId, _roundId)
nonReentrant
notContract
{
ClaimInfo memory claimInfo;
claimInfo.account = msg.sender;
claimInfo.project = _projects[_projectId];
claimInfo.possibilityClaim = _possibilityClaim(
_projectId,
_roundId,
claimInfo.account
);
claimInfo.balance = balanceOf(_projectId, uint8(_roundId));
uint256 actualBalanceToken = IERC20Extented(
claimInfo.project.tokenAddress
).balanceOf(address(this));
uint256 actualBalancexToken = actualBalanceToken;
if (claimInfo.project.tokenAddress != claimInfo.project.xTokenAddress) {
actualBalancexToken = IERC20Extented(
claimInfo.project.xTokenAddress
).balanceOf(address(this));
}
if (claimInfo.possibilityClaim.token > 0) {
require(
actualBalanceToken >= claimInfo.possibilityClaim.token,
"IDO::INSUF TOKEN"
);
TransferHelper.safeTransfer(
claimInfo.project.tokenAddress,
claimInfo.account,
claimInfo.possibilityClaim.token
);
}
if (claimInfo.possibilityClaim.xToken > 0) {
require(
actualBalancexToken >= claimInfo.possibilityClaim.xToken,
"IDO::INSUF X TOKEN"
);
TransferHelper.safeTransfer(
claimInfo.project.xTokenAddress,
claimInfo.account,
claimInfo.possibilityClaim.xToken
);
}
uint256 amountToken = claimInfo.possibilityClaim.token +
claimInfo.possibilityClaim.xToken;
_balances[claimInfo.account][_projectId][
uint8(_roundId)
] -= amountToken;
Claim memory claimData = Claim({
user: claimInfo.account,
amountToken: amountToken,
standardAmoutToken: claimInfo.possibilityClaim.token,
xAmountToken: claimInfo.possibilityClaim.xToken,
roundId: _roundId,
projectId: _projectId,
timestamp: block.timestamp
});
_claims[claimInfo.account].push(claimData);
emit EClaim(claimInfo.account, claimData);
}
function maxPossiblityClaim(
bytes32 _projectId,
uint256 _roundId,
address _account
)
public
view
checkRound(_projectId, _roundId)
checkStartClaim(_projectId, _roundId)
returns (uint256)
{
return _maxPossiblityClaim(_projectId, _roundId, _account);
}
function _maxPossiblityClaim(
bytes32 _projectId,
uint256 _roundId,
address _account
) internal view returns (uint256) {
uint256 distMaxPossibility = 0;
if (
_distributionMaxPossibility[_account][_projectId][uint8(_roundId)] >
0
) {
distMaxPossibility = _distributionMaxPossibility[_account][
_projectId
][uint8(_roundId)];
} else {
distMaxPossibility = _balances[msg.sender][_projectId][
uint8(_roundId)
];
}
return distMaxPossibility;
}
function alreadyClaim(
bytes32 _projectId,
uint256 _roundId
)
external
view
checkRound(_projectId, _roundId)
checkStartClaim(_projectId, _roundId)
returns (uint256 fullClaims, uint256 standardClaims, uint256 xClaims)
{
return _alreadyClaim(_projectId, _roundId, msg.sender);
}
function _alreadyClaim(bytes32 _projectId, uint256 _roundId, address _account) internal view returns (uint256 fullClaims, uint256 standardClaims, uint256 xClaims) {
for (uint256 i = 0; i < _claims[_account].length; i++) {
if (
_claims[_account][i].projectId == _projectId &&
_claims[_account][i].roundId == _roundId
) {
fullClaims += _claims[_account][i].amountToken;
standardClaims += _claims[_account][i].standardAmoutToken;
xClaims += _claims[_account][i].xAmountToken;
}
}
return (fullClaims, standardClaims, xClaims);
}
function _getFirstPurchaseByRound(
bytes32 _projectId,
uint256 _roundId,
address _account
) internal view returns (Purchase memory purchase) {
for (uint256 i = 0; i < _purchases[_account].length; i++) {
if (
_purchases[_account][i].projectId == _projectId &&
_purchases[_account][i].roundId == _roundId
) {
purchase = _purchases[_account][i];
break;
}
}
}
function possibilityClaim(
bytes32 _projectId,
uint256 _roundId,
address _account
)
external
view
checkRound(_projectId, _roundId)
checkStartClaim(_projectId, _roundId)
returns (PossibilityClaim memory)
{
return _possibilityClaim(_projectId, _roundId, _account);
}
function _possibilityClaim(
bytes32 _projectId,
uint256 _roundId,
address _account
) internal view returns (PossibilityClaim memory posInfo) {
uint256 balance = _balances[_account][_projectId][uint8(_roundId)];
if (balance == 0) {
return posInfo;
}
posInfo = _currentMaxPosibilityClaim(_projectId, _roundId, _account);
(uint256 fullClaims, uint256 standardClaims, uint256 xClaims) = _alreadyClaim(_projectId, _roundId, _account);
if (
_maxPossiblityClaim(_projectId, _roundId, _account) >= balance &&
fullClaims > 0
) {
posInfo.token = posInfo.token - standardClaims;
posInfo.xToken = posInfo.xToken - xClaims;
}
}
function _currentMaxPosibilityClaim(
bytes32 _projectId,
uint256 _roundId,
address _address
) internal view returns (PossibilityClaim memory posInfo) {
uint8 decimalsToken = IERC20Extented(_projects[_projectId].tokenAddress)
.decimals();
uint8 xDecimalsToken = IERC20Extented(_projects[_projectId].xTokenAddress)
.decimals();
(
,
UnlockPercentWithType[2] memory unlockPercentWithType
) = IDOLibrary._percentClaim(
_rounds[_projectId][_roundId].unlockTable.percent,
_rounds[_projectId][_roundId].unlockTable.month,
_rounds[_projectId][_roundId].unlockTable.unlockToken,
_rounds[_projectId][_roundId].startClaim,
block.timestamp
);
if (unlockPercentWithType[0].percent > 0) {
posInfo.token = _calcClaimValue(
unlockPercentWithType[0].percent,
decimalsToken,
_projectId,
_roundId,
_address
);
}
if (unlockPercentWithType[1].percent > 0) {
posInfo.xToken = _calcClaimValue(
unlockPercentWithType[1].percent,
xDecimalsToken,
_projectId,
_roundId,
_address
);
}
}
function _calcClaimValue(
uint256 _percent,
uint8 _decimalsToken,
bytes32 _projectId,
uint256 _roundId,
address _address
) private view returns (uint256) {
uint256 percent = IDOLibrary._convertFromDecimalToDecimal(
_percent,
1000000000000000000,
18,
_decimalsToken
);
return
(percent * _maxPossiblityClaim(_projectId, _roundId, _address)) /
IDOLibrary._convertFromDecimalToDecimal(
100000000000000000000,
1000000000000000000,
18,
_decimalsToken
);
}
function startVesting(
bytes32 _projectId,
uint256 _roundId
) public view checkRound(_projectId, _roundId) returns (uint256) {
return _rounds[_projectId][_roundId].startClaim;
}
function endVesting(
bytes32 _projectId,
uint256 _roundId
) external view checkRound(_projectId, _roundId) returns (uint256) {
uint8 lastMonth = IDOLibrary._calculateLastMonth(
_rounds[_projectId][_roundId].unlockTable.percent,
_rounds[_projectId][_roundId].unlockTable.month
);
return
startVesting(_projectId, _roundId) +
(lastMonth * IDOLibrary._daysInMonth);
}
}
{
"compilationTarget": {
"IDOClaim.sol": "IDOClaim"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_usdc","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EmptyName","type":"error"},{"inputs":[],"name":"MustBeContractAddress","type":"error"},{"inputs":[],"name":"ProjectNotExist","type":"error"},{"inputs":[],"name":"RoundNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"standardAmoutToken","type":"uint256"},{"internalType":"uint256","name":"xAmountToken","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"projectId","type":"bytes32"}],"indexed":false,"internalType":"struct IDOClaim.Claim","name":"claim","type":"tuple"}],"name":"EClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"xTokenAddress","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"indexed":false,"internalType":"struct IDOProject.Project","name":"project","type":"tuple"}],"name":"EProject","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"factAmount","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"projectId","type":"bytes32"}],"indexed":false,"internalType":"struct IDOPurchase.Purchase","name":"pur","type":"tuple"}],"name":"EPurchase","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"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_xTokenAddress","type":"address"}],"name":"addProject","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_swapRate","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"},{"internalType":"uint256","name":"_startClaim","type":"uint256"},{"internalType":"uint256","name":"_allocationToken","type":"uint256"},{"internalType":"uint256","name":"_maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"_minPerWallet","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"percent","type":"uint256[]"},{"internalType":"uint8[]","name":"month","type":"uint8[]"},{"internalType":"enum UnlockToken[]","name":"unlockToken","type":"uint8[]"}],"internalType":"struct IDORound.UnlockTable","name":"_unlockTable","type":"tuple"},{"internalType":"bool","name":"_checkAllocation","type":"bool"},{"internalType":"bool","name":"_active","type":"bool"},{"internalType":"enum IDORound.DepositToken","name":"_depositToken","type":"uint8"}],"internalType":"struct IDORound.AddRoundToProject","name":"roundData","type":"tuple"}],"name":"addRoundToProject","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"alreadyClaim","outputs":[{"internalType":"uint256","name":"fullClaims","type":"uint256"},{"internalType":"uint256","name":"standardClaims","type":"uint256"},{"internalType":"uint256","name":"xClaims","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint8","name":"_roundId","type":"uint8"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"endVesting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProjectIds","outputs":[{"internalType":"bytes32[]","name":"ids","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getProjectInfo","outputs":[{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"xTokenAddress","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct IDOProject.Project","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint8","name":"_roundId","type":"uint8"}],"name":"investmentInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"maxPossiblityClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"possibilityChangeData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"possibilityClaim","outputs":[{"components":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"uint256","name":"xToken","type":"uint256"}],"internalType":"struct IDOClaim.PossibilityClaim","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint8","name":"_roundId","type":"uint8"},{"internalType":"uint256","name":"_deposit","type":"uint256"},{"internalType":"uint256","name":"_factDeposit","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"}],"internalType":"struct IDOPurchase.CreatePurchase","name":"p","type":"tuple"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"purchasesByUser","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"factAmount","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"projectId","type":"bytes32"}],"internalType":"struct IDOPurchase.Purchase[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"roundInfo","outputs":[{"components":[{"internalType":"uint256","name":"swapRate","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"startClaim","type":"uint256"},{"internalType":"uint256","name":"allocationToken","type":"uint256"},{"internalType":"uint256","name":"raisedFunds","type":"uint256"},{"internalType":"uint256","name":"raisedTokens","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"minPerWallet","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"percent","type":"uint256[]"},{"internalType":"uint8[]","name":"month","type":"uint8[]"},{"internalType":"enum UnlockToken[]","name":"unlockToken","type":"uint8[]"}],"internalType":"struct IDORound.UnlockTable","name":"unlockTable","type":"tuple"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"bool","name":"checkAllocation","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"enum IDORound.DepositToken","name":"depositToken","type":"uint8"}],"internalType":"struct IDORound.Round","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"}],"name":"roundsByProject","outputs":[{"components":[{"internalType":"uint256","name":"swapRate","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"startClaim","type":"uint256"},{"internalType":"uint256","name":"allocationToken","type":"uint256"},{"internalType":"uint256","name":"raisedFunds","type":"uint256"},{"internalType":"uint256","name":"raisedTokens","type":"uint256"},{"internalType":"uint256","name":"maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"minPerWallet","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"percent","type":"uint256[]"},{"internalType":"uint8[]","name":"month","type":"uint8[]"},{"internalType":"enum UnlockToken[]","name":"unlockToken","type":"uint8[]"}],"internalType":"struct IDORound.UnlockTable","name":"unlockTable","type":"tuple"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"bool","name":"checkAllocation","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"enum IDORound.DepositToken","name":"depositToken","type":"uint8"}],"internalType":"struct IDORound.Round[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setUSDCContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"startVesting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_xTokenAddress","type":"address"},{"internalType":"bool","name":"_active","type":"bool"}],"name":"updateProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_swapRate","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"},{"internalType":"uint256","name":"_startClaim","type":"uint256"},{"internalType":"uint256","name":"_allocationToken","type":"uint256"},{"internalType":"uint256","name":"_maxPerWallet","type":"uint256"},{"internalType":"uint256","name":"_minPerWallet","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"percent","type":"uint256[]"},{"internalType":"uint8[]","name":"month","type":"uint8[]"},{"internalType":"enum UnlockToken[]","name":"unlockToken","type":"uint8[]"}],"internalType":"struct IDORound.UnlockTable","name":"_unlockTable","type":"tuple"},{"internalType":"bool","name":"_checkAllocation","type":"bool"},{"internalType":"bool","name":"_active","type":"bool"},{"internalType":"enum IDORound.DepositToken","name":"_depositToken","type":"uint8"}],"internalType":"struct IDORound.AddRoundToProject","name":"roundData","type":"tuple"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"updateRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"bool","name":"_active","type":"bool"}],"name":"updateRoundActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"uint256","name":"_allocation","type":"uint256"}],"name":"updateRoundAllocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateRoundCheckAllocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"updateRoundMaxPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint256","name":"_roundId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"updateRoundMinPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_projectId","type":"bytes32"},{"internalType":"uint8","name":"_roundId","type":"uint8"}],"name":"usersByProjectRound","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAnyToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawNativeToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]