-
Notifications
You must be signed in to change notification settings - Fork 73
/
Bull&Bear.sol
196 lines (155 loc) · 6.8 KB
/
Bull&Bear.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
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
// Chainlink Imports
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// This import includes functions from both ./KeeperBase.sol and
// ./interfaces/KeeperCompatibleInterface.sol
import "@chainlink/contracts/src/v0.8/KeeperCompatible.sol";
// Dev imports
import "hardhat/console.sol";
contract BullBear is ERC721, ERC721Enumerable, ERC721URIStorage, KeeperCompatibleInterface, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
AggregatorV3Interface public pricefeed;
/**
* Use an interval in seconds and a timestamp to slow execution of Upkeep
*/
uint public /* immutable */ interval;
uint public lastTimeStamp;
int256 public currentPrice;
// IPFS URIs for the dynamic nft graphics/metadata.
// NOTE: These connect to my IPFS Companion node.
// You should upload the contents of the /ipfs folder to your own node for development.
string[] bullUrisIpfs = [
"https://ipfs.io/ipfs/QmRXyfi3oNZCubDxiVFre3kLZ8XeGt6pQsnAQRZ7akhSNs?filename=gamer_bull.json",
"https://ipfs.io/ipfs/QmRJVFeMrtYS2CUVUM2cHJpBV5aX2xurpnsfZxLTTQbiD3?filename=party_bull.json",
"https://ipfs.io/ipfs/QmdcURmN1kEEtKgnbkVJJ8hrmsSWHpZvLkRgsKKoiWvW9g?filename=simple_bull.json"
];
string[] bearUrisIpfs = [
"https://ipfs.io/ipfs/Qmdx9Hx7FCDZGExyjLR6vYcnutUR8KhBZBnZfAPHiUommN?filename=beanie_bear.json",
"https://ipfs.io/ipfs/QmTVLyTSuiKGUEmb88BgXG3qNC8YgpHZiFbjHrXKH3QHEu?filename=coolio_bear.json",
"https://ipfs.io/ipfs/QmbKhBXVWmwrYsTPFYfroR2N7NAekAMxHUVg2CWks7i9qj?filename=simple_bear.json"
];
event TokensUpdated(string marketTrend);
// For testing with the mock on Rinkeby, pass in 10(seconds) for `updateInterval` and the address of my
// deployed MockPriceFeed.sol contract (0xD753A1c190091368EaC67bbF3Ee5bAEd265aC420).
constructor(uint updateInterval, address _pricefeed) ERC721("Bull&Bear", "BBTK") {
// Set the keeper update interval
interval = updateInterval;
lastTimeStamp = block.timestamp; // seconds since unix epoch
// set the price feed address to
// BTC/USD Price Feed Contract Address on Rinkeby: https://rinkeby.etherscan.io/address/0xECe365B379E1dD183B20fc5f022230C044d51404
// or the MockPriceFeed Contract
pricefeed = AggregatorV3Interface(_pricefeed); // To pass in the mock
// set the price for the chosen currency pair.
currentPrice = getLatestPrice();
}
function safeMint(address to) public {
// Current counter value will be the minted token's token ID.
uint256 tokenId = _tokenIdCounter.current();
// Increment it so next time it's correct when we call .current()
_tokenIdCounter.increment();
// Mint the token
_safeMint(to, tokenId);
// Default to a bull NFT
string memory defaultUri = bullUrisIpfs[0];
_setTokenURI(tokenId, defaultUri);
console.log("DONE!!! minted token ", tokenId, " and assigned token url: ", defaultUri);
}
function checkUpkeep(bytes calldata /* checkData */) external view override returns (bool upkeepNeeded, bytes memory /*performData */) {
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
}
function performUpkeep(bytes calldata /* performData */ ) external override {
//We highly recommend revalidating the upkeep in the performUpkeep function
if ((block.timestamp - lastTimeStamp) > interval ) {
lastTimeStamp = block.timestamp;
int latestPrice = getLatestPrice();
if (latestPrice == currentPrice) {
console.log("NO CHANGE -> returning!");
return;
}
if (latestPrice < currentPrice) {
// bear
console.log("ITS BEAR TIME");
updateAllTokenUris("bear");
} else {
// bull
console.log("ITS BULL TIME");
updateAllTokenUris("bull");
}
// update currentPrice
currentPrice = latestPrice;
} else {
console.log(
" INTERVAL NOT UP!"
);
return;
}
}
// Helpers
function getLatestPrice() public view returns (int256) {
(
/*uint80 roundID*/,
int price,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = pricefeed.latestRoundData();
return price; // example price returned 3034715771688
}
function updateAllTokenUris(string memory trend) internal {
if (compareStrings("bear", trend)) {
console.log(" UPDATING TOKEN URIS WITH ", "bear", trend);
for (uint i = 0; i < _tokenIdCounter.current() ; i++) {
_setTokenURI(i, bearUrisIpfs[0]);
}
} else {
console.log(" UPDATING TOKEN URIS WITH ", "bull", trend);
for (uint i = 0; i < _tokenIdCounter.current() ; i++) {
_setTokenURI(i, bullUrisIpfs[0]);
}
}
emit TokensUpdated(trend);
}
function setPriceFeed(address newFeed) public onlyOwner {
pricefeed = AggregatorV3Interface(newFeed);
}
function setInterval(uint256 newInterval) public onlyOwner {
interval = newInterval;
}
function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}