-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathinput2.json
More file actions
72 lines (72 loc) · 46.8 KB
/
input2.json
File metadata and controls
72 lines (72 loc) · 46.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {OwnableUpgradeable} from \"./OwnableUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step\n struct Ownable2StepStorage {\n address _pendingOwner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable2Step\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;\n\n function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {\n assembly {\n $.slot := Ownable2StepStorageLocation\n }\n }\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n function __Ownable2Step_init() internal onlyInitializing {\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n return $._pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n $._pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n delete $._pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n if (pendingOwner() != sender) {\n revert OwnableUnauthorizedAccount(sender);\n }\n _transferOwnership(sender);\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n struct OwnableStorage {\n address _owner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n assembly {\n $.slot := OwnableStorageLocation\n }\n }\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n function __Ownable_init(address initialOwner) internal onlyInitializing {\n __Ownable_init_unchained(initialOwner);\n }\n\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n OwnableStorage storage $ = _getOwnableStorage();\n return $._owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n OwnableStorage storage $ = _getOwnableStorage();\n address oldOwner = $._owner;\n $._owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n assembly {\n $.slot := INITIALIZABLE_STORAGE\n }\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n struct ReentrancyGuardStorage {\n uint256 _status;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n assembly {\n $.slot := ReentrancyGuardStorageLocation\n }\n }\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if ($._status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n $._status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n return $._status == ENTERED;\n }\n}\n"
},
"contracts/external/IERC3525.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\nimport \"./IERC721.sol\";\n\ninterface IERC3525 is IERC721 {\n function valueDecimals() external view returns (uint8);\n function balanceOf(uint256 tokenId) external view returns (uint256);\n function slotOf(uint256 tokenId) external view returns (uint256);\n function allowance(uint256 tokenId, address operator) external view returns (uint256);\n \n function approve(address operator, uint256 tokenId) external payable;\n function approve(uint256 tokenId, address operator, uint256 value) external payable;\n function transferFrom(uint256 fromTokenId, uint256 toTokenId, uint256 value) external payable;\n function transferFrom(uint256 fromTokenId, address to, uint256 value) external payable returns (uint256);\n}\n"
},
"contracts/external/IERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\ninterface IERC721 {\n function balanceOf(address owner) external view returns (uint256);\n function ownerOf(uint256 tokenId) external view returns (address);\n function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);\n function getApproved(uint256 tokenId) external view returns (address);\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n function approve(address approved, uint256 tokenId) external payable;\n function setApprovalForAll(address operator, bool approved) external;\n function transferFrom(address from, address to, uint256 tokenId) external payable;\n function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external payable;\n function safeTransferFrom(address from, address to, uint256 tokenId) external payable;\n}\n"
},
"contracts/external/IOpenFundMarket.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\nstruct SubscribeLimitInfo {\n uint256 hardCap;\n uint256 subscribeMin;\n uint256 subscribeMax;\n uint64 fundraisingStartTime;\n uint64 fundraisingEndTime;\n}\n\nstruct PoolSFTInfo {\n address openFundShare;\n address openFundRedemption;\n uint256 openFundShareSlot;\n uint256 latestRedeemSlot;\n}\n\nstruct PoolFeeInfo {\n uint16 carryRate;\n address carryCollector;\n uint64 latestProtocolFeeSettleTime;\n}\n\nstruct ManagerInfo {\n address poolManager;\n address subscribeNavManager;\n address redeemNavManager;\n}\n\nstruct PoolInfo {\n PoolSFTInfo poolSFTInfo;\n PoolFeeInfo poolFeeInfo;\n ManagerInfo managerInfo;\n SubscribeLimitInfo subscribeLimitInfo;\n address vault;\n address currency;\n address navOracle;\n uint64 valueDate;\n bool permissionless;\n uint256 fundraisingAmount;\n}\n\ninterface IOpenFundMarket {\n function subscribe(bytes32 poolId, uint256 currencyAmount, uint256 openFundShareId, uint64 expireTime)\n external\n returns (uint256 value_);\n function requestRedeem(bytes32 poolId, uint256 openFundShareId, uint256 openFundRedemptionId, uint256 redeemValue)\n external;\n function revokeRedeem(bytes32 poolId, uint256 openFundRedemptionId) external;\n\n function poolInfos(bytes32 poolId) external view returns (PoolInfo memory);\n function getAddress(bytes32 name) external view returns (address);\n function purchasedRecords(bytes32 poolId, address buyer) external view returns (uint256);\n}\n\ninterface IOFMWhitelistStrategyManager {\n function isWhitelisted(bytes32 poolId_, address buyer_) external view returns (bool);\n}\n"
},
"contracts/external/IOpenFundRedemption.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\nstruct RedeemInfo {\n bytes32 poolId;\n address currency;\n uint256 createTime;\n uint256 nav;\n}\n\ninterface IOpenFundRedemptionDelegate {\n function concrete() external view returns (address);\n}\n\ninterface IOpenFundRedemptionConcrete {\n function getRedeemInfo(uint256 slot) external view returns (RedeemInfo memory);\n}\n"
},
"contracts/ISolvBTCMultiAssetPool.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\ninterface ISolvBTCMultiAssetPool {\n function deposit(address sft_, uint256 sftId_, uint256 value_) external;\n function withdraw(address sft, uint256 slot, uint256 sftId, uint256 value) external returns (uint256 toSftId_);\n\n function isSftSlotDepositAllowed(address sft_, uint256 slot_) external view returns (bool);\n function isSftSlotWithdrawAllowed(address sft_, uint256 slot_) external view returns (bool);\n function getERC20(address sft_, uint256 slot_) external view returns (address);\n function getHoldingValueSftId(address sft_, uint256 slot_) external view returns (uint256);\n function getSftSlotBalance(address sft_, uint256 slot_) external view returns (uint256);\n}\n"
},
"contracts/SolvBTCRouterV2.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport {IOpenFundMarket, IOFMWhitelistStrategyManager, PoolInfo} from \"./external/IOpenFundMarket.sol\";\nimport {IOpenFundRedemptionDelegate, IOpenFundRedemptionConcrete, RedeemInfo} from \"./external/IOpenFundRedemption.sol\";\nimport {IERC721} from \"./external/IERC721.sol\";\nimport {IERC3525} from \"./external/IERC3525.sol\";\nimport {ERC20TransferHelper} from \"./utils/ERC20TransferHelper.sol\";\nimport {ERC3525TransferHelper} from \"./utils/ERC3525TransferHelper.sol\";\nimport {ISolvBTCMultiAssetPool} from \"./ISolvBTCMultiAssetPool.sol\";\n\ncontract SolvBTCRouterV2 is ReentrancyGuardUpgradeable, Ownable2StepUpgradeable {\n\n event Deposit(\n address indexed targetToken,\n address indexed currency,\n address indexed depositor,\n uint256 targetTokenAmount,\n uint256 currencyAmount,\n address[] path,\n bytes32[] poolIds\n );\n event WithdrawRequest(\n address indexed targetToken, \n address indexed currency, \n address indexed requester, \n bytes32 poolId,\n uint256 withdrawAmount,\n uint256 redemptionId \n );\n event CancelWithdrawRequest(\n address indexed targetToken, \n address indexed redemption, \n address indexed requester,\n bytes32 poolId,\n uint256 redemptionId, \n uint256 targetTokenAmount\n );\n event SetOpenFundMarket(address indexed openFundMarket);\n event AddKycSBTVerifier(address indexed verifier);\n event RemoveKycSBTVerifier(address indexed verifier);\n event SetPath(address indexed currency, address indexed targetToken, address[] path);\n event SetPoolId(address indexed targetToken, address indexed currency, bytes32 indexed poolId);\n event SetMultiAssetPool(address indexed token, address indexed multiAssetPool);\n\n address public openFundMarket;\n\n address[] public kycSBTVerifiers;\n\n // currency => target ERC20 => path(ERC20[])\n mapping(address => mapping(address => address[])) public paths;\n\n // target ERC20 (SolvBTC or LSTs) => currency => poolId\n mapping(address => mapping(address => bytes32)) public poolIds;\n\n // ERC20 => multiAssetPool\n mapping(address => address) public multiAssetPools;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n function initialize(address owner_) external initializer {\n require(owner_ != address(0), \"SolvBTCRouterV2: invalid admin\");\n __Ownable_init_unchained(owner_);\n __ReentrancyGuard_init();\n }\n\n function deposit(address targetToken_, address currency_, uint256 currencyAmount_) \n external \n virtual \n nonReentrant \n returns (uint256 targetTokenAmount_) \n {\n require(currencyAmount_ > 0, \"SolvBTCRouterV2: invalid currency amount\");\n ERC20TransferHelper.doTransferIn(currency_, msg.sender, currencyAmount_);\n\n address[] memory path = paths[currency_][targetToken_];\n bytes32[] memory pathPoolIds = new bytes32[](path.length + 1);\n targetTokenAmount_ = currencyAmount_;\n for (uint256 i = 0; i <= path.length; i++) {\n address paidToken = i == 0 ? currency_ : path[i - 1];\n address receivedToken = i == path.length ? targetToken_ : path[i];\n pathPoolIds[i] = poolIds[receivedToken][paidToken];\n targetTokenAmount_ = _deposit(receivedToken, paidToken, targetTokenAmount_);\n }\n ERC20TransferHelper.doTransferOut(targetToken_, payable(msg.sender), targetTokenAmount_);\n\n emit Deposit(targetToken_, currency_, msg.sender, targetTokenAmount_, currencyAmount_, path, pathPoolIds);\n }\n\n function _deposit(address targetToken_, address currency_, uint256 currencyAmount_)\n internal\n returns (uint256 targetTokenAmount_)\n {\n bytes32 targetPoolId = poolIds[targetToken_][currency_];\n require(targetPoolId > 0, \"SolvBTCRouterV2: poolId not found\");\n require(checkPoolPermission(targetPoolId), \"SolvBTCRouterV2: pool permission denied\");\n\n PoolInfo memory poolInfo = IOpenFundMarket(openFundMarket).poolInfos(targetPoolId);\n require(currency_ == poolInfo.currency, \"SolvBTCRouterV2: currency not match\");\n IERC3525 share = IERC3525(poolInfo.poolSFTInfo.openFundShare);\n uint256 shareSlot = poolInfo.poolSFTInfo.openFundShareSlot;\n\n address multiAssetPool = multiAssetPools[targetToken_];\n require(\n targetToken_ == ISolvBTCMultiAssetPool(multiAssetPool).getERC20(address(share), shareSlot), \n \"SolvBTCRouterV2: target token not match\"\n );\n\n ERC20TransferHelper.doApprove(currency_, openFundMarket, currencyAmount_);\n targetTokenAmount_ = IOpenFundMarket(openFundMarket).subscribe(\n targetPoolId, currencyAmount_, 0, uint64(block.timestamp + 300)\n );\n\n uint256 shareCount = share.balanceOf(address(this));\n uint256 shareId = share.tokenOfOwnerByIndex(address(this), shareCount - 1);\n require(shareSlot == share.slotOf(shareId), \"SolvBTCRouterV2: share slot not match\");\n require(targetTokenAmount_ == share.balanceOf(shareId), \"SolvBTCRouterV2: share value not match\");\n\n share.approve(multiAssetPool, shareId);\n ISolvBTCMultiAssetPool(multiAssetPool).deposit(address(share), shareId, targetTokenAmount_);\n }\n\n function withdrawRequest(address targetToken_, address currency_, uint256 withdrawAmount_) \n external\n virtual\n nonReentrant\n returns (address, uint256) \n {\n bytes32 targetPoolId = poolIds[targetToken_][currency_];\n require(targetPoolId > 0, \"SolvBTCRouterV2: poolId not found\");\n\n PoolInfo memory poolInfo = IOpenFundMarket(openFundMarket).poolInfos(targetPoolId);\n require(currency_ == poolInfo.currency, \"SolvBTCRouterV2: currency not match\");\n IERC3525 share = IERC3525(poolInfo.poolSFTInfo.openFundShare);\n IERC3525 redemption = IERC3525(poolInfo.poolSFTInfo.openFundRedemption);\n uint256 shareSlot = poolInfo.poolSFTInfo.openFundShareSlot;\n\n address multiAssetPool = multiAssetPools[targetToken_];\n require(\n targetToken_ == ISolvBTCMultiAssetPool(multiAssetPool).getERC20(address(share), shareSlot), \n \"SolvBTCRouterV2: target token not match\"\n );\n\n {\n ERC20TransferHelper.doTransferIn(targetToken_, msg.sender, withdrawAmount_);\n uint256 shareId = ISolvBTCMultiAssetPool(multiAssetPool).withdraw(address(share), shareSlot, 0, withdrawAmount_);\n require(withdrawAmount_ == share.balanceOf(shareId), \"SolvBTCRouterV2: share value not match\");\n\n ERC3525TransferHelper.doApproveId(address(share), openFundMarket, shareId);\n IOpenFundMarket(openFundMarket).requestRedeem(targetPoolId, shareId, 0, withdrawAmount_);\n }\n\n uint256 redemptionCount = redemption.balanceOf(address(this));\n uint256 redemptionId_ = redemption.tokenOfOwnerByIndex(address(this), redemptionCount - 1);\n require(withdrawAmount_ == redemption.balanceOf(redemptionId_), \"SolvBTCRouterV2: redemption value not match\");\n ERC3525TransferHelper.doTransferOut(address(redemption), payable(msg.sender), redemptionId_);\n\n emit WithdrawRequest(targetToken_, currency_, msg.sender, targetPoolId, withdrawAmount_, redemptionId_);\n return (address(redemption), redemptionId_);\n }\n\n function cancelWithdrawRequest(address targetToken_, address redemption_, uint256 redemptionId_) \n external \n virtual \n nonReentrant \n returns (uint256 targetTokenAmount_)\n {\n bytes32 targetPoolId = _getPoolIdByRedemptionId(redemption_, redemptionId_);\n PoolInfo memory poolInfo = IOpenFundMarket(openFundMarket).poolInfos(targetPoolId);\n IERC3525 share = IERC3525(poolInfo.poolSFTInfo.openFundShare);\n uint256 shareSlot = poolInfo.poolSFTInfo.openFundShareSlot;\n\n address multiAssetPool = multiAssetPools[targetToken_];\n require(\n targetToken_ == ISolvBTCMultiAssetPool(multiAssetPool).getERC20(address(share), shareSlot), \n \"SolvBTCRouterV2: target token not match\"\n );\n\n targetTokenAmount_ = IERC3525(redemption_).balanceOf(redemptionId_);\n ERC3525TransferHelper.doTransferIn(redemption_, msg.sender, redemptionId_);\n ERC3525TransferHelper.doApproveId(redemption_, openFundMarket, redemptionId_);\n IOpenFundMarket(openFundMarket).revokeRedeem(targetPoolId, redemptionId_);\n uint256 shareCount = share.balanceOf(address(this));\n uint256 shareId = share.tokenOfOwnerByIndex(address(this), shareCount - 1);\n require(targetTokenAmount_ == share.balanceOf(shareId), \"SolvBTCRouterV2: cancel amount not match\");\n\n ERC3525TransferHelper.doApproveId(address(share), multiAssetPool, shareId);\n ISolvBTCMultiAssetPool(multiAssetPool).deposit(address(share), shareId, targetTokenAmount_);\n ERC20TransferHelper.doTransferOut(targetToken_, payable(msg.sender), targetTokenAmount_);\n\n emit CancelWithdrawRequest(targetToken_, redemption_, msg.sender, targetPoolId, redemptionId_, targetTokenAmount_);\n }\n\n function checkPoolPermission(bytes32 poolId_) public view virtual returns (bool) {\n PoolInfo memory poolInfo = IOpenFundMarket(openFundMarket).poolInfos(poolId_);\n if (poolInfo.permissionless) {\n return true;\n }\n address whiteListManager = IOpenFundMarket(openFundMarket).getAddress(\"OFMWhitelistStrategyManager\");\n return \n IOFMWhitelistStrategyManager(whiteListManager).isWhitelisted(poolId_, msg.sender) ||\n checkKycSBT();\n }\n\n function checkKycSBT() public view virtual returns (bool) {\n for (uint256 i = 0; i < kycSBTVerifiers.length; i++) {\n if (IERC721(kycSBTVerifiers[i]).balanceOf(msg.sender) > 0) {\n return true;\n }\n }\n return kycSBTVerifiers.length == 0;\n }\n\n function addKycSBTVerifier(address kycSBTVerifier_) external onlyOwner {\n require(kycSBTVerifier_ != address(0), \"SolvBTCRouterV2: invalid verifier\");\n kycSBTVerifiers.push(kycSBTVerifier_);\n emit AddKycSBTVerifier(kycSBTVerifier_);\n }\n\n function removeKycSBTVerifier(address kycSBTVerifier_) external onlyOwner {\n for (uint256 i = 0; i < kycSBTVerifiers.length; i++) {\n if (kycSBTVerifiers[i] == kycSBTVerifier_) {\n kycSBTVerifiers[i] = kycSBTVerifiers[kycSBTVerifiers.length - 1];\n kycSBTVerifiers.pop();\n emit RemoveKycSBTVerifier(kycSBTVerifier_);\n break;\n }\n }\n }\n\n function _getPoolIdByRedemptionId(address redemption_, uint256 redemptionId_) internal virtual returns (bytes32) {\n address redemptionConcrete = IOpenFundRedemptionDelegate(redemption_).concrete();\n uint256 redemptionSlot = IERC3525(redemption_).slotOf(redemptionId_);\n RedeemInfo memory redeemInfo = IOpenFundRedemptionConcrete(redemptionConcrete).getRedeemInfo(redemptionSlot);\n return redeemInfo.poolId;\n }\n\n function setOpenFundMarket(address openFundMarket_) external onlyOwner {\n require(openFundMarket_ != address(0), \"SolvBTCRouterV2: invalid openFundMarket\");\n openFundMarket = openFundMarket_;\n emit SetOpenFundMarket(openFundMarket_);\n }\n\n function setPoolId(address targetToken_, address currency_, bytes32 poolId_) external onlyOwner {\n require(targetToken_ != address(0), \"SolvBTCRouterV2: invalid targetToken\");\n require(currency_ != address(0), \"SolvBTCRouterV2: invalid currency\");\n require(poolId_ > 0, \"SolvBTCRouterV2: invalid poolId\");\n\n poolIds[targetToken_][currency_] = poolId_;\n emit SetPoolId(targetToken_, currency_, poolId_);\n }\n\n function setPath(address currency_, address targetToken_, address[] memory path_) external onlyOwner {\n require(currency_ != address(0), \"SolvBTCRouterV2: invalid currency\");\n require(targetToken_ != address(0), \"SolvBTCRouterV2: invalid targetToken\");\n for (uint256 i = 0; i < path_.length; i++) {\n require(path_[i] != address(0), \"SolvBTCRouterV2: invalid path token\");\n }\n \n paths[currency_][targetToken_] = path_;\n emit SetPath(currency_, targetToken_, path_);\n }\n\n function setMultiAssetPool(address token_, address multiAssetPool_) external onlyOwner {\n require(token_ != address(0), \"SolvBTCRouterV2: invalid token\");\n require(multiAssetPool_ != address(0), \"SolvBTCRouterV2: invalid multiAssetPool\");\n multiAssetPools[token_] = multiAssetPool_;\n emit SetMultiAssetPool(token_, multiAssetPool_);\n }\n\n uint256[45] private __gap;\n}\n"
},
"contracts/utils/ERC20TransferHelper.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\ninterface ERC20Interface {\n function balanceOf(address account) external view returns (uint256);\n\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n function approve(address spender, uint256 amount) external returns (bool);\n}\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary ERC20TransferHelper {\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n function doApprove(address underlying, address spender, uint256 amount) internal {\n require(underlying.code.length > 0, \"invalid underlying\");\n (bool success, bytes memory data) = underlying.call(\n abi.encodeWithSelector(\n ERC20Interface.approve.selector,\n spender,\n amount\n )\n );\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"SAF\");\n }\n\n function doTransferIn(address underlying, address from, uint256 amount) internal {\n if (underlying == ETH_ADDRESS) {\n // Sanity checks\n require(tx.origin == from || msg.sender == from, \"sender mismatch\");\n require(msg.value >= amount, \"value mismatch\");\n } else {\n require(underlying.code.length > 0, \"invalid underlying\");\n (bool success, bytes memory data) = underlying.call(\n abi.encodeWithSelector(\n ERC20Interface.transferFrom.selector,\n from,\n address(this),\n amount\n )\n );\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"STF\");\n }\n }\n\n function doTransferOut(address underlying, address payable to, uint256 amount) internal {\n if (underlying == ETH_ADDRESS) {\n (bool success, ) = to.call{value: amount}(new bytes(0));\n require(success, \"STE\");\n } else {\n require(underlying.code.length > 0, \"invalid underlying\");\n (bool success, bytes memory data) = underlying.call(\n abi.encodeWithSelector(\n ERC20Interface.transfer.selector,\n to,\n amount\n )\n );\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"ST\");\n }\n }\n}\n"
},
"contracts/utils/ERC3525TransferHelper.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.20;\n\ninterface ERC721Interface {\n function approve(address to, uint256 tokenId) external;\n function transferFrom(address from, address to, uint256 tokenId) external;\n function safeTransferFrom(address from, address to, uint256 tokenId) external;\n}\n\ninterface ERC3525Interface {\n function approve(uint256 tokenId, address to, uint256 allowance) external payable;\n function transferFrom(uint256 fromTokenId, uint256 toTokenId, uint256 value) external payable;\n function transferFrom(uint256 fromTokenId, address to, uint256 value) external payable returns (uint256); \n}\n\nlibrary ERC3525TransferHelper {\n function doApproveId(address underlying, address to, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.approve(to, tokenId);\n }\n\n function doApproveValue(address underlying, uint256 tokenId, address to, uint256 allowance) internal {\n ERC3525Interface token = ERC3525Interface(underlying);\n token.approve(tokenId, to, allowance);\n }\n\n function doTransferIn(address underlying, address from, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.transferFrom(from, address(this), tokenId);\n }\n \n function doSafeTransferIn(address underlying, address from, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.safeTransferFrom(from, address(this), tokenId);\n }\n\n function doSafeTransferOut(address underlying, address to, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.safeTransferFrom(address(this), to, tokenId);\n }\n\n function doTransferOut(address underlying, address to, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.transferFrom(address(this), to, tokenId);\n }\n\n function doTransferIn(address underlying, uint256 fromTokenId, uint256 value) internal returns (uint256 newTokenId) {\n ERC3525Interface token = ERC3525Interface(underlying);\n return token.transferFrom(fromTokenId, address(this), value);\n }\n\n function doTransferOut(address underlying, uint256 fromTokenId, address to, uint256 value) internal returns (uint256 newTokenId) {\n ERC3525Interface token = ERC3525Interface(underlying);\n newTokenId = token.transferFrom(fromTokenId, to, value);\n }\n\n function doTransfer(address underlying, address from, address to, uint256 tokenId) internal {\n ERC721Interface token = ERC721Interface(underlying);\n token.transferFrom(from, to, tokenId);\n }\n\n function doTransfer(address underlying, uint256 fromTokenId, uint256 toTokenId, uint256 value) internal {\n ERC3525Interface token = ERC3525Interface(underlying);\n token.transferFrom(fromTokenId, toTokenId, value);\n }\n\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 1
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}