-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathEntityForging.sol
More file actions
208 lines (174 loc) · 6.53 KB
/
EntityForging.sol
File metadata and controls
208 lines (174 loc) · 6.53 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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/security/Pausable.sol';
import './IEntityForging.sol';
import '../TraitForgeNft/ITraitForgeNft.sol';
contract EntityForging is IEntityForging, ReentrancyGuard, Ownable, Pausable {
ITraitForgeNft public nftContract;
address payable public nukeFundAddress;
uint256 public taxCut = 10;
uint256 public oneYearInDays = 365 days;
uint256 public listingCount = 0;
uint256 public minimumListFee = 0.01 ether;
/// @dev tokenid -> listings index
mapping(uint256 => uint256) public listedTokenIds;
/// @dev index -> listing info
mapping(uint256 => Listing) public listings;
mapping(uint256 => uint8) public forgingCounts; // track forgePotential
mapping(uint256 => uint256) private lastForgeResetTimestamp;
constructor(address _traitForgeNft) {
nftContract = ITraitForgeNft(_traitForgeNft);
}
// allows the owner to set NukeFund address
function setNukeFundAddress(
address payable _nukeFundAddress
) external onlyOwner {
nukeFundAddress = _nukeFundAddress;
}
function setTaxCut(uint256 _taxCut) external onlyOwner {
taxCut = _taxCut;
}
function setOneYearInDays(uint256 value) external onlyOwner {
oneYearInDays = value;
}
function setMinimumListingFee(uint256 _fee) external onlyOwner {
minimumListFee = _fee;
}
function fetchListings() external view returns (Listing[] memory _listings) {
_listings = new Listing[](listingCount + 1);
for (uint256 i = 1; i <= listingCount; ++i) {
_listings[i] = listings[i];
}
}
function getListedTokenIds(
uint tokenId_
) external view override returns (uint) {
return listedTokenIds[tokenId_];
}
function getListings(
uint id
) external view override returns (Listing memory) {
return listings[id];
}
function listForForging(
uint256 tokenId,
uint256 fee
) public whenNotPaused nonReentrant {
Listing memory _listingInfo = listings[listedTokenIds[tokenId]];
require(!_listingInfo.isListed, 'Token is already listed for forging');
require(
nftContract.ownerOf(tokenId) == msg.sender,
'Caller must own the token'
);
require(
fee >= minimumListFee,
'Fee should be higher than minimum listing fee'
);
_resetForgingCountIfNeeded(tokenId);
uint256 entropy = nftContract.getTokenEntropy(tokenId); // Retrieve entropy for tokenId
uint8 forgePotential = uint8((entropy / 10) % 10); // Extract the 5th digit from the entropy
require(
forgePotential > 0 && forgingCounts[tokenId] <= forgePotential,
'Entity has reached its forging limit'
);
bool isForger = (entropy % 3) == 0; // Determine if the token is a forger based on entropy
require(isForger, 'Only forgers can list for forging');
++listingCount;
listings[listingCount] = Listing(msg.sender, tokenId, true, fee);
listedTokenIds[tokenId] = listingCount;
emit ListedForForging(tokenId, fee);
}
function forgeWithListed(
uint256 forgerTokenId,
uint256 mergerTokenId
) external payable whenNotPaused nonReentrant returns (uint256) {
Listing memory _forgerListingInfo = listings[listedTokenIds[forgerTokenId]];
require(
_forgerListingInfo.isListed,
"Forger's entity not listed for forging"
);
require(
nftContract.ownerOf(mergerTokenId) == msg.sender,
'Caller must own the merger token'
);
require(
nftContract.ownerOf(forgerTokenId) != msg.sender,
'Caller should be different from forger token owner'
);
require(
nftContract.getTokenGeneration(mergerTokenId) ==
nftContract.getTokenGeneration(forgerTokenId),
'Invalid token generation'
);
uint256 forgingFee = _forgerListingInfo.fee;
require(msg.value >= forgingFee, 'Insufficient fee for forging');
_resetForgingCountIfNeeded(forgerTokenId); // Reset for forger if needed
_resetForgingCountIfNeeded(mergerTokenId); // Reset for merger if needed
// Check forger's breed count increment but do not check forge potential here
// as it is already checked in listForForging for the forger
forgingCounts[forgerTokenId]++;
// Check and update for merger token's forge potential
uint256 mergerEntropy = nftContract.getTokenEntropy(mergerTokenId);
require(mergerEntropy % 3 != 0, 'Not merger');
uint8 mergerForgePotential = uint8((mergerEntropy / 10) % 10); // Extract the 5th digit from the entropy
forgingCounts[mergerTokenId]++;
require(
mergerForgePotential > 0 &&
forgingCounts[mergerTokenId] <= mergerForgePotential,
'forgePotential insufficient'
);
uint256 devFee = forgingFee / taxCut;
uint256 forgerShare = forgingFee - devFee;
address payable forgerOwner = payable(nftContract.ownerOf(forgerTokenId));
uint256 newTokenId = nftContract.forge(
msg.sender,
forgerTokenId,
mergerTokenId,
''
);
(bool success, ) = nukeFundAddress.call{ value: devFee }('');
require(success, 'Failed to send to NukeFund');
(bool success_forge, ) = forgerOwner.call{ value: forgerShare }('');
require(success_forge, 'Failed to send to Forge Owner');
// Cancel listed forger nft
_cancelListingForForging(forgerTokenId);
uint256 newEntropy = nftContract.getTokenEntropy(newTokenId);
emit EntityForged(
newTokenId,
forgerTokenId,
mergerTokenId,
newEntropy,
forgingFee
);
return newTokenId;
}
function cancelListingForForging(
uint256 tokenId
) external whenNotPaused nonReentrant {
require(
nftContract.ownerOf(tokenId) == msg.sender ||
msg.sender == address(nftContract),
'Caller must own the token'
);
require(
listings[listedTokenIds[tokenId]].isListed,
'Token not listed for forging'
);
_cancelListingForForging(tokenId);
}
function _cancelListingForForging(uint256 tokenId) internal {
delete listings[listedTokenIds[tokenId]];
emit CancelledListingForForging(tokenId); // Emitting with 0 fee to denote cancellation
}
function _resetForgingCountIfNeeded(uint256 tokenId) private {
uint256 oneYear = oneYearInDays;
if (lastForgeResetTimestamp[tokenId] == 0) {
lastForgeResetTimestamp[tokenId] = block.timestamp;
} else if (block.timestamp >= lastForgeResetTimestamp[tokenId] + oneYear) {
forgingCounts[tokenId] = 0; // Reset to the forge potential
lastForgeResetTimestamp[tokenId] = block.timestamp;
}
}
}