@gooddollar/goodcollective-contracts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/contracts/DirectPayments/DirectPaymentsFactory.sol +108 -0
- package/contracts/DirectPayments/DirectPaymentsPool.sol +333 -0
- package/contracts/DirectPayments/ProvableNFT.sol +178 -0
- package/package.json +59 -0
- package/releases/deployment.json +7118 -0
- package/typechain-types/@openzeppelin/contracts/index.ts +7 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/IERC1967.ts +115 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC1822.sol/IERC1822Proxiable.ts +87 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC1822.sol/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.ts +115 -0
- package/typechain-types/@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.ts +115 -0
- package/typechain-types/@openzeppelin/contracts/proxy/ERC1967/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts/proxy/Proxy.ts +55 -0
- package/typechain-types/@openzeppelin/contracts/proxy/beacon/IBeacon.ts +87 -0
- package/typechain-types/@openzeppelin/contracts/proxy/beacon/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts/proxy/index.ts +8 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.ts +410 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.ts +341 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/access/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/index.ts +13 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/interfaces/IERC1967Upgradeable.ts +115 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol/IERC1822ProxiableUpgradeable.ts +87 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/interfaces/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.ts +127 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/ERC1967/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.ts +87 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/beacon/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/index.ts +9 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.ts +69 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.ts +238 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/proxy/utils/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.ts +342 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.ts +193 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol/IERC20PermitUpgradeable.ts +193 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC20/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.ts +631 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.ts +126 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.ts +559 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.ts +619 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/ERC721/index.ts +8 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/token/index.ts +7 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.ts +69 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/utils/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.ts +121 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.ts +103 -0
- package/typechain-types/@openzeppelin/contracts-upgradeable/utils/introspection/index.ts +5 -0
- package/typechain-types/@openzeppelin/index.ts +7 -0
- package/typechain-types/common.ts +46 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsFactory.ts +1034 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool.ts +1381 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2.ts +105 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator.ts +125 -0
- package/typechain-types/contracts/DirectPayments/DirectPaymentsPool.sol/index.ts +6 -0
- package/typechain-types/contracts/DirectPayments/ProvableNFT.ts +1489 -0
- package/typechain-types/contracts/DirectPayments/index.ts +7 -0
- package/typechain-types/contracts/Lock.ts +148 -0
- package/typechain-types/contracts/index.ts +6 -0
- package/typechain-types/factories/@openzeppelin/contracts/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/IERC1967__factory.ts +71 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC1822.sol/IERC1822Proxiable__factory.ts +39 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC1822.sol/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy__factory.ts +147 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade__factory.ts +71 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/Proxy__factory.ts +31 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/beacon/IBeacon__factory.ts +39 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/beacon/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/proxy/index.ts +6 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable__factory.ts +247 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable__factory.ts +202 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/access/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/index.ts +8 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/interfaces/IERC1967Upgradeable__factory.ts +71 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol/IERC1822ProxiableUpgradeable__factory.ts +43 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/interfaces/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable__factory.ts +88 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/ERC1967/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable__factory.ts +39 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/beacon/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/index.ts +6 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable__factory.ts +39 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable__factory.ts +128 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/proxy/utils/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable__factory.ts +209 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable__factory.ts +105 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol/IERC20PermitUpgradeable__factory.ts +105 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/extensions/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC20/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable__factory.ts +406 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable__factory.ts +64 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable__factory.ts +311 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable__factory.ts +360 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/ERC721/index.ts +7 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/token/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable__factory.ts +39 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/utils/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable__factory.ts +58 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable__factory.ts +45 -0
- package/typechain-types/factories/@openzeppelin/contracts-upgradeable/utils/introspection/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/index.ts +5 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsFactory__factory.ts +707 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/DirectPaymentsPool__factory.ts +1094 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/IIdentityV2__factory.ts +45 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/IMembersValidator__factory.ts +60 -0
- package/typechain-types/factories/contracts/DirectPayments/DirectPaymentsPool.sol/index.ts +6 -0
- package/typechain-types/factories/contracts/DirectPayments/ProvableNFT__factory.ts +1184 -0
- package/typechain-types/factories/contracts/DirectPayments/index.ts +6 -0
- package/typechain-types/factories/contracts/Lock__factory.ts +129 -0
- package/typechain-types/factories/contracts/index.ts +5 -0
- package/typechain-types/factories/index.ts +5 -0
- package/typechain-types/hardhat.d.ts +294 -0
- package/typechain-types/index.ts +66 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# contracts
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.8.0;
|
|
3
|
+
|
|
4
|
+
// import the DirectPayments contract
|
|
5
|
+
import "./DirectPaymentsPool.sol";
|
|
6
|
+
import "./ProvableNFT.sol";
|
|
7
|
+
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
8
|
+
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
9
|
+
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
10
|
+
|
|
11
|
+
import "hardhat/console.sol";
|
|
12
|
+
|
|
13
|
+
contract DirectPaymentsFactory is AccessControlUpgradeable, UUPSUpgradeable {
|
|
14
|
+
error NOT_PROJECT_OWNER();
|
|
15
|
+
|
|
16
|
+
event PoolCreated(address indexed pool, string indexed projectId, string ipfs, uint32 indexed nftType);
|
|
17
|
+
event PoolDetailsChanged(address indexed pool, string ipfs);
|
|
18
|
+
event PoolVerifiedChanged(address indexed pool, bool isVerified);
|
|
19
|
+
event UpdatedImpl(address indexed impl);
|
|
20
|
+
|
|
21
|
+
struct PoolRegistry {
|
|
22
|
+
string ipfs;
|
|
23
|
+
bool isVerified;
|
|
24
|
+
string projectId;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
address public impl;
|
|
28
|
+
ProvableNFT public nft;
|
|
29
|
+
uint32 public nextNftType;
|
|
30
|
+
|
|
31
|
+
mapping(address => PoolRegistry) public registry;
|
|
32
|
+
mapping(bytes32 => DirectPaymentsPool) public projectIdToControlPool;
|
|
33
|
+
|
|
34
|
+
modifier onlyProjectOwnerOrNon(string memory projectId) {
|
|
35
|
+
DirectPaymentsPool controlPool = projectIdToControlPool[keccak256(bytes(projectId))];
|
|
36
|
+
console.log("control:%s sender:%s %s", address(controlPool), msg.sender);
|
|
37
|
+
// console.log("result %s", controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender));
|
|
38
|
+
if (address(controlPool) != address(0)) {
|
|
39
|
+
if (controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) {
|
|
40
|
+
revert NOT_PROJECT_OWNER();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
_;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
modifier onlyProjectOwnerByPool(DirectPaymentsPool pool) {
|
|
47
|
+
string memory projectId = registry[address(pool)].projectId;
|
|
48
|
+
DirectPaymentsPool controlPool = projectIdToControlPool[keccak256(bytes(projectId))];
|
|
49
|
+
if (controlPool.hasRole(controlPool.DEFAULT_ADMIN_ROLE(), msg.sender) == false) {
|
|
50
|
+
revert NOT_PROJECT_OWNER();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function _authorizeUpgrade(address _impl) internal virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
|
|
57
|
+
|
|
58
|
+
function initialize(address _owner, address _dpimpl, address _nftimpl) external initializer {
|
|
59
|
+
nextNftType = 1;
|
|
60
|
+
impl = _dpimpl;
|
|
61
|
+
bytes memory initCall = abi.encodeWithSelector(ProvableNFT.initialize.selector, "DirectPayments NFT", "DPNFT");
|
|
62
|
+
nft = ProvableNFT(address(new ERC1967Proxy(_nftimpl, initCall)));
|
|
63
|
+
|
|
64
|
+
nft.grantRole(DEFAULT_ADMIN_ROLE, _owner);
|
|
65
|
+
_setupRole(DEFAULT_ADMIN_ROLE, _owner);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createPool(
|
|
69
|
+
string memory _projectId,
|
|
70
|
+
string memory _ipfs,
|
|
71
|
+
DirectPaymentsPool.PoolSettings memory _settings,
|
|
72
|
+
DirectPaymentsPool.SafetyLimits memory _limits
|
|
73
|
+
) external onlyProjectOwnerOrNon(_projectId) returns (DirectPaymentsPool pool) {
|
|
74
|
+
//TODO: add check if msg.sender is whitelisted
|
|
75
|
+
|
|
76
|
+
_settings.nftType = nextNftType;
|
|
77
|
+
bytes memory initCall = abi.encodeWithSelector(DirectPaymentsPool.initialize.selector, nft, _settings, _limits);
|
|
78
|
+
pool = DirectPaymentsPool(address(new ERC1967Proxy(impl, initCall)));
|
|
79
|
+
|
|
80
|
+
nft.grantRole(nft.getManagerRole(nextNftType), _settings.manager);
|
|
81
|
+
nft.grantRole(nft.getManagerRole(nextNftType), address(pool));
|
|
82
|
+
pool.grantRole(pool.MINTER_ROLE(), _settings.manager);
|
|
83
|
+
|
|
84
|
+
projectIdToControlPool[keccak256(bytes(_projectId))] = pool;
|
|
85
|
+
registry[address(pool)].ipfs = _ipfs;
|
|
86
|
+
registry[address(pool)].projectId = _projectId;
|
|
87
|
+
|
|
88
|
+
pool.renounceRole(DEFAULT_ADMIN_ROLE, address(this));
|
|
89
|
+
emit PoolCreated(address(pool), _projectId, _ipfs, nextNftType);
|
|
90
|
+
|
|
91
|
+
nextNftType++;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function changePoolDetails(DirectPaymentsPool _pool, string memory _ipfs) external onlyProjectOwnerByPool(_pool) {
|
|
95
|
+
registry[address(_pool)].ipfs = _ipfs;
|
|
96
|
+
emit PoolDetailsChanged(address(_pool), _ipfs);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setVerified(DirectPaymentsPool _pool, bool _isVerified) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
100
|
+
registry[address(_pool)].isVerified = _isVerified;
|
|
101
|
+
emit PoolVerifiedChanged(address(_pool), _isVerified);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function updateImpl(address _impl) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
105
|
+
impl = _impl;
|
|
106
|
+
emit UpdatedImpl(_impl);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.8;
|
|
3
|
+
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
4
|
+
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
+
import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
|
|
6
|
+
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
|
|
7
|
+
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
|
|
8
|
+
import { IERC721ReceiverUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
|
|
9
|
+
|
|
10
|
+
import { ProvableNFT } from "./ProvableNFT.sol";
|
|
11
|
+
import { DirectPaymentsFactory } from "./DirectPaymentsFactory.sol";
|
|
12
|
+
|
|
13
|
+
interface IMembersValidator {
|
|
14
|
+
function isMemberValid(
|
|
15
|
+
address pool,
|
|
16
|
+
address operator,
|
|
17
|
+
address member,
|
|
18
|
+
bytes memory extraData
|
|
19
|
+
) external returns (bool);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface IIdentityV2 {
|
|
23
|
+
function getWhitelistedRoot(address member) external returns (address);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
- optional members validator (but need atleast uniqueness or members)
|
|
28
|
+
- anyone can claim an nfttype
|
|
29
|
+
- project id at the registery?
|
|
30
|
+
- factory -> register the pool, claim nfttype, deploy pool
|
|
31
|
+
- events
|
|
32
|
+
*/
|
|
33
|
+
contract DirectPaymentsPool is IERC721ReceiverUpgradeable, AccessControlUpgradeable, UUPSUpgradeable {
|
|
34
|
+
using SafeERC20Upgradeable for IERC20Upgradeable;
|
|
35
|
+
error NOT_MANAGER();
|
|
36
|
+
error ALREADY_CLAIMED(uint256);
|
|
37
|
+
error NFT_MISSING(uint256);
|
|
38
|
+
error NOT_MEMBER(address);
|
|
39
|
+
error NOT_WHITELISTED(address);
|
|
40
|
+
error OVER_MEMBER_LIMITS(address);
|
|
41
|
+
error OVER_GLOBAL_LIMITS();
|
|
42
|
+
error UNSUPPORTED_NFT();
|
|
43
|
+
error NO_BALANCE();
|
|
44
|
+
|
|
45
|
+
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
|
|
46
|
+
bytes32 public constant MINTER_ROLE = keccak256("MINTER");
|
|
47
|
+
|
|
48
|
+
event PoolSettingsChanged(PoolSettings settings);
|
|
49
|
+
event PoolLimitsChanged(SafetyLimits limits);
|
|
50
|
+
event MemberAdded(address member);
|
|
51
|
+
event MemberRemoved(address member);
|
|
52
|
+
event RewardClaimed(uint256 indexed tokenId, uint256 totalRewards);
|
|
53
|
+
|
|
54
|
+
// Define functions
|
|
55
|
+
struct PoolSettings {
|
|
56
|
+
uint32 nftType;
|
|
57
|
+
uint16[] validEvents;
|
|
58
|
+
uint128[] rewardPerEvent;
|
|
59
|
+
address manager;
|
|
60
|
+
IMembersValidator membersValidator;
|
|
61
|
+
IIdentityV2 uniqunessValidator;
|
|
62
|
+
IERC20Upgradeable rewardToken;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
struct SafetyLimits {
|
|
66
|
+
uint maxTotalPerMonth;
|
|
67
|
+
uint256 maxMemberPerMonth;
|
|
68
|
+
uint256 maxMemberPerDay;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
struct LimitsData {
|
|
72
|
+
uint128 daily;
|
|
73
|
+
uint128 monthly;
|
|
74
|
+
uint128 total;
|
|
75
|
+
uint64 lastReward;
|
|
76
|
+
uint64 lastMonth;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
PoolSettings public settings;
|
|
80
|
+
SafetyLimits public limits;
|
|
81
|
+
ProvableNFT public nft;
|
|
82
|
+
|
|
83
|
+
mapping(uint256 => bool) public claimedNfts;
|
|
84
|
+
mapping(address => bool) public members;
|
|
85
|
+
mapping(address => LimitsData) public memberLimits;
|
|
86
|
+
LimitsData public globalLimits;
|
|
87
|
+
address public createdBy;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @dev Authorizes an upgrade for the implementation contract.
|
|
91
|
+
* @param impl The address of the new implementation contract.
|
|
92
|
+
*/
|
|
93
|
+
function _authorizeUpgrade(address impl) internal virtual override {}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @dev Initializes the contract with the given settings and limits.
|
|
97
|
+
* @param _nft The ProvableNFT contract address.
|
|
98
|
+
* @param _settings The PoolSettings struct containing pool settings.
|
|
99
|
+
* @param _limits The SafetyLimits struct containing safety limits.
|
|
100
|
+
*/
|
|
101
|
+
function initialize(
|
|
102
|
+
ProvableNFT _nft,
|
|
103
|
+
PoolSettings memory _settings,
|
|
104
|
+
SafetyLimits memory _limits
|
|
105
|
+
) external initializer {
|
|
106
|
+
uint l = 5;
|
|
107
|
+
createdBy = msg.sender;
|
|
108
|
+
settings = _settings;
|
|
109
|
+
limits = _limits;
|
|
110
|
+
nft = _nft;
|
|
111
|
+
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
112
|
+
_setupRole(DEFAULT_ADMIN_ROLE, _settings.manager);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function upgradeToLatest(bytes memory data) external payable virtual onlyProxy {
|
|
116
|
+
address impl = DirectPaymentsFactory(createdBy).impl();
|
|
117
|
+
_authorizeUpgrade(impl);
|
|
118
|
+
_upgradeToAndCallUUPS(impl, data, false);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @dev Claims rewards for the specified NFT ID.
|
|
123
|
+
* @param _nftId The ID of the NFT to claim rewards for.
|
|
124
|
+
*/
|
|
125
|
+
function claim(uint256 _nftId) external {
|
|
126
|
+
claim(_nftId, nft.getNFTData(_nftId));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @dev Claims rewards for a given NFT ID and its associated data.
|
|
131
|
+
* @param _nftId The ID of the NFT to claim rewards for.
|
|
132
|
+
* @param _data The associated data for the NFT.
|
|
133
|
+
* Emits a {ALREADY_CLAIMED} error if the NFT has already been claimed.
|
|
134
|
+
* Emits a {NFT_MISSING} error if the NFT is not owned by this contract.
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
function claim(uint256 _nftId, ProvableNFT.NFTData memory _data) public {
|
|
138
|
+
nft.proveNFTData(_nftId, _data);
|
|
139
|
+
if (claimedNfts[_nftId]) revert ALREADY_CLAIMED(_nftId);
|
|
140
|
+
|
|
141
|
+
// TODO: should pool own the NFTs?
|
|
142
|
+
// if (settings.collectNfts && nft.ownerOf(_nftId) != address(this)) revert NFT_MISSING(_nftId);
|
|
143
|
+
|
|
144
|
+
_claim(_nftId, _data);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @dev Claims rewards for the specified NFT ID.
|
|
149
|
+
* @param _nftId The ID of the NFT to claim rewards for.
|
|
150
|
+
* @param _data The NFTData struct containing data about the NFT.
|
|
151
|
+
*/
|
|
152
|
+
function _claim(uint256 _nftId, ProvableNFT.NFTData memory _data) internal {
|
|
153
|
+
claimedNfts[_nftId] = true;
|
|
154
|
+
uint totalRewards;
|
|
155
|
+
uint rewardsBalance = settings.rewardToken.balanceOf(address(this));
|
|
156
|
+
|
|
157
|
+
for (uint256 i = 0; i < _data.events.length; i++) {
|
|
158
|
+
uint128 reward = _eventReward(_data.events[i].subtype);
|
|
159
|
+
if (reward > 0) {
|
|
160
|
+
totalRewards += reward * _data.events[i].quantity;
|
|
161
|
+
if (totalRewards > rewardsBalance) revert NO_BALANCE();
|
|
162
|
+
rewardsBalance -= totalRewards;
|
|
163
|
+
_sendReward(_data.events[i].contributers, uint128(reward * _data.events[i].quantity));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
emit RewardClaimed(_nftId, totalRewards);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @dev Returns the reward amount for the specified event type.
|
|
172
|
+
* @param _eventType The type of the event to get the reward for.
|
|
173
|
+
* @return reward amount for the specified event type.
|
|
174
|
+
*/
|
|
175
|
+
function _eventReward(uint16 _eventType) internal view returns (uint128 reward) {
|
|
176
|
+
for (uint i = 0; i < settings.validEvents.length; i++) {
|
|
177
|
+
if (_eventType == settings.validEvents[i]) return settings.rewardPerEvent[i];
|
|
178
|
+
}
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @dev Sends rewards to the specified recipients.
|
|
184
|
+
* @param recipients The addresses of the recipients to send rewards to.
|
|
185
|
+
* @param reward The total amount of rewards to send.
|
|
186
|
+
*/
|
|
187
|
+
function _sendReward(address[] memory recipients, uint128 reward) internal {
|
|
188
|
+
uint128 perReward = uint128(reward / recipients.length);
|
|
189
|
+
for (uint i = 0; i < recipients.length; i++) {
|
|
190
|
+
_enforceAndUpdateMemberLimits(recipients[i], perReward);
|
|
191
|
+
settings.rewardToken.safeTransfer(recipients[i], perReward);
|
|
192
|
+
}
|
|
193
|
+
_enforceAndUpdateGlobalLimits(reward);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @dev Enforces and updates the reward limits for the specified member.
|
|
198
|
+
* @param member The address of the member to enforce and update limits for.
|
|
199
|
+
* @param reward The amount of rewards to enforce and update limits for.
|
|
200
|
+
*/
|
|
201
|
+
function _enforceAndUpdateMemberLimits(address member, uint128 reward) internal {
|
|
202
|
+
if (members[member] == false) revert NOT_MEMBER(member);
|
|
203
|
+
|
|
204
|
+
uint64 curMonth = _month();
|
|
205
|
+
if (memberLimits[member].lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
206
|
+
{
|
|
207
|
+
memberLimits[member].daily = reward;
|
|
208
|
+
} else {
|
|
209
|
+
memberLimits[member].daily += reward;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (memberLimits[member].lastMonth < curMonth) //month switched
|
|
213
|
+
{
|
|
214
|
+
memberLimits[member].monthly = reward;
|
|
215
|
+
} else {
|
|
216
|
+
memberLimits[member].monthly += reward;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
memberLimits[member].total += reward;
|
|
220
|
+
memberLimits[member].lastReward = uint64(block.timestamp);
|
|
221
|
+
memberLimits[member].lastMonth = curMonth;
|
|
222
|
+
|
|
223
|
+
if (
|
|
224
|
+
memberLimits[member].daily > limits.maxMemberPerDay ||
|
|
225
|
+
memberLimits[member].monthly > limits.maxMemberPerMonth
|
|
226
|
+
) revert OVER_MEMBER_LIMITS(member);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @dev Enforces and updates the global reward limits.
|
|
231
|
+
* @param reward The amount of rewards to enforce and update limits for.
|
|
232
|
+
*/
|
|
233
|
+
function _enforceAndUpdateGlobalLimits(uint128 reward) internal {
|
|
234
|
+
uint64 curMonth = _month();
|
|
235
|
+
|
|
236
|
+
if (globalLimits.lastReward + 60 * 60 * 24 < block.timestamp) //more than a day passed since last reward
|
|
237
|
+
{
|
|
238
|
+
globalLimits.daily = reward;
|
|
239
|
+
} else {
|
|
240
|
+
globalLimits.daily += reward;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (globalLimits.lastMonth < curMonth) //month switched
|
|
244
|
+
{
|
|
245
|
+
globalLimits.monthly = reward;
|
|
246
|
+
} else {
|
|
247
|
+
globalLimits.monthly += reward;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
globalLimits.total += reward;
|
|
251
|
+
globalLimits.lastReward = uint64(block.timestamp);
|
|
252
|
+
globalLimits.lastMonth = curMonth;
|
|
253
|
+
|
|
254
|
+
if (globalLimits.monthly > limits.maxTotalPerMonth) revert OVER_GLOBAL_LIMITS();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* @dev Returns the current month.
|
|
259
|
+
* @return month current month as a uint64 value.
|
|
260
|
+
*/
|
|
261
|
+
function _month() internal view returns (uint64 month) {
|
|
262
|
+
return uint64(block.timestamp / (60 * 60 * 24 * 30));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @dev Adds a member to the contract.
|
|
267
|
+
* @param member The address of the member to add.
|
|
268
|
+
* @param extraData Additional data to validate the member.
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
function addMember(address member, bytes memory extraData) external {
|
|
272
|
+
if (address(settings.uniqunessValidator) != address(0)) {
|
|
273
|
+
address rootAddress = settings.uniqunessValidator.getWhitelistedRoot(member);
|
|
274
|
+
if (rootAddress == address(0)) revert NOT_WHITELISTED(member);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (address(settings.membersValidator) != address(0)) {
|
|
278
|
+
if (settings.membersValidator.isMemberValid(address(this), msg.sender, member, extraData) == false) {
|
|
279
|
+
revert NOT_MEMBER(member);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
// if no members validator then only admin can add members
|
|
283
|
+
if (hasRole(DEFAULT_ADMIN_ROLE, msg.sender) == false) revert NOT_MANAGER();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
members[member] = true;
|
|
287
|
+
emit MemberAdded(member);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @dev Removes a member from the contract.
|
|
292
|
+
* @param member The address of the member to remove.
|
|
293
|
+
*/
|
|
294
|
+
function removeMember(address member) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
295
|
+
members[member] = false;
|
|
296
|
+
emit MemberRemoved(member);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function mintNFT(address _to, ProvableNFT.NFTData memory _nftData, bool withClaim) external onlyRole(MINTER_ROLE) {
|
|
300
|
+
uint nftId = nft.mintPermissioned(_to, _nftData, true, "");
|
|
301
|
+
if (withClaim) {
|
|
302
|
+
claim(nftId, _nftData);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @dev Receives an ERC721 token and triggers a claim for rewards.
|
|
308
|
+
* @param operator The address of the operator that sent the token.
|
|
309
|
+
* @param from The address of the sender that sent the token.
|
|
310
|
+
* @param tokenId The ID of the token received.
|
|
311
|
+
* @param data Additional data to trigger a claim for rewards.
|
|
312
|
+
* @return A bytes4 value indicating success or failure.
|
|
313
|
+
*/
|
|
314
|
+
function onERC721Received(
|
|
315
|
+
address operator,
|
|
316
|
+
address from,
|
|
317
|
+
uint256 tokenId,
|
|
318
|
+
bytes calldata data
|
|
319
|
+
) external returns (bytes4) {
|
|
320
|
+
// bool triggerClaim;
|
|
321
|
+
// if (data.length > 0) (triggerClaim) = abi.decode(data, (bool));
|
|
322
|
+
// if (triggerClaim) {
|
|
323
|
+
// ProvableNFT.NFTData memory nftData = nft.getNFTData(tokenId);
|
|
324
|
+
// if (nftData.nftType > 0) // check the nftData is actually stored on-chain, otherwise claim will not work
|
|
325
|
+
// {
|
|
326
|
+
// claim(tokenId, nftData);
|
|
327
|
+
// }
|
|
328
|
+
// }
|
|
329
|
+
ProvableNFT.NFTData memory nftData = nft.getNFTData(tokenId);
|
|
330
|
+
if (nftData.nftType != settings.nftType) revert UNSUPPORTED_NFT();
|
|
331
|
+
return DirectPaymentsPool.onERC721Received.selector;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
|
|
6
|
+
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
7
|
+
import { StringsUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
|
|
8
|
+
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
An NFT that can store data related to actions, the data is stored on-chain or as hash of the content that can later be proved.
|
|
12
|
+
*/
|
|
13
|
+
contract ProvableNFT is ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgradeable {
|
|
14
|
+
error BAD_DATAHASH(bytes32 dataHash, bytes32 tokenId);
|
|
15
|
+
error NOT_MINTER();
|
|
16
|
+
error NOT_MANAGER(uint32);
|
|
17
|
+
error BAD_NFTTYPE();
|
|
18
|
+
|
|
19
|
+
bytes32 public constant MINTER_ROLE = keccak256(abi.encodePacked("MINTER"));
|
|
20
|
+
bytes16 private constant _SYMBOLS = "0123456789abcdef";
|
|
21
|
+
|
|
22
|
+
struct EventData {
|
|
23
|
+
uint16 subtype;
|
|
24
|
+
uint32 timestamp;
|
|
25
|
+
uint256 quantity;
|
|
26
|
+
string eventUri; //extra data related to event
|
|
27
|
+
address[] contributers;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
struct NFTData {
|
|
31
|
+
uint32 nftType; //should be non zero
|
|
32
|
+
uint16 version;
|
|
33
|
+
string nftUri; //extra data related to nft
|
|
34
|
+
EventData[] events;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
mapping(uint256 => NFTData) internal nftDatas;
|
|
38
|
+
|
|
39
|
+
function initialize(string memory _name, string memory _symbol) external initializer {
|
|
40
|
+
__ERC721_init(_name, _symbol);
|
|
41
|
+
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _authorizeUpgrade(address newimpl) internal virtual override onlyManager(0) {}
|
|
45
|
+
|
|
46
|
+
function supportsInterface(
|
|
47
|
+
bytes4 interfaceId
|
|
48
|
+
) public view virtual override(AccessControlUpgradeable, ERC721Upgradeable) returns (bool) {
|
|
49
|
+
return super.supportsInterface(interfaceId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
modifier onlyManager(uint32 nftType) {
|
|
53
|
+
if (
|
|
54
|
+
((nftType > 0 && hasRole(getManagerRole(nftType), msg.sender)) ||
|
|
55
|
+
hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) == false
|
|
56
|
+
) {
|
|
57
|
+
revert NOT_MANAGER(nftType);
|
|
58
|
+
}
|
|
59
|
+
_;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @dev Mint a new NFT with the given URI and data hash.
|
|
64
|
+
*
|
|
65
|
+
* Requirements:
|
|
66
|
+
* - The caller must have the `Manager` role.
|
|
67
|
+
*
|
|
68
|
+
* Emits a {Transfer} event and a {URI} event.
|
|
69
|
+
*
|
|
70
|
+
* @param _to The address that will receive the minted NFT.
|
|
71
|
+
* @param _uri The URI for the NFT's metadata.
|
|
72
|
+
* @param _nftDataHash The hash of the NFT's data.
|
|
73
|
+
* @return tokenId ID of the newly minted NFT.
|
|
74
|
+
*/
|
|
75
|
+
function mint(
|
|
76
|
+
address _to,
|
|
77
|
+
string memory _uri,
|
|
78
|
+
bytes32 _nftDataHash
|
|
79
|
+
) public onlyManager(0) returns (uint256 tokenId) {
|
|
80
|
+
return _mint(_to, _uri, _nftDataHash, ""); //send false in calldata, assuming default receiver is a directpaymentspool. without nft data on chain it will fail.
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _mint(
|
|
84
|
+
address _to,
|
|
85
|
+
string memory _uri,
|
|
86
|
+
bytes32 _nftDataHash,
|
|
87
|
+
bytes memory _callData
|
|
88
|
+
) internal returns (uint256 tokenId) {
|
|
89
|
+
tokenId = uint256(_nftDataHash);
|
|
90
|
+
nftDatas[tokenId].nftUri = _uri;
|
|
91
|
+
_safeMint(_to, tokenId, _callData);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @dev Mint a new permissioned NFT with the given data.
|
|
96
|
+
*
|
|
97
|
+
* This function is only accessible to users with the `Manager` role for the given NFT type.
|
|
98
|
+
*
|
|
99
|
+
* Stores nftData in contract storage if `_withStore` is true.
|
|
100
|
+
*
|
|
101
|
+
* @param _to The address that will receive the minted NFT.
|
|
102
|
+
* @param _nftData The data for the NFT.
|
|
103
|
+
* @param _withStore Whether or not to store the NFT data in the contract.
|
|
104
|
+
* @param _callData call data to pass to erc721receiver
|
|
105
|
+
* @return tokenId ID of the newly minted NFT.
|
|
106
|
+
*/
|
|
107
|
+
function mintPermissioned(
|
|
108
|
+
address _to,
|
|
109
|
+
NFTData memory _nftData,
|
|
110
|
+
bool _withStore,
|
|
111
|
+
bytes memory _callData
|
|
112
|
+
) external onlyManager(_nftData.nftType) returns (uint256 tokenId) {
|
|
113
|
+
if (_nftData.nftType == 0) revert BAD_NFTTYPE();
|
|
114
|
+
|
|
115
|
+
bytes32 dataHash = keccak256(abi.encode(_nftData));
|
|
116
|
+
tokenId = uint256(dataHash);
|
|
117
|
+
if (_withStore) {
|
|
118
|
+
NFTData storage store = nftDatas[tokenId];
|
|
119
|
+
store.nftUri = _nftData.nftUri;
|
|
120
|
+
store.nftType = _nftData.nftType;
|
|
121
|
+
store.version = _nftData.version;
|
|
122
|
+
for (uint256 i = 0; i < _nftData.events.length; i++) {
|
|
123
|
+
store.events.push(_nftData.events[i]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
_mint(_to, _nftData.nftUri, dataHash, _callData);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function proveNFTData(uint256 _tokenId, NFTData memory _nftData) public view returns (NFTData memory data) {
|
|
130
|
+
_requireMinted(_tokenId);
|
|
131
|
+
if (keccak256(abi.encode(_nftData)) != bytes32(_tokenId))
|
|
132
|
+
revert BAD_DATAHASH(keccak256(abi.encode(_nftData)), bytes32(_tokenId));
|
|
133
|
+
|
|
134
|
+
return _nftData;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function getNFTData(uint256 _tokenId) external view returns (NFTData memory) {
|
|
138
|
+
return nftDatas[_tokenId];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getNFTEvent(uint256 _tokenId, uint256 _index) external view returns (EventData memory) {
|
|
142
|
+
return nftDatas[_tokenId].events[_index];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getNFTEvents(uint256 _tokenId) external view returns (EventData[] memory) {
|
|
146
|
+
return nftDatas[_tokenId].events;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function addManager(address _manager, uint32 _nftType) external {
|
|
150
|
+
grantRole(getManagerRole(_nftType), _manager);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getManagerRole(uint32 _nftType) public pure returns (bytes32 roleHash) {
|
|
154
|
+
return keccak256(abi.encodePacked("MANAGER_", _nftType));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @dev See {IERC721Metadata-tokenURI}.
|
|
159
|
+
*/
|
|
160
|
+
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
|
|
161
|
+
_requireMinted(tokenId);
|
|
162
|
+
|
|
163
|
+
string memory baseURI = _baseURI();
|
|
164
|
+
return
|
|
165
|
+
bytes(baseURI).length > 0
|
|
166
|
+
? string(abi.encodePacked(baseURI, nftDatas[tokenId].nftUri))
|
|
167
|
+
: nftDatas[tokenId].nftUri;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
|
|
172
|
+
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
|
|
173
|
+
* by default, can be overridden in child contracts.
|
|
174
|
+
*/
|
|
175
|
+
function _baseURI() internal view virtual override returns (string memory) {
|
|
176
|
+
return "";
|
|
177
|
+
}
|
|
178
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gooddollar/goodcollective-contracts",
|
|
3
|
+
"packageManager": "yarn@3.2.1",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"types": "./typechain-types/index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"contracts",
|
|
9
|
+
"typechain-types",
|
|
10
|
+
"releases"
|
|
11
|
+
],
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@gooddollar/goodprotocol": "file:.yalc/@gooddollar/goodprotocol",
|
|
14
|
+
"@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
|
|
15
|
+
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
|
|
16
|
+
"@nomicfoundation/hardhat-toolbox": "2.*",
|
|
17
|
+
"@nomicfoundation/hardhat-verify": "^1.0.1",
|
|
18
|
+
"@nomiclabs/hardhat-ethers": "^2.0.0",
|
|
19
|
+
"@nomiclabs/hardhat-etherscan": "^3.0.0",
|
|
20
|
+
"@openzeppelin/contracts": "^4.9.2",
|
|
21
|
+
"@openzeppelin/contracts-upgradeable": "4.8.3",
|
|
22
|
+
"@openzeppelin/hardhat-upgrades": "1.20.0",
|
|
23
|
+
"@superfluid-finance/ethereum-contracts": "^1.7.0",
|
|
24
|
+
"@typechain/ethers-v5": "^10.1.0",
|
|
25
|
+
"@types/chai": "^4.2.0",
|
|
26
|
+
"@types/mocha": ">=9.1.0",
|
|
27
|
+
"@types/prettier": "^2",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
29
|
+
"chai": "^4.2.0",
|
|
30
|
+
"dotenv": "^16.3.1",
|
|
31
|
+
"hardhat": "2.14.*",
|
|
32
|
+
"hardhat-abi-exporter": "^2.10.1",
|
|
33
|
+
"hardhat-contract-sizer": "^2.10.0",
|
|
34
|
+
"hardhat-deploy": "^0.11.31",
|
|
35
|
+
"hardhat-gas-reporter": "^1.0.8",
|
|
36
|
+
"prettier": "^2.8.8",
|
|
37
|
+
"prettier-plugin-solidity": "^1.1.3",
|
|
38
|
+
"solhint-plugin-prettier": "^0.0.5",
|
|
39
|
+
"solidity-coverage": "^0.8.1",
|
|
40
|
+
"typechain": "^8.1.0",
|
|
41
|
+
"typescript": "^5.1.3"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"compile": "npx hardhat compile",
|
|
45
|
+
"clean": "npx hardhat clean",
|
|
46
|
+
"solhint": "solhint ./contracts/**/*.sol",
|
|
47
|
+
"format": "yarn prettier -w ./test/**/*.ts ./contracts/**/*.sol",
|
|
48
|
+
"format:check": "yarn prettier -c ./test/**/*.ts ./contracts/**/*.sol",
|
|
49
|
+
"lint:ts": "eslint scripts/ test/ --ext=ts",
|
|
50
|
+
"lint:sol": "solhint 'contracts/**/*.sol'",
|
|
51
|
+
"lint": "npm run lint:sol && npm run lint:ts",
|
|
52
|
+
"lint:fix": "npm run lint:sol:fix && npm run lint:ts:fix",
|
|
53
|
+
"lint:ts:fix": "eslint scripts/ test/ --ext=ts --fix",
|
|
54
|
+
"lint:sol:fix": "solhint 'contracts/**/*.sol' --fix",
|
|
55
|
+
"test": "npx hardhat test",
|
|
56
|
+
"test:coverage": "npx hardhat coverage",
|
|
57
|
+
"deploy": "hardhat deploy --export-all ./releases/deployment.json"
|
|
58
|
+
}
|
|
59
|
+
}
|