// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual override returns (uint256[] memory) {
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(address from, uint256 id, uint256 amount) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./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);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}
// SPDX-License-Identifier: MIT
/*
Version 1 of the HyperCycle Share contract.
*/
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "../interfaces/IHyperCycleLicense.sol";
import "../interfaces/ICHYPC.sol";
import "../interfaces/IHYPCSwapV2.sol";
import "../interfaces/IHyperCycleShareTokens.sol";
import "../interfaces/IHYPC.sol";
/*
@title HyperCycle Share ERC1155, revenue sharing contract.
@author Barry Rowe, Rodolfo Cova
@notice This contract is a mechanism to share revenue for participants in the HyperCycle system.
HyperCycle is a network of AI computation nodes offering different AI services in a
decentralized manner. In this system, there are license holders, token holders, hardware
operators, and AI developers. Using the HyperCycleSwapV2 contract, an amount of HyPC (erc20)
can be swapped for a cHyPC (containerized HyPC) token, which can then point towards a
license (HyperCycleLicense) NFT id. At this point, the owner of this license can assign
their license to some hardware running the HyperCycle Node Manager, and can from then
on accept AI service requests on the network.
While all of this can be done by a single user, there are benefits to dividing up the
responsibilities of each party, so a user can participate as a license holder, token holder,
hardware operator, or AI developer. This is where the HyperCycle Share contracts come into
play. The HyperCycleShareTokens contract is an ERC1155 contract that accepts a deposit of
a license NFT and a cHyPC NFT, and creates two new tokens: a wealth token, and a revenue
token. While the license and cHyPC are locked in the new Share, revenue can be deposited
into the HyperCycleShareTokens by the hardware manager (that is, using the node manager
software) with the depositRevenue() method. After some HyPC has been deposited this way,
the revenue becomes locked for a minimum waiting period (for example, 7 days), after which,
this revenue can be unlocked, and at that point, owners of the revenue token can claim
their portion of the share's income by using the claimRevenue() method. This will update
their withdrawable amount of HyPC that they can then withdraw from the contract. The revenue
deposit delay is useful for ensuring more fairness of the revenue sharing. For instance,
without a delay, the hardware operator could buy a lot of revenue tokens from an exchange,
then make a huge revenue deposit into the contract, and then immediately claim their revenue
and then sell the revenue tokens back to the exchange. With a delay period, the hardware
operator would have to hold onto those tokens for the 7 day period, and with the pending
deposit coming through, the revenue token price would increase (similar to dividend yielding
stocks when leading up to the day a dividend will be paid out). The other holders of the
revenue tokens can sell their tokens at the higher price, and then buy back the revenue
tokens after the revenue is unlocked and claimable by the contract, when the price is lower.
This counteracts the advantage the hardware operator,or users who would front run a deposit
transaction, would have.
Since revenue tokens can be transferred at any time, while revenue is collected only on the
claimRevenue call, whenever a transfer of revenue tokens happens, a claimRevenue call is
made for both the sender and receiver of the tokens first via the safeTransferFrom ERC1155
overrides defined at the end of the contract. This prevents the following situation:
suppose Alice and Bob have 50% of the revenue tokens each, and the contract earns 1000 HyPC.
Alice then sends Bob half of her revenue tokens. Bob now owns 75% of the revenue tokens and
can claim 75% of the 1000 HyPC, even though the 1000 HyPC was deposited when Alice owned
50% of those tokens.
The claimRevenue hook on the transfer of revenue tokens fixes this issue by forcing the
revenue to be claimed whenever revenue tokens are transferred between parties. In effect,
the issue is that revenue tokens are only fungible if they have collected revenue at the
same time (if Alice claims revenue on her tokens while Bob has not, then these tokens
are not equivalent to each other). If both holders of the tokens have collected at the
same time however, then these tokens are indeed equivalent.
Besides the revenue tokens, there are also the wealth tokens. In this contract they do not
have any special usage, but are intended for use in future contracts (for example: a share
manager contract) that can use them for governance functions. Right now, the current contract
is intended to be used either via a multi-sig wallet with a general delgation mechanism
(eg: gnosis), or more likely via an external manager contract that interfaces with this
contract. In that case, the license holder and cHyPC holders would use the manager contract
to create the share and divide the wealth and revenue tokens amongst themselves, or other
parties, using governing mechanisms inside the manager contract.
If the original creator of the share (or someone that had the share transferred to them)
decides to cancel the share itself by calling the cancelShareTokens() method, then the
original license and cHyPC NFTs are sent back to the creator (or new owner), and future
deposits to share are halted. At this time, owners of the revenue tokens can claim their
last amounts of HyPC, and withdraw their HyPC from the contract.
As well, while the typical use case is that the original creator of the share deposits
both the license and cHyPC tokens into the share contract, there are some use cases where
it might make sense to only deposit the license instead. This could be the case where
this creator is a smart contract that used the CrowdFundHYPCPoolV2 contract get an
assignment pointed to the license Id. In this case, the smart contract would have an
external guarantee that the license has backing but does not own the cHyPC itself.
In this case, a share can be created instead with a cHyPC id of 0, which will bypass the
cHyPC retrieval and assignment in that case.
Finally, there's also a message function to allow the owner of a share to set a message
associated to this share. This is mainly intended for future manager contracts to use.
*/
/* Errors */
// Modifier Errors
//@dev Error for when requiring the caller to be the owner of the share
error MustBeShareOwner();
//@dev Error for when the given share has to be active (not previously cancelled).
error ShareMustBeActive();
//@dev Error for when the given shareNumber has not been created yet.
error ShareDoesntExist();
//@dev Error for when the pending deposit does not exist.
error PendingDepositMustExist();
/* Constructor Errors */
//@dev Error for when the give end share number would cause an overflow when creating the token Ids.
error EndShareNumberWouldOverflow();
//@dev Error for when the inputed end number is greater than 2 times the start number.
// This ensures that 2 times the current share number (ie: the revenueToken id) will be unique.
// This error is also raised when the endNumber given is less than the startNumber.
error InvalidShareNumberRange();
//@dev Error for when the license contract address is zero.
error InvalidLicenseAddress();
//@dev Error for when the swapV2 contract address is zero.
error InvalidSwapV2Address();
//@dev Error for when the HyPC contract address is zero.
error InvalidHYPCAddress();
//@dev Error for when the cHyPCV1 contract address is zero.
error InvalidCHYPCV1Address();
//@dev Error for when the startLimit amount for the constructor is outside the share number range.
error InvalidStartingLimit();
/* increaseShareLimit Errors */
//@dev Error for when trying to increase the soft share limit beyond the endShareNumber.
error ShareLimitIncreasedTooMuch();
/* createShareTokens Errors */
//@dev Error for when trying to create a share beyond the share limit.
error CantCreateSharesBeyondShareLimit();
//@dev Error for when trying to create a share without CHYPC backing (via SwapV1 or SwapV2).
error LicenseMustHaveCHYPCBacking();
//@dev Error for when trying to create a share with CHYPC level lower than license level.
error InvalidCHYPCTokenLevel();
/* unlockRevenue Errors */
//@dev Error for when trying to unlock a pending deposits before the delay time has passed.
error UnlockingRevenueTooEarly();
/* claimRevenue Errors */
//@dev Error for when trying to claim revenue for a share when you don't have any of its revenue tokens.
error NoRevenueTokensForThisShare();
//@dev Error for when trying to claim revenue when there is none to claim.
error NoRevenueToClaim();
/* transferShareOwnership Errors */
//@dev Error for when trying to transfer ownership of a share to the zero address.
error CantTransferToZeroAddress();
/* cancelShareTokens Errors */
//@dev Error for when trying to cancel a share before the MIN_DURATION time has passed.
error ShareMinDurationHasNotPassed();
/* withdrawEarnings Errors */
//@dev Error for when trying to withdraw claimed revenue when there is none in the contract.
error NothingToWithdraw();
/* burn Errors */
//@dev Error for when trying to burn revenue tokens that have unclaimed revenue
error MustClaimRevenueToBurnTokens();
//@dev Error for when trying to burn revenue tokens before a share has ended.
error ShareMustBeEnded();
//@dev Error for when trying to burn zero revenue tokens.
error MustBurnSomeRevenueTokens();
//@dev Error for when user trys to burn more revenue tokens than they own.
error NotEnoughRevenueTokensOwned();
//@dev Error for when trying to burn zero wealth tokens.
error MustBurnSomeWealthTokens();
//@dev Error for when user trys to burn more wealth tokens than they own.
error NotEnoughWealthTokensOwned();
contract HyperCycleShareTokensV2 is
ERC1155, ERC721Holder, Ownable, ReentrancyGuard, IHyperCycleShareTokens {
//@dev Contract interfaces
IHYPC private immutable hypcToken;
ICHYPC private immutable chypcV1Contract;
IHYPCSwapV2 private immutable swapV2Contract;
IHyperCycleLicense private immutable licenseContract;
// Contract constants
//@dev The max supply to use for revenue tokens.
uint256 public constant REVENUE_TOKEN_MAX_SUPPLY = 2**19;
//@dev The max supply to use for wealth tokens.
uint256 public constant WEALTH_TOKEN_MAX_SUPPLY = 2**19;
//@dev The minimum time that has to pass before a share can be cancelled.
uint256 public constant MIN_SHARE_DURATION = 24 hours;
//@dev The number of decimals to use when doing revenue sharing calculations.
uint256 public constant RATIO_DECIMALS = 10**12;
//@dev Enum for the status of a share.
enum Status {
NOT_CREATED,
STARTED,
ENDED
}
//@dev Struct for data specific to a single share, accessible via the following mapping.
struct ShareData {
uint256 licenseId;
uint256 chypcId;
Status status;
address owner;
uint256 rTokenNumber;
uint256 wTokenNumber;
uint256 rTokenSupply;
uint256 wTokenSupply;
uint256 startTimestamp;
uint256 revenueDeposited;
uint256 revenueDepositDelay;
string message;
bool chypcTokenHeld;
}
//@dev Struct for storing pending share deposits
//struct PendingDeposit {
// uint256 availableAtTimestamp;
// uint256 amount;
//}
// Mappings
//@dev Main storage for individual share information
mapping(uint256=>ShareData) public shareData;
//@dev Storage for keeping track of the last totalRevenue a revenue token owner claimed their
// revenue against.
mapping(uint256=>mapping(address=>uint256)) public lastShareClaimRevenue;
//@dev Storage for keeping track of how much HyPC a given address can withdraw, updated by
// claimRevenue() calls.
mapping(uint256=>mapping(address=>uint256)) public withdrawableAmounts;
//@dev Helper function to get the last shareNumber to use this given licenseId NFT.
mapping(uint256=>uint256) public licenseToShareNumber;
//@dev Storage array for pending revenue deposits.
mapping(uint256=> PendingDeposit[]) public pendingDeposits;
// Variables
//@dev The starting shareNumber to be issued.
uint256 public startShareNumber;
//@dev The last possible shareNumber to be issued.
uint256 public endShareNumber;
//@dev Soft limit for the upper value of shareNumbers. Can be increased by the owner of this
// contract.
uint256 public shareLimitNumber;
//@dev The next valid shareNumber to be issued.
uint256 public currentShareNumber;
//@dev The total amount of HyPC deposited so far into this contract.
uint256 public totalDeposited;
// Events
// @dev The event for when the contract owner increase the soft share limit.
// @param amount: The amount that the soft shareNumber limit was increased by.
event IncreaseShareLimit(uint256 amount);
// @dev The event for when a user creates a new share.
// @param licenseNumber: The HyperCycleLicense NFT id used for this share.
// @param chypcNumber: The SwapV2 cHyPC NFT id used for this share.
// @param owner: The user that created this share.
// @param shareNumber: The shareNumber given to this new share.
// @param rToken: The revenue token id in this contract for this share.
// @param wToken: The wealth token id in the contract for this share.
// @param startTime: The timestamp for when this share was created.
// @param startingMessage: The message assigned to this share when created.
event CreateShare(
uint256 licenseNumber,
uint256 chypcNumber,
address owner,
uint256 shareNumber,
bool chypcTokenHeld
);
// @dev The event for when an owner of a share transfers it to someone else.
// @param shareNumber: The share being transferred.
// @param to: The address this share is being transferred to.
event ShareOwnershipTransferred(uint256 shareNumber, address to);
// @dev The event for when an owner of a share changes the pending revenue delay.
// @param shareNumber: The share to change the maximum revenue deposit of.
// @param newDelay: The new pending revenue minimum delay, in seconds.
event PendingRevenueDelayChange(uint256 shareNumber, uint256 newDelay);
// @dev The event for when revenue is deposited into a share.
// @param shareNumber: The share receiving the revenue.
// @param amount: The amount of HyPC being deposited.
// @param timestamp: The time this revenue was deposited.
event RevenueDeposited(uint256 shareNumber, uint256 amount, uint256 timestamp);
// @dev The event for when pending revenue is deposited into a share.
// @param shareNumber: The share receiving the revenue.
// @param amount: The amount of HyPC being deposited.
// @param pendingUntil: The time this deposit becomes available to be claimed.
event PendingRevenueDeposit(uint256 shareNumber, uint256 index, uint256 amount);
// @dev The event for when a share is cancelled and the NFTs returned to the owner.
// @param shareNumber: The share being cancelled.
// @param chypcNumber: The cHyPC NFT id being returned.
// @param licenseNumber: The license NFT id being returned.
event CancelledSharedTokens(uint256 shareNumber, uint256 chypcNumber, uint256 licenseNumber);
// @dev The event for when an address claims HyPC from deposits.
// @param shareNumber: The share whose revenue is being withdrawn.
// @param claimer: The address withdrawing its claimed revenue.
// @param amount: The amount of HyPC claimed.
event ClaimRevenue(uint256 shareNumber, address claimer, uint256 amount);
// @dev The event for when an address withdraws its claimed HyPC from deposits.
// @param shareNumber: The share whose revenue is being withdrawn.
// @param claimer: The address withdrawing its claimed revenue.
// @param amount: The amount of HyPC that was withdrawn.
event EarningsWithdrawal(uint256 shareNumber, address claimer, uint256 amount);
// @dev The event for when an share has its message changed.
// @param shareNumber: The share whose message is being changed.
// @param message: The new message
event ShareMessageChangedTo(uint256 shareNumber, string message);
// Modifiers
// @dev Checks if the sender is the owner of this share.
// @param shareNumber: The share id to check.
modifier shareOwner(uint256 shareNumber) {
if (shareData[shareNumber].owner != msg.sender) revert MustBeShareOwner();
_;
}
// @dev Checks if the given share is still active.
// @param shareNumber: The share id to check.
modifier shareActive(uint256 shareNumber) {
if (shareData[shareNumber].status != Status.STARTED) revert ShareMustBeActive();
_;
}
// @dev Checks if the given share was created.
// @param shareNumber: The share id to check.
modifier shareExists(uint256 shareNumber) {
if (shareData[shareNumber].status == Status.NOT_CREATED) revert ShareDoesntExist();
_;
}
// @dev Checks if the given share has been ended.
// @param shareNumber: The share id to check.
modifier shareEnded(uint256 shareNumber) {
if (shareData[shareNumber].status != Status.ENDED) revert ShareMustBeEnded();
_;
}
// @dev Checks if the given pending deposit exists.
// @param shareNumber: The share to check the pending deposits of.
// @param index: The index to check
modifier pendingDepositExists(uint256 shareNumber, uint256 index) {
if (index >= pendingDeposits[shareNumber].length) revert PendingDepositMustExist();
_;
}
/**
@dev The constructor takes in the share range to use, from startNumber to endNumber
inclusive, as well as the contract addresses for the license and cHyPC NFTs, and the
address for the HyPC token. The revenue token Id for a share is twice its shareNumber,
and twice the shareNumber plus one for the corresponding wealth token. To ensure no
overlap between shareNumbers and token Ids, the endNumber must be greater than or
equal to the startNumber and less than the startNumber times two.
@param startNumber: The first shareNumber id to use.
@param endNumber: The last shareNumber id to use.
@param startLimit: The starting shareLimtt to use.
@param licenseAddress: The license ERC721 contract address.
@param swapV2Address: The cHyPC ERC721 contract address.
@param hypcAddress: The HyPC ERC20 contract address.
*/
constructor(uint256 startNumber, uint256 endNumber, uint256 startLimit, address licenseAddress,
address chypcV1Address, address swapV2Address, address hypcAddress) ERC1155("") {
if (endNumber >= 2**255 - 2) revert EndShareNumberWouldOverflow();
if (endNumber/2 >= startNumber) revert InvalidShareNumberRange();
if (endNumber < startNumber) revert InvalidShareNumberRange();
if (licenseAddress == address(0)) revert InvalidLicenseAddress();
if (swapV2Address == address(0)) revert InvalidSwapV2Address();
if (hypcAddress == address(0)) revert InvalidHYPCAddress();
if (chypcV1Address == address(0)) revert InvalidCHYPCV1Address();
if (startLimit < startNumber || startLimit > endNumber) revert InvalidStartingLimit();
startShareNumber = startNumber;//8590983168 = 2**33+2**20
endShareNumber = endNumber;//8592031743 = 2**33 + 2**21 - 1
shareLimitNumber = startLimit;
currentShareNumber = startShareNumber;
chypcV1Contract = ICHYPC(chypcV1Address);
swapV2Contract = IHYPCSwapV2(swapV2Address);
licenseContract = IHyperCycleLicense(licenseAddress);
hypcToken = IHYPC(hypcAddress);
}
// @notice Allows the owner of the contract to increase the soft limit of share numbers in the
// contract. This is put in place to alow future upgrades of this contract to reserve
// higher ranges of shareNumbers, and restrict the older contract from overlapping the
// shareNumbers.
// @param number: The amount to increase the soft share limit by.
function increaseShareLimit(uint256 number) external onlyOwner {
if (shareLimitNumber+number > endShareNumber) revert ShareLimitIncreasedTooMuch();
shareLimitNumber+=number;
emit IncreaseShareLimit({amount: number});
}
// @notice Allows a user to create a new share. Takes the given licenseNumber and chypcNumber NFTs
// and sends the wealth and revenue tokens to the owner for the corresponding created
// share.
// @param licenseNumber: The license NFT Id to deposit into this share.
// @param chypcNumber: The cHyPC NFT Id to deposit into this share.
function createShareTokens(uint256 licenseNumber, uint256 chypcNumber, bool chypcTokenHeld, string memory startingMessage, uint256 revenueDepositDelay) external nonReentrant {
if (currentShareNumber > shareLimitNumber) revert CantCreateSharesBeyondShareLimit();
if (!chypcTokenHeld) {
_verifyCHYPCAssignment(chypcNumber, licenseNumber);
}
if (_getLicenseLevel(licenseNumber) > _getCHYPCLevel(chypcNumber)) {
revert InvalidCHYPCTokenLevel();
}
address to = msg.sender;
uint256 shareNumber = currentShareNumber;
uint256 rTokenType = shareNumber*2;
uint256 wTokenType = shareNumber*2+1;
uint256 licenseLevel = _getLicenseLevel(licenseNumber);
currentShareNumber+=1;
shareData[shareNumber] = ShareData(
licenseNumber,
chypcNumber,
Status.STARTED,
to,
rTokenType,
wTokenType,
REVENUE_TOKEN_MAX_SUPPLY/(2**(19-licenseLevel)),
WEALTH_TOKEN_MAX_SUPPLY/(2**(19-licenseLevel)),
block.timestamp,
0,
revenueDepositDelay,
startingMessage,
chypcTokenHeld
);
licenseToShareNumber[licenseNumber] = shareNumber;
licenseContract.safeTransferFrom(to, address(this), licenseNumber);
if (chypcTokenHeld) {
swapV2Contract.safeTransferFrom(to, address(this), chypcNumber);
swapV2Contract.assignNumber(chypcNumber, licenseNumber);
}
_mint(to, rTokenType, REVENUE_TOKEN_MAX_SUPPLY/(2**(19-licenseLevel)), "");
_mint(to, wTokenType, WEALTH_TOKEN_MAX_SUPPLY/(2**(19-licenseLevel)), "");
emit CreateShare({licenseNumber: licenseNumber,
chypcNumber: chypcNumber,
owner: to,
shareNumber: shareNumber,
chypcTokenHeld: chypcTokenHeld
});
}
// @notice An internal function to check the backing of the license from the given
// chypcNumber. This checks assignments via the SwapV2 contract first, and
// then the SwapV1 contract.
// @param chypcNumber: The cHyPC NFT Id pointing to the licenseNumber.
// @param licenseNumber: The license NFT Id to deposit into this share.
function _verifyCHYPCAssignment(uint256 chypcNumber, uint256 licenseNumber) internal {
string memory stringAssigned = Strings.toString(licenseNumber);
if (swapV2Contract.getAssignmentNumber(chypcNumber) != licenseNumber &&
!Strings.equal(swapV2Contract.getAssignmentString(chypcNumber), stringAssigned) &&
!Strings.equal(chypcV1Contract.getAssignment(chypcNumber), stringAssigned)) {
revert LicenseMustHaveCHYPCBacking();
}
}
// @notice An internal function to return the license level of a license token.
// @param licenseNumber: The license NFT id.
function _getLicenseLevel(uint256 licenseNumber) internal returns (uint256) {
return licenseContract.getLicenseHeight(licenseNumber);
}
// @notice An internal function to return the chypc level of a chypc token.
// @param chypcNumber: The chypc NFT id (V1 or V2) to check.
function _getCHYPCLevel(uint256 chypcNumber) internal returns (uint256) {
//@dev SwapV2 token
try swapV2Contract.getTokenLevel(chypcNumber) returns (uint256) {
return swapV2Contract.getTokenLevel(chypcNumber);
} catch {}
//@dev SwapV1 token
if (chypcNumber >= 67108864 && chypcNumber < 67108864+160) {
return 19;
}
return 0;
}
// @notice Transfers the ownership of a share to another address. Useful for transferring from an
// existing multi-sig or manager contract to another one.
// @param shareNumber: The share to transfer to a new owner
// @parma to: The new owner of this share.
function transferShareOwnership(uint256 shareNumber, address to) external shareOwner(shareNumber) shareActive(shareNumber) {
if (to == address(0)) revert CantTransferToZeroAddress();
shareData[shareNumber].owner = to;
emit ShareOwnershipTransferred({shareNumber: shareNumber, to: to});
}
// @notice Changes the maximum allowed revenue deposit.
// @param shareNumber: The share to change the maximum revenue deposit of.
// @param newDelay: The new delay to wait for in seconds.
function changePendingRevenueDelay(uint256 shareNumber, uint256 newDelay) external shareOwner(shareNumber) shareActive(shareNumber) {
shareData[shareNumber].revenueDepositDelay = newDelay;
emit PendingRevenueDelayChange({shareNumber: shareNumber, newDelay: newDelay});
}
// @notice Cancels a given share and returns the deposited license and cHyPC NFTs to the owner.
// Once cancelled, no more revenue can be deposited to this share, but existing owners
// of revenue tokens can still claim any deposited HyPC they previously didn't claim.
// @param shareNumber: The share to cancel.
function cancelShareTokens(uint256 shareNumber) external shareOwner(shareNumber) shareActive(shareNumber) nonReentrant {
if (shareData[shareNumber].startTimestamp + MIN_SHARE_DURATION > block.timestamp) revert ShareMinDurationHasNotPassed();
uint256 licenseNumber = shareData[shareNumber].licenseId;
uint256 chypcNumber = shareData[shareNumber].chypcId;
bool chypcTokenHeld = shareData[shareNumber].chypcTokenHeld;
shareData[shareNumber].status = Status.ENDED;
delete licenseToShareNumber[licenseNumber];
if (chypcTokenHeld) {
swapV2Contract.assignNumber(chypcNumber, 0);
swapV2Contract.safeTransferFrom(address(this), msg.sender, chypcNumber);
}
licenseContract.safeTransferFrom(address(this), msg.sender, licenseNumber);
emit CancelledSharedTokens({
shareNumber: shareNumber,
chypcNumber: chypcNumber,
licenseNumber: licenseNumber
});
}
// @notice Sets the stored message for this share.
// @param shareNumber: The share to set the message of.
// @param message: The message to set for this share.
function setShareMessage(uint256 shareNumber, string memory message) external shareOwner(shareNumber) shareActive(shareNumber) {
shareData[shareNumber].message = message;
emit ShareMessageChangedTo({shareNumber: shareNumber, message: message});
}
/* Revenue sharing functions */
// @notice Deposits revenue into a share. It remains locked until it is later released.
// @param shareNumber: The share this revenue is deposited for.
// @param amt: The amount of HyPC being deposited.
function depositRevenue(uint256 shareNumber, uint256 amt) external shareActive(shareNumber) {
pendingDeposits[shareNumber].push(
PendingDeposit({
availableAtTimestamp: block.timestamp+shareData[shareNumber].revenueDepositDelay,
amount: amt
})
);
hypcToken.transferFrom(msg.sender, address(this), amt);
emit PendingRevenueDeposit({
shareNumber: shareNumber,
index: pendingDeposits[shareNumber].length-1,
amount: amt
});
}
// @notice Unlocks a pending revenue deposit to be claimable by the rToken holders
// @param shareNumber: The share this revenue is being unlocked for.
// @param index: The index of the pending deposit to unlock.
function unlockRevenue(uint256 shareNumber, uint256 index) external pendingDepositExists(shareNumber, index) {
PendingDeposit memory pd = pendingDeposits[shareNumber][index];
if (pd.availableAtTimestamp > block.timestamp) {
revert UnlockingRevenueTooEarly();
}
totalDeposited += pd.amount;
shareData[shareNumber].revenueDeposited += pd.amount;
//Remove old index now;
if (pendingDeposits[shareNumber].length > 1 && index < pendingDeposits[shareNumber].length -1 ) {
pendingDeposits[shareNumber][index] = pendingDeposits[shareNumber][pendingDeposits[shareNumber].length -1];
}
pendingDeposits[shareNumber].pop();
emit RevenueDeposited({
shareNumber: shareNumber,
amount: pd.amount,
timestamp: block.timestamp
});
}
// @notice Internal function for claiming revenue share of a token. This is called whenever a
// revenue token holder wants to claim their propotional revenue in this contract. This
// is also called whenever a user transfers revenue tokens to another user as mentioned
// in the contract description above.
// @param shareNumber: The share to claim revenue for.
// @param claimerAddress: The address claiming their revenue.
function _claimRevenue(uint256 shareNumber, address claimerAddress) internal returns (uint256) {
uint256 rTokenNumber = shareData[shareNumber].rTokenNumber;
uint256 revenueDeposited = shareData[shareNumber].revenueDeposited;
uint256 licenseLevel = _getLicenseLevel(shareData[shareNumber].licenseId);
uint256 rTokenStartingSupply = REVENUE_TOKEN_MAX_SUPPLY/(2**(19-licenseLevel));
uint256 ownershipRatio = RATIO_DECIMALS*balanceOf(claimerAddress, rTokenNumber)/rTokenStartingSupply;
uint256 amountToGiveAddress = (revenueDeposited-lastShareClaimRevenue[shareNumber][claimerAddress])*ownershipRatio/RATIO_DECIMALS;
lastShareClaimRevenue[shareNumber][claimerAddress] = revenueDeposited;
withdrawableAmounts[shareNumber][claimerAddress] += amountToGiveAddress;
emit ClaimRevenue(shareNumber, claimerAddress, amountToGiveAddress);
return amountToGiveAddress;
}
// @notice External function for _claimRevenue for when a user wants to explictly claim their
// revenue for a given share (without any revenue token transfer).
// @param shareNumber: The share to claim the revenue of.
function claimRevenue(uint256 shareNumber) external shareExists(shareNumber) {
if (balanceOf(msg.sender, shareData[shareNumber].rTokenNumber) == 0) revert NoRevenueTokensForThisShare();
if (_claimRevenue(shareNumber, msg.sender) == 0) revert NoRevenueToClaim();
}
// @notice Internal function for withdrawEarnings, which withdraws HyPC from the share.
// @param shareNumber: The share to withdraw from.
function _withdrawEarnings(uint256 shareNumber) internal shareExists(shareNumber) {
uint256 amt = withdrawableAmounts[shareNumber][msg.sender];
if (amt == 0) revert NothingToWithdraw();
withdrawableAmounts[shareNumber][msg.sender] = 0;
hypcToken.transfer(msg.sender, amt);
emit EarningsWithdrawal({
shareNumber: shareNumber,
claimer: msg.sender,
amount: amt
});
}
// @notice Withdraws claimed revenue for this user, if there is any.
// @param shareNumber: The share to withdraw revenue from.
function withdrawEarnings(uint256 shareNumber) external {
_withdrawEarnings(shareNumber);
}
// @notice Utility function to claim and withdraw from a share.
// @param shareNumber: The share to claim and withdraw revenue from.
function claimAndWithdraw(uint256 shareNumber) external {
if (balanceOf(msg.sender, shareData[shareNumber].rTokenNumber) == 0) revert NoRevenueTokensForThisShare();
if (_claimRevenue(shareNumber, msg.sender) == 0) revert NoRevenueToClaim();
_withdrawEarnings(shareNumber);
}
// @notice Allows a user to burn revenue tokens from an ended share.
// @param shareNumber: The share to burn revenue tokens from.
// @param amount: The amount of revenue tokens to burn.
function burnRevenueTokens(uint256 shareNumber, uint256 amount) external shareEnded(shareNumber) {
if (_claimRevenue(shareNumber, msg.sender) > 0) revert MustClaimRevenueToBurnTokens();
if (amount == 0) revert MustBurnSomeRevenueTokens();
if (balanceOf(msg.sender, shareData[shareNumber].rTokenNumber) < amount) revert NotEnoughRevenueTokensOwned();
shareData[shareNumber].rTokenSupply -= amount;
_burn(msg.sender, shareData[shareNumber].rTokenNumber, amount);
}
// @notice Allows a user to burn wealth tokens from an ended share.
// @param shareNumber: The share to burn wealth tokens from.
// @param amount: The amount of wealth tokens to burn.
function burnWealthTokens(uint256 shareNumber, uint256 amount) external shareOwner(shareNumber) shareEnded(shareNumber) {
if (amount == 0) revert MustBurnSomeWealthTokens();
if (balanceOf(msg.sender, shareData[shareNumber].wTokenNumber) < amount) revert NotEnoughWealthTokensOwned();
shareData[shareNumber].wTokenSupply -= amount;
}
/* Getters */
// @notice Returns the license NFT Id for a share.
// @param shareNumber: The share to get the license Id of.
// @return licenseId: The license NFT Id.
function getShareLicenseId(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].licenseId;
}
// @notice Returns the cHypC NFT Id for a share.
// @param shareNumber: The share to get the cHyPC Id of.
// @return chypcId: The cHyPC NFT Id.
function getShareCHyPCId(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].chypcId;
}
// @notice Returns the owner of a share.
// @param shareNumber: The share to get the owner of.
// @return owner: The owner address.
function getShareOwner(uint256 shareNumber) external view returns (address) {
return shareData[shareNumber].owner;
}
// @notice Returns the revenue token Id for a share.
// @param shareNumber: The share to get the revenue token Id of.
// @return rTokenNumber: The revenue token Id.
function getShareRevenueTokenId(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].rTokenNumber;
}
// @notice Returns the wealth token Id for a share.
// @param shareNumber: The share to get the wealth token Id of.
// @return wTokenNumber: The wealth token Id.
function getShareWealthTokenId(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].wTokenNumber;
}
// @notice Returns the total revenue obtained for a share.
// @param shareNumber: The share to get the total revenue of.
// @return revenueDeposited: The total revenue deposited for this share.
function getShareTotalRevenue(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].revenueDeposited;
}
// @notice Returns the start time of a share.
// @param shareNumber: The share to get the start time of.
// @return startTimestamp: The block timestamp when this share was created.
function getShareStartTime(uint256 shareNumber) external view returns (uint256) {
return shareData[shareNumber].startTimestamp;
}
// @notice Returns the message for a share.
// @param shareNumber: The share to get the message of.
// @return message: The message that was set for this share.
function getShareMessage(uint256 shareNumber) external view returns (string memory) {
return shareData[shareNumber].message;
}
// @notice Returns whether the given share is active.
// @param shareNumber: The share to get the status of.
// @return active: Returns true if the share is active, otherwise false.
function isShareActive(uint256 shareNumber) external view returns (bool) {
return shareData[shareNumber].status == Status.STARTED;
}
// @notice Returns whether the given share was created yet or not.
// @param shareNumber: The share to get the created status of.
// @return active: Returns true if the share was created, otherwise false.
function shareCreated(uint256 shareNumber) external view returns (bool) {
return shareData[shareNumber].status != Status.NOT_CREATED;
}
// @notice Returns the total supply of revenue tokens for a share.
// @param shareNumber: The share to get the total supply of revenue tokens.
function getRevenueTokenTotalSupply(uint256 shareNumber) external shareExists(shareNumber) view returns (uint256) {
return shareData[shareNumber].rTokenSupply;
}
// @notice Returns the total supply of wealth tokens for a share.
// @param shareNumber: The share to get the total supply of wealth tokens.
function getWealthTokenTotalSupply(uint256 shareNumber) external shareExists(shareNumber) view returns (uint256) {
return shareData[shareNumber].wTokenSupply;
}
// @notice Returns the pending deposit at the given index.
// @param shareNumber: The share to get the pending deposit of.
// @param index: The index to look up.
function getPendingDeposit(uint256 shareNumber, uint256 index) external pendingDepositExists(shareNumber, index) view returns (PendingDeposit memory) {
return pendingDeposits[shareNumber][index];
}
// @notice Returns the length of the pending deposits array for this shareNumber.
// @param shareNumber: The share to look up.
function getPendingDepositsLength(uint256 shareNumber) external shareExists(shareNumber) view returns (uint256) {
return pendingDeposits[shareNumber].length;
}
/* ERC1155 Overrides */
// @notice Override hooks into the transfer functions of the ERC1155 contract for revenue
// claiming. This allows ERC20-like tokens to be used for revenue sharing purposes.
// See ERC1155 contract for details on parameters.
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public override(ERC1155, IERC1155) {
//@dev If this is a revenue sharing token, then update the claimed revenue before transfering
if (id % 2 == 0) {
uint256 shareNumber = id/2;
if (shareData[shareNumber].status == Status.NOT_CREATED) revert ShareDoesntExist();
_claimRevenue(shareNumber, from);
_claimRevenue(shareNumber, to);
}
super.safeTransferFrom(from, to, id, value, data);
}
// @notice Override hooks into the batch transfer functions of the ERC1155 contract for revenue
// claiming. This allows ERC20-like tokens to be used for revenue sharing purposes.
// See ERC1155 contract for details on parameters.
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public override(ERC1155, IERC1155) {
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
if (id % 2 == 0) {
uint256 shareNumber = id/2;
if (shareData[shareNumber].status == Status.NOT_CREATED) revert ShareDoesntExist();
_claimRevenue(shareNumber, from);
_claimRevenue(shareNumber, to);
}
}
super.safeBatchTransferFrom(from, to, ids, values, data);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
/// @notice Interface for the CHYPC.sol contract.
interface ICHYPC is IERC721 {
/**
* Accesses the assignment function of c_HyPC so the swap can remove
* the assignment data when a token is redeemed or swapped.
*/
/// @notice Assigns a string to the given c_HyPC token.
function assign(
uint256 tokenId,
string memory data
) external;
/// @notice Returns the assigned string for this token.
function getAssignment(
uint256 tokenId
) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @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 v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @notice Interface for the HyperCycleToken.sol contract.
interface IHYPC is IERC20 {
/*
* Accesses the ERC20 functions of the HYPC contract. The burn function
* is also exposed for future contracts.
*/
/// @notice Burns an amount of the HyPC ERC20.
function burn(uint256 amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/interfaces/IERC721.sol";
/// @notice Interface for the HYPCSwap.sol contract.
interface IHYPCSwapV2 is IERC721 {
/**
* Accesses the addNFT function so that the CHYPC contract can
* add the newly created NFT into this contract.
*/
function addRootTokens(uint256 tokens) external;
function splitHeldToken(uint256 level, uint256 skipLevels) external;
function swapV2(uint256 level) external;
function redeem(uint256 tokenNumber) external;
function assignNumber(uint256 tokenNumber, uint256 targetNumber) external;
function assignString(uint256 tokenNumber, string memory data) external;
function burn(uint256 tokenNumber, string memory data) external;
function assign(uint256 tokenNumber, string memory data) external;
function swap() external;
function getAssignment(uint256 tokenNumber) external view returns (string memory);
function getAssignmentNumber(uint256 tokenNumber) external view returns (uint256);
function getAssignmentString(uint256 tokenNumber) external view returns (string memory);
function getBurnData(uint256 tokenNumber) external view returns (string memory);
function getAvailableToken(uint256 level, uint256 index) external view returns (uint256);
function getTokenLevel(uint256 tokenNumber) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
/// @notice Interface for the CHYPC.sol contract.
interface IHyperCycleLicense is IERC721 {
/**
* Accesses the assignment function of c_HyPC so the swap can remove
* the assignment data when a token is redeemed or swapped.
*/
/// @notice Creates a new root token inside this contract, with a specified licenseID.
function mint(
uint256 numTokens
) external;
/// @notice Splits a given token into two new tokens, with corresponding licenseID's.
function split(
uint256 tokenId
) external;
/// @notice Burns a given tokenId with a specified burn string.
function burn(
uint256 tokenId,
string memory burnString
) external;
/// @notice Merges together two child licenses into a parent license.
function merge(
uint256 tokenId
) external;
/// @notice Returns the burn data from the given tokenId.
function getBurnData(
uint256 tokenId
) external view returns (string memory);
/// @notice Returns the license height of the given tokenId.
function getLicenseHeight(
uint256 licenseId
) external view returns (uint8);
/// @notice Returns the license height of the given tokenId.
function getLicenseStatus(
uint256 licenseId
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
/// @notice Interface for the HyperCycleShareTokens.sol contract.
interface IHyperCycleShareTokens is IERC1155 {
struct PendingDeposit {
uint256 availableAtTimestamp;
uint256 amount;
}
function increaseShareLimit(uint256 number) external;
function createShareTokens(uint256 licenseNumber, uint256 chypcNumber, bool chypcTokenHeld, string memory startingMessage, uint256 maxRevenueDeposit) external;
function transferShareOwnership(uint256 shareNumber, address to) external;
function cancelShareTokens(uint256 shareNumber) external;
function depositRevenue(uint256 shareNumber, uint256 amt) external;
function claimRevenue(uint256 shareNumber) external;
function withdrawEarnings(uint256 shareNumber) external;
function setShareMessage(uint256 shareNumber, string memory message) external;
function burnRevenueTokens(uint256 shareNumber, uint256 amount) external;
function burnWealthTokens(uint256 shareNumber, uint256 amount) external;
function getShareLicenseId(uint256 shareNumber) external view returns (uint256);
function getShareCHyPCId(uint256 shareNumber) external view returns (uint256);
function getShareOwner(uint256 shareNumber) external view returns (address);
function getShareRevenueTokenId(uint256 shareNumber) external view returns (uint256);
function getShareWealthTokenId(uint256 shareNumber) external view returns (uint256);
function getShareTotalRevenue(uint256 shareNumber) external view returns (uint256);
function getShareStartTime(uint256 shareNumber) external view returns (uint256);
function getShareMessage(uint256 shareNumber) external view returns (string memory);
function isShareActive(uint256 shareNumber) external view returns (bool);
function shareCreated(uint256 shareNumber) external view returns (bool);
function getRevenueTokenTotalSupply(uint256 shareNumber) external view returns (uint256);
function getWealthTokenTotalSupply(uint256 shareNumber) external view returns (uint256);
function getPendingDeposit(uint256 shareNumber, uint256 index) external view returns (PendingDeposit memory);
function getPendingDepositsLength(uint256 shareNumber) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
{
"compilationTarget": {
"contracts/ethereum/core/HyperCycleShareTokensV2.sol": "HyperCycleShareTokensV2"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"startNumber","type":"uint256"},{"internalType":"uint256","name":"endNumber","type":"uint256"},{"internalType":"uint256","name":"startLimit","type":"uint256"},{"internalType":"address","name":"licenseAddress","type":"address"},{"internalType":"address","name":"chypcV1Address","type":"address"},{"internalType":"address","name":"swapV2Address","type":"address"},{"internalType":"address","name":"hypcAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CantCreateSharesBeyondShareLimit","type":"error"},{"inputs":[],"name":"CantTransferToZeroAddress","type":"error"},{"inputs":[],"name":"EndShareNumberWouldOverflow","type":"error"},{"inputs":[],"name":"InvalidCHYPCTokenLevel","type":"error"},{"inputs":[],"name":"InvalidCHYPCV1Address","type":"error"},{"inputs":[],"name":"InvalidHYPCAddress","type":"error"},{"inputs":[],"name":"InvalidLicenseAddress","type":"error"},{"inputs":[],"name":"InvalidShareNumberRange","type":"error"},{"inputs":[],"name":"InvalidStartingLimit","type":"error"},{"inputs":[],"name":"InvalidSwapV2Address","type":"error"},{"inputs":[],"name":"LicenseMustHaveCHYPCBacking","type":"error"},{"inputs":[],"name":"MustBeShareOwner","type":"error"},{"inputs":[],"name":"MustBurnSomeRevenueTokens","type":"error"},{"inputs":[],"name":"MustBurnSomeWealthTokens","type":"error"},{"inputs":[],"name":"MustClaimRevenueToBurnTokens","type":"error"},{"inputs":[],"name":"NoRevenueToClaim","type":"error"},{"inputs":[],"name":"NoRevenueTokensForThisShare","type":"error"},{"inputs":[],"name":"NotEnoughRevenueTokensOwned","type":"error"},{"inputs":[],"name":"NotEnoughWealthTokensOwned","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[],"name":"PendingDepositMustExist","type":"error"},{"inputs":[],"name":"ShareDoesntExist","type":"error"},{"inputs":[],"name":"ShareLimitIncreasedTooMuch","type":"error"},{"inputs":[],"name":"ShareMinDurationHasNotPassed","type":"error"},{"inputs":[],"name":"ShareMustBeActive","type":"error"},{"inputs":[],"name":"ShareMustBeEnded","type":"error"},{"inputs":[],"name":"UnlockingRevenueTooEarly","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chypcNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"licenseNumber","type":"uint256"}],"name":"CancelledSharedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimRevenue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"licenseNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chypcNumber","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"bool","name":"chypcTokenHeld","type":"bool"}],"name":"CreateShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EarningsWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreaseShareLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDelay","type":"uint256"}],"name":"PendingRevenueDelayChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PendingRevenueDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RevenueDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"ShareMessageChangedTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shareNumber","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"ShareOwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"MIN_SHARE_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATIO_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVENUE_TOKEN_MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEALTH_TOKEN_MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnRevenueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnWealthTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"cancelShareTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"newDelay","type":"uint256"}],"name":"changePendingRevenueDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"claimAndWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"claimRevenue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseNumber","type":"uint256"},{"internalType":"uint256","name":"chypcNumber","type":"uint256"},{"internalType":"bool","name":"chypcTokenHeld","type":"bool"},{"internalType":"string","name":"startingMessage","type":"string"},{"internalType":"uint256","name":"revenueDepositDelay","type":"uint256"}],"name":"createShareTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentShareNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"depositRevenue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endShareNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getPendingDeposit","outputs":[{"components":[{"internalType":"uint256","name":"availableAtTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IHyperCycleShareTokens.PendingDeposit","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getPendingDepositsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getRevenueTokenTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareCHyPCId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareLicenseId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareMessage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareRevenueTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareTotalRevenue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getShareWealthTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"getWealthTokenTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"increaseShareLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"isShareActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lastShareClaimRevenue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"licenseToShareNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingDeposits","outputs":[{"internalType":"uint256","name":"availableAtTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"string","name":"message","type":"string"}],"name":"setShareMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"shareCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shareData","outputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"},{"internalType":"uint256","name":"chypcId","type":"uint256"},{"internalType":"enum HyperCycleShareTokensV2.Status","name":"status","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"rTokenNumber","type":"uint256"},{"internalType":"uint256","name":"wTokenNumber","type":"uint256"},{"internalType":"uint256","name":"rTokenSupply","type":"uint256"},{"internalType":"uint256","name":"wTokenSupply","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"revenueDeposited","type":"uint256"},{"internalType":"uint256","name":"revenueDepositDelay","type":"uint256"},{"internalType":"string","name":"message","type":"string"},{"internalType":"bool","name":"chypcTokenHeld","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareLimitNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startShareNumber","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":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"transferShareOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"unlockRevenue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareNumber","type":"uint256"}],"name":"withdrawEarnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"withdrawableAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]