本文將詳細介紹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基礎設施Dmail完成Pre-A輪融資:7月24日消息,多鏈Web3基礎設施Dmail Network宣布完成Pre-A輪融資,Amino Capital、OIG VC、Draper Dragon、KuCoin Labs、HG Ventures、Spark Digital Capital、Bixin Ventures、Wagmi Ventures、Gate Labs、Kretos Ventures和Red Swiss等參投。[2023/7/24 15:55:48]
Ava Labs 推出 Web3 無代碼 Launchpad AvaCloud:金色財經報道,Ava Labs 推出 Web3 無代碼 Launchpad AvaCloud,主要包括自動化區塊鏈構建器、托管驗證器、綜合數據工具和鏈互操作性四款工具,旨在幫助企業建立無代碼、完全托管的區塊鏈生態系統。[2023/5/24 22:15:26]
數據:一季度Web3領域攻擊事件總損失金額約2.95億美元,環比下降77%:4月12日消息,據區塊鏈安全審計公司Beosin旗下Beosin EagleEye安全風險監控、預警與阻斷平臺共監測,2023年第一季度,監測到Web3領域主要攻擊事件61起,總損失金額約為2.95億美元,較2022年第4季度下降了約77%。2023年第一季度的總損失金額低于2022年的任何一個季度。除攻擊事件外,2023年第一季度還監測到主要Rug Pull事件41起,涉及金額約2034萬美元。
DeFi為本季度被攻擊頻次最高、損失金額最多的項目類型。42次安全事件總損失金額達到了2.48億美元 ,占總損失金額的84%。80.8%的損失金額來自Ethereum,居所有鏈平臺的第一位。本季度損失金額最高的攻擊手法為閃電貸攻擊,8次閃電貸事件損失約1.98億美元;攻擊手法頻率最高的為合約漏洞利用,27次攻擊占所有事件數量的44%。本季度約有2億美元的被盜資產得以追回。本季度資金追回的情況優于2022年的任何一個季度。被攻擊的項目中,僅有41%的項目經過了審計。[2023/4/12 13:58:53]
火狐瀏覽器開發公司Mozilla收購Active Replica,擬拓展Web3和元宇宙市場:12月4日消息,火狐瀏覽器開發公司Mozilla近日宣布完成對沉浸式體驗開發公司Active Replica公司的收購,擬加速拓展Web3和元宇宙市場,具體收購金額暫未披露。
Active Replica將會加入Mozilla的Hubs創作者平臺,構建個性化訂閱層和元宇宙虛擬活動并在Hubs引擎中加入全新交互功能。此外,Mozilla還宣布收購了機器學習開發公司Pulse。(Cointelegraph)[2022/12/4 21:21:45]
Web3聲譽平臺Noox完成200萬美元種子輪融資:4月9日消息,Web3聲譽平臺Noox完成200萬美元種子輪融資,Collab+Currency領投,ElectricCapital、Sfermion、SamsungNext、POAP和Alphanonce參投。Noox是一個供Web3用戶基于鏈上操作鑄造徽章的平臺。這些徽章將是無法轉讓的靈魂綁定NFT,用戶擁有的NFT就是唯一的標識符,可以作為他們的鏈上身份來解鎖新的機會。該項目計劃在四月底推出帶有Web3個人資料和徽章瀏覽器功能的封閉測試版產品。[2022/4/9 14:13:48]
6月10日午間,加密貨幣市場風云突變。山寨幣普遍出現了10%-40%的跌幅。從OKX跌幅榜上看,可以看到包括LOOKS、TON、CETUS、DASH等多個較知名山寨幣的跌幅均在25%以上.
1900/1/1 0:00:00吳京和彭于晏感情相當要好,并且也在《危城》中合作過,私下以“師兄弟”相稱。彭于晏的探班《戰狼2》照片中,兩人勾肩搭背非常親密.
1900/1/1 0:00:00思域鑰匙更換電池的方法如下: 1、取出機械鑰匙。 2、用硬幣小心撬開邊緣拆下上半部分,撬開汽車鑰匙蓋.
1900/1/1 0:00:00保時捷911這款車我想諸位應該真的是耳熟能詳了,畢竟作為保時捷家族最成功的車型之一,在全球擁有非常龐大的粉絲群體,前幾年經濟條件好的時候.
1900/1/1 0:00:00新京報快訊(記者宓迪金彧)9月15日晚間,被認為國內交易量最大的兩家比特幣交易平臺之火幣網、OKCoin幣行陸續發布公告,宣布停止人民幣交易業務.
1900/1/1 0:00:00“凡大醫治病,必當安神定志向,無欲無求,先發大慈惻隱之心,誓愿普求含靈之苦。”——題記·摘自唐代《大醫精誠》兩次獲得武警部隊“優秀專業人才獎”,享受“特殊崗位津貼”,小針刀針灸脈絡理療術和推拿正.
1900/1/1 0:00:00