-
Notifications
You must be signed in to change notification settings - Fork 1
/
BullBear.sol
253 lines (199 loc) · 6.61 KB
/
BullBear.sol
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import './BullBearToken.sol';
import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/Counters.sol';
struct LastHappiness {
uint256 time;
uint8 happiness;
}
error TooSoonToPet(uint256 minPetTime);
error Rekt();
struct Urls {
string baseUrl;
string modelUrl;
string behaveGraphUrl;
}
contract BullBear is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
uint8 constant MAX_HAPPINESS = 100;
uint8 constant INITIAL_HAPPINESS = MAX_HAPPINESS / 2;
uint8 constant INITIAL_FOOD = 3;
uint8 constant HAPPINESS_DECAY_RATE_PER_MINUTE = 50;
uint8 constant PETTING_BONUS = 50;
uint8 constant MIN_PETTING_INTERVAL_SECONDS = 5;
Counters.Counter private _tokenIdCounter;
BullBearToken public immutable bullBearToken;
// BullBearFood public immutable bullBearFood;
event Petted(uint256 tokenId);
mapping(uint256 => LastHappiness) private lastHappiness;
mapping(uint256 => uint256) private lastPetTime;
string public baseURI;
string public modelURI;
string public behaveGraphURI;
constructor(
string memory _initialBaseUri,
string memory _modelUrl,
string memory _initialBehaveGraphURI
) ERC721('BullBear', 'BBTK') {
baseURI = _initialBaseUri;
bullBearToken = new BullBearToken();
modelURI = _modelUrl;
behaveGraphURI = _initialBehaveGraphURI;
// bullBearFood = new BullBearFood();
}
function safeMint(address to) public returns (uint256) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
lastHappiness[tokenId] = LastHappiness(block.timestamp, INITIAL_HAPPINESS);
_safeMint(to, tokenId);
// bullBearFood.mint(to, INITIAL_FOOD);
return tokenId;
}
function setBehaveGraphURI(string memory _behaveGraphURI) external onlyOwner {
behaveGraphURI = _behaveGraphURI;
}
function canPet(uint256 tokenId) public view returns (bool) {
if (lastPetTime[tokenId] == 0) return true;
uint256 elapsed = block.timestamp - lastPetTime[tokenId];
return elapsed >= MIN_PETTING_INTERVAL_SECONDS;
}
function pet(uint256 tokenId) public {
// check if can pet according to the time
// if this is a new pet, then we can pet
if (!canPet(tokenId)) {
revert TooSoonToPet({minPetTime: MIN_PETTING_INTERVAL_SECONDS});
}
lastPetTime[tokenId] = block.timestamp;
emit Petted(tokenId);
_increaseHappiness(tokenId, PETTING_BONUS);
}
function getHappiness(uint256 tokenId) public view returns (uint8) {
LastHappiness storage _lastHappiness = lastHappiness[tokenId];
uint256 elapsed = block.timestamp - _lastHappiness.time;
uint256 decay = (HAPPINESS_DECAY_RATE_PER_MINUTE * elapsed) / 60;
if (decay >= _lastHappiness.happiness) {
return 0;
}
return _lastHappiness.happiness - uint8(decay);
}
function isRekt(uint256 tokenId) public view returns (bool) {
return getHappiness(tokenId) == 0;
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function _baseURI() internal view override returns (string memory) {
return baseURI;
}
function tokenURI(
uint256 tokenId
) public view override(ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}
function supportsInterface(
bytes4 interfaceId
) public view override(ERC721, ERC721URIStorage) returns (bool) {
return super.supportsInterface(interfaceId);
}
function pettingBonus() external pure returns (uint8) {
return PETTING_BONUS;
}
function initialHappiness() external pure returns (uint8) {
return INITIAL_HAPPINESS;
}
function happinessDecayRatePerMinute() external pure returns (uint8) {
return HAPPINESS_DECAY_RATE_PER_MINUTE;
}
function minPettingIntervalSeconds() external pure returns (uint8) {
return MIN_PETTING_INTERVAL_SECONDS;
}
function modelAndGraphUrls() external view returns (Urls memory) {
return Urls(baseURI, modelURI, behaveGraphURI);
}
function _increaseHappiness(uint256 tokenId, uint8 amount) private {
lastHappiness[tokenId] = LastHappiness(
block.timestamp,
_min(getHappiness(tokenId) + amount, MAX_HAPPINESS)
);
}
function _min(uint8 a, uint8 b) private pure returns (uint8) {
if (a < b) {
return a;
}
return b;
}
}
/*
contract BullBear is
Initializable,
ERC721Upgradeable,
ERC721URIStorageUpgradeable,
OwnableUpgradeable,
UUPSUpgradeable
{
using CountersUpgradeable for CountersUpgradeable.Counter;
uint8 constant MAX_HAPPINESS = 100;
uint constant INITIAL_FOOD = 3;
uint256 public immutable maxSupply;
string public baseURI;
BullBearToken public immutable bullBearToken;
BullBearFood public immutable bullBearFood;
CountersUpgradeable.Counter private _tokenIdCounter;
mapping(uint256 => uint8) public happiness;
mapping(uint256 => uint256) public lastWithdrawn;
mapping(uint256 => uint8) public happinessWhenWithdrawn;
mapping(uint256 => uint256) public withdrawals;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(uint256 _maxSupply, string memory _initialBaseUri) {
_disableInitializers();
maxSupply = _maxSupply;
baseURI = _initialBaseUri;
bullBearToken = new BullBearToken();
bullBearFood = new BullBearFood();
}
function initialize() public initializer {
__ERC721_init('BullBear', 'BLBR');
__ERC721URIStorage_init();
__Ownable_init();
__UUPSUpgradeable_init();
}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
if (tokenId >= maxSupply) {
revert('Max supply reached');
}
_tokenIdCounter.increment();
happiness[tokenId] = MAX_HAPPINESS / 2;
_safeMint(to, tokenId);
bullBearFood.mint(to, INITIAL_FOOD);
}
function setBaseUri(string calldata _newBaseUri) public onlyOwner {
baseURI = _newBaseUri;
}
function _burn(
uint256 tokenId
) internal override(ERC721Upgradeable, ERC721URIStorageUpgradeable) {
super._burn(tokenId);
}
function _baseURI() internal view override returns (string memory) {
return baseURI;
}
function tokenURI(
uint256 tokenId
)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
}
*/