// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/governance/IGovernor.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "./IAgentFactoryV3.sol";
import "./IAgentToken.sol";
import "./IAgentVeToken.sol";
import "./IAgentDAO.sol";
import "./IAgentNft.sol";
import "../libs/IERC6551Registry.sol";
contract AgentFactoryV3 is
IAgentFactoryV3,
Initializable,
AccessControl,
PausableUpgradeable
{
using SafeERC20 for IERC20;
uint256 private _nextId;
address public tokenImplementation;
address public daoImplementation;
address public nft;
address public tbaRegistry; // Token bound account
uint256 public applicationThreshold;
address[] public allTokens;
address[] public allDAOs;
address public assetToken; // Base currency
uint256 public maturityDuration; // Staking duration in seconds for initial LP. eg: 10years
bytes32 public constant WITHDRAW_ROLE = keccak256("WITHDRAW_ROLE"); // Able to withdraw and execute applications
event NewPersona(
uint256 virtualId,
address token,
address dao,
address tba,
address veToken,
address lp
);
event NewApplication(uint256 id);
enum ApplicationStatus {
Active,
Executed,
Withdrawn
}
struct Application {
string name;
string symbol;
string tokenURI;
ApplicationStatus status;
uint256 withdrawableAmount;
address proposer;
uint8[] cores;
uint256 proposalEndBlock;
uint256 virtualId;
bytes32 tbaSalt;
address tbaImplementation;
uint32 daoVotingPeriod;
uint256 daoThreshold;
}
mapping(uint256 => Application) private _applications;
address public gov; // Deprecated in v2, execution of application does not require DAO decision anymore
modifier onlyGov() {
require(msg.sender == gov, "Only DAO can execute proposal");
_;
}
event ApplicationThresholdUpdated(uint256 newThreshold);
event GovUpdated(address newGov);
event ImplContractsUpdated(address token, address dao);
address private _vault; // Vault to hold all Virtual NFTs
bool internal locked;
modifier noReentrant() {
require(!locked, "cannot reenter");
locked = true;
_;
locked = false;
}
///////////////////////////////////////////////////////////////
// V2 Storage
///////////////////////////////////////////////////////////////
address[] public allTradingTokens;
address private _uniswapRouter;
address public veTokenImplementation;
address private _minter; // Unused
address private _tokenAdmin;
address public defaultDelegatee;
// Default agent token params
bytes private _tokenSupplyParams;
bytes private _tokenTaxParams;
uint16 private _tokenMultiplier; // Unused
bytes32 public constant BONDING_ROLE = keccak256("BONDING_ROLE");
///////////////////////////////////////////////////////////////
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
address tokenImplementation_,
address veTokenImplementation_,
address daoImplementation_,
address tbaRegistry_,
address assetToken_,
address nft_,
uint256 applicationThreshold_,
address vault_,
uint256 nextId_
) public initializer {
__Pausable_init();
tokenImplementation = tokenImplementation_;
veTokenImplementation = veTokenImplementation_;
daoImplementation = daoImplementation_;
assetToken = assetToken_;
tbaRegistry = tbaRegistry_;
nft = nft_;
applicationThreshold = applicationThreshold_;
_nextId = nextId_;
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_vault = vault_;
}
function getApplication(
uint256 proposalId
) public view returns (Application memory) {
return _applications[proposalId];
}
function proposeAgent(
string memory name,
string memory symbol,
string memory tokenURI,
uint8[] memory cores,
bytes32 tbaSalt,
address tbaImplementation,
uint32 daoVotingPeriod,
uint256 daoThreshold
) public whenNotPaused returns (uint256) {
address sender = _msgSender();
require(
IERC20(assetToken).balanceOf(sender) >= applicationThreshold,
"Insufficient asset token"
);
require(
IERC20(assetToken).allowance(sender, address(this)) >=
applicationThreshold,
"Insufficient asset token allowance"
);
require(cores.length > 0, "Cores must be provided");
IERC20(assetToken).safeTransferFrom(
sender,
address(this),
applicationThreshold
);
uint256 id = _nextId++;
uint256 proposalEndBlock = block.number; // No longer required in v2
Application memory application = Application(
name,
symbol,
tokenURI,
ApplicationStatus.Active,
applicationThreshold,
sender,
cores,
proposalEndBlock,
0,
tbaSalt,
tbaImplementation,
daoVotingPeriod,
daoThreshold
);
_applications[id] = application;
emit NewApplication(id);
return id;
}
function withdraw(uint256 id) public noReentrant {
Application storage application = _applications[id];
require(
msg.sender == application.proposer ||
hasRole(WITHDRAW_ROLE, msg.sender),
"Not proposer"
);
require(
application.status == ApplicationStatus.Active,
"Application is not active"
);
require(
block.number > application.proposalEndBlock,
"Application is not matured yet"
);
uint256 withdrawableAmount = application.withdrawableAmount;
application.withdrawableAmount = 0;
application.status = ApplicationStatus.Withdrawn;
IERC20(assetToken).safeTransfer(
application.proposer,
withdrawableAmount
);
}
function _executeApplication(
uint256 id,
bool canStake,
bytes memory tokenSupplyParams_
) internal {
require(
_applications[id].status == ApplicationStatus.Active,
"Application is not active"
);
require(_tokenAdmin != address(0), "Token admin not set");
Application storage application = _applications[id];
uint256 initialAmount = application.withdrawableAmount;
application.withdrawableAmount = 0;
application.status = ApplicationStatus.Executed;
// C1
address token = _createNewAgentToken(
application.name,
application.symbol,
tokenSupplyParams_
);
// C2
address lp = IAgentToken(token).liquidityPools()[0];
IERC20(assetToken).safeTransfer(token, initialAmount);
IAgentToken(token).addInitialLiquidity(address(this));
// C3
address veToken = _createNewAgentVeToken(
string.concat("Staked ", application.name),
string.concat("s", application.symbol),
lp,
application.proposer,
canStake
);
// C4
string memory daoName = string.concat(application.name, " DAO");
address payable dao = payable(
_createNewDAO(
daoName,
IVotes(veToken),
application.daoVotingPeriod,
application.daoThreshold
)
);
// C5
uint256 virtualId = IAgentNft(nft).nextVirtualId();
IAgentNft(nft).mint(
virtualId,
_vault,
application.tokenURI,
dao,
application.proposer,
application.cores,
lp,
token
);
application.virtualId = virtualId;
// C6
uint256 chainId;
assembly {
chainId := chainid()
}
address tbaAddress = IERC6551Registry(tbaRegistry).createAccount(
application.tbaImplementation,
application.tbaSalt,
chainId,
nft,
virtualId
);
IAgentNft(nft).setTBA(virtualId, tbaAddress);
// C7
IERC20(lp).approve(veToken, type(uint256).max);
IAgentVeToken(veToken).stake(
IERC20(lp).balanceOf(address(this)),
application.proposer,
defaultDelegatee
);
emit NewPersona(virtualId, token, dao, tbaAddress, veToken, lp);
}
function executeApplication(uint256 id, bool canStake) public noReentrant {
// This will bootstrap an Agent with following components:
// C1: Agent Token
// C2: LP Pool + Initial liquidity
// C3: Agent veToken
// C4: Agent DAO
// C5: Agent NFT
// C6: TBA
// C7: Stake liquidity token to get veToken
Application storage application = _applications[id];
require(
msg.sender == application.proposer ||
hasRole(WITHDRAW_ROLE, msg.sender),
"Not proposer"
);
_executeApplication(id, canStake, _tokenSupplyParams);
}
function _createNewDAO(
string memory name,
IVotes token,
uint32 daoVotingPeriod,
uint256 daoThreshold
) internal returns (address instance) {
instance = Clones.clone(daoImplementation);
IAgentDAO(instance).initialize(
name,
token,
nft,
daoThreshold,
daoVotingPeriod
);
allDAOs.push(instance);
return instance;
}
function _createNewAgentToken(
string memory name,
string memory symbol,
bytes memory tokenSupplyParams_
) internal returns (address instance) {
instance = Clones.clone(tokenImplementation);
IAgentToken(instance).initialize(
[_tokenAdmin, _uniswapRouter, assetToken],
abi.encode(name, symbol),
tokenSupplyParams_,
_tokenTaxParams
);
allTradingTokens.push(instance);
return instance;
}
function _createNewAgentVeToken(
string memory name,
string memory symbol,
address stakingAsset,
address founder,
bool canStake
) internal returns (address instance) {
instance = Clones.clone(veTokenImplementation);
IAgentVeToken(instance).initialize(
name,
symbol,
founder,
stakingAsset,
block.timestamp + maturityDuration,
address(nft),
canStake
);
allTokens.push(instance);
return instance;
}
function totalAgents() public view returns (uint256) {
return allTokens.length;
}
function setApplicationThreshold(
uint256 newThreshold
) public onlyRole(DEFAULT_ADMIN_ROLE) {
applicationThreshold = newThreshold;
emit ApplicationThresholdUpdated(newThreshold);
}
function setVault(address newVault) public onlyRole(DEFAULT_ADMIN_ROLE) {
_vault = newVault;
}
function setImplementations(
address token,
address veToken,
address dao
) public onlyRole(DEFAULT_ADMIN_ROLE) {
tokenImplementation = token;
daoImplementation = dao;
veTokenImplementation = veToken;
}
function setMaturityDuration(
uint256 newDuration
) public onlyRole(DEFAULT_ADMIN_ROLE) {
maturityDuration = newDuration;
}
function setUniswapRouter(
address router
) public onlyRole(DEFAULT_ADMIN_ROLE) {
_uniswapRouter = router;
}
function setTokenAdmin(
address newTokenAdmin
) public onlyRole(DEFAULT_ADMIN_ROLE) {
_tokenAdmin = newTokenAdmin;
}
function setTokenSupplyParams(
uint256 maxSupply,
uint256 lpSupply,
uint256 vaultSupply,
uint256 maxTokensPerWallet,
uint256 maxTokensPerTxn,
uint256 botProtectionDurationInSeconds,
address vault
) public onlyRole(DEFAULT_ADMIN_ROLE) {
_tokenSupplyParams = abi.encode(
maxSupply,
lpSupply,
vaultSupply,
maxTokensPerWallet,
maxTokensPerTxn,
botProtectionDurationInSeconds,
vault
);
}
function setTokenTaxParams(
uint256 projectBuyTaxBasisPoints,
uint256 projectSellTaxBasisPoints,
uint256 taxSwapThresholdBasisPoints,
address projectTaxRecipient
) public onlyRole(DEFAULT_ADMIN_ROLE) {
_tokenTaxParams = abi.encode(
projectBuyTaxBasisPoints,
projectSellTaxBasisPoints,
taxSwapThresholdBasisPoints,
projectTaxRecipient
);
}
function setAssetToken(
address newToken
) public onlyRole(DEFAULT_ADMIN_ROLE) {
assetToken = newToken;
}
function pause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_pause();
}
function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function _msgSender()
internal
view
override(Context, ContextUpgradeable)
returns (address sender)
{
sender = ContextUpgradeable._msgSender();
}
function _msgData()
internal
view
override(Context, ContextUpgradeable)
returns (bytes calldata)
{
return ContextUpgradeable._msgData();
}
function initFromBondingCurve(
string memory name,
string memory symbol,
uint8[] memory cores,
bytes32 tbaSalt,
address tbaImplementation,
uint32 daoVotingPeriod,
uint256 daoThreshold,
uint256 applicationThreshold_,
address creator
) public whenNotPaused onlyRole(BONDING_ROLE) returns (uint256) {
address sender = _msgSender();
require(
IERC20(assetToken).balanceOf(sender) >= applicationThreshold_,
"Insufficient asset token"
);
require(
IERC20(assetToken).allowance(sender, address(this)) >=
applicationThreshold_,
"Insufficient asset token allowance"
);
require(cores.length > 0, "Cores must be provided");
IERC20(assetToken).safeTransferFrom(
sender,
address(this),
applicationThreshold_
);
uint256 id = _nextId++;
uint256 proposalEndBlock = block.number; // No longer required in v2
Application memory application = Application(
name,
symbol,
"",
ApplicationStatus.Active,
applicationThreshold_,
creator,
cores,
proposalEndBlock,
0,
tbaSalt,
tbaImplementation,
daoVotingPeriod,
daoThreshold
);
_applications[id] = application;
emit NewApplication(id);
return id;
}
function executeBondingCurveApplication(
uint256 id,
uint256 totalSupply,
uint256 lpSupply,
address vault
) public onlyRole(BONDING_ROLE) noReentrant returns (address) {
bytes memory tokenSupplyParams = abi.encode(
totalSupply,
lpSupply,
totalSupply - lpSupply,
totalSupply,
totalSupply,
0,
vault
);
_executeApplication(id, true, tokenSupplyParams);
Application memory application = _applications[id];
return IAgentNft(nft).virtualInfo(application.virtualId).token;
}
function setDefaultDelegatee(
address newDelegatee
) public onlyRole(DEFAULT_ADMIN_ROLE) {
defaultDelegatee = newDelegatee;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Genesis} from "./Genesis.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../virtualPersona/AgentFactoryV3.sol";
import "./GenesisTypes.sol";
import "./GenesisLib.sol";
import "../virtualPersona/AgentFactoryV3.sol";
contract FGenesis is Initializable, AccessControlUpgradeable {
using GenesisLib for *;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant OPERATION_ROLE = keccak256("OPERATION_ROLE");
struct Params {
address virtualToken;
uint256 reserve;
uint256 maxContribution;
address feeAddr;
uint256 feeAmt;
uint256 duration;
bytes32 tbaSalt;
address tbaImpl;
uint32 votePeriod;
uint256 threshold;
address agentFactory;
uint256 agentTokenTotalSupply;
uint256 agentTokenLpSupply;
}
Params public params;
mapping(uint256 => address) public genesisContracts;
uint256 public genesisID;
event GenesisCreated(uint256 indexed id, address indexed addr);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(Params memory p) external initializer {
__AccessControl_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
_setParams(p);
}
function setParams(
Params calldata p
) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setParams(p);
}
function _setParams(Params memory p) internal {
require(
p.virtualToken != address(0) &&
p.feeAddr != address(0) &&
p.tbaImpl != address(0) &&
p.agentFactory != address(0),
"Invalid addr"
);
require(
p.reserve > 0 &&
p.maxContribution > 0 &&
p.feeAmt > 0 &&
p.duration > 0,
"Invalid amt"
);
require(
p.agentTokenTotalSupply > 0 &&
p.agentTokenLpSupply > 0 &&
p.agentTokenTotalSupply >= p.agentTokenLpSupply,
"Invalid amt"
);
params = p;
}
function createGenesis(
GenesisCreationParams memory gParams
) external returns (address) {
require(
IERC20(params.virtualToken).transferFrom(
msg.sender,
params.feeAddr,
params.feeAmt
),
"transfer createGenesis fee failed"
);
gParams.endTime = gParams.startTime + params.duration;
genesisID++;
address addr = GenesisLib.validateAndDeploy(
genesisID,
address(this),
gParams,
params.tbaSalt,
params.tbaImpl,
params.votePeriod,
params.threshold,
params.agentFactory,
params.virtualToken,
params.reserve,
params.maxContribution,
params.agentTokenTotalSupply,
params.agentTokenLpSupply
);
// Grant BONDING_ROLE of ato the new Genesis contract
bytes32 BONDING_ROLE = AgentFactoryV3(params.agentFactory)
.BONDING_ROLE();
AgentFactoryV3(params.agentFactory).grantRole(
BONDING_ROLE,
address(addr)
);
genesisContracts[genesisID] = addr;
emit GenesisCreated(genesisID, addr);
return addr;
}
function _getGenesis(uint256 id) internal view returns (Genesis) {
address addr = genesisContracts[id];
require(addr != address(0), "Not found");
return Genesis(addr);
}
function onGenesisSuccess(
uint256 id,
SuccessParams calldata p
) external onlyRole(OPERATION_ROLE) returns (address) {
return
_getGenesis(id).onGenesisSuccess(
p.refundAddresses,
p.refundAmounts,
p.distributeAddresses,
p.distributeAmounts,
p.creator
);
}
function onGenesisFailed(
uint256 id,
uint256[] calldata participantIndexes
) external onlyRole(OPERATION_ROLE) {
_getGenesis(id).onGenesisFailed(participantIndexes);
}
function withdrawLeftAssetsAfterFinalized(
uint256 id,
address to,
address token,
uint256 amount
) external onlyRole(ADMIN_ROLE) {
_getGenesis(id).withdrawLeftAssetsAfterFinalized(to, token, amount);
}
function resetTime(
uint256 id,
uint256 newStartTime,
uint256 newEndTime
) external onlyRole(OPERATION_ROLE) {
_getGenesis(id).resetTime(newStartTime, newEndTime);
}
function cancelGenesis(uint256 id) external onlyRole(OPERATION_ROLE) {
_getGenesis(id).cancelGenesis();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./FGenesis.sol";
import "../virtualPersona/IAgentFactoryV3.sol";
// import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./GenesisTypes.sol";
contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
using SafeERC20 for IERC20;
bytes32 public constant FACTORY_ROLE = keccak256("FACTORY_ROLE");
mapping(address => uint256) public mapAddrToVirtuals;
mapping(address => uint256) public claimableAgentTokens;
address[] public participants;
uint256 public refundUserCountForFailed;
uint256 public genesisId;
FGenesis public factory;
// Genesis-related variables
uint256 public startTime;
uint256 public endTime;
string public genesisName;
string public genesisTicker;
uint8[] public genesisCores;
// TBA and DAO parameters
bytes32 public tbaSalt;
address public tbaImplementation;
uint32 public daoVotingPeriod;
uint256 public daoThreshold;
address public agentFactoryAddress;
address public virtualTokenAddress;
uint256 public reserveAmount;
uint256 public maxContributionVirtualAmount;
uint256 public agentTokenTotalSupply;
uint256 public agentTokenLpSupply;
address public agentTokenAddress;
bool public isFailed;
bool public isCancelled;
event AssetsWithdrawn(
uint256 indexed genesisID,
address indexed to,
address token,
uint256 amount
);
event TimeReset(
uint256 oldStartTime,
uint256 oldEndTime,
uint256 newStartTime,
uint256 newEndTime
);
event GenesisCancelled(uint256 indexed genesisID);
event GenesisSucceeded(uint256 indexed genesisID);
event GenesisFailed(uint256 indexed genesisID);
event Participated(
uint256 indexed genesisID,
address indexed user,
uint256 point,
uint256 virtuals
);
event RefundClaimed(
uint256 indexed genesisID,
address indexed user,
uint256 amount
);
event AgentTokenClaimed(
uint256 indexed genesisID,
address indexed user,
uint256 amount
);
event VirtualsWithdrawn(
uint256 indexed genesisID,
address indexed to,
address token,
uint256 amount
);
string private constant ERR_NOT_STARTED = "Genesis not started yet";
string private constant ERR_ALREADY_STARTED = "Genesis already started";
string private constant ERR_NOT_ENDED = "Genesis not ended yet";
string private constant ERR_ALREADY_ENDED = "Genesis already ended";
string private constant ERR_ALREADY_FAILED = "Genesis already failed";
string private constant ERR_ALREADY_CANCELLED = "Genesis already cancelled";
string private constant ERR_START_TIME_FUTURE =
"Start time must be in the future";
string private constant ERR_END_AFTER_START =
"End time must be after start time";
string private constant ERR_TOKEN_LAUNCHED = "Agent token already launched";
string private constant ERR_TOKEN_NOT_LAUNCHED = "Agent token not launched";
// Common validation modifiers
modifier whenNotStarted() {
require(!isStarted(), ERR_ALREADY_STARTED);
_;
}
modifier whenStarted() {
require(isStarted(), ERR_NOT_STARTED);
_;
}
modifier whenNotEnded() {
require(!isEnded(), ERR_ALREADY_ENDED);
_;
}
modifier whenEnded() {
require(isEnded(), ERR_NOT_ENDED);
_;
}
modifier whenNotFailed() {
require(!isFailed, ERR_ALREADY_FAILED);
_;
}
modifier whenNotCancelled() {
require(!isCancelled, ERR_ALREADY_CANCELLED);
_;
}
modifier whenTokenNotLaunched() {
require(agentTokenAddress == address(0), ERR_TOKEN_LAUNCHED);
_;
}
modifier whenTokenLaunched() {
require(agentTokenAddress != address(0), ERR_TOKEN_NOT_LAUNCHED);
_;
}
// Combined state checks
modifier whenActive() {
require(isStarted(), ERR_NOT_STARTED);
require(!isEnded(), ERR_ALREADY_ENDED);
require(!isFailed, ERR_ALREADY_FAILED);
require(!isCancelled, ERR_ALREADY_CANCELLED);
_;
}
modifier whenFinalized() {
require(isEnded(), ERR_NOT_ENDED);
require(
isFailed || isCancelled || agentTokenAddress != address(0),
"Genesis not finalized yet"
);
_;
}
function _validateTime(uint256 _startTime, uint256 _endTime) internal view {
require(_startTime > block.timestamp, ERR_START_TIME_FUTURE);
require(_endTime > _startTime, ERR_END_AFTER_START);
}
function initialize(
GenesisInitParams calldata params
) external initializer {
__AccessControl_init();
require(params.genesisID > 0, "Invalid genesis ID");
require(params.factory != address(0), "Invalid factory address");
_validateTime(params.startTime, params.endTime);
require(bytes(params.genesisName).length > 0, "Invalid genesis name");
require(
bytes(params.genesisTicker).length > 0,
"Invalid genesis ticker"
);
require(params.genesisCores.length > 0, "Invalid genesis cores");
require(
params.tbaImplementation != address(0),
"Invalid TBA implementation address"
);
require(
params.agentFactoryAddress != address(0),
"Invalid agent factory address"
);
require(
params.virtualTokenAddress != address(0),
"Invalid virtual token address"
);
require(
params.reserveAmount > 0,
"Reserve amount must be greater than 0"
);
require(
params.maxContributionVirtualAmount > 0,
"Max contribution must be greater than 0"
);
require(
params.agentTokenTotalSupply > 0,
"Agent token total supply must be greater than 0"
);
require(
params.agentTokenLpSupply > 0,
"Agent token lp supply must be greater than 0"
);
require(
params.agentTokenTotalSupply >= params.agentTokenLpSupply,
"Agent token total supply must be greater than agent token lp supply"
);
genesisId = params.genesisID;
factory = FGenesis(params.factory); // the FGenesis Proxy
startTime = params.startTime;
endTime = params.endTime;
genesisName = params.genesisName;
genesisTicker = params.genesisTicker;
genesisCores = params.genesisCores;
tbaSalt = params.tbaSalt;
tbaImplementation = params.tbaImplementation;
daoVotingPeriod = params.daoVotingPeriod;
daoThreshold = params.daoThreshold;
agentFactoryAddress = params.agentFactoryAddress;
virtualTokenAddress = params.virtualTokenAddress;
reserveAmount = params.reserveAmount;
maxContributionVirtualAmount = params.maxContributionVirtualAmount;
agentTokenTotalSupply = params.agentTokenTotalSupply;
agentTokenLpSupply = params.agentTokenLpSupply;
_grantRole(DEFAULT_ADMIN_ROLE, params.factory);
_grantRole(FACTORY_ROLE, params.factory);
}
function participate(
uint256 pointAmt,
uint256 virtualsAmt
) external nonReentrant whenActive {
require(pointAmt > 0, "Point amount must be greater than 0");
require(virtualsAmt > 0, "Virtuals must be greater than 0");
// Check single submission upper limit
require(
virtualsAmt <= maxContributionVirtualAmount,
"Exceeds maximum virtuals per contribution"
);
// Add balance check
require(
IERC20(virtualTokenAddress).balanceOf(msg.sender) >= virtualsAmt,
"Insufficient Virtual Token balance"
);
// Add allowance check
require(
IERC20(virtualTokenAddress).allowance(msg.sender, address(this)) >=
virtualsAmt,
"Insufficient Virtual Token allowance"
);
// Update participant list
if (mapAddrToVirtuals[msg.sender] == 0) {
participants.push(msg.sender);
}
// Update state
mapAddrToVirtuals[msg.sender] += virtualsAmt;
IERC20(virtualTokenAddress).safeTransferFrom(
msg.sender,
address(this),
virtualsAmt
);
emit Participated(genesisId, msg.sender, pointAmt, virtualsAmt);
}
function onGenesisSuccess(
address[] calldata refundVirtualsTokenUserAddresses,
uint256[] calldata refundVirtualsTokenUserAmounts,
address[] calldata distributeAgentTokenUserAddresses,
uint256[] calldata distributeAgentTokenUserAmounts,
address creator
)
external
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenNotFailed
whenEnded
returns (address)
{
require(
refundUserCountForFailed == 0,
"OnGenesisFailed already called"
);
require(
refundVirtualsTokenUserAddresses.length ==
refundVirtualsTokenUserAmounts.length,
"Mismatched refund arrays"
);
require(
distributeAgentTokenUserAddresses.length ==
distributeAgentTokenUserAmounts.length,
"Mismatched distribution arrays"
);
// Calculate total refund amount
uint256 totalRefundAmount = 0;
for (uint256 i = 0; i < refundVirtualsTokenUserAmounts.length; i++) {
// check if the user has enough virtuals committed
require(
mapAddrToVirtuals[refundVirtualsTokenUserAddresses[i]] >=
refundVirtualsTokenUserAmounts[i],
"Insufficient Virtual Token committed"
);
totalRefundAmount += refundVirtualsTokenUserAmounts[i];
}
// Check if launch has been called before
bool isFirstLaunch = agentTokenAddress == address(0);
// Calculate required balance based on whether this is first launch
uint256 requiredVirtualsBalance = isFirstLaunch
? totalRefundAmount + reserveAmount
: totalRefundAmount;
// Check if contract has enough virtuals balance
require(
IERC20(virtualTokenAddress).balanceOf(address(this)) >=
requiredVirtualsBalance,
"Insufficient Virtual Token balance"
);
// Only do launch related operations if this is first launch
if (isFirstLaunch) {
// grant allowance to agentFactoryAddress for launch
IERC20(virtualTokenAddress).approve(
agentFactoryAddress,
reserveAmount
);
// Call initFromBondingCurve and executeBondingCurveApplication
uint256 id = IAgentFactoryV3(agentFactoryAddress)
.initFromBondingCurve(
string.concat(genesisName, " by Virtuals"),
genesisTicker,
genesisCores,
tbaSalt,
tbaImplementation,
daoVotingPeriod,
daoThreshold,
reserveAmount,
creator
);
address agentToken = IAgentFactoryV3(agentFactoryAddress)
.executeBondingCurveApplication(
id,
agentTokenTotalSupply,
agentTokenLpSupply,
address(this) // vault
);
require(agentToken != address(0), "Agent token creation failed");
// Store the created agent token address
agentTokenAddress = agentToken;
}
// Calculate total distribution amount
uint256 totalDistributionAmount = 0;
for (uint256 i = 0; i < distributeAgentTokenUserAmounts.length; i++) {
totalDistributionAmount += distributeAgentTokenUserAmounts[i];
}
// Check if contract has enough agent token balance only after agentTokenAddress be set
require(
IERC20(agentTokenAddress).balanceOf(address(this)) >=
totalDistributionAmount,
"Insufficient Agent Token balance"
);
// Directly transfer Virtual Token refunds
for (uint256 i = 0; i < refundVirtualsTokenUserAddresses.length; i++) {
// first decrease the virtuals mapping of the user to prevent reentrancy attacks
mapAddrToVirtuals[
refundVirtualsTokenUserAddresses[i]
] -= refundVirtualsTokenUserAmounts[i];
// then transfer the virtuals
IERC20(virtualTokenAddress).safeTransfer(
refundVirtualsTokenUserAddresses[i],
refundVirtualsTokenUserAmounts[i]
);
emit RefundClaimed(
genesisId,
refundVirtualsTokenUserAddresses[i],
refundVirtualsTokenUserAmounts[i]
);
}
// save the amount of agent tokens to claim
for (uint256 i = 0; i < distributeAgentTokenUserAddresses.length; i++) {
claimableAgentTokens[
distributeAgentTokenUserAddresses[i]
] = distributeAgentTokenUserAmounts[i];
}
emit GenesisSucceeded(genesisId);
return agentTokenAddress;
}
// can try to claim at any time
function claimAgentToken(address userAddress) external nonReentrant {
uint256 amount = claimableAgentTokens[userAddress];
require(amount > 0, "No tokens to claim");
// set the amount of claimable agent tokens to 0, to prevent duplicate claims
claimableAgentTokens[userAddress] = 0;
// transfer the agent token
IERC20(agentTokenAddress).safeTransfer(userAddress, amount);
emit AgentTokenClaimed(genesisId, userAddress, amount);
}
function getClaimableAgentToken(
address userAddress
) external view returns (uint256) {
return claimableAgentTokens[userAddress];
}
function onGenesisFailed(
uint256[] calldata participantIndexes
)
external
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenNotFailed
whenTokenNotLaunched
whenEnded
{
for (uint256 i = 0; i < participantIndexes.length; i++) {
require(
participantIndexes[i] < participants.length,
"Index out of bounds"
);
address participant = participants[participantIndexes[i]];
uint256 virtualsAmt = mapAddrToVirtuals[participant];
if (virtualsAmt > 0) {
// increase the refund user count for failed, only increase once
refundUserCountForFailed++;
// first clear the virtuals mapping of the user to prevent reentrancy attacks
mapAddrToVirtuals[participant] = 0;
// then transfer the virtuals
IERC20(virtualTokenAddress).safeTransfer(
participant,
virtualsAmt
);
emit RefundClaimed(genesisId, participant, virtualsAmt);
}
}
// when all participants have been refunded, set the genesis to failed
if (refundUserCountForFailed == participants.length) {
isFailed = true;
emit GenesisFailed(genesisId);
}
}
function isEnded() public view returns (bool) {
return block.timestamp >= endTime;
}
function isStarted() public view returns (bool) {
return block.timestamp >= startTime;
}
function getParticipantCount() external view returns (uint256) {
return participants.length;
}
function getParticipantsPaginated(
uint256 startIndex,
uint256 pageSize
) external view returns (address[] memory) {
require(startIndex < participants.length, "Start index out of bounds");
uint256 actualPageSize = pageSize;
if (startIndex + pageSize > participants.length) {
actualPageSize = participants.length - startIndex;
}
address[] memory page = new address[](actualPageSize);
for (uint256 i = 0; i < actualPageSize; i++) {
page[i] = participants[startIndex + i];
}
return page;
}
struct ParticipantInfo {
address userAddress;
uint256 virtuals;
}
function getParticipantsInfo(
uint256[] calldata participantIndexes
) external view returns (ParticipantInfo[] memory) {
uint256 length = participantIndexes.length;
ParticipantInfo[] memory result = new ParticipantInfo[](length);
for (uint256 i = 0; i < length; i++) {
// check if the index is out of bounds
require(
participantIndexes[i] < participants.length,
"Index out of bounds"
);
address userAddress = participants[participantIndexes[i]];
result[i] = ParticipantInfo({
userAddress: userAddress,
virtuals: mapAddrToVirtuals[userAddress]
});
}
return result;
}
struct GenesisInfo {
uint256 genesisId;
address factory;
uint256 startTime;
uint256 endTime;
string genesisName;
string genesisTicker;
uint8[] genesisCores;
bytes32 tbaSalt;
address tbaImplementation;
uint32 daoVotingPeriod;
uint256 daoThreshold;
address agentFactoryAddress;
address virtualTokenAddress;
uint256 reserveAmount;
uint256 maxContributionVirtualAmount;
uint256 agentTokenTotalSupply;
uint256 agentTokenLpSupply;
address agentTokenAddress;
bool isFailed;
bool isCancelled;
}
function getGenesisInfo() public view returns (GenesisInfo memory) {
return
GenesisInfo({
genesisId: genesisId,
factory: address(factory),
startTime: startTime,
endTime: endTime,
genesisName: genesisName,
genesisTicker: genesisTicker,
genesisCores: genesisCores,
tbaSalt: tbaSalt,
tbaImplementation: tbaImplementation,
daoVotingPeriod: daoVotingPeriod,
daoThreshold: daoThreshold,
agentFactoryAddress: agentFactoryAddress,
virtualTokenAddress: virtualTokenAddress,
reserveAmount: reserveAmount,
maxContributionVirtualAmount: maxContributionVirtualAmount,
agentTokenTotalSupply: agentTokenTotalSupply,
agentTokenLpSupply: agentTokenLpSupply,
agentTokenAddress: agentTokenAddress,
isFailed: isFailed,
isCancelled: isCancelled
});
}
function withdrawLeftAssetsAfterFinalized(
address to,
address token,
uint256 amount
)
external
onlyRole(DEFAULT_ADMIN_ROLE)
nonReentrant
whenEnded
whenFinalized
{
require(token != address(0), "Invalid token address");
require(
amount <= IERC20(token).balanceOf(address(this)),
"Insufficient balance to withdraw"
);
IERC20(token).safeTransfer(to, amount);
// emit an event to record the withdrawal
emit AssetsWithdrawn(genesisId, to, token, amount);
}
function resetTime(
uint256 newStartTime,
uint256 newEndTime
)
external
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenNotFailed
whenNotStarted
whenNotEnded
{
_validateTime(newStartTime, newEndTime);
uint256 oldStartTime = startTime;
uint256 oldEndTime = endTime;
startTime = newStartTime;
endTime = newEndTime;
emit TimeReset(oldStartTime, oldEndTime, newStartTime, newEndTime);
}
function cancelGenesis()
external
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenNotFailed
whenNotStarted
whenNotEnded
{
isCancelled = true;
emit GenesisCancelled(genesisId);
}
}
// GenesisLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Genesis} from "./Genesis.sol";
import "./GenesisTypes.sol";
library GenesisLib {
function validateAndDeploy(
uint256 genesisID,
address factory,
GenesisCreationParams memory params,
bytes32 tbaSalt,
address tbaImpl,
uint32 daoVotingPeriod,
uint256 daoThreshold,
address agentFactoryAddress,
address virtualToken,
uint256 reserve,
uint256 maxContribution,
uint256 agentTokenTotalSupply,
uint256 agentTokenLpSupply
) internal returns (address) {
require(
bytes(params.genesisName).length > 0 &&
bytes(params.genesisTicker).length > 0 &&
params.genesisCores.length > 0,
"Invalid params"
);
Genesis newGenesis = new Genesis();
GenesisInitParams memory initParams = GenesisInitParams({
genesisID: genesisID,
factory: factory,
startTime: params.startTime,
endTime: params.endTime,
genesisName: params.genesisName,
genesisTicker: params.genesisTicker,
genesisCores: params.genesisCores,
tbaSalt: tbaSalt,
tbaImplementation: tbaImpl,
daoVotingPeriod: daoVotingPeriod,
daoThreshold: daoThreshold,
agentFactoryAddress: agentFactoryAddress,
virtualTokenAddress: virtualToken,
reserveAmount: reserve,
maxContributionVirtualAmount: maxContribution,
agentTokenTotalSupply: agentTokenTotalSupply,
agentTokenLpSupply: agentTokenLpSupply
});
newGenesis.initialize(initParams);
return address(newGenesis);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
struct GenesisCreationParams {
uint256 startTime;
uint256 endTime;
string genesisName;
string genesisTicker;
uint8[] genesisCores;
}
struct SuccessParams {
address[] refundAddresses;
uint256[] refundAmounts;
address[] distributeAddresses;
uint256[] distributeAmounts;
address creator;
}
struct GenesisInitParams {
uint256 genesisID;
address factory;
uint256 startTime;
uint256 endTime;
string genesisName;
string genesisTicker;
uint8[] genesisCores;
bytes32 tbaSalt;
address tbaImplementation;
uint32 daoVotingPeriod;
uint256 daoThreshold;
address agentFactoryAddress;
address virtualTokenAddress;
uint256 reserveAmount;
uint256 maxContributionVirtualAmount;
uint256 agentTokenTotalSupply;
uint256 agentTokenLpSupply;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/governance/IGovernor.sol";
import "@openzeppelin/contracts/governance/utils/IVotes.sol";
interface IAgentDAO {
function initialize(
string memory name,
IVotes token,
address agentNft,
uint256 threshold,
uint32 votingPeriod_
) external;
function proposalCount() external view returns (uint256);
function scoreOf(address account) external view returns (uint256);
function totalScore() external view returns (uint256);
function getPastScore(
address account,
uint256 timepoint
) external view returns (uint256);
function getMaturity(uint256 proposalId) external view returns (uint256);
event ValidatorEloRating(uint256 proposalId, address voter, uint256 score, uint8[] votes);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/governance/IGovernor.sol";
interface IAgentFactoryV3 {
function proposeAgent(
string memory name,
string memory symbol,
string memory tokenURI,
uint8[] memory cores,
bytes32 tbaSalt,
address tbaImplementation,
uint32 daoVotingPeriod,
uint256 daoThreshold
) external returns (uint256);
function withdraw(uint256 id) external;
function totalAgents() external view returns (uint256);
function initFromBondingCurve(
string memory name,
string memory symbol,
uint8[] memory cores,
bytes32 tbaSalt,
address tbaImplementation,
uint32 daoVotingPeriod,
uint256 daoThreshold,
uint256 applicationThreshold_,
address creator
) external returns (uint256);
function executeBondingCurveApplication(
uint256 id,
uint256 totalSupply,
uint256 lpSupply,
address vault
) external returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./IValidatorRegistry.sol";
interface IAgentNft is IValidatorRegistry {
struct VirtualInfo {
address dao; // Agent DAO can update the agent metadata
address token;
address founder;
address tba; // Token Bound Address
uint8[] coreTypes;
}
event CoresUpdated(uint256 virtualId, uint8[] coreTypes);
struct VirtualLP {
address pool; // Liquidity pool for the agent
address veToken; // Voting escrow token
}
function mint(
uint256 id,
address to,
string memory newTokenURI,
address payable theDAO,
address founder,
uint8[] memory coreTypes,
address pool,
address token
) external returns (uint256);
function stakingTokenToVirtualId(
address daoToken
) external view returns (uint256);
function setTBA(uint256 virtualId, address tba) external;
function virtualInfo(
uint256 virtualId
) external view returns (VirtualInfo memory);
function virtualLP(
uint256 virtualId
) external view returns (VirtualLP memory);
function totalSupply() external view returns (uint256);
function totalStaked(uint256 virtualId) external view returns (uint256);
function getVotes(
uint256 virtualId,
address validator
) external view returns (uint256);
function totalProposals(uint256 virtualId) external view returns (uint256);
function getContributionNft() external view returns (address);
function getServiceNft() external view returns (address);
function getAllServices(
uint256 virtualId
) external view returns (uint256[] memory);
function nextVirtualId() external view returns (uint256);
function isBlacklisted(uint256 virtualId) external view returns (bool);
function getEloCalculator() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IERC20Config.sol";
import "./IErrors.sol";
interface IAgentToken is
IERC20,
IERC20Config,
IERC20Metadata,
IErrors
{
event AutoSwapThresholdUpdated(uint256 oldThreshold, uint256 newThreshold);
event ExternalCallError(uint256 identifier);
event InitialLiquidityAdded(
uint256 tokenA,
uint256 tokenB,
uint256 lpToken
);
event LimitsUpdated(
uint256 oldMaxTokensPerTransaction,
uint256 newMaxTokensPerTransaction,
uint256 oldMaxTokensPerWallet,
uint256 newMaxTokensPerWallet
);
event LiquidityPoolCreated(address addedPool);
event LiquidityPoolAdded(address addedPool);
event LiquidityPoolRemoved(address removedPool);
event ProjectTaxBasisPointsChanged(
uint256 oldBuyBasisPoints,
uint256 newBuyBasisPoints,
uint256 oldSellBasisPoints,
uint256 newSellBasisPoints
);
event RevenueAutoSwap();
event ProjectTaxRecipientUpdated(address treasury);
event ValidCallerAdded(bytes32 addedValidCaller);
event ValidCallerRemoved(bytes32 removedValidCaller);
/**
* @dev function {addInitialLiquidity}
*
* Add initial liquidity to the uniswap pair
*
* @param lpOwner The recipient of LP tokens
*/
function addInitialLiquidity(address lpOwner) external;
/**
* @dev function {isLiquidityPool}
*
* Return if an address is a liquidity pool
*
* @param queryAddress_ The address being queried
* @return bool The address is / isn't a liquidity pool
*/
function isLiquidityPool(
address queryAddress_
) external view returns (bool);
/**
* @dev function {liquidityPools}
*
* Returns a list of all liquidity pools
*
* @return liquidityPools_ a list of all liquidity pools
*/
function liquidityPools()
external
view
returns (address[] memory liquidityPools_);
/**
* @dev function {addLiquidityPool} onlyOwner
*
* Allows the manager to add a liquidity pool to the pool enumerable set
*
* @param newLiquidityPool_ The address of the new liquidity pool
*/
function addLiquidityPool(address newLiquidityPool_) external;
/**
* @dev function {removeLiquidityPool} onlyOwner
*
* Allows the manager to remove a liquidity pool
*
* @param removedLiquidityPool_ The address of the old removed liquidity pool
*/
function removeLiquidityPool(address removedLiquidityPool_) external;
/**
* @dev function {isValidCaller}
*
* Return if an address is a valid caller
*
* @param queryHash_ The code hash being queried
* @return bool The address is / isn't a valid caller
*/
function isValidCaller(bytes32 queryHash_) external view returns (bool);
/**
* @dev function {validCallers}
*
* Returns a list of all valid caller code hashes
*
* @return validCallerHashes_ a list of all valid caller code hashes
*/
function validCallers()
external
view
returns (bytes32[] memory validCallerHashes_);
/**
* @dev function {addValidCaller} onlyOwner
*
* Allows the owner to add the hash of a valid caller
*
* @param newValidCallerHash_ The hash of the new valid caller
*/
function addValidCaller(bytes32 newValidCallerHash_) external;
/**
* @dev function {removeValidCaller} onlyOwner
*
* Allows the owner to remove a valid caller
*
* @param removedValidCallerHash_ The hash of the old removed valid caller
*/
function removeValidCaller(bytes32 removedValidCallerHash_) external;
/**
* @dev function {setProjectTaxRecipient} onlyOwner
*
* Allows the manager to set the project tax recipient address
*
* @param projectTaxRecipient_ New recipient address
*/
function setProjectTaxRecipient(address projectTaxRecipient_) external;
/**
* @dev function {setSwapThresholdBasisPoints} onlyOwner
*
* Allows the manager to set the autoswap threshold
*
* @param swapThresholdBasisPoints_ New swap threshold in basis points
*/
function setSwapThresholdBasisPoints(
uint16 swapThresholdBasisPoints_
) external;
/**
* @dev function {setProjectTaxRates} onlyOwner
*
* Change the tax rates, subject to only ever decreasing
*
* @param newProjectBuyTaxBasisPoints_ The new buy tax rate
* @param newProjectSellTaxBasisPoints_ The new sell tax rate
*/
function setProjectTaxRates(
uint16 newProjectBuyTaxBasisPoints_,
uint16 newProjectSellTaxBasisPoints_
) external;
/**
* @dev totalBuyTaxBasisPoints
*
* Provide easy to view tax total:
*/
function totalBuyTaxBasisPoints() external view returns (uint256);
/**
* @dev totalSellTaxBasisPoints
*
* Provide easy to view tax total:
*/
function totalSellTaxBasisPoints() external view returns (uint256);
/**
* @dev distributeTaxTokens
*
* Allows the distribution of tax tokens to the designated recipient(s)
*
* As part of standard processing the tax token balance being above the threshold
* will trigger an autoswap to ETH and distribution of this ETH to the designated
* recipients. This is automatic and there is no need for user involvement.
*
* As part of this swap there are a number of calculations performed, particularly
* if the tax balance is above MAX_SWAP_THRESHOLD_MULTIPLE.
*
* Testing indicates that these calculations are safe. But given the data / code
* interactions it remains possible that some edge case set of scenarios may cause
* an issue with these calculations.
*
* This method is therefore provided as a 'fallback' option to safely distribute
* accumulated taxes from the contract, with a direct transfer of the ERC20 tokens
* themselves.
*/
function distributeTaxTokens() external;
/**
* @dev function {withdrawETH} onlyOwner
*
* A withdraw function to allow ETH to be withdrawn by the manager
*
* This contract should never hold ETH. The only envisaged scenario where
* it might hold ETH is a failed autoswap where the uniswap swap has completed,
* the recipient of ETH reverts, the contract then wraps to WETH and the
* wrap to WETH fails.
*
* This feels unlikely. But, for safety, we include this method.
*
* @param amount_ The amount to withdraw
*/
function withdrawETH(uint256 amount_) external;
/**
* @dev function {withdrawERC20} onlyOwner
*
* A withdraw function to allow ERC20s (except address(this)) to be withdrawn.
*
* This contract should never hold ERC20s other than tax tokens. The only envisaged
* scenario where it might hold an ERC20 is a failed autoswap where the uniswap swap
* has completed, the recipient of ETH reverts, the contract then wraps to WETH, the
* wrap to WETH succeeds, BUT then the transfer of WETH fails.
*
* This feels even less likely than the scenario where ETH is held on the contract.
* But, for safety, we include this method.
*
* @param token_ The ERC20 contract
* @param amount_ The amount to withdraw
*/
function withdrawERC20(address token_, uint256 amount_) external;
/**
* @dev Destroys a `value` amount of tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) external;
/**
* @dev Destroys a `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) external;
/**
* @dev {initializer}
*
* @param integrationAddresses_ The project owner, uniswap router, LP currency
* @param baseParams_ configuration of this ERC20.
* param supplyParams_ Supply configuration of this ERC20.
* param taxParams_ Tax configuration of this ERC20
* param taxParams_ Launch pool configuration of this ERC20
* param lpSupply_ Initial supply to be minted for LP
*/
function initialize(
address[3] memory integrationAddresses_,
bytes memory baseParams_,
bytes memory supplyParams_,
bytes memory taxParams_
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IAgentVeToken {
function initialize(
string memory _name,
string memory _symbol,
address _founder,
address _assetToken,
uint256 _matureAt,
address _agentNft,
bool _canStake
) external;
function stake(
uint256 amount,
address receiver,
address delegatee
) external;
function withdraw(uint256 amount) external;
function getPastDelegates(
address account,
uint256 timepoint
) external view returns (address);
function getPastBalanceOf(
address account,
uint256 timepoint
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20Config {
struct ERC20Config {
bytes baseParameters;
bytes supplyParameters;
bytes taxParameters;
bytes poolParameters;
}
struct ERC20BaseParameters {
string name;
string symbol;
}
struct ERC20SupplyParameters {
uint256 maxSupply;
uint256 lpSupply;
uint256 vaultSupply;
uint256 maxTokensPerWallet;
uint256 maxTokensPerTxn;
uint256 botProtectionDurationInSeconds;
address vault;
}
struct ERC20TaxParameters {
uint256 projectBuyTaxBasisPoints;
uint256 projectSellTaxBasisPoints;
uint256 taxSwapThresholdBasisPoints;
address projectTaxRecipient;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)
pragma solidity ^0.8.20;
interface IERC6372 {
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
*/
function clock() external view returns (uint48);
/**
* @dev Description of the clock
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() external view returns (string memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC6551Registry {
/**
* @dev The registry SHALL emit the AccountCreated event upon successful account creation
*/
event AccountCreated(
address account,
address indexed implementation,
uint256 chainId,
address indexed tokenContract,
uint256 indexed tokenId,
uint256 salt
);
/**
* @dev Creates a token bound account for a non-fungible token
*
* If account has already been created, returns the account address without calling create2
*
* If initData is not empty and account has not yet been created, calls account with
* provided initData after creation
*
* Emits AccountCreated event
*
* @return the address of the account
*/
function createAccount(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address);
/**
* @dev Returns the computed token bound account address for a non-fungible token
*
* @return The computed address of the token bound account
*/
function account(
address implementation,
uint256 chainId,
address tokenContract,
uint256 tokenId,
uint256 salt
) external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IErrors {
enum BondingCurveErrorType {
OK, // No error
INVALID_NUMITEMS, // The numItem value is 0
SPOT_PRICE_OVERFLOW // The updated spot price doesn't fit into 128 bits
}
error AdapterParamsMustBeEmpty(); // The adapter parameters on this LZ call must be empty.
error AdditionToPoolIsBelowPerTransactionMinimum(); // The contribution amount is less than the minimum.
error AdditionToPoolWouldExceedPoolCap(); // This addition to the pool would exceed the pool cap.
error AdditionToPoolWouldExceedPerAddressCap(); // This addition to the pool would exceed the per address cap.
error AddressAlreadySet(); // The address being set can only be set once, and is already non-0.
error AllowanceDecreasedBelowZero(); // You cannot decrease the allowance below zero.
error AlreadyInitialised(); // The contract is already initialised: it cannot be initialised twice!
error ApprovalCallerNotOwnerNorApproved(); // The caller must own the token or be an approved operator.
error ApproveFromTheZeroAddress(); // Approval cannot be called from the zero address (indeed, how have you??).
error ApproveToTheZeroAddress(); // Approval cannot be given to the zero address.
error ApprovalQueryForNonexistentToken(); // The token does not exist.
error AuctionStatusIsNotEnded(); // Throw if the action required the auction to be closed, and it isn't.
error AuctionStatusIsNotOpen(); // Throw if the action requires the auction to be open, and it isn't.
error AuxCallFailed(
address[] modules,
uint256 value,
bytes data,
uint256 txGas
); // An auxilliary call from the drop factory failed.
error BalanceMismatch(); // An error when comparing balance amounts.
error BalanceQueryForZeroAddress(); // Cannot query the balance for the zero address.
error BidMustBeBelowTheFloorWhenReducingQuantity(); // Only bids that are below the floor can reduce the quantity of the bid.
error BidMustBeBelowTheFloorForRefundDuringAuction(); // Only bids that are below the floor can be refunded during the auction.
error BondingCurveError(BondingCurveErrorType error); // An error of the type specified has occured in bonding curve processing.
error BurnExceedsBalance(); // The amount you have selected to burn exceeds the addresses balance.
error BurnFromTheZeroAddress(); // Tokens cannot be burned from the zero address. (Also, how have you called this!?!)
error CallerIsNotDepositBoxOwner(); // The caller is not the owner of the deposit box.
error CallerIsNotFactory(); // The caller of this function must match the factory address in storage.
error CallerIsNotFactoryOrProjectOwner(); // The caller of this function must match the factory address OR project owner address.
error CallerIsNotFactoryProjectOwnerOrPool(); // The caller of this function must match the factory address, project owner or pool address.
error CallerIsNotTheOwner(); // The caller is not the owner of this contract.
error CallerIsNotTheManager(); // The caller is not the manager of this contract.
error CallerMustBeLzApp(); // The caller must be an LZ application.
error CallerIsNotPlatformAdmin(address caller); // The caller of this function must be part of the platformAdmin group.
error CallerIsNotSuperAdmin(address caller); // The caller of this function must match the superAdmin address in storage.
error CannotAddLiquidityOnCreateAndUseDRIPool(); // Cannot use both liquidity added on create and a DRIPool in the same token.
error CannotSetNewOwnerToTheZeroAddress(); // You can't set the owner of this contract to the zero address (address(0)).
error CannotSetToZeroAddress(); // The corresponding address cannot be set to the zero address (address(0)).
error CannotSetNewManagerToTheZeroAddress(); // Cannot transfer the manager to the zero address (address(0)).
error CannotWithdrawThisToken(); // Cannot withdraw the specified token.
error CanOnlyReduce(); // The given operation can only reduce the value specified.
error CollectionAlreadyRevealed(); // The collection is already revealed; you cannot call reveal again.
error ContractIsDecommissioned(); // This contract is decommissioned!
error ContractIsPaused(); // The call requires the contract to be unpaused, and it is paused.
error ContractIsNotPaused(); // The call required the contract to be paused, and it is NOT paused.
error DecreasedAllowanceBelowZero(); // The request would decrease the allowance below zero, and that is not allowed.
error DestinationIsNotTrustedSource(); // The destination that is being called through LZ has not been set as trusted.
error DeployerOnly(); // This method can only be called by the deployer address.
error DeploymentError(); // Error on deployment.
error DepositBoxIsNotOpen(); // This action cannot complete as the deposit box is not open.
error DriPoolAddressCannotBeAddressZero(); // The Dri Pool address cannot be the zero address.
error GasLimitIsTooLow(); // The gas limit for the LayerZero call is too low.
error IncorrectConfirmationValue(); // You need to enter the right confirmation value to call this funtion (usually 69420).
error IncorrectPayment(); // The function call did not include passing the correct payment.
error InitialLiquidityAlreadyAdded(); // Initial liquidity has already been added. You can't do it again.
error InitialLiquidityNotYetAdded(); // Initial liquidity needs to have been added for this to succedd.
error InsufficientAllowance(); // There is not a high enough allowance for this operation.
error InvalidAdapterParams(); // The current adapter params for LayerZero on this contract won't work :(.
error InvalidAddress(); // An address being processed in the function is not valid.
error InvalidEndpointCaller(); // The calling address is not a valid LZ endpoint. The LZ endpoint was set at contract creation
// and cannot be altered after. Check the address LZ endpoint address on the contract.
error InvalidMinGas(); // The minimum gas setting for LZ in invalid.
error InvalidOracleSignature(); // The signature provided with the contract call is not valid, either in format or signer.
error InvalidPayload(); // The LZ payload is invalid
error InvalidReceiver(); // The address used as a target for funds is not valid.
error InvalidSourceSendingContract(); // The LZ message is being related from a source contract on another chain that is NOT trusted.
error InvalidTotalShares(); // Total shares must equal 100 percent in basis points.
error LimitsCanOnlyBeRaised(); // Limits are UP ONLY.
error ListLengthMismatch(); // Two or more lists were compared and they did not match length.
error LiquidityPoolMustBeAContractAddress(); // Cannot add a non-contract as a liquidity pool.
error LiquidityPoolCannotBeAddressZero(); // Cannot add a liquidity pool from the zero address.
error LPLockUpMustFitUint88(); // LP lockup is held in a uint88, so must fit.
error NoTrustedPathRecord(); // LZ needs a trusted path record for this to work. What's that, you ask?
error MachineAddressCannotBeAddressZero(); // Cannot set the machine address to the zero address.
error ManagerUnauthorizedAccount(); // The caller is not the pending manager.
error MaxBidQuantityIs255(); // Validation: as we use a uint8 array to track bid positions the max bid quantity is 255.
error MaxPublicMintAllowanceExceeded(
uint256 requested,
uint256 alreadyMinted,
uint256 maxAllowance
); // The calling address has requested a quantity that would exceed the max allowance.
error MaxSupplyTooHigh(); // Max supply must fit in a uint128.
error MaxTokensPerWalletExceeded(); // The transfer would exceed the max tokens per wallet limit.
error MaxTokensPerTxnExceeded(); // The transfer would exceed the max tokens per transaction limit.
error MetadataIsLocked(); // The metadata on this contract is locked; it cannot be altered!
error MinGasLimitNotSet(); // The minimum gas limit for LayerZero has not been set.
error MintERC2309QuantityExceedsLimit(); // The `quantity` minted with ERC2309 exceeds the safety limit.
error MintingIsClosedForever(); // Minting is, as the error suggests, so over (and locked forever).
error MintToZeroAddress(); // Cannot mint to the zero address.
error MintZeroQuantity(); // The quantity of tokens minted must be more than zero.
error NewBuyTaxBasisPointsExceedsMaximum(); // Project owner trying to set the tax rate too high.
error NewSellTaxBasisPointsExceedsMaximum(); // Project owner trying to set the tax rate too high.
error NoETHForLiquidityPair(); // No ETH has been provided for the liquidity pair.
error TaxPeriodStillInForce(); // The minimum tax period has not yet expired.
error NoPaymentDue(); // No payment is due for this address.
error NoRefundForCaller(); // Error thrown when the calling address has no refund owed.
error NoStoredMessage(); // There is no stored message matching the passed parameters.
error NothingToClaim(); // The calling address has nothing to claim.
error NoTokenForLiquidityPair(); // There is no token to add to the LP.
error OperationDidNotSucceed(); // The operation failed (vague much?).
error OracleSignatureHasExpired(); // A signature has been provided but it is too old.
error OwnershipNotInitializedForExtraData(); // The `extraData` cannot be set on an uninitialized ownership slot.
error OwnerQueryForNonexistentToken(); // The token does not exist.
error CallerIsNotAdminNorFactory(); // The caller of this function must match the factory address or be an admin.
error ParametersDoNotMatchSignedMessage(); // The parameters passed with the signed message do not match the message itself.
error ParamTooLargeStartDate(); // The passed parameter exceeds the var type max.
error ParamTooLargeEndDate(); // The passed parameter exceeds the var type max.
error ParamTooLargeMinETH(); // The passed parameter exceeds the var type max.
error ParamTooLargePerAddressMax(); // The passed parameter exceeds the var type max.
error ParamTooLargeVestingDays(); // The passed parameter exceeds the var type max.
error ParamTooLargePoolSupply(); // The passed parameter exceeds the var type max.
error ParamTooLargePoolPerTxnMinETH(); // The passed parameter exceeds the var type max.
error PassedConfigDoesNotMatchApproved(); // The config provided on the call does not match the approved config.
error PauseCutOffHasPassed(); // The time period in which we can pause has passed; this contract can no longer be paused.
error PaymentMustCoverPerMintFee(); // The payment passed must at least cover the per mint fee for the quantity requested.
error PermitDidNotSucceed(); // The safeERC20 permit failed.
error PlatformAdminCannotBeAddressZero(); // We cannot use the zero address (address(0)) as a platformAdmin.
error PlatformTreasuryCannotBeAddressZero(); // The treasury address cannot be set to the zero address.
error PoolIsAboveMinimum(); // You required the pool to be below the minimum, and it is not
error PoolIsBelowMinimum(); // You required the pool to be above the minimum, and it is not
error PoolPhaseIsClosed(); // The block.timestamp is either before the pool is open or after it is closed.
error PoolPhaseIsNotAfter(); // The block.timestamp is either before or during the pool open phase.
error PoolVestingNotYetComplete(); // Tokens in the pool are not yet vested.
error ProjectOwnerCannotBeAddressZero(); // The project owner has to be a non zero address.
error ProofInvalid(); // The provided proof is not valid with the provided arguments.
error QuantityExceedsRemainingCollectionSupply(); // The requested quantity would breach the collection supply.
error QuantityExceedsRemainingPhaseSupply(); // The requested quantity would breach the phase supply.
error QuantityExceedsMaxPossibleCollectionSupply(); // The requested quantity would breach the maximum trackable supply
error ReferralIdAlreadyUsed(); // This referral ID has already been used; they are one use only.
error RequestingMoreThanAvailableBalance(); // The request exceeds the available balance.
error RequestingMoreThanRemainingAllocation(
uint256 previouslyMinted,
uint256 requested,
uint256 remainingAllocation
); // Number of tokens requested for this mint exceeds the remaining allocation (taking the
// original allocation from the list and deducting minted tokens).
error RoyaltyFeeWillExceedSalePrice(); // The ERC2981 royalty specified will exceed the sale price.
error ShareTotalCannotBeZero(); // The total of all the shares cannot be nothing.
error SliceOutOfBounds(); // The bytes slice operation was out of bounds.
error SliceOverflow(); // The bytes slice operation overlowed.
error SuperAdminCannotBeAddressZero(); // The superAdmin cannot be the sero address (address(0)).
error SupplyTotalMismatch(); // The sum of the team supply and lp supply does not match.
error SupportWindowIsNotOpen(); // The project owner has not requested support within the support request expiry window.
error TaxFreeAddressCannotBeAddressZero(); // A tax free address cannot be address(0)
error TemplateCannotBeAddressZero(); // The address for a template cannot be address zero (address(0)).
error TemplateNotFound(); // There is no template that matches the passed template Id.
error ThisMintIsClosed(); // It's over (well, this mint is, anyway).
error TotalSharesMustMatchDenominator(); // The total of all shares must equal the denominator value.
error TransferAmountExceedsBalance(); // The transfer amount exceeds the accounts available balance.
error TransferCallerNotOwnerNorApproved(); // The caller must own the token or be an approved operator.
error TransferFailed(); // The transfer has failed.
error TransferFromIncorrectOwner(); // The token must be owned by `from`.
error TransferToNonERC721ReceiverImplementer(); // Cannot safely transfer to a contract that does not implement the ERC721Receiver interface.
error TransferFromZeroAddress(); // Cannot transfer from the zero address. Indeed, this surely is impossible, and likely a waste to check??
error TransferToZeroAddress(); // Cannot transfer to the zero address.
error UnrecognisedVRFMode(); // Currently supported VRF modes are 0: chainlink and 1: arrng
error URIQueryForNonexistentToken(); // The token does not exist.
error ValueExceedsMaximum(); // The value sent exceeds the maximum allowed (super useful explanation huh?).
error VRFCoordinatorCannotBeAddressZero(); // The VRF coordinator cannot be the zero address (address(0)).
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/IGovernor.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../interfaces/IERC165.sol";
import {IERC6372} from "../interfaces/IERC6372.sol";
/**
* @dev Interface of the {Governor} core.
*/
interface IGovernor is IERC165, IERC6372 {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
/**
* @dev Empty proposal or a mismatch between the parameters length for a proposal call.
*/
error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values);
/**
* @dev The vote was already cast.
*/
error GovernorAlreadyCastVote(address voter);
/**
* @dev Token deposits are disabled in this contract.
*/
error GovernorDisabledDeposit();
/**
* @dev The `account` is not a proposer.
*/
error GovernorOnlyProposer(address account);
/**
* @dev The `account` is not the governance executor.
*/
error GovernorOnlyExecutor(address account);
/**
* @dev The `proposalId` doesn't exist.
*/
error GovernorNonexistentProposal(uint256 proposalId);
/**
* @dev The current state of a proposal is not the required for performing an operation.
* The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position
* counting from right to left.
*
* NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist).
* This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated).
*
* See {Governor-_encodeStateBitmap}.
*/
error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates);
/**
* @dev The voting period set is not a valid period.
*/
error GovernorInvalidVotingPeriod(uint256 votingPeriod);
/**
* @dev The `proposer` does not have the required votes to create a proposal.
*/
error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold);
/**
* @dev The `proposer` is not allowed to create a proposal.
*/
error GovernorRestrictedProposer(address proposer);
/**
* @dev The vote type used is not valid for the corresponding counting module.
*/
error GovernorInvalidVoteType();
/**
* @dev Queue operation is not implemented for this governor. Execute should be called directly.
*/
error GovernorQueueNotImplemented();
/**
* @dev The proposal hasn't been queued yet.
*/
error GovernorNotQueuedProposal(uint256 proposalId);
/**
* @dev The proposal has already been queued.
*/
error GovernorAlreadyQueuedProposal(uint256 proposalId);
/**
* @dev The provided signature is not valid for the expected `voter`.
* If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}.
*/
error GovernorInvalidSignature(address voter);
/**
* @dev Emitted when a proposal is created.
*/
event ProposalCreated(
uint256 proposalId,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 voteStart,
uint256 voteEnd,
string description
);
/**
* @dev Emitted when a proposal is queued.
*/
event ProposalQueued(uint256 proposalId, uint256 etaSeconds);
/**
* @dev Emitted when a proposal is executed.
*/
event ProposalExecuted(uint256 proposalId);
/**
* @dev Emitted when a proposal is canceled.
*/
event ProposalCanceled(uint256 proposalId);
/**
* @dev Emitted when a vote is cast without params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
*/
event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);
/**
* @dev Emitted when a vote is cast with params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
* `params` are additional encoded parameters. Their interpepretation also depends on the voting module used.
*/
event VoteCastWithParams(
address indexed voter,
uint256 proposalId,
uint8 support,
uint256 weight,
string reason,
bytes params
);
/**
* @notice module:core
* @dev Name of the governor instance (used in building the ERC712 domain separator).
*/
function name() external view returns (string memory);
/**
* @notice module:core
* @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1"
*/
function version() external view returns (string memory);
/**
* @notice module:voting
* @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
* be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
* key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
*
* There are 2 standard keys: `support` and `quorum`.
*
* - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
* - `quorum=bravo` means that only For votes are counted towards quorum.
* - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
*
* If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique
* name that describes the behavior. For example:
*
* - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
* - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
*
* NOTE: The string can be decoded by the standard
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
* JavaScript class.
*/
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() external view returns (string memory);
/**
* @notice module:core
* @dev Hashing function used to (re)build the proposal id from the proposal details..
*/
function hashProposal(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external pure returns (uint256);
/**
* @notice module:core
* @dev Current state of a proposal, following Compound's convention
*/
function state(uint256 proposalId) external view returns (ProposalState);
/**
* @notice module:core
* @dev The number of votes required in order for a voter to become a proposer.
*/
function proposalThreshold() external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the
* snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the
* following block.
*/
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is
* possible to cast a vote during this block.
*/
function proposalDeadline(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev The account that created a proposal.
*/
function proposalProposer(uint256 proposalId) external view returns (address);
/**
* @notice module:core
* @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and
* {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be
* different. In most cases this will be a timestamp.
*/
function proposalEta(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Whether a proposal needs to be queued before execution.
*/
function proposalNeedsQueuing(uint256 proposalId) external view returns (bool);
/**
* @notice module:user-config
* @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends
* on the clock (see EIP-6372) this contract uses.
*
* This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a
* proposal starts.
*
* NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type.
* Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}.
*/
function votingDelay() external view returns (uint256);
/**
* @notice module:user-config
* @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock
* (see EIP-6372) this contract uses.
*
* NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting
* duration compared to the voting delay.
*
* NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect
* proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this
* interface returns a uint256, the value it returns should fit in a uint32.
*/
function votingPeriod() external view returns (uint256);
/**
* @notice module:user-config
* @dev Minimum number of cast voted required for a proposal to be successful.
*
* NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
* quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
*/
function quorum(uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint`.
*
* Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
* multiple), {ERC20Votes} tokens.
*/
function getVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters.
*/
function getVotesWithParams(
address account,
uint256 timepoint,
bytes memory params
) external view returns (uint256);
/**
* @notice module:voting
* @dev Returns whether `account` has cast a vote on `proposalId`.
*/
function hasVoted(uint256 proposalId, address account) external view returns (bool);
/**
* @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a
* duration specified by {IGovernor-votingPeriod}.
*
* Emits a {ProposalCreated} event.
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) external returns (uint256 proposalId);
/**
* @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing
* is not necessary, this function may revert.
* Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
*
* Emits a {ProposalQueued} event.
*/
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
/**
* @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
* deadline to be reached. Depending on the governor it might also be required that the proposal was queued and
* that some delay passed.
*
* Emits a {ProposalExecuted} event.
*
* NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock.
*/
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external payable returns (uint256 proposalId);
/**
* @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e.
* before the vote starts.
*
* Emits a {ProposalCanceled} event.
*/
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
/**
* @dev Cast a vote
*
* Emits a {VoteCast} event.
*/
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason
*
* Emits a {VoteCast} event.
*/
function castVoteWithReason(
uint256 proposalId,
uint8 support,
string calldata reason
) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParams(
uint256 proposalId,
uint8 support,
string calldata reason,
bytes memory params
) external returns (uint256 balance);
/**
* @dev Cast a vote using the voter's signature, including ERC-1271 signature support.
*
* Emits a {VoteCast} event.
*/
function castVoteBySig(
uint256 proposalId,
uint8 support,
address voter,
bytes memory signature
) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters using the voter's signature,
* including ERC-1271 signature support.
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParamsBySig(
uint256 proposalId,
uint8 support,
address voter,
string calldata reason,
bytes memory params,
bytes memory signature
) external returns (uint256 balance);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IValidatorRegistry {
event NewValidator(uint256 virtualId, address account);
function isValidator(
uint256 virtualId,
address account
) external view returns (bool);
function validatorScore(
uint256 virtualId,
address validator
) external view returns (uint256);
function getPastValidatorScore(
uint256 virtualId,
address validator,
uint256 timepoint
) external view returns (uint256);
function validatorCount(uint256 virtualId) external view returns (uint256);
function validatorAt(
uint256 virtualId,
uint256 index
) external view returns (address);
function totalUptimeScore(
uint256 virtualId
) external view returns (uint256);
function addValidator(uint256 virtualId, address validator) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.20;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
/**
* @dev The signature used has expired.
*/
error VotesExpiredSignature(uint256 expiry);
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
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
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// 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;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"contracts/genesis/Genesis.sol": "Genesis"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AgentTokenClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AssetsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"}],"name":"GenesisCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"}],"name":"GenesisFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"}],"name":"GenesisSucceeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"point","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"virtuals","type":"uint256"}],"name":"Participated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTime","type":"uint256"}],"name":"TimeReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"genesisID","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VirtualsWithdrawn","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentFactoryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentTokenLpSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentTokenTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelGenesis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"claimAgentToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimableAgentTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daoThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daoVotingPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract FGenesis","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"genesisCores","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisTicker","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getClaimableAgentToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGenesisInfo","outputs":[{"components":[{"internalType":"uint256","name":"genesisId","type":"uint256"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"string","name":"genesisName","type":"string"},{"internalType":"string","name":"genesisTicker","type":"string"},{"internalType":"uint8[]","name":"genesisCores","type":"uint8[]"},{"internalType":"bytes32","name":"tbaSalt","type":"bytes32"},{"internalType":"address","name":"tbaImplementation","type":"address"},{"internalType":"uint32","name":"daoVotingPeriod","type":"uint32"},{"internalType":"uint256","name":"daoThreshold","type":"uint256"},{"internalType":"address","name":"agentFactoryAddress","type":"address"},{"internalType":"address","name":"virtualTokenAddress","type":"address"},{"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"internalType":"uint256","name":"maxContributionVirtualAmount","type":"uint256"},{"internalType":"uint256","name":"agentTokenTotalSupply","type":"uint256"},{"internalType":"uint256","name":"agentTokenLpSupply","type":"uint256"},{"internalType":"address","name":"agentTokenAddress","type":"address"},{"internalType":"bool","name":"isFailed","type":"bool"},{"internalType":"bool","name":"isCancelled","type":"bool"}],"internalType":"struct Genesis.GenesisInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getParticipantCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"participantIndexes","type":"uint256[]"}],"name":"getParticipantsInfo","outputs":[{"components":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"virtuals","type":"uint256"}],"internalType":"struct Genesis.ParticipantInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"pageSize","type":"uint256"}],"name":"getParticipantsPaginated","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"genesisID","type":"uint256"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"string","name":"genesisName","type":"string"},{"internalType":"string","name":"genesisTicker","type":"string"},{"internalType":"uint8[]","name":"genesisCores","type":"uint8[]"},{"internalType":"bytes32","name":"tbaSalt","type":"bytes32"},{"internalType":"address","name":"tbaImplementation","type":"address"},{"internalType":"uint32","name":"daoVotingPeriod","type":"uint32"},{"internalType":"uint256","name":"daoThreshold","type":"uint256"},{"internalType":"address","name":"agentFactoryAddress","type":"address"},{"internalType":"address","name":"virtualTokenAddress","type":"address"},{"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"internalType":"uint256","name":"maxContributionVirtualAmount","type":"uint256"},{"internalType":"uint256","name":"agentTokenTotalSupply","type":"uint256"},{"internalType":"uint256","name":"agentTokenLpSupply","type":"uint256"}],"internalType":"struct GenesisInitParams","name":"params","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEnded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFailed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mapAddrToVirtuals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxContributionVirtualAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"participantIndexes","type":"uint256[]"}],"name":"onGenesisFailed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"refundVirtualsTokenUserAddresses","type":"address[]"},{"internalType":"uint256[]","name":"refundVirtualsTokenUserAmounts","type":"uint256[]"},{"internalType":"address[]","name":"distributeAgentTokenUserAddresses","type":"address[]"},{"internalType":"uint256[]","name":"distributeAgentTokenUserAmounts","type":"uint256[]"},{"internalType":"address","name":"creator","type":"address"}],"name":"onGenesisSuccess","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"participants","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pointAmt","type":"uint256"},{"internalType":"uint256","name":"virtualsAmt","type":"uint256"}],"name":"participate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refundUserCountForFailed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStartTime","type":"uint256"},{"internalType":"uint256","name":"newEndTime","type":"uint256"}],"name":"resetTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tbaImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tbaSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"virtualTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLeftAssetsAfterFinalized","outputs":[],"stateMutability":"nonpayable","type":"function"}]