百亿项目 Alchemy Road to Web3 第五周 NFT 获取教程
2022-08-16 20:29
Greta
2022-08-16 20:29
Greta
2022-08-16 20:29
订阅此专栏
收藏此文章

Alchemy 是什么项目?

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 数量极少,估计由于任务难度大,很多小伙伴直接放弃,这样的项目若是空投,绝对是大毛。

手把手第五周教程开始:使用 Chainlink 预言机构建基于市场数据变化的动态 NFT

什么是动态 NFT?这一课很有趣。

NFT 会变化,就像下面一样,我们开始吧!

step1 领取测试币

1.小狐狸钱包调整到 rinkey 测试网,进 faucets.chain.link ,领取测试币。

step2 编译合约

1.进入remix.ethereum.org ,如图新建一个工作台,随意命名。

2.右键删除 contract 下面的三个文件。

3.在 contracts 下面新建名为 Bull&Bear.sol 的文件夹。

4.将下面的代码复制粘贴进来。

// SPDX-License-Identifier: GPL-3.0pragma 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 Importsimport "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";// This import includes functions from both ./KeeperBase.sol and// ./interfaces/KeeperCompatibleInterface.solimport "@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 测试网,其他选项如图中红框所示。

step3 获取预言机订阅号

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,大家的这个不一样哈。

step4 部署合约

1.回到 remix 界面。

第一行输入 10;

第二行输入 0xECe365B379E1dD183B20fc5f022230C044d51404 ;

第三行输入刚才获取的编号,我的是 11513。

2.然后点击 transact 部署合约,出现小狐狸点击确认。

3.出现这样的信息就对了。

4.回到 step3 的预言机界面,点击 Add consumer。

5.将刚刚生成的合约地址复制下来,粘贴进预言机界面,点击 Add consumer,然后在小狐狸中确认。

6.点击 close 关闭,即可。

step5 mint NFT

1.点击下箭头出现合约详情,点击 requestRandomWords,弹出小狐狸钱包点击确认。

出现这个勾就继续。

2.在 s_randomWords 中输入 0,点击 call。

3.然后在 safemint 里面填写自己的 ETH 地址,点击 transact,弹出小狐狸钱包后点击确认。

出现如图所示就成功了。

4.此时进入openseatest 查看,就可以看到刚才 mint 的 NFT 了。

step6 提交项目

提交地址

提交合约地址就可以了!

step7 NFT 领取

很多人问 NFT 怎么没有领取链接哈哈,其实都在这里呀。

还有人私信说看不到前面的课程。。。。。估计是新关注的小伙伴吧,都贴下面了。

https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/egs3DyvaUmAYlQXrufE55p9sJ80coSDDxOfTCR-7e3o

https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/JCRkc6KJPrpJX3A03E0fzF96oNzOY6tCDxn9Duz_p3I

https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/kbBuWvxErpmIgOCkI6HyHEb2XDpManoxSTxhV0zTtSQ

https://mirror.xyz/0xCD0e394639B2D0b159B41F9dBe0583C33d85e874/XlXqh697bnRkkmzb9jdC4rHOMpPI0KPe6FCBZANZdHU

相关Wiki

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

Greta
数据请求中
查看更多

推荐专栏

数据请求中
在 App 打开