本文將詳細介紹Web3DApp開發的架構、技術,以及使用哪些工具,并給出完整示例。我們先介紹Web3用到的技術:區塊鏈,以以太坊為主流,也包括Solana、Aptos等其他非EVM鏈。區塊鏈本身是軟件,需要運行在一系列節點上,這些節點組成P2P網絡或者半中心化網絡。節點不僅負責接收新的輸入并生成新的區塊,還需要存儲區塊鏈運行時產生的所有數據,并負責同步、對外提供查詢等RPC服務。錢包:幫助用戶管理自己在區塊鏈上資產的軟件,加密存儲用戶的私鑰。當用戶需要和區塊鏈交互時,就需要用到私鑰簽名;智能合約:運行在區塊鏈上的一段托管程序,主要用來和外部賬戶交互;UI:這里特指前端頁面,因為直接通過RPC調用合約僅限個別高級用戶,普通用戶仍需要一個前端頁面,并通過JavaScript腳本配合錢包簽名與合約交互。因為區塊鏈上所有數據全透明,要查詢任意區塊的數據,可以通過EtherScan這個網站查。其他公鏈,無論是與Ethereum兼容的BSC、Polygon,還是不兼容的Solana、Aptos等,也提供類似XxxScan這樣的查詢網站。這些Scan能提供基本的讀寫合約的能力,有助于開發階段的測試。區塊鏈本身以及錢包、EtherScan等屬于基礎設施,如何基礎設施不在本文討論范圍之內。本文僅限定如何開發DApp。一個完整的DApp需要開發以下部分:智能合約:將邏輯寫入合約,并部署在鏈上;UI:為用戶提供一個交互式UI,配合錢包完成特定功能。此外,對后端開發有經驗的同學應該知道,通常來說,App數據會存儲在數據庫中,前端與后端交互,離不開后端對數據的查詢和修改。在DApp中,同樣需要一個查詢的“后端”,但這個后端通常不是數據庫。有的同學會認為,既然節點本身提供了查詢鏈上全部數據的PRC接口,那么,前端直接查詢節點是否可行?答案是不行。因為節點提供的數據,是用戶產生的原始日志。舉個例子,假設有個NFT合約,允許用戶創建NFT,那么,一段時間內,節點產生的日志如下:用戶A創建了NFT-1;用戶B創建了NFT-2;用戶B把NFT-2轉移給了用戶X;用戶C創建了NFT-3;...這些未經聚合處理的數據沒法生成一個不斷更新的數據庫表:OwnerNFTID用戶A1用戶X2用戶C3所以,一個DApp除了前端外,還需要一個后端服務,它主要功能是不斷聚合鏈上產生的數據,并根據DApp的業務需求設計表結構以方便查詢。一個直觀的想法是用Java或者Go語言等編寫一個后端服務,再配上一個數據庫,就可以為前端提供RESTAPI來實現查詢。只不過自己維護后端服務比較麻煩,還需要租用云端服務器、數據庫等資源,費時費力。我們推薦另一種后端服務:TheGraph。它本身也可看作是一個基礎設置。TheGraph可以讓我們部署一個Graph查詢服務,如何定義表結構以及如何更新則由我們提供一個預編譯的WASM。整個配置、WASM代碼以及查詢服務都托管在TheGraph中,無需自己搭建服務器,非常方便。因此,一個完整的DApp架構如下:┌───────┐┌───────────│DApp│───────────┐│└───────┘││read/writequery││contractdata│▼▼┌───────┐┌───────┐│Wallet││Graph│└───────┘└───────┘│▲│signindex││broadcastdata││││┌─────────────││┌────┐┌────┐┌────┐││└──┼?│Node││Node│...│Node│───┘└────┘└────┘└────┘││Ethereum─────────────┘我們看看開發各個組件所需的技能樹需求。由于本文僅討論ETH以及ETH兼容鏈的DApp開發,所以,以下技能樹僅適用于ETH系:合約開發:使用Solidity語言;合約部署工具:可以選擇Hardhat、Truffle或Foundry,建議使用Hardhat;數據聚合服務:選擇TheGraph提供的托管服務;數據聚合開發:TheGraph給出的模板代碼是TypeScript,因此這里使用TypeScript;前端頁面:HTML+JavaScript/TypeScript,也可配合任意前端框架如Vue、React等;合約交互框架:雖然理論上使用JSONRPC就可以讀寫合約,但使用Ethers.js可以大大簡化開發;錢包支持:如果僅支持MetaMask,則使用Ethers.js已足夠,如果要支持多種錢包,尤其是需要連接手機錢包,則需要使用Web3Modal。綜上所述,我們可以總結一個基本的Web3全棧開發技術需求:Solidity語言;JavaScript語言;TypeScript語言;HTML/CSS等前端技能。以及用到的服務:將所有源碼托管在GitHub;使用TheGraph提供的HostedService;使用GitHubPage實現靜態頁托管;可選:綁定一個域名。下面我們以一個具體的項目來演示Web3全棧開發的完整流程。該項目允許用戶在Polygon上創建屬于自己的NFT卡片,并可在頁面查看鏈上鑄造的所有NFT卡片:圖片Polygon是兼容以太坊的PoS鏈,特點是Gas便宜,速度快,領測試幣方便。編寫合約創建Web3DApp的第一步是編寫合約。我們使用Hardhat工具,它是Node.js開發的,確保本機安裝了Node.js和NPM,先安裝Solidity編譯器:$npminstall-gsolc$solc--versionsolc,thesoliditycompilercommandlineinterfaceVersion:0.8.17然后創建目錄web3stack并安裝Hardhat:$mkdirweb3stack$cdweb3stack$npminstall--save-devhardhat然后輸入命令npxhardhat開始創建一個新的合約項目:$npxhardhatHardhat提示選擇項目類型:?Whatdoyouwanttodo?…?CreateaJavaScriptprojectCreateaTypeScriptprojectCreateanemptyhardhat.config.jsQuit這里選擇JavaScript項目。后續接著提示項目根目錄、是否添加.gitignore、是否安裝相關依賴等:?Whatdoyouwanttodo?·CreateaJavaScriptproject?Hardhatprojectroot:·/path/to/web3stack?Doyouwanttoadda.gitignore?(Y/n)·y?Doyouwanttoinstallthissampleproject'sdependencieswithnpm(@nomicfoundation/hardhat-toolbox)?(Y/n)·y全部按默認值來。完成后查看package.json應該有兩個dev依賴:{"devDependencies":{"@nomicfoundation/hardhat-toolbox":"^2.0.1","hardhat":"^2.12.7"}}Hardhat默認創建了一個Lock合約,以及相關配置。我們可以自己再寫一個Card合約://SPDX-License-Identifier:GPL-v3pragmasolidity=0.8.17;import"@openzeppelin/contracts/token/ERC721/ERC721.sol";contractCardisERC721{...}直接編譯:$npxhardhatcompileErrorHH411:Thelibrary@openzeppelin/contracts,importedfromcontracts/Card.sol,isnotinstalled.Tryinstallingitusingnpm.編譯提示找不到library報錯,因為我們引用了OpenZeppelin的庫,所以要先用NPM安裝一下:npminstall--save@openzeppelin/contracts這條命令會在package.json中添加一個新的依賴:{..."dependencies":{"@openzeppelin/contracts":"^4.8.1"}}再次編譯:npxhardhatcompile生成的合約存放在artifacts/contracts/Card.sol/Card.json,它包括了ABI接口、字節碼等所有信息。部署合約就是把字節碼部署到鏈上。Hardhat提供了一個示例代碼script/deploy.js用于部署Lock合約,我們可以仿照這個腳本,復制一份script/deploy-card.js來部署Card合約:consthre=require("hardhat");asyncfunctionmain(){//合約工廠:constCard=awaithre.ethers.getContractFactory("Card");//部署:constcard=awaitCard.deploy();awaitcard.deployed();//打印部署的地址:console.log(`Carddeployedto${card.address}`);}main().catch((error)=>{console.error(error);process.exitCode=1;});部署時,直接運行腳本:$npxhardhatrunscripts/deploy-card.js但是,我們并沒有在本地配置任何關于鏈的信息,也沒有配置私鑰等賬戶信息,這個合約是不可能部署到鏈上的,那它部署到哪了?實際上合約默認部署到Hardhat提供的“虛擬JavaScript環境”,它可以在本地用Node執行合約代碼,主要用于測試。要部署到真實的鏈上,我們首先要在hardhat.config.js中加一點關于鏈的配置:module.exports={...//定義所有的鏈:networks:{//定義名為testnet的鏈:testnet:{//配置私鑰:accounts:,//配置為PolygonTestnet節點的PRC:url:"https://matic-mumbai.chainstacklabs.com"}},...}這里為了方便我們把私鑰直接寫進配置里,實際開發可從環境變量讀取。在部署前,確保私鑰對應的地址有一點MATIC測試幣。可以從這里領測試幣。然后用帶--network參數的命令部署:$npxhardhatrunscripts/deploy-card.js--networktestnet如果部署成功,則顯示Card合約被部署的地址:Carddeployedto0x8131aa1B766966f9F8ec3E1132D9d29D92311AB0在PolygonScan上就能查看該合約。順便可以將合約源碼在PolygonScan上驗證,驗證后即可在PolygonScan對合約進行基本的讀寫操作。開發DAppUIDAppUI就是前端頁面,既可以手寫HTML+JavaScript,也可以使用React、Vue等任何前端框架與Webpack等前端工具。為了簡化開發流程,這里我們直接手寫一個index.html頁,讓用戶能在頁面創建一個NFT。頁面引入的第三方庫包括jQuery、BootstrapCSS、Vue,以及用于合約交互的Ethers.js:<scriptsrc="https://cdn.jsdelivr.net/npm/ethers@5.0.32/dist/ethers.umd.min.js"></script>安裝了MetaMask插件后,頁面會獲得一個注入的window.ethereum全局變量,通過此變量與錢包進行交互,例如,連接錢包:awaitwindow.ethereum.request({method:'eth_requestAccounts',});調用合約方法則使用Ethers.js。下面的代碼創建了Card合約并調用mint()方法創建NFT:asyncfunction(){//創建合約:letcontract=newethers.Contract(//合約地址:'0x8131aa1b766966f9f8ec3e1132d9d29d92311ab0',//合約的ABI接口'',//錢包簽名對象:newethers.providers.Web3Provider(window.ethereum,"any").getSigner());//調用mint()方法:lettx=awaitcontract.mint();//等待1個確認:awaittx.wait(1);//TODO:解析tx的日志并拿到TokenID}異步調用mint()方法時,會拉起MetaMask,提示用戶對交易進行簽名。簽名后返回tx對象代表已發送的交易。等待1個確認后,如果要獲取交易信息,則需要解析tx的日志以便拿到TokenID等信息。最后注意到合約的ABI接口包含了合約完整的讀寫方法以及輸入輸出,它是一個JSON對象,這里以字符串形式傳入。Card合約的ABI可以在Card.json中找到并復制出來,不過我們可以使用Hardhat的一個插件直接輸出ABI文件。我們先用NPM安裝插件:$npminstall--save-devhardhat-abi-exporter然后在hardhat.config.js中添加插件配置://用require引入插件:require('hardhat-abi-exporter');...module.exports={...//使用ABIExporter插件:abiExporter:{//輸出到abi目錄:path:"./abi",clear:false,flat:true,pretty:false,//編譯時輸出:runOnCompile:true,}};再運行一次編譯,我們就可在abi目錄下看到若干.json文件。找到Card.json,整理下格式,變成一個字符串粘貼至HTML:...window.NFT_ABI=',"stateMutability":"nonpayable","type":"constructor"}...';...這樣,通過前端頁面,就可以調用合約方法。通過mint()方法寫入后,NFT已經生成,在PolygonScan查找對應的tx可查看詳細信息。通過PolygonScan的ReadContract頁面調用getImage()可獲得NFT圖片信息:圖片把返回的data:image/svg...復制到瀏覽器的地址欄,可查看圖片:圖片也可在OpenSea等第三方NFT市場看到該NFT的圖片。不過我們還有最后一個問題,就是如何在我們自己的頁面上展示用戶創建的NFT。有的同學會想到在頁面調用Card合約的讀方法,依次讀出每個NFT的信息,這種方式會非常慢,因為需要反復多次調用讀方法,且無法實現條件查詢,比如根據地址查詢該地址擁有的NFT,或者創建于一個月內的NFT。因此,我們還需要用到TheGraph提供的數據聚合服務。創建Graph查詢為了創建Graph查詢,我們需要使用TheGraph提供的托管服務。先注冊TheGraph,然后安裝全局命令行工具,只需運行一次:npminstall-g@graphprotocol/graph-cli安裝后可使用命令graph,例如查看版本:$graph--version0.38.0第二步是在TheGraph的HostedService-MyDashboard-AddSubgraph創建一個項目,創建成功后TheGraph顯示狀態為未部署。為了把Subgraph部署上去,我們在本地項目根目錄創建一個subgraph目錄,然后在此目錄下執行命令:$graphinit--producthosted-servicemichaelliao/web3stack注意將登錄名替換為你的GitHub用戶名,將項目名替換為TheGraph上創建的項目名。接下來依次輸入信息:選擇協議的類型:選ethereum;填寫subgraph名稱:用默認的名稱;填寫目錄名:用默認目錄名;選擇鏈:選mumbai;填寫合約地址:填入部署的地址0x8131...1ab0;嘗試自動獲取ABI,一般都能成功;填寫從指定的塊開始:查看合約部署的TX所在塊填入區塊高度;填寫合約名字:與合約代碼保持一致,此處必須為Card;是否索引事件:默認是。接下來會安裝一系列依賴。如果填寫的信息有問題,或者NPM運行出錯,刪掉subgraph目錄再來一遍即可。然后按照提示,先運行graphauth輸入TheGraph給的一個AccessToken,然后進入subgraph/web3stack目錄,運行:npmrundeploy幾秒鐘后,就可以在TheGraph提供的Playground輸入查詢并查看結果:圖片為什么我們可以直接查詢transfers?首先,我們查看schema.graphql,默認有3個Entity,把Entity看作是數據庫表,這3個Entity是TheGraph根據合約定義的Event自動生成的:typeApproval@entity(immutable:true){...}typeApprovalForAll@entity(immutable:true){...}typeTransfer@entity(immutable:true){...}但并不是我們的業務需要的。我們需要的是Card類型,包括owner、image等信息。因此,刪掉自動生成的代碼,換成我們自定義的Card:typeCard@entity(immutable:false){id:String!owner:Bytes!blockNumber:BigInt!blockTimestamp:BigInt!transactionHash:Bytes!image:String!}其中,id是唯一主鍵,這里用NFT的TokenID即可,但類型是String而不是BigInt。接下來,在subgraph.yaml中定義了如何處理事件,需要修改的有兩處,一是entities,刪除原有的3個Entity,換成我們定義的Card:dataSources:-kind:ethereum...mapping:...entities:-Card二是在eventHandlers中刪除我們不關心的Approval和ApprovalForAll事件,僅保留Transfer:dataSources:-kind:ethereum...mapping:...eventHandlers:-event:Transfer(indexedaddress,indexedaddress,indexeduint256)handler:handleTransfer當TheGraph的節點掃描到我們部署的合約產生了Transfer事件后,它將調用handleTransfer處理,這個函數定義在src/card.ts中,自動生成的代碼如下:exportfunctionhandleTransfer(event:TransferEvent):void{letentity=newTransfer(event.transaction.hash.concatI32(event.logIndex.toI32()))entity.from=event.params.fromentity.to=event.params.toentity.tokenId=event.params.tokenIdentity.blockNumber=event.block.numberentity.blockTimestamp=event.block.timestampentity.transactionHash=event.transaction.hashentity.save(。因此,每捕獲到一個Transfer事件,會保存一個Transfer的Entity,這就是我們前面在TheGraph的Playground中能查詢transfers的原因。現在我們不需要Transfer這個Entity,改成Card,先定義Card這個Entity:exportclassCardextendsEntity{...}再修改handleTransfer()的代碼:exportfunctionhandleTransfer(event:TransferEvent):void{lettokenId=event.params.tokenId;letcontract=CardContract.bind(event.address);if(event.params.from.equals(Address.zero())){//如果from=0,表示創建了新的NFT:letnft=newCard(tokenId.toString());nft.owner=event.params.to;nft.image=contract.getImage(tokenId);nft.blockNumber=event.block.number;nft.blockTimestamp=event.block.timestamp;nft.transactionHash=event.transaction.hash;nft.save();}else{//from!=0,表示NFT發生了轉移,需要更新owner和image:letnft=Card.load(tokenId.toString());if(nft===null){log.error('failedloadNFTbytoken:{}',);}else{nft.owner=event.params.to;nft.image=contract.getImage(tokenId);nft.save();}}}再次運行npmrundeploy,我們可以在TheGraph的Playground中查詢到cards:圖片這樣,支持頁面顯示的后端查詢服務就準備就緒。下一步,我們在頁面中添加一點查詢代碼:asyncfunctionquery(){letquery={"query"://輸入為Graph查詢字符串:`{cards(first:20,orderBy:blockTimestamp,orderDirection:desc){idownerimage}}`};//調用jQuery發送POST請求并獲得JSON結果:letopt={type:'POST',dataType:'json',contentType:'application/json',//與Graph服務接口保持一致:url:'https://api.thegraph.com/subgraphs/name/michaelliao/web3stack',data:JSON.stringify(query。;letresult=await$.ajax(opt);letcards=result.data.cards;}拿到查詢結果,我們就能直接在頁面展示:圖片最后一步就是把頁面發布到GitHubPages,然后綁一個域名,就可以讓用戶訪問了:https://web3stack.itranswarp.com至此,一個完整的DApp就開發完畢。FAQQ:可以不用TheGraph,自己寫后端服務嗎?A:可以,很多需求,例如用戶實名認證、發送Email是TheGraph服務無法支持的,必須自己編寫后端服務,配合數據庫實現。Q:可以同時支持多鏈嗎?A:可以,用戶在錢包切換鏈時,DApp可以通過chainChanged事件拿到鏈ID,提前配置好鏈ID與不同鏈的合約地址,就可以正常在不同鏈調用不同合約。Q:可以支持多種錢包嗎?A:可以,需要使用Web3Modal這個庫,能簡化連接多個錢包的代碼。小結從本文給出的完整示例來看,Web3全棧開發,最適合前端開發人員。當年國外有個前端開發叫Hayden,在17年失業了,他決定自學Solidity并花了幾個月的時間為以太坊開發了一個DeFi應用,后來這個應用火爆了,它叫Uniswap。
Web3身份系統Gitcoin Passport推出Scorer API用于防御女巫攻擊:金色財經報道,Web3身份系統Gitcoin Passport宣布已推出Scorer API,開發人員通過該API只需要幾行代碼就可以獲得與Gitcoin Grants等級相同的女巫保護。此外,為了配合Scorer API的發布,官方徹底修改了其開發人員文檔。[2023/2/21 12:19:16]
SAVAGE與三星達成合作,將為Web3用戶提供高質量照片和視頻:1月4日消息,基于Polygon區塊鏈的流媒體應用SAVAGE宣布與三星達成合作,將在Web3中為用戶提供高質量的照片和視頻。SAVAGE智能電視應用可以實現IRL顯示連接,并在任何市場中實現最高畫質的上傳(最高 8K)。[2023/1/4 9:51:25]
Web3游戲和娛樂工作室Heroic Story完成600萬美元種子輪融資:金色財經報道,Web3游戲和娛樂工作室Heroic Story在Upfront Ventures領投的種子輪融資中籌集了600萬美元,Multicoin Capital和Polygon Technology參投,Andreessen Horowitz的Jonathan Lai和Miramax的電影負責人Wolfgang Hammer等天使投資人也參與其中。Heroic Story由Jay和Scott Rosenkrantz兄弟于2019年在Y Combinator成立,旨在為web3時代重新構想類似于龍與地下城的傳統桌面角色扮演游戲(RPG)。[2022/11/18 13:18:48]
Web3娛樂社交應用Melody代幣地址被黑客盜用,團隊暫時關閉提現功能:10月25日消息,Web3娛樂社交應用Melody在官網推特發布提醒,其應用代幣地址已被黑客盜用,請不要相信任何未經證實的信息。目前,相關技術漏洞已經修復,但因維護合約已經暫停體提現等功能。[2022/10/25 16:37:53]
Web3技術基礎設施項目Saito完成200萬美元戰略融資:3月25日消息,Web3 技術基礎設施項目 Saito 宣布完成 200 萬美元融資,領投方為 DFG、Candaq、Spark Digital 和 Block Dream Fund,參投方為 In Blockchain、NGC、Signum、Delean、PAKA、Kernel Ventures、Tripara Ventures、Infinity Labs、Waterdrip、Angel One、OnePiece Capital、Hotbit、 Lotus Capital、PhoenixVC、A195 (Four Seasons)、AU21、Master Ventures、Momtemum 6、BlockSync 等數十家投資機構。
Saito旨在通過Web3開放網絡層讓DApp可以在沒有封閉插件、沒有私有API或在開放基礎設施的情況下運行,同時可以為Saito和其他公鏈中提供路由和用戶基礎設施的節點提供資助。[2021/3/25 19:17:32]
千呼萬喚始出來,早前承諾給XRP持有者發放空投的FlareNetwork終于上線主網,即將兌現空投承諾.
1900/1/1 0:00:00大家都知道思域在我國人氣火爆,不過有很多朋友在購買前又開始糾結了,自己該買哪一款?轎跑還是轎車,抑或是掀背車?如果你不確定這款緊湊型車輛的哪個版本適合你,那么你點進來就對了.
1900/1/1 0:00:00青島啤酒股份3月21日發布盈利警告,公司去年歸于股東凈利潤預計下降39%。而公司2015年的凈利潤為17.13億元人民幣,總營收為256.04億元人民幣.
1900/1/1 0:00:00圖片來源視覺中國 鈦媒體注:FinTech分析及研究公司AutonomousNEXT近日發布了對于區塊鏈領域的ICO現狀的調查報告.
1900/1/1 0:00:00比特幣冷了,玩客幣火了。一個多月的時間,玩客幣漲了80倍,大量投機者涌入這個市場。與此同時,迅雷股價的表現也非常強勁,28個交易日累計上漲394.5%.
1900/1/1 0:00:00本文作者:王默之、wesely視界 摘要: 這篇研究將沿著時間脈絡推演區塊鏈從誕生到發展出當下復雜生態的過程:第一個階段以比特幣的誕生開始,第二個階段以以太坊的誕生紀元.
1900/1/1 0:00:00