2019年12月,Alchemy完成1500万美元A轮融资,资方为Pantera Capital,斯坦福大学,Coinbase,三星等。
2021年4月,Alchemy以5.05亿美元估值完成8000万美元B轮融资,Coatue和Addition领投,DFJ Growth、K5 Global、Chainsmokers(烟鬼组合)、演员Jared Leto和Glazer家族参投。
2021年10月,Alchemy以35亿美元估值完成2.5亿美元C轮融资,由a16z领投的。
2022年2月,Alchemy以102亿美元估值完成2亿美元融资,Lightspeed与Silver Lake领投。
Alchemy是一个背景强大、经费充足、踏实做事、没有发币的团队,这样的项目不刷,难道去刷土狗吗?
并且,Alchemy计划将新资金用于推广Web3采用,这方面的一些举措包括推出Web3 University,就是现在的 Road to Web3 活动,活动为期10周,每周一个NFT。看了下nft数量极少,估计由于任务难度大,很多小伙伴直接放弃,这样的项目若是空投,绝对是大毛。
什么是动态NFT?这一课很有趣。
NFT会变化,就像下面一样,我们开始吧!
1.小狐狸钱包调整到rinkey测试网,进 faucets.chain.link ,领取测试币。
1.进入remix.ethereum.org ,如图新建一个工作台,随意命名。
2.右键删除contract下面的三个文件。
3.在contracts下面新建名为Bull&Bear.sol 的文件夹。
4.将下面的代码复制粘贴进来。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
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";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
// Dev imports. This only works on a local dev network
// and will not work on any test or main livenets.
import "hardhat/console.sol";
contract BullBear is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable, VRFConsumerBaseV2, KeeperCompatibleInterface {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
uint public interval;
uint public lastTimeStamp;
AggregatorV3Interface public priceFeed;
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"
];
// random
VRFCoordinatorV2Interface COORDINATOR;
// Your subscription ID.
uint64 s_subscriptionId;
// Goerli coordinator. For other networks,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
address vrfCoordinator = 0x6168499c0cFfCaCD319c818142124B7A15E857ab;
// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
bytes32 keyHash = 0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Storing each word costs about 20,000 gas,
// so 100,000 is a safe default for this example contract. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 callbackGasLimit = 100000;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;
// For this example, retrieve 2 random values in one request.
// Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
uint32 numWords = 2;
uint256[] public s_randomWords;
uint256 public s_requestId;
event TokensUpdated(string marketTrend);
constructor(uint updateInterval, address _priceFeed, uint64 subscriptionId) ERC721("Bull&Bear", "BBTK") VRFConsumerBaseV2(vrfCoordinator) {
interval = updateInterval;
lastTimeStamp = block.timestamp;
// https://rinkeby.etherscan.io/address/0xECe365B379E1dD183B20fc5f022230C044d51404
priceFeed = AggregatorV3Interface(_priceFeed);
currentPrice = getLatestPrice();
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
s_subscriptionId = subscriptionId;
}
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[s_randomWords[0]%3];
_setTokenURI(tokenId, defaultUri);
console.log(
"DONE!!! minted token ",
tokenId,
" and assigned token url: ",
defaultUri
);
}
function checkUpkeep(bytes calldata) external view override returns (bool upkeepNeeded, bytes memory /*performData*/){
upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
}
function performUpkeep(bytes calldata) external override{
if((block.timestamp - lastTimeStamp) > interval){
lastTimeStamp = block.timestamp;
int latestPrice = getLatestPrice();
if(latestPrice == currentPrice){
return;
}else if(latestPrice < currentPrice){
updateAllTokenUris("bears");
}else{
updateAllTokenUris("bull");
}
currentPrice = latestPrice;
}
}
function getLatestPrice() public view returns(int256){
(,
int price,
,
,) = priceFeed.latestRoundData();
return price;
}
function updateAllTokenUris(string memory trend) internal{
if(compareStrings("bears", trend)){
for(uint i=0; i< _tokenIdCounter.current(); i++){
_setTokenURI(i,bearUrisIpfs[s_randomWords[0]%3]);
}
}else {
for(uint i=0; i< _tokenIdCounter.current(); i++){
_setTokenURI(i,bullUrisIpfs[s_randomWords[0]%3]);
}
}
emit TokensUpdated(trend);
}
function setInterval(uint256 newInterval) public onlyOwner{
interval = newInterval;
}
function setPriceFeed(address newFeed) public onlyOwner{
priceFeed = AggregatorV3Interface(newFeed);
}
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);
}
// Assumes the subscription is funded sufficiently.
function requestRandomWords() external onlyOwner {
// Will revert if subscription is not set and funded.
s_requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
}
}
5.点击左侧的编译器菜单,版本选0.8.4,然后点击编译。
6.然后点击“Deploy and Run Transactions”菜单,此时确保小狐狸的网络是rinkey测试网,其他选项如图中红框所示。
1.进入 vrf.chain.link 并连接小狐狸。
2.点击Create Subscription。
3.继续点击Create Subscription,并在跳出的小狐狸对话框点击确认。
4.再点击Add funds。
4.再输入任意数字,点击Add funds,并在小狐狸确认。
5.等待十几秒,再点击Add consumer。
6.到这个页面,先空着,等会儿补上,直接点I’ll do it later。
7.好了,如图,我这里获取的编号为11513,大家的这个不一样哈。
1.回到remix界面。
第一行输入10;
第二行输入0xECe365B379E1dD183B20fc5f022230C044d51404 ;
第三行输入刚才获取的编号,我的是11513。
2.然后点击transact部署合约,出现小狐狸点击确认。
3.出现这样的信息就对了。
4.回到step3的预言机界面,点击Add consumer。
5.将刚刚生成的合约地址复制下来,粘贴进预言机界面,点击Add consumer,然后在小狐狸中确认。
6.点击close关闭,即可。
1.点击下箭头出现合约详情,点击requestRandomWords,弹出小狐狸钱包点击确认。
出现这个勾就继续。
2.在s_randomWords中输入0,点击call。
3.然后在safemint里面填写自己的ETH地址,点击transact,弹出小狐狸钱包后点击确认。
出现如图所示就成功了。
4.此时进入openseatest 查看,就可以看到刚才mint的NFT了。
提交合约地址就可以了!
很多人问NFT怎么没有领取链接哈哈,其实都在这里呀。
还有人私信说看不到前面的课程。。。。。估计是新关注的小伙伴吧,都贴下面了。